Completed
Branch FET/extra-logging-when-trashin... (67e303)
by
unknown
15:01 queued 12:34
created
core/db_classes/EE_Registration.class.php 2 patches
Spacing   +15 added lines, -15 removed lines patch added patch discarded remove patch
@@ -148,7 +148,7 @@  discard block
 block discarded – undo
148 148
     {
149 149
         switch ($field_name) {
150 150
             case 'REG_code':
151
-                if (! empty($field_value) && $this->reg_code() === null) {
151
+                if ( ! empty($field_value) && $this->reg_code() === null) {
152 152
                     $this->set_reg_code($field_value, $use_default);
153 153
                 }
154 154
                 break;
@@ -449,7 +449,7 @@  discard block
 block discarded – undo
449 449
     public function event()
450 450
     {
451 451
         $event = $this->get_first_related('Event');
452
-        if (! $event instanceof \EE_Event) {
452
+        if ( ! $event instanceof \EE_Event) {
453 453
             throw new EntityNotFoundException('Event ID', $this->event_ID());
454 454
         }
455 455
         return $event;
@@ -496,7 +496,7 @@  discard block
 block discarded – undo
496 496
     {
497 497
         // reserved ticket and datetime counts will be decremented as sold counts are incremented
498 498
         // so stop tracking that this reg has a ticket reserved
499
-        $this->release_reserved_ticket(false, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
499
+        $this->release_reserved_ticket(false, "REG: {$this->ID()} (ln:".__LINE__.')');
500 500
         $ticket = $this->ticket();
501 501
         $ticket->increaseSold();
502 502
         // possibly set event status to sold out
@@ -546,7 +546,7 @@  discard block
 block discarded – undo
546 546
             $reserved = $this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true);
547 547
             if ($reserved && $update_ticket) {
548 548
                 $ticket = $this->ticket();
549
-                $ticket->increaseReserved(1, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
549
+                $ticket->increaseReserved(1, "REG: {$this->ID()} (ln:".__LINE__.')');
550 550
                 $this->update_extra_meta('reserve_ticket', "{$this->ticket_ID()} from {$source}");
551 551
                 $ticket->save();
552 552
             }
@@ -574,7 +574,7 @@  discard block
 block discarded – undo
574 574
             $reserved = $this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, false);
575 575
             if ($reserved && $update_ticket) {
576 576
                 $ticket = $this->ticket();
577
-                $ticket->decreaseReserved(1, true, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
577
+                $ticket->decreaseReserved(1, true, "REG: {$this->ID()} (ln:".__LINE__.')');
578 578
                 $this->update_extra_meta('release_reserved_ticket', "{$this->ticket_ID()} from {$source}");
579 579
             }
580 580
         }
@@ -1460,7 +1460,7 @@  discard block
 block discarded – undo
1460 1460
                     : '';
1461 1461
                 break;
1462 1462
         }
1463
-        return $icon . $status[ $this->status_ID() ];
1463
+        return $icon.$status[$this->status_ID()];
1464 1464
     }
1465 1465
 
1466 1466
 
@@ -1716,7 +1716,7 @@  discard block
 block discarded – undo
1716 1716
     {
1717 1717
         $DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1718 1718
         // first check registration status
1719
-        if (! $DTT_ID || ($check_approved && ! $this->is_approved())) {
1719
+        if ( ! $DTT_ID || ($check_approved && ! $this->is_approved())) {
1720 1720
             return false;
1721 1721
         }
1722 1722
         // is there a datetime ticket that matches this dtt_ID?
@@ -1756,7 +1756,7 @@  discard block
 block discarded – undo
1756 1756
     {
1757 1757
         $DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1758 1758
 
1759
-        if (! $DTT_ID) {
1759
+        if ( ! $DTT_ID) {
1760 1760
             return false;
1761 1761
         }
1762 1762
 
@@ -1764,7 +1764,7 @@  discard block
 block discarded – undo
1764 1764
 
1765 1765
         // if max uses is not set or equals infinity then return true cause its not a factor for whether user can
1766 1766
         // check-in or not.
1767
-        if (! $max_uses || $max_uses === EE_INF) {
1767
+        if ( ! $max_uses || $max_uses === EE_INF) {
1768 1768
             return true;
1769 1769
         }
1770 1770
 
@@ -1828,7 +1828,7 @@  discard block
 block discarded – undo
1828 1828
             $datetime = $this->get_latest_related_datetime();
1829 1829
             $DTT_ID = $datetime instanceof EE_Datetime ? $datetime->ID() : 0;
1830 1830
             // verify the registration can checkin for the given DTT_ID
1831
-        } elseif (! $this->can_checkin($DTT_ID, $verify)) {
1831
+        } elseif ( ! $this->can_checkin($DTT_ID, $verify)) {
1832 1832
             EE_Error::add_error(
1833 1833
                 sprintf(
1834 1834
                     esc_html__(
@@ -1851,7 +1851,7 @@  discard block
 block discarded – undo
1851 1851
         );
1852 1852
         // start by getting the current status so we know what status we'll be changing to.
1853 1853
         $cur_status = $this->check_in_status_for_datetime($DTT_ID);
1854
-        $status_to = $status_paths[ $cur_status ];
1854
+        $status_to = $status_paths[$cur_status];
1855 1855
         // database only records true for checked IN or false for checked OUT
1856 1856
         // no record ( null ) means checked in NEVER, but we obviously don't save that
1857 1857
         $new_status = $status_to === EE_Checkin::status_checked_in;
@@ -2042,7 +2042,7 @@  discard block
 block discarded – undo
2042 2042
     public function transaction()
2043 2043
     {
2044 2044
         $transaction = $this->get_first_related('Transaction');
2045
-        if (! $transaction instanceof \EE_Transaction) {
2045
+        if ( ! $transaction instanceof \EE_Transaction) {
2046 2046
             throw new EntityNotFoundException('Transaction ID', $this->transaction_ID());
2047 2047
         }
2048 2048
         return $transaction;
@@ -2115,11 +2115,11 @@  discard block
 block discarded – undo
2115 2115
             );
2116 2116
             return;
2117 2117
         }
2118
-        if (! $this->reg_code()) {
2118
+        if ( ! $this->reg_code()) {
2119 2119
             parent::set('REG_code', $REG_code, $use_default);
2120 2120
         } else {
2121 2121
             EE_Error::doing_it_wrong(
2122
-                __CLASS__ . '::' . __FUNCTION__,
2122
+                __CLASS__.'::'.__FUNCTION__,
2123 2123
                 esc_html__('Can not change a registration REG_code once it has been set.', 'event_espresso'),
2124 2124
                 '4.6.0'
2125 2125
             );
@@ -2310,7 +2310,7 @@  discard block
 block discarded – undo
2310 2310
                 break;
2311 2311
             }
2312 2312
         }
2313
-        if (! ($line_item instanceof \EE_Line_Item && $line_item->OBJ_type() === 'Ticket')) {
2313
+        if ( ! ($line_item instanceof \EE_Line_Item && $line_item->OBJ_type() === 'Ticket')) {
2314 2314
             throw new EntityNotFoundException('Line Item Ticket ID', $ticket->ID());
2315 2315
         }
2316 2316
         return $line_item;
Please login to merge, or discard this patch.
Indentation   +2499 added lines, -2499 removed lines patch added patch discarded remove patch
@@ -16,2503 +16,2503 @@
 block discarded – undo
16 16
  */
17 17
 class EE_Registration extends EE_Soft_Delete_Base_Class implements EEI_Registration, EEI_Admin_Links
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
-    /**
59
-     * @param array  $props_n_values          incoming values
60
-     * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
61
-     *                                        used.)
62
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
63
-     *                                        date_format and the second value is the time format
64
-     * @return EE_Registration
65
-     * @throws EE_Error
66
-     * @throws InvalidArgumentException
67
-     * @throws InvalidDataTypeException
68
-     * @throws InvalidInterfaceException
69
-     * @throws ReflectionException
70
-     */
71
-    public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
72
-    {
73
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
74
-        return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
75
-    }
76
-
77
-
78
-    /**
79
-     * @param array  $props_n_values  incoming values from the database
80
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
81
-     *                                the website will be used.
82
-     * @return EE_Registration
83
-     * @throws EE_Error
84
-     * @throws InvalidArgumentException
85
-     * @throws InvalidDataTypeException
86
-     * @throws InvalidInterfaceException
87
-     * @throws ReflectionException
88
-     */
89
-    public static function new_instance_from_db($props_n_values = array(), $timezone = null)
90
-    {
91
-        return new self($props_n_values, true, $timezone);
92
-    }
93
-
94
-
95
-    /**
96
-     *        Set Event ID
97
-     *
98
-     * @param        int $EVT_ID Event ID
99
-     * @throws DomainException
100
-     * @throws EE_Error
101
-     * @throws EntityNotFoundException
102
-     * @throws InvalidArgumentException
103
-     * @throws InvalidDataTypeException
104
-     * @throws InvalidInterfaceException
105
-     * @throws ReflectionException
106
-     * @throws RuntimeException
107
-     * @throws UnexpectedEntityException
108
-     */
109
-    public function set_event($EVT_ID = 0)
110
-    {
111
-        $this->set('EVT_ID', $EVT_ID);
112
-    }
113
-
114
-
115
-    /**
116
-     * Overrides parent set() method so that all calls to set( 'REG_code', $REG_code ) OR set( 'STS_ID', $STS_ID ) can
117
-     * be routed to internal methods
118
-     *
119
-     * @param string $field_name
120
-     * @param mixed  $field_value
121
-     * @param bool   $use_default
122
-     * @throws DomainException
123
-     * @throws EE_Error
124
-     * @throws EntityNotFoundException
125
-     * @throws InvalidArgumentException
126
-     * @throws InvalidDataTypeException
127
-     * @throws InvalidInterfaceException
128
-     * @throws ReflectionException
129
-     * @throws RuntimeException
130
-     * @throws UnexpectedEntityException
131
-     */
132
-    public function set($field_name, $field_value, $use_default = false)
133
-    {
134
-        switch ($field_name) {
135
-            case 'REG_code':
136
-                if (! empty($field_value) && $this->reg_code() === null) {
137
-                    $this->set_reg_code($field_value, $use_default);
138
-                }
139
-                break;
140
-            case 'STS_ID':
141
-                $this->set_status($field_value, $use_default);
142
-                break;
143
-            default:
144
-                parent::set($field_name, $field_value, $use_default);
145
-        }
146
-    }
147
-
148
-
149
-    /**
150
-     * Set Status ID
151
-     * updates the registration status and ALSO...
152
-     * calls reserve_registration_space() if the reg status changes TO approved from any other reg status
153
-     * calls release_registration_space() if the reg status changes FROM approved to any other reg status
154
-     *
155
-     * @param string                $new_STS_ID
156
-     * @param boolean               $use_default
157
-     * @param ContextInterface|null $context
158
-     * @return bool
159
-     * @throws DomainException
160
-     * @throws EE_Error
161
-     * @throws EntityNotFoundException
162
-     * @throws InvalidArgumentException
163
-     * @throws InvalidDataTypeException
164
-     * @throws InvalidInterfaceException
165
-     * @throws ReflectionException
166
-     * @throws RuntimeException
167
-     * @throws UnexpectedEntityException
168
-     */
169
-    public function set_status($new_STS_ID = null, $use_default = false, ContextInterface $context = null)
170
-    {
171
-        // get current REG_Status
172
-        $old_STS_ID = $this->status_ID();
173
-        // if status has changed
174
-        if (
175
-            $old_STS_ID !== $new_STS_ID // and that status has actually changed
176
-            && ! empty($old_STS_ID) // and that old status is actually set
177
-            && ! empty($new_STS_ID) // as well as the new status
178
-            && $this->ID() // ensure registration is in the db
179
-        ) {
180
-            // update internal status first
181
-            parent::set('STS_ID', $new_STS_ID, $use_default);
182
-            // THEN handle other changes that occur when reg status changes
183
-            // TO approved
184
-            if ($new_STS_ID === EEM_Registration::status_id_approved) {
185
-                // reserve a space by incrementing ticket and datetime sold values
186
-                $this->reserveRegistrationSpace();
187
-                do_action('AHEE__EE_Registration__set_status__to_approved', $this, $old_STS_ID, $new_STS_ID, $context);
188
-                // OR FROM  approved
189
-            } elseif ($old_STS_ID === EEM_Registration::status_id_approved) {
190
-                // release a space by decrementing ticket and datetime sold values
191
-                $this->releaseRegistrationSpace();
192
-                do_action(
193
-                    'AHEE__EE_Registration__set_status__from_approved',
194
-                    $this,
195
-                    $old_STS_ID,
196
-                    $new_STS_ID,
197
-                    $context
198
-                );
199
-            }
200
-            // update status
201
-            parent::set('STS_ID', $new_STS_ID, $use_default);
202
-            $this->updateIfCanceledOrReinstated($new_STS_ID, $old_STS_ID, $context);
203
-            if ($this->statusChangeUpdatesTransaction($context)) {
204
-                $this->updateTransactionAfterStatusChange();
205
-            }
206
-            do_action('AHEE__EE_Registration__set_status__after_update', $this, $old_STS_ID, $new_STS_ID, $context);
207
-            return true;
208
-        }
209
-        // even though the old value matches the new value, it's still good to
210
-        // allow the parent set method to have a say
211
-        parent::set('STS_ID', $new_STS_ID, $use_default);
212
-        return true;
213
-    }
214
-
215
-
216
-    /**
217
-     * update REGs and TXN when cancelled or declined registrations involved
218
-     *
219
-     * @param string                $new_STS_ID
220
-     * @param string                $old_STS_ID
221
-     * @param ContextInterface|null $context
222
-     * @throws EE_Error
223
-     * @throws InvalidArgumentException
224
-     * @throws InvalidDataTypeException
225
-     * @throws InvalidInterfaceException
226
-     * @throws ReflectionException
227
-     * @throws RuntimeException
228
-     */
229
-    private function updateIfCanceledOrReinstated($new_STS_ID, $old_STS_ID, ContextInterface $context = null)
230
-    {
231
-        // these reg statuses should not be considered in any calculations involving monies owing
232
-        $closed_reg_statuses = EEM_Registration::closed_reg_statuses();
233
-        // true if registration has been cancelled or declined
234
-        $this->updateIfCanceled(
235
-            $closed_reg_statuses,
236
-            $new_STS_ID,
237
-            $old_STS_ID,
238
-            $context
239
-        );
240
-        $this->updateIfReinstated(
241
-            $closed_reg_statuses,
242
-            $new_STS_ID,
243
-            $old_STS_ID,
244
-            $context
245
-        );
246
-    }
247
-
248
-
249
-    /**
250
-     * update REGs and TXN when cancelled or declined registrations involved
251
-     *
252
-     * @param array                 $closed_reg_statuses
253
-     * @param string                $new_STS_ID
254
-     * @param string                $old_STS_ID
255
-     * @param ContextInterface|null $context
256
-     * @throws EE_Error
257
-     * @throws InvalidArgumentException
258
-     * @throws InvalidDataTypeException
259
-     * @throws InvalidInterfaceException
260
-     * @throws ReflectionException
261
-     * @throws RuntimeException
262
-     */
263
-    private function updateIfCanceled(
264
-        array $closed_reg_statuses,
265
-        $new_STS_ID,
266
-        $old_STS_ID,
267
-        ContextInterface $context = null
268
-    ) {
269
-        // true if registration has been cancelled or declined
270
-        if (
271
-            in_array($new_STS_ID, $closed_reg_statuses, true)
272
-            && ! in_array($old_STS_ID, $closed_reg_statuses, true)
273
-        ) {
274
-            /** @type EE_Registration_Processor $registration_processor */
275
-            $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
276
-            /** @type EE_Transaction_Processor $transaction_processor */
277
-            $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
278
-            // cancelled or declined registration
279
-            $registration_processor->update_registration_after_being_canceled_or_declined(
280
-                $this,
281
-                $closed_reg_statuses
282
-            );
283
-            $transaction_processor->update_transaction_after_canceled_or_declined_registration(
284
-                $this,
285
-                $closed_reg_statuses,
286
-                false
287
-            );
288
-            do_action(
289
-                'AHEE__EE_Registration__set_status__canceled_or_declined',
290
-                $this,
291
-                $old_STS_ID,
292
-                $new_STS_ID,
293
-                $context
294
-            );
295
-            return;
296
-        }
297
-    }
298
-
299
-
300
-    /**
301
-     * update REGs and TXN when cancelled or declined registrations involved
302
-     *
303
-     * @param array                 $closed_reg_statuses
304
-     * @param string                $new_STS_ID
305
-     * @param string                $old_STS_ID
306
-     * @param ContextInterface|null $context
307
-     * @throws EE_Error
308
-     * @throws InvalidArgumentException
309
-     * @throws InvalidDataTypeException
310
-     * @throws InvalidInterfaceException
311
-     * @throws ReflectionException
312
-     * @throws RuntimeException
313
-     */
314
-    private function updateIfReinstated(
315
-        array $closed_reg_statuses,
316
-        $new_STS_ID,
317
-        $old_STS_ID,
318
-        ContextInterface $context = null
319
-    ) {
320
-        // true if reinstating cancelled or declined registration
321
-        if (
322
-            in_array($old_STS_ID, $closed_reg_statuses, true)
323
-            && ! in_array($new_STS_ID, $closed_reg_statuses, true)
324
-        ) {
325
-            /** @type EE_Registration_Processor $registration_processor */
326
-            $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
327
-            /** @type EE_Transaction_Processor $transaction_processor */
328
-            $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
329
-            // reinstating cancelled or declined registration
330
-            $registration_processor->update_canceled_or_declined_registration_after_being_reinstated(
331
-                $this,
332
-                $closed_reg_statuses
333
-            );
334
-            $transaction_processor->update_transaction_after_reinstating_canceled_registration(
335
-                $this,
336
-                $closed_reg_statuses,
337
-                false
338
-            );
339
-            do_action(
340
-                'AHEE__EE_Registration__set_status__after_reinstated',
341
-                $this,
342
-                $old_STS_ID,
343
-                $new_STS_ID,
344
-                $context
345
-            );
346
-        }
347
-    }
348
-
349
-
350
-    /**
351
-     * @param ContextInterface|null $context
352
-     * @return bool
353
-     */
354
-    private function statusChangeUpdatesTransaction(ContextInterface $context = null)
355
-    {
356
-        $contexts_that_do_not_update_transaction = (array) apply_filters(
357
-            'AHEE__EE_Registration__statusChangeUpdatesTransaction__contexts_that_do_not_update_transaction',
358
-            array('spco_reg_step_attendee_information_process_registrations'),
359
-            $context,
360
-            $this
361
-        );
362
-        return ! (
363
-            $context instanceof ContextInterface
364
-            && in_array($context->slug(), $contexts_that_do_not_update_transaction, true)
365
-        );
366
-    }
367
-
368
-
369
-    /**
370
-     * @throws EE_Error
371
-     * @throws EntityNotFoundException
372
-     * @throws InvalidArgumentException
373
-     * @throws InvalidDataTypeException
374
-     * @throws InvalidInterfaceException
375
-     * @throws ReflectionException
376
-     * @throws RuntimeException
377
-     */
378
-    private function updateTransactionAfterStatusChange()
379
-    {
380
-        /** @type EE_Transaction_Payments $transaction_payments */
381
-        $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
382
-        $transaction_payments->recalculate_transaction_total($this->transaction(), false);
383
-        $this->transaction()->update_status_based_on_total_paid();
384
-    }
385
-
386
-
387
-    /**
388
-     * get Status ID
389
-     *
390
-     * @throws EE_Error
391
-     * @throws InvalidArgumentException
392
-     * @throws InvalidDataTypeException
393
-     * @throws InvalidInterfaceException
394
-     * @throws ReflectionException
395
-     */
396
-    public function status_ID()
397
-    {
398
-        return $this->get('STS_ID');
399
-    }
400
-
401
-
402
-    /**
403
-     * Gets the ticket this registration is for
404
-     *
405
-     * @param boolean $include_archived whether to include archived tickets or not.
406
-     * @return EE_Ticket|EE_Base_Class
407
-     * @throws EE_Error
408
-     * @throws InvalidArgumentException
409
-     * @throws InvalidDataTypeException
410
-     * @throws InvalidInterfaceException
411
-     * @throws ReflectionException
412
-     */
413
-    public function ticket($include_archived = true)
414
-    {
415
-        $query_params = array();
416
-        if ($include_archived) {
417
-            $query_params['default_where_conditions'] = 'none';
418
-        }
419
-        return $this->get_first_related('Ticket', $query_params);
420
-    }
421
-
422
-
423
-    /**
424
-     * Gets the event this registration is for
425
-     *
426
-     * @return EE_Event
427
-     * @throws EE_Error
428
-     * @throws EntityNotFoundException
429
-     * @throws InvalidArgumentException
430
-     * @throws InvalidDataTypeException
431
-     * @throws InvalidInterfaceException
432
-     * @throws ReflectionException
433
-     */
434
-    public function event()
435
-    {
436
-        $event = $this->get_first_related('Event');
437
-        if (! $event instanceof \EE_Event) {
438
-            throw new EntityNotFoundException('Event ID', $this->event_ID());
439
-        }
440
-        return $event;
441
-    }
442
-
443
-
444
-    /**
445
-     * Gets the "author" of the registration.  Note that for the purposes of registrations, the author will correspond
446
-     * with the author of the event this registration is for.
447
-     *
448
-     * @since 4.5.0
449
-     * @return int
450
-     * @throws EE_Error
451
-     * @throws EntityNotFoundException
452
-     * @throws InvalidArgumentException
453
-     * @throws InvalidDataTypeException
454
-     * @throws InvalidInterfaceException
455
-     * @throws ReflectionException
456
-     */
457
-    public function wp_user()
458
-    {
459
-        $event = $this->event();
460
-        if ($event instanceof EE_Event) {
461
-            return $event->wp_user();
462
-        }
463
-        return 0;
464
-    }
465
-
466
-
467
-    /**
468
-     * increments this registration's related ticket sold and corresponding datetime sold values
469
-     *
470
-     * @return void
471
-     * @throws DomainException
472
-     * @throws EE_Error
473
-     * @throws EntityNotFoundException
474
-     * @throws InvalidArgumentException
475
-     * @throws InvalidDataTypeException
476
-     * @throws InvalidInterfaceException
477
-     * @throws ReflectionException
478
-     * @throws UnexpectedEntityException
479
-     */
480
-    private function reserveRegistrationSpace()
481
-    {
482
-        // reserved ticket and datetime counts will be decremented as sold counts are incremented
483
-        // so stop tracking that this reg has a ticket reserved
484
-        $this->release_reserved_ticket(false, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
485
-        $ticket = $this->ticket();
486
-        $ticket->increaseSold();
487
-        // possibly set event status to sold out
488
-        $this->event()->perform_sold_out_status_check();
489
-    }
490
-
491
-
492
-    /**
493
-     * decrements (subtracts) this registration's related ticket sold and corresponding datetime sold values
494
-     *
495
-     * @return void
496
-     * @throws DomainException
497
-     * @throws EE_Error
498
-     * @throws EntityNotFoundException
499
-     * @throws InvalidArgumentException
500
-     * @throws InvalidDataTypeException
501
-     * @throws InvalidInterfaceException
502
-     * @throws ReflectionException
503
-     * @throws UnexpectedEntityException
504
-     */
505
-    private function releaseRegistrationSpace()
506
-    {
507
-        $ticket = $this->ticket();
508
-        $ticket->decreaseSold();
509
-        // possibly change event status from sold out back to previous status
510
-        $this->event()->perform_sold_out_status_check();
511
-    }
512
-
513
-
514
-    /**
515
-     * tracks this registration's ticket reservation in extra meta
516
-     * and can increment related ticket reserved and corresponding datetime reserved values
517
-     *
518
-     * @param bool   $update_ticket if true, will increment ticket and datetime reserved count
519
-     * @param string $source
520
-     * @return void
521
-     * @throws EE_Error
522
-     * @throws InvalidArgumentException
523
-     * @throws InvalidDataTypeException
524
-     * @throws InvalidInterfaceException
525
-     * @throws ReflectionException
526
-     */
527
-    public function reserve_ticket($update_ticket = false, $source = 'unknown')
528
-    {
529
-        // only reserve ticket if space is not currently reserved
530
-        if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) !== true) {
531
-            $reserved = $this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true);
532
-            if ($reserved && $update_ticket) {
533
-                $ticket = $this->ticket();
534
-                $ticket->increaseReserved(1, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
535
-                $this->update_extra_meta('reserve_ticket', "{$this->ticket_ID()} from {$source}");
536
-                $ticket->save();
537
-            }
538
-        }
539
-    }
540
-
541
-
542
-    /**
543
-     * stops tracking this registration's ticket reservation in extra meta
544
-     * decrements (subtracts) related ticket reserved and corresponding datetime reserved values
545
-     *
546
-     * @param bool   $update_ticket if true, will decrement ticket and datetime reserved count
547
-     * @param string $source
548
-     * @return void
549
-     * @throws EE_Error
550
-     * @throws InvalidArgumentException
551
-     * @throws InvalidDataTypeException
552
-     * @throws InvalidInterfaceException
553
-     * @throws ReflectionException
554
-     */
555
-    public function release_reserved_ticket($update_ticket = false, $source = 'unknown')
556
-    {
557
-        // only release ticket if space is currently reserved
558
-        if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) === true) {
559
-            $reserved = $this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, false);
560
-            if ($reserved && $update_ticket) {
561
-                $ticket = $this->ticket();
562
-                $ticket->decreaseReserved(1, true, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
563
-                $this->update_extra_meta('release_reserved_ticket', "{$this->ticket_ID()} from {$source}");
564
-            }
565
-        }
566
-    }
567
-
568
-
569
-    /**
570
-     * Set Attendee ID
571
-     *
572
-     * @param        int $ATT_ID Attendee ID
573
-     * @throws DomainException
574
-     * @throws EE_Error
575
-     * @throws EntityNotFoundException
576
-     * @throws InvalidArgumentException
577
-     * @throws InvalidDataTypeException
578
-     * @throws InvalidInterfaceException
579
-     * @throws ReflectionException
580
-     * @throws RuntimeException
581
-     * @throws UnexpectedEntityException
582
-     */
583
-    public function set_attendee_id($ATT_ID = 0)
584
-    {
585
-        $this->set('ATT_ID', $ATT_ID);
586
-    }
587
-
588
-
589
-    /**
590
-     *        Set Transaction ID
591
-     *
592
-     * @param        int $TXN_ID Transaction ID
593
-     * @throws DomainException
594
-     * @throws EE_Error
595
-     * @throws EntityNotFoundException
596
-     * @throws InvalidArgumentException
597
-     * @throws InvalidDataTypeException
598
-     * @throws InvalidInterfaceException
599
-     * @throws ReflectionException
600
-     * @throws RuntimeException
601
-     * @throws UnexpectedEntityException
602
-     */
603
-    public function set_transaction_id($TXN_ID = 0)
604
-    {
605
-        $this->set('TXN_ID', $TXN_ID);
606
-    }
607
-
608
-
609
-    /**
610
-     *        Set Session
611
-     *
612
-     * @param    string $REG_session PHP Session ID
613
-     * @throws DomainException
614
-     * @throws EE_Error
615
-     * @throws EntityNotFoundException
616
-     * @throws InvalidArgumentException
617
-     * @throws InvalidDataTypeException
618
-     * @throws InvalidInterfaceException
619
-     * @throws ReflectionException
620
-     * @throws RuntimeException
621
-     * @throws UnexpectedEntityException
622
-     */
623
-    public function set_session($REG_session = '')
624
-    {
625
-        $this->set('REG_session', $REG_session);
626
-    }
627
-
628
-
629
-    /**
630
-     *        Set Registration URL Link
631
-     *
632
-     * @param    string $REG_url_link Registration URL Link
633
-     * @throws DomainException
634
-     * @throws EE_Error
635
-     * @throws EntityNotFoundException
636
-     * @throws InvalidArgumentException
637
-     * @throws InvalidDataTypeException
638
-     * @throws InvalidInterfaceException
639
-     * @throws ReflectionException
640
-     * @throws RuntimeException
641
-     * @throws UnexpectedEntityException
642
-     */
643
-    public function set_reg_url_link($REG_url_link = '')
644
-    {
645
-        $this->set('REG_url_link', $REG_url_link);
646
-    }
647
-
648
-
649
-    /**
650
-     *        Set Attendee Counter
651
-     *
652
-     * @param        int $REG_count Primary Attendee
653
-     * @throws DomainException
654
-     * @throws EE_Error
655
-     * @throws EntityNotFoundException
656
-     * @throws InvalidArgumentException
657
-     * @throws InvalidDataTypeException
658
-     * @throws InvalidInterfaceException
659
-     * @throws ReflectionException
660
-     * @throws RuntimeException
661
-     * @throws UnexpectedEntityException
662
-     */
663
-    public function set_count($REG_count = 1)
664
-    {
665
-        $this->set('REG_count', $REG_count);
666
-    }
667
-
668
-
669
-    /**
670
-     *        Set Group Size
671
-     *
672
-     * @param        boolean $REG_group_size Group Registration
673
-     * @throws DomainException
674
-     * @throws EE_Error
675
-     * @throws EntityNotFoundException
676
-     * @throws InvalidArgumentException
677
-     * @throws InvalidDataTypeException
678
-     * @throws InvalidInterfaceException
679
-     * @throws ReflectionException
680
-     * @throws RuntimeException
681
-     * @throws UnexpectedEntityException
682
-     */
683
-    public function set_group_size($REG_group_size = false)
684
-    {
685
-        $this->set('REG_group_size', $REG_group_size);
686
-    }
687
-
688
-
689
-    /**
690
-     *    is_not_approved -  convenience method that returns TRUE if REG status ID ==
691
-     *    EEM_Registration::status_id_not_approved
692
-     *
693
-     * @return        boolean
694
-     * @throws EE_Error
695
-     * @throws InvalidArgumentException
696
-     * @throws InvalidDataTypeException
697
-     * @throws InvalidInterfaceException
698
-     * @throws ReflectionException
699
-     */
700
-    public function is_not_approved()
701
-    {
702
-        return $this->status_ID() === EEM_Registration::status_id_not_approved;
703
-    }
704
-
705
-
706
-    /**
707
-     *    is_pending_payment -  convenience method that returns TRUE if REG status ID ==
708
-     *    EEM_Registration::status_id_pending_payment
709
-     *
710
-     * @return        boolean
711
-     * @throws EE_Error
712
-     * @throws InvalidArgumentException
713
-     * @throws InvalidDataTypeException
714
-     * @throws InvalidInterfaceException
715
-     * @throws ReflectionException
716
-     */
717
-    public function is_pending_payment()
718
-    {
719
-        return $this->status_ID() === EEM_Registration::status_id_pending_payment;
720
-    }
721
-
722
-
723
-    /**
724
-     *    is_approved -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_approved
725
-     *
726
-     * @return        boolean
727
-     * @throws EE_Error
728
-     * @throws InvalidArgumentException
729
-     * @throws InvalidDataTypeException
730
-     * @throws InvalidInterfaceException
731
-     * @throws ReflectionException
732
-     */
733
-    public function is_approved()
734
-    {
735
-        return $this->status_ID() === EEM_Registration::status_id_approved;
736
-    }
737
-
738
-
739
-    /**
740
-     *    is_cancelled -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_cancelled
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_cancelled()
750
-    {
751
-        return $this->status_ID() === EEM_Registration::status_id_cancelled;
752
-    }
753
-
754
-
755
-    /**
756
-     *    is_declined -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_declined
757
-     *
758
-     * @return        boolean
759
-     * @throws EE_Error
760
-     * @throws InvalidArgumentException
761
-     * @throws InvalidDataTypeException
762
-     * @throws InvalidInterfaceException
763
-     * @throws ReflectionException
764
-     */
765
-    public function is_declined()
766
-    {
767
-        return $this->status_ID() === EEM_Registration::status_id_declined;
768
-    }
769
-
770
-
771
-    /**
772
-     *    is_incomplete -  convenience method that returns TRUE if REG status ID ==
773
-     *    EEM_Registration::status_id_incomplete
774
-     *
775
-     * @return        boolean
776
-     * @throws EE_Error
777
-     * @throws InvalidArgumentException
778
-     * @throws InvalidDataTypeException
779
-     * @throws InvalidInterfaceException
780
-     * @throws ReflectionException
781
-     */
782
-    public function is_incomplete()
783
-    {
784
-        return $this->status_ID() === EEM_Registration::status_id_incomplete;
785
-    }
786
-
787
-
788
-    /**
789
-     *        Set Registration Date
790
-     *
791
-     * @param        mixed ( int or string ) $REG_date Registration Date - Unix timestamp or string representation of
792
-     *                                                 Date
793
-     * @throws DomainException
794
-     * @throws EE_Error
795
-     * @throws EntityNotFoundException
796
-     * @throws InvalidArgumentException
797
-     * @throws InvalidDataTypeException
798
-     * @throws InvalidInterfaceException
799
-     * @throws ReflectionException
800
-     * @throws RuntimeException
801
-     * @throws UnexpectedEntityException
802
-     */
803
-    public function set_reg_date($REG_date = false)
804
-    {
805
-        $this->set('REG_date', $REG_date);
806
-    }
807
-
808
-
809
-    /**
810
-     *    Set final price owing for this registration after all ticket/price modifications
811
-     *
812
-     * @param    float $REG_final_price
813
-     * @throws DomainException
814
-     * @throws EE_Error
815
-     * @throws EntityNotFoundException
816
-     * @throws InvalidArgumentException
817
-     * @throws InvalidDataTypeException
818
-     * @throws InvalidInterfaceException
819
-     * @throws ReflectionException
820
-     * @throws RuntimeException
821
-     * @throws UnexpectedEntityException
822
-     */
823
-    public function set_final_price($REG_final_price = 0.00)
824
-    {
825
-        $this->set('REG_final_price', $REG_final_price);
826
-    }
827
-
828
-
829
-    /**
830
-     *    Set amount paid towards this registration's final price
831
-     *
832
-     * @param    float $REG_paid
833
-     * @throws DomainException
834
-     * @throws EE_Error
835
-     * @throws EntityNotFoundException
836
-     * @throws InvalidArgumentException
837
-     * @throws InvalidDataTypeException
838
-     * @throws InvalidInterfaceException
839
-     * @throws ReflectionException
840
-     * @throws RuntimeException
841
-     * @throws UnexpectedEntityException
842
-     */
843
-    public function set_paid($REG_paid = 0.00)
844
-    {
845
-        $this->set('REG_paid', $REG_paid);
846
-    }
847
-
848
-
849
-    /**
850
-     *        Attendee Is Going
851
-     *
852
-     * @param        boolean $REG_att_is_going Attendee Is Going
853
-     * @throws DomainException
854
-     * @throws EE_Error
855
-     * @throws EntityNotFoundException
856
-     * @throws InvalidArgumentException
857
-     * @throws InvalidDataTypeException
858
-     * @throws InvalidInterfaceException
859
-     * @throws ReflectionException
860
-     * @throws RuntimeException
861
-     * @throws UnexpectedEntityException
862
-     */
863
-    public function set_att_is_going($REG_att_is_going = false)
864
-    {
865
-        $this->set('REG_att_is_going', $REG_att_is_going);
866
-    }
867
-
868
-
869
-    /**
870
-     * Gets the related attendee
871
-     *
872
-     * @return EE_Attendee|EE_Base_Class
873
-     * @throws EE_Error
874
-     * @throws InvalidArgumentException
875
-     * @throws InvalidDataTypeException
876
-     * @throws InvalidInterfaceException
877
-     * @throws ReflectionException
878
-     */
879
-    public function attendee()
880
-    {
881
-        return $this->get_first_related('Attendee');
882
-    }
883
-
884
-    /**
885
-     * Gets the name of the attendee.
886
-     * @since 4.10.12.p
887
-     * @param bool $apply_html_entities set to true if you want to use HTML entities.
888
-     * @return string
889
-     * @throws EE_Error
890
-     * @throws InvalidArgumentException
891
-     * @throws InvalidDataTypeException
892
-     * @throws InvalidInterfaceException
893
-     * @throws ReflectionException
894
-     */
895
-    public function attendeeName($apply_html_entities = false)
896
-    {
897
-        $attendee = $this->get_first_related('Attendee');
898
-        if ($attendee instanceof EE_Attendee) {
899
-            $attendee_name = $attendee->full_name($apply_html_entities);
900
-        } else {
901
-            $attendee_name = esc_html__('Unknown', 'event_espresso');
902
-        }
903
-        return $attendee_name;
904
-    }
905
-
906
-
907
-    /**
908
-     *        get Event ID
909
-     */
910
-    public function event_ID()
911
-    {
912
-        return $this->get('EVT_ID');
913
-    }
914
-
915
-
916
-    /**
917
-     *        get Event ID
918
-     */
919
-    public function event_name()
920
-    {
921
-        $event = $this->event_obj();
922
-        if ($event) {
923
-            return $event->name();
924
-        } else {
925
-            return null;
926
-        }
927
-    }
928
-
929
-
930
-    /**
931
-     * Fetches the event this registration is for
932
-     *
933
-     * @return EE_Base_Class|EE_Event
934
-     * @throws EE_Error
935
-     * @throws InvalidArgumentException
936
-     * @throws InvalidDataTypeException
937
-     * @throws InvalidInterfaceException
938
-     * @throws ReflectionException
939
-     */
940
-    public function event_obj()
941
-    {
942
-        return $this->get_first_related('Event');
943
-    }
944
-
945
-
946
-    /**
947
-     *        get Attendee ID
948
-     */
949
-    public function attendee_ID()
950
-    {
951
-        return $this->get('ATT_ID');
952
-    }
953
-
954
-
955
-    /**
956
-     *        get PHP Session ID
957
-     */
958
-    public function session_ID()
959
-    {
960
-        return $this->get('REG_session');
961
-    }
962
-
963
-
964
-    /**
965
-     * Gets the string which represents the URL trigger for the receipt template in the message template system.
966
-     *
967
-     * @param string $messenger 'pdf' or 'html'.  Default 'html'.
968
-     * @return string
969
-     * @throws DomainException
970
-     * @throws EE_Error
971
-     * @throws InvalidArgumentException
972
-     * @throws InvalidDataTypeException
973
-     * @throws InvalidInterfaceException
974
-     * @throws ReflectionException
975
-     */
976
-    public function receipt_url($messenger = 'html')
977
-    {
978
-
979
-        /**
980
-         * The below will be deprecated one version after this.  We check first if there is a custom receipt template
981
-         * already in use on old system.  If there is then we just return the standard url for it.
982
-         *
983
-         * @since 4.5.0
984
-         */
985
-        $template_relative_path = 'modules/gateways/Invoice/lib/templates/receipt_body.template.php';
986
-        $has_custom = EEH_Template::locate_template(
987
-            $template_relative_path,
988
-            array(),
989
-            true,
990
-            true,
991
-            true
992
-        );
993
-
994
-        if ($has_custom) {
995
-            return add_query_arg(array('receipt' => 'true'), $this->invoice_url('launch'));
996
-        }
997
-        return apply_filters('FHEE__EE_Registration__receipt_url__receipt_url', '', $this, $messenger, 'receipt');
998
-    }
999
-
1000
-
1001
-    /**
1002
-     * Gets the string which represents the URL trigger for the invoice template in the message template system.
1003
-     *
1004
-     * @param string $messenger 'pdf' or 'html'.  Default 'html'.
1005
-     * @return string
1006
-     * @throws DomainException
1007
-     * @throws EE_Error
1008
-     * @throws InvalidArgumentException
1009
-     * @throws InvalidDataTypeException
1010
-     * @throws InvalidInterfaceException
1011
-     * @throws ReflectionException
1012
-     */
1013
-    public function invoice_url($messenger = 'html')
1014
-    {
1015
-        /**
1016
-         * The below will be deprecated one version after this.  We check first if there is a custom invoice template
1017
-         * already in use on old system.  If there is then we just return the standard url for it.
1018
-         *
1019
-         * @since 4.5.0
1020
-         */
1021
-        $template_relative_path = 'modules/gateways/Invoice/lib/templates/invoice_body.template.php';
1022
-        $has_custom = EEH_Template::locate_template(
1023
-            $template_relative_path,
1024
-            array(),
1025
-            true,
1026
-            true,
1027
-            true
1028
-        );
1029
-
1030
-        if ($has_custom) {
1031
-            if ($messenger == 'html') {
1032
-                return $this->invoice_url('launch');
1033
-            }
1034
-            $route = $messenger == 'download' || $messenger == 'pdf' ? 'download_invoice' : 'launch_invoice';
1035
-
1036
-            $query_args = array('ee' => $route, 'id' => $this->reg_url_link());
1037
-            if ($messenger == 'html') {
1038
-                $query_args['html'] = true;
1039
-            }
1040
-            return add_query_arg($query_args, get_permalink(EE_Registry::instance()->CFG->core->thank_you_page_id));
1041
-        }
1042
-        return apply_filters('FHEE__EE_Registration__invoice_url__invoice_url', '', $this, $messenger, 'invoice');
1043
-    }
1044
-
1045
-
1046
-    /**
1047
-     * get Registration URL Link
1048
-     *
1049
-     * @return string
1050
-     * @throws EE_Error
1051
-     * @throws InvalidArgumentException
1052
-     * @throws InvalidDataTypeException
1053
-     * @throws InvalidInterfaceException
1054
-     * @throws ReflectionException
1055
-     */
1056
-    public function reg_url_link()
1057
-    {
1058
-        return (string) $this->get('REG_url_link');
1059
-    }
1060
-
1061
-
1062
-    /**
1063
-     * Echoes out invoice_url()
1064
-     *
1065
-     * @param string $type 'download','launch', or 'html' (default is 'launch')
1066
-     * @return void
1067
-     * @throws DomainException
1068
-     * @throws EE_Error
1069
-     * @throws InvalidArgumentException
1070
-     * @throws InvalidDataTypeException
1071
-     * @throws InvalidInterfaceException
1072
-     * @throws ReflectionException
1073
-     */
1074
-    public function e_invoice_url($type = 'launch')
1075
-    {
1076
-        echo esc_url_raw($this->invoice_url($type));
1077
-    }
1078
-
1079
-
1080
-    /**
1081
-     * Echoes out payment_overview_url
1082
-     */
1083
-    public function e_payment_overview_url()
1084
-    {
1085
-        echo esc_url_raw($this->payment_overview_url());
1086
-    }
1087
-
1088
-
1089
-    /**
1090
-     * Gets the URL for the checkout payment options reg step
1091
-     * with this registration's REG_url_link added as a query parameter
1092
-     *
1093
-     * @param bool $clear_session Set to true when you want to clear the session on revisiting the
1094
-     *                            payment overview url.
1095
-     * @return string
1096
-     * @throws EE_Error
1097
-     * @throws InvalidArgumentException
1098
-     * @throws InvalidDataTypeException
1099
-     * @throws InvalidInterfaceException
1100
-     * @throws ReflectionException
1101
-     */
1102
-    public function payment_overview_url($clear_session = false)
1103
-    {
1104
-        return add_query_arg(
1105
-            (array) apply_filters(
1106
-                'FHEE__EE_Registration__payment_overview_url__query_args',
1107
-                array(
1108
-                    'e_reg_url_link' => $this->reg_url_link(),
1109
-                    'step'           => 'payment_options',
1110
-                    'revisit'        => true,
1111
-                    'clear_session'  => (bool) $clear_session,
1112
-                ),
1113
-                $this
1114
-            ),
1115
-            EE_Registry::instance()->CFG->core->reg_page_url()
1116
-        );
1117
-    }
1118
-
1119
-
1120
-    /**
1121
-     * Gets the URL for the checkout attendee information reg step
1122
-     * with this registration's REG_url_link added as a query parameter
1123
-     *
1124
-     * @return string
1125
-     * @throws EE_Error
1126
-     * @throws InvalidArgumentException
1127
-     * @throws InvalidDataTypeException
1128
-     * @throws InvalidInterfaceException
1129
-     * @throws ReflectionException
1130
-     */
1131
-    public function edit_attendee_information_url()
1132
-    {
1133
-        return add_query_arg(
1134
-            (array) apply_filters(
1135
-                'FHEE__EE_Registration__edit_attendee_information_url__query_args',
1136
-                array(
1137
-                    'e_reg_url_link' => $this->reg_url_link(),
1138
-                    'step'           => 'attendee_information',
1139
-                    'revisit'        => true,
1140
-                ),
1141
-                $this
1142
-            ),
1143
-            EE_Registry::instance()->CFG->core->reg_page_url()
1144
-        );
1145
-    }
1146
-
1147
-
1148
-    /**
1149
-     * Simply generates and returns the appropriate admin_url link to edit this registration
1150
-     *
1151
-     * @return string
1152
-     * @throws EE_Error
1153
-     * @throws InvalidArgumentException
1154
-     * @throws InvalidDataTypeException
1155
-     * @throws InvalidInterfaceException
1156
-     * @throws ReflectionException
1157
-     */
1158
-    public function get_admin_edit_url()
1159
-    {
1160
-        return EEH_URL::add_query_args_and_nonce(
1161
-            array(
1162
-                'page'    => 'espresso_registrations',
1163
-                'action'  => 'view_registration',
1164
-                '_REG_ID' => $this->ID(),
1165
-            ),
1166
-            admin_url('admin.php')
1167
-        );
1168
-    }
1169
-
1170
-
1171
-    /**
1172
-     * is_primary_registrant?
1173
-     *
1174
-     * @throws EE_Error
1175
-     * @throws InvalidArgumentException
1176
-     * @throws InvalidDataTypeException
1177
-     * @throws InvalidInterfaceException
1178
-     * @throws ReflectionException
1179
-     */
1180
-    public function is_primary_registrant()
1181
-    {
1182
-        return (int) $this->get('REG_count') === 1;
1183
-    }
1184
-
1185
-
1186
-    /**
1187
-     * This returns the primary registration object for this registration group (which may be this object).
1188
-     *
1189
-     * @return EE_Registration
1190
-     * @throws EE_Error
1191
-     * @throws InvalidArgumentException
1192
-     * @throws InvalidDataTypeException
1193
-     * @throws InvalidInterfaceException
1194
-     * @throws ReflectionException
1195
-     */
1196
-    public function get_primary_registration()
1197
-    {
1198
-        if ($this->is_primary_registrant()) {
1199
-            return $this;
1200
-        }
1201
-
1202
-        // k reg_count !== 1 so let's get the EE_Registration object matching this txn_id and reg_count == 1
1203
-        /** @var EE_Registration $primary_registrant */
1204
-        $primary_registrant = EEM_Registration::instance()->get_one(
1205
-            array(
1206
-                array(
1207
-                    'TXN_ID'    => $this->transaction_ID(),
1208
-                    'REG_count' => 1,
1209
-                ),
1210
-            )
1211
-        );
1212
-        return $primary_registrant;
1213
-    }
1214
-
1215
-
1216
-    /**
1217
-     * get  Attendee Number
1218
-     *
1219
-     * @throws EE_Error
1220
-     * @throws InvalidArgumentException
1221
-     * @throws InvalidDataTypeException
1222
-     * @throws InvalidInterfaceException
1223
-     * @throws ReflectionException
1224
-     */
1225
-    public function count()
1226
-    {
1227
-        return $this->get('REG_count');
1228
-    }
1229
-
1230
-
1231
-    /**
1232
-     * get Group Size
1233
-     *
1234
-     * @throws EE_Error
1235
-     * @throws InvalidArgumentException
1236
-     * @throws InvalidDataTypeException
1237
-     * @throws InvalidInterfaceException
1238
-     * @throws ReflectionException
1239
-     */
1240
-    public function group_size()
1241
-    {
1242
-        return $this->get('REG_group_size');
1243
-    }
1244
-
1245
-
1246
-    /**
1247
-     * get Registration Date
1248
-     *
1249
-     * @throws EE_Error
1250
-     * @throws InvalidArgumentException
1251
-     * @throws InvalidDataTypeException
1252
-     * @throws InvalidInterfaceException
1253
-     * @throws ReflectionException
1254
-     */
1255
-    public function date()
1256
-    {
1257
-        return $this->get('REG_date');
1258
-    }
1259
-
1260
-
1261
-    /**
1262
-     * gets a pretty date
1263
-     *
1264
-     * @param string $date_format
1265
-     * @param string $time_format
1266
-     * @return string
1267
-     * @throws EE_Error
1268
-     * @throws InvalidArgumentException
1269
-     * @throws InvalidDataTypeException
1270
-     * @throws InvalidInterfaceException
1271
-     * @throws ReflectionException
1272
-     */
1273
-    public function pretty_date($date_format = null, $time_format = null)
1274
-    {
1275
-        return $this->get_datetime('REG_date', $date_format, $time_format);
1276
-    }
1277
-
1278
-
1279
-    /**
1280
-     * final_price
1281
-     * the registration's share of the transaction total, so that the
1282
-     * sum of all the transaction's REG_final_prices equal the transaction's total
1283
-     *
1284
-     * @return float
1285
-     * @throws EE_Error
1286
-     * @throws InvalidArgumentException
1287
-     * @throws InvalidDataTypeException
1288
-     * @throws InvalidInterfaceException
1289
-     * @throws ReflectionException
1290
-     */
1291
-    public function final_price()
1292
-    {
1293
-        return $this->get('REG_final_price');
1294
-    }
1295
-
1296
-
1297
-    /**
1298
-     * pretty_final_price
1299
-     *  final price as formatted string, with correct decimal places and currency symbol
1300
-     *
1301
-     * @return string
1302
-     * @throws EE_Error
1303
-     * @throws InvalidArgumentException
1304
-     * @throws InvalidDataTypeException
1305
-     * @throws InvalidInterfaceException
1306
-     * @throws ReflectionException
1307
-     */
1308
-    public function pretty_final_price()
1309
-    {
1310
-        return $this->get_pretty('REG_final_price');
1311
-    }
1312
-
1313
-
1314
-    /**
1315
-     * get paid (yeah)
1316
-     *
1317
-     * @return float
1318
-     * @throws EE_Error
1319
-     * @throws InvalidArgumentException
1320
-     * @throws InvalidDataTypeException
1321
-     * @throws InvalidInterfaceException
1322
-     * @throws ReflectionException
1323
-     */
1324
-    public function paid()
1325
-    {
1326
-        return $this->get('REG_paid');
1327
-    }
1328
-
1329
-
1330
-    /**
1331
-     * pretty_paid
1332
-     *
1333
-     * @return float
1334
-     * @throws EE_Error
1335
-     * @throws InvalidArgumentException
1336
-     * @throws InvalidDataTypeException
1337
-     * @throws InvalidInterfaceException
1338
-     * @throws ReflectionException
1339
-     */
1340
-    public function pretty_paid()
1341
-    {
1342
-        return $this->get_pretty('REG_paid');
1343
-    }
1344
-
1345
-
1346
-    /**
1347
-     * owes_monies_and_can_pay
1348
-     * whether or not this registration has monies owing and it's' status allows payment
1349
-     *
1350
-     * @param array $requires_payment
1351
-     * @return bool
1352
-     * @throws EE_Error
1353
-     * @throws InvalidArgumentException
1354
-     * @throws InvalidDataTypeException
1355
-     * @throws InvalidInterfaceException
1356
-     * @throws ReflectionException
1357
-     */
1358
-    public function owes_monies_and_can_pay($requires_payment = array())
1359
-    {
1360
-        // these reg statuses require payment (if event is not free)
1361
-        $requires_payment = ! empty($requires_payment)
1362
-            ? $requires_payment
1363
-            : EEM_Registration::reg_statuses_that_allow_payment();
1364
-        if (
1365
-            $this->final_price() !== 0 &&
1366
-            $this->final_price() !== $this->paid() &&
1367
-            in_array($this->status_ID(), $requires_payment)
1368
-        ) {
1369
-            return true;
1370
-        }
1371
-        return false;
1372
-    }
1373
-
1374
-
1375
-    /**
1376
-     * Prints out the return value of $this->pretty_status()
1377
-     *
1378
-     * @param bool $show_icons
1379
-     * @return void
1380
-     * @throws EE_Error
1381
-     * @throws InvalidArgumentException
1382
-     * @throws InvalidDataTypeException
1383
-     * @throws InvalidInterfaceException
1384
-     * @throws ReflectionException
1385
-     */
1386
-    public function e_pretty_status($show_icons = false)
1387
-    {
1388
-        echo wp_kses($this->pretty_status($show_icons), AllowedTags::getAllowedTags());
1389
-    }
1390
-
1391
-
1392
-    /**
1393
-     * Returns a nice version of the status for displaying to customers
1394
-     *
1395
-     * @param bool $show_icons
1396
-     * @return string
1397
-     * @throws EE_Error
1398
-     * @throws InvalidArgumentException
1399
-     * @throws InvalidDataTypeException
1400
-     * @throws InvalidInterfaceException
1401
-     * @throws ReflectionException
1402
-     */
1403
-    public function pretty_status($show_icons = false)
1404
-    {
1405
-        $status = EEM_Status::instance()->localized_status(
1406
-            array($this->status_ID() => esc_html__('unknown', 'event_espresso')),
1407
-            false,
1408
-            'sentence'
1409
-        );
1410
-        $icon = '';
1411
-        switch ($this->status_ID()) {
1412
-            case EEM_Registration::status_id_approved:
1413
-                $icon = $show_icons
1414
-                    ? '<span class="dashicons dashicons-star-filled ee-icon-size-16 green-text"></span>'
1415
-                    : '';
1416
-                break;
1417
-            case EEM_Registration::status_id_pending_payment:
1418
-                $icon = $show_icons
1419
-                    ? '<span class="dashicons dashicons-star-half ee-icon-size-16 orange-text"></span>'
1420
-                    : '';
1421
-                break;
1422
-            case EEM_Registration::status_id_not_approved:
1423
-                $icon = $show_icons
1424
-                    ? '<span class="dashicons dashicons-marker ee-icon-size-16 orange-text"></span>'
1425
-                    : '';
1426
-                break;
1427
-            case EEM_Registration::status_id_cancelled:
1428
-                $icon = $show_icons
1429
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 lt-grey-text"></span>'
1430
-                    : '';
1431
-                break;
1432
-            case EEM_Registration::status_id_incomplete:
1433
-                $icon = $show_icons
1434
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 lt-orange-text"></span>'
1435
-                    : '';
1436
-                break;
1437
-            case EEM_Registration::status_id_declined:
1438
-                $icon = $show_icons
1439
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>'
1440
-                    : '';
1441
-                break;
1442
-            case EEM_Registration::status_id_wait_list:
1443
-                $icon = $show_icons
1444
-                    ? '<span class="dashicons dashicons-clipboard ee-icon-size-16 purple-text"></span>'
1445
-                    : '';
1446
-                break;
1447
-        }
1448
-        return $icon . $status[ $this->status_ID() ];
1449
-    }
1450
-
1451
-
1452
-    /**
1453
-     *        get Attendee Is Going
1454
-     */
1455
-    public function att_is_going()
1456
-    {
1457
-        return $this->get('REG_att_is_going');
1458
-    }
1459
-
1460
-
1461
-    /**
1462
-     * Gets related answers
1463
-     *
1464
-     * @param array $query_params @see
1465
-     *                            https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1466
-     * @return EE_Answer[]|EE_Base_Class[]
1467
-     * @throws EE_Error
1468
-     * @throws InvalidArgumentException
1469
-     * @throws InvalidDataTypeException
1470
-     * @throws InvalidInterfaceException
1471
-     * @throws ReflectionException
1472
-     */
1473
-    public function answers($query_params = null)
1474
-    {
1475
-        return $this->get_many_related('Answer', $query_params);
1476
-    }
1477
-
1478
-
1479
-    /**
1480
-     * Gets the registration's answer value to the specified question
1481
-     * (either the question's ID or a question object)
1482
-     *
1483
-     * @param EE_Question|int $question
1484
-     * @param bool            $pretty_value
1485
-     * @return array|string if pretty_value= true, the result will always be a string
1486
-     * (because the answer might be an array of answer values, so passing pretty_value=true
1487
-     * will convert it into some kind of string)
1488
-     * @throws EE_Error
1489
-     * @throws InvalidArgumentException
1490
-     * @throws InvalidDataTypeException
1491
-     * @throws InvalidInterfaceException
1492
-     */
1493
-    public function answer_value_to_question($question, $pretty_value = true)
1494
-    {
1495
-        $question_id = EEM_Question::instance()->ensure_is_ID($question);
1496
-        return EEM_Answer::instance()->get_answer_value_to_question($this, $question_id, $pretty_value);
1497
-    }
1498
-
1499
-
1500
-    /**
1501
-     * question_groups
1502
-     * returns an array of EE_Question_Group objects for this registration
1503
-     *
1504
-     * @return EE_Question_Group[]
1505
-     * @throws EE_Error
1506
-     * @throws InvalidArgumentException
1507
-     * @throws InvalidDataTypeException
1508
-     * @throws InvalidInterfaceException
1509
-     * @throws ReflectionException
1510
-     */
1511
-    public function question_groups()
1512
-    {
1513
-        return EEM_Event::instance()->get_question_groups_for_event($this->event_ID(), $this);
1514
-    }
1515
-
1516
-
1517
-    /**
1518
-     * count_question_groups
1519
-     * returns a count of the number of EE_Question_Group objects for this registration
1520
-     *
1521
-     * @return int
1522
-     * @throws EE_Error
1523
-     * @throws EntityNotFoundException
1524
-     * @throws InvalidArgumentException
1525
-     * @throws InvalidDataTypeException
1526
-     * @throws InvalidInterfaceException
1527
-     * @throws ReflectionException
1528
-     */
1529
-    public function count_question_groups()
1530
-    {
1531
-        return EEM_Event::instance()->count_related(
1532
-            $this->event_ID(),
1533
-            'Question_Group',
1534
-            [
1535
-                [
1536
-                    'Event_Question_Group.'
1537
-                    . EEM_Event_Question_Group::instance()->fieldNameForContext($this->is_primary_registrant()) => true,
1538
-                ]
1539
-            ]
1540
-        );
1541
-    }
1542
-
1543
-
1544
-    /**
1545
-     * Returns the registration date in the 'standard' string format
1546
-     * (function may be improved in the future to allow for different formats and timezones)
1547
-     *
1548
-     * @return string
1549
-     * @throws EE_Error
1550
-     * @throws InvalidArgumentException
1551
-     * @throws InvalidDataTypeException
1552
-     * @throws InvalidInterfaceException
1553
-     * @throws ReflectionException
1554
-     */
1555
-    public function reg_date()
1556
-    {
1557
-        return $this->get_datetime('REG_date');
1558
-    }
1559
-
1560
-
1561
-    /**
1562
-     * Gets the datetime-ticket for this registration (ie, it can be used to isolate
1563
-     * the ticket this registration purchased, or the datetime they have registered
1564
-     * to attend)
1565
-     *
1566
-     * @return EE_Base_Class|EE_Datetime_Ticket
1567
-     * @throws EE_Error
1568
-     * @throws InvalidArgumentException
1569
-     * @throws InvalidDataTypeException
1570
-     * @throws InvalidInterfaceException
1571
-     * @throws ReflectionException
1572
-     */
1573
-    public function datetime_ticket()
1574
-    {
1575
-        return $this->get_first_related('Datetime_Ticket');
1576
-    }
1577
-
1578
-
1579
-    /**
1580
-     * Sets the registration's datetime_ticket.
1581
-     *
1582
-     * @param EE_Datetime_Ticket $datetime_ticket
1583
-     * @return EE_Base_Class|EE_Datetime_Ticket
1584
-     * @throws EE_Error
1585
-     * @throws InvalidArgumentException
1586
-     * @throws InvalidDataTypeException
1587
-     * @throws InvalidInterfaceException
1588
-     * @throws ReflectionException
1589
-     */
1590
-    public function set_datetime_ticket($datetime_ticket)
1591
-    {
1592
-        return $this->_add_relation_to($datetime_ticket, 'Datetime_Ticket');
1593
-    }
1594
-
1595
-
1596
-    /**
1597
-     * Gets deleted
1598
-     *
1599
-     * @return bool
1600
-     * @throws EE_Error
1601
-     * @throws InvalidArgumentException
1602
-     * @throws InvalidDataTypeException
1603
-     * @throws InvalidInterfaceException
1604
-     * @throws ReflectionException
1605
-     */
1606
-    public function deleted()
1607
-    {
1608
-        return $this->get('REG_deleted');
1609
-    }
1610
-
1611
-
1612
-    /**
1613
-     * Sets deleted
1614
-     *
1615
-     * @param boolean $deleted
1616
-     * @return void
1617
-     * @throws DomainException
1618
-     * @throws EE_Error
1619
-     * @throws EntityNotFoundException
1620
-     * @throws InvalidArgumentException
1621
-     * @throws InvalidDataTypeException
1622
-     * @throws InvalidInterfaceException
1623
-     * @throws ReflectionException
1624
-     * @throws RuntimeException
1625
-     * @throws UnexpectedEntityException
1626
-     */
1627
-    public function set_deleted($deleted)
1628
-    {
1629
-        if ($deleted) {
1630
-            $this->delete();
1631
-        } else {
1632
-            $this->restore();
1633
-        }
1634
-    }
1635
-
1636
-
1637
-    /**
1638
-     * Get the status object of this object
1639
-     *
1640
-     * @return EE_Base_Class|EE_Status
1641
-     * @throws EE_Error
1642
-     * @throws InvalidArgumentException
1643
-     * @throws InvalidDataTypeException
1644
-     * @throws InvalidInterfaceException
1645
-     * @throws ReflectionException
1646
-     */
1647
-    public function status_obj()
1648
-    {
1649
-        return $this->get_first_related('Status');
1650
-    }
1651
-
1652
-
1653
-    /**
1654
-     * Returns the number of times this registration has checked into any of the datetimes
1655
-     * its available for
1656
-     *
1657
-     * @return int
1658
-     * @throws EE_Error
1659
-     * @throws InvalidArgumentException
1660
-     * @throws InvalidDataTypeException
1661
-     * @throws InvalidInterfaceException
1662
-     * @throws ReflectionException
1663
-     */
1664
-    public function count_checkins()
1665
-    {
1666
-        return $this->get_model()->count_related($this, 'Checkin');
1667
-    }
1668
-
1669
-
1670
-    /**
1671
-     * Returns the number of current Check-ins this registration is checked into for any of the datetimes the
1672
-     * registration is for.  Note, this is ONLY checked in (does not include checkedout)
1673
-     *
1674
-     * @return int
1675
-     * @throws EE_Error
1676
-     * @throws InvalidArgumentException
1677
-     * @throws InvalidDataTypeException
1678
-     * @throws InvalidInterfaceException
1679
-     * @throws ReflectionException
1680
-     */
1681
-    public function count_checkins_not_checkedout()
1682
-    {
1683
-        return $this->get_model()->count_related($this, 'Checkin', array(array('CHK_in' => 1)));
1684
-    }
1685
-
1686
-
1687
-    /**
1688
-     * The purpose of this method is simply to check whether this registration can checkin to the given datetime.
1689
-     *
1690
-     * @param int | EE_Datetime $DTT_OR_ID      The datetime the registration is being checked against
1691
-     * @param bool              $check_approved This is used to indicate whether the caller wants can_checkin to also
1692
-     *                                          consider registration status as well as datetime access.
1693
-     * @return bool
1694
-     * @throws EE_Error
1695
-     * @throws InvalidArgumentException
1696
-     * @throws InvalidDataTypeException
1697
-     * @throws InvalidInterfaceException
1698
-     * @throws ReflectionException
1699
-     */
1700
-    public function can_checkin($DTT_OR_ID, $check_approved = true)
1701
-    {
1702
-        $DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1703
-        // first check registration status
1704
-        if (! $DTT_ID || ($check_approved && ! $this->is_approved())) {
1705
-            return false;
1706
-        }
1707
-        // is there a datetime ticket that matches this dtt_ID?
1708
-        if (
1709
-            ! (EEM_Datetime_Ticket::instance()->exists(
1710
-                array(
1711
-                    array(
1712
-                        'TKT_ID' => $this->get('TKT_ID'),
1713
-                        'DTT_ID' => $DTT_ID,
1714
-                    ),
1715
-                )
1716
-            ))
1717
-        ) {
1718
-            return false;
1719
-        }
1720
-
1721
-        // final check is against TKT_uses
1722
-        return $this->verify_can_checkin_against_TKT_uses($DTT_ID);
1723
-    }
1724
-
1725
-
1726
-    /**
1727
-     * This method verifies whether the user can checkin for the given datetime considering the max uses value set on
1728
-     * the ticket. To do this,  a query is done to get the count of the datetime records already checked into.  If the
1729
-     * datetime given does not have a check-in record and checking in for that datetime will exceed the allowed uses,
1730
-     * then return false.  Otherwise return true.
1731
-     *
1732
-     * @param int | EE_Datetime $DTT_OR_ID The datetime the registration is being checked against
1733
-     * @return bool true means can checkin.  false means cannot checkin.
1734
-     * @throws EE_Error
1735
-     * @throws InvalidArgumentException
1736
-     * @throws InvalidDataTypeException
1737
-     * @throws InvalidInterfaceException
1738
-     * @throws ReflectionException
1739
-     */
1740
-    public function verify_can_checkin_against_TKT_uses($DTT_OR_ID)
1741
-    {
1742
-        $DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1743
-
1744
-        if (! $DTT_ID) {
1745
-            return false;
1746
-        }
1747
-
1748
-        $max_uses = $this->ticket() instanceof EE_Ticket ? $this->ticket()->uses() : EE_INF;
1749
-
1750
-        // if max uses is not set or equals infinity then return true cause its not a factor for whether user can
1751
-        // check-in or not.
1752
-        if (! $max_uses || $max_uses === EE_INF) {
1753
-            return true;
1754
-        }
1755
-
1756
-        // does this datetime have a checkin record?  If so, then the dtt count has already been verified so we can just
1757
-        // go ahead and toggle.
1758
-        if (EEM_Checkin::instance()->exists(array(array('REG_ID' => $this->ID(), 'DTT_ID' => $DTT_ID)))) {
1759
-            return true;
1760
-        }
1761
-
1762
-        // made it here so the last check is whether the number of checkins per unique datetime on this registration
1763
-        // disallows further check-ins.
1764
-        $count_unique_dtt_checkins = EEM_Checkin::instance()->count(
1765
-            array(
1766
-                array(
1767
-                    'REG_ID' => $this->ID(),
1768
-                    'CHK_in' => true,
1769
-                ),
1770
-            ),
1771
-            'DTT_ID',
1772
-            true
1773
-        );
1774
-        // checkins have already reached their max number of uses
1775
-        // so registrant can NOT checkin
1776
-        if ($count_unique_dtt_checkins >= $max_uses) {
1777
-            EE_Error::add_error(
1778
-                esc_html__(
1779
-                    'Check-in denied because number of datetime uses for the ticket has been reached or exceeded.',
1780
-                    'event_espresso'
1781
-                ),
1782
-                __FILE__,
1783
-                __FUNCTION__,
1784
-                __LINE__
1785
-            );
1786
-            return false;
1787
-        }
1788
-        return true;
1789
-    }
1790
-
1791
-
1792
-    /**
1793
-     * toggle Check-in status for this registration
1794
-     * Check-ins are toggled in the following order:
1795
-     * never checked in -> checked in
1796
-     * checked in -> checked out
1797
-     * checked out -> checked in
1798
-     *
1799
-     * @param  int $DTT_ID  include specific datetime to toggle Check-in for.
1800
-     *                      If not included or null, then it is assumed latest datetime is being toggled.
1801
-     * @param bool $verify  If true then can_checkin() is used to verify whether the person
1802
-     *                      can be checked in or not.  Otherwise this forces change in checkin status.
1803
-     * @return bool|int     the chk_in status toggled to OR false if nothing got changed.
1804
-     * @throws EE_Error
1805
-     * @throws InvalidArgumentException
1806
-     * @throws InvalidDataTypeException
1807
-     * @throws InvalidInterfaceException
1808
-     * @throws ReflectionException
1809
-     */
1810
-    public function toggle_checkin_status($DTT_ID = null, $verify = false)
1811
-    {
1812
-        if (empty($DTT_ID)) {
1813
-            $datetime = $this->get_latest_related_datetime();
1814
-            $DTT_ID = $datetime instanceof EE_Datetime ? $datetime->ID() : 0;
1815
-            // verify the registration can checkin for the given DTT_ID
1816
-        } elseif (! $this->can_checkin($DTT_ID, $verify)) {
1817
-            EE_Error::add_error(
1818
-                sprintf(
1819
-                    esc_html__(
1820
-                        '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',
1821
-                        'event_espresso'
1822
-                    ),
1823
-                    $this->ID(),
1824
-                    $DTT_ID
1825
-                ),
1826
-                __FILE__,
1827
-                __FUNCTION__,
1828
-                __LINE__
1829
-            );
1830
-            return false;
1831
-        }
1832
-        $status_paths = array(
1833
-            EE_Checkin::status_checked_never => EE_Checkin::status_checked_in,
1834
-            EE_Checkin::status_checked_in    => EE_Checkin::status_checked_out,
1835
-            EE_Checkin::status_checked_out   => EE_Checkin::status_checked_in,
1836
-        );
1837
-        // start by getting the current status so we know what status we'll be changing to.
1838
-        $cur_status = $this->check_in_status_for_datetime($DTT_ID);
1839
-        $status_to = $status_paths[ $cur_status ];
1840
-        // database only records true for checked IN or false for checked OUT
1841
-        // no record ( null ) means checked in NEVER, but we obviously don't save that
1842
-        $new_status = $status_to === EE_Checkin::status_checked_in;
1843
-        // add relation - note Check-ins are always creating new rows
1844
-        // because we are keeping track of Check-ins over time.
1845
-        // Eventually we'll probably want to show a list table
1846
-        // for the individual Check-ins so that they can be managed.
1847
-        $checkin = EE_Checkin::new_instance(
1848
-            array(
1849
-                'REG_ID' => $this->ID(),
1850
-                'DTT_ID' => $DTT_ID,
1851
-                'CHK_in' => $new_status,
1852
-            )
1853
-        );
1854
-        // if the record could not be saved then return false
1855
-        if ($checkin->save() === 0) {
1856
-            if (WP_DEBUG) {
1857
-                global $wpdb;
1858
-                $error = sprintf(
1859
-                    esc_html__(
1860
-                        'Registration check in update failed because of the following database error: %1$s%2$s',
1861
-                        'event_espresso'
1862
-                    ),
1863
-                    '<br />',
1864
-                    $wpdb->last_error
1865
-                );
1866
-            } else {
1867
-                $error = esc_html__(
1868
-                    'Registration check in update failed because of an unknown database error',
1869
-                    'event_espresso'
1870
-                );
1871
-            }
1872
-            EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
1873
-            return false;
1874
-        }
1875
-        // Fire a checked_in and checkout_out action.
1876
-        $checked_status = $status_to === EE_Checkin::status_checked_in ? 'checked_in' : 'checked_out';
1877
-        do_action("AHEE__EE_Registration__toggle_checkin_status__{$checked_status}", $this, $DTT_ID);
1878
-        return $status_to;
1879
-    }
1880
-
1881
-
1882
-    /**
1883
-     * Returns the latest datetime related to this registration (via the ticket attached to the registration).
1884
-     * "Latest" is defined by the `DTT_EVT_start` column.
1885
-     *
1886
-     * @return EE_Datetime|null
1887
-     * @throws EE_Error
1888
-     * @throws InvalidArgumentException
1889
-     * @throws InvalidDataTypeException
1890
-     * @throws InvalidInterfaceException
1891
-     * @throws ReflectionException
1892
-     */
1893
-    public function get_latest_related_datetime()
1894
-    {
1895
-        return EEM_Datetime::instance()->get_one(
1896
-            array(
1897
-                array(
1898
-                    'Ticket.Registration.REG_ID' => $this->ID(),
1899
-                ),
1900
-                'order_by' => array('DTT_EVT_start' => 'DESC'),
1901
-            )
1902
-        );
1903
-    }
1904
-
1905
-
1906
-    /**
1907
-     * Returns the earliest datetime related to this registration (via the ticket attached to the registration).
1908
-     * "Earliest" is defined by the `DTT_EVT_start` column.
1909
-     *
1910
-     * @return EE_Base_Class|EE_Soft_Delete_Base_Class|NULL
1911
-     * @throws EE_Error
1912
-     * @throws InvalidArgumentException
1913
-     * @throws InvalidDataTypeException
1914
-     * @throws InvalidInterfaceException
1915
-     * @throws ReflectionException
1916
-     */
1917
-    public function get_earliest_related_datetime()
1918
-    {
1919
-        return EEM_Datetime::instance()->get_one(
1920
-            array(
1921
-                array(
1922
-                    'Ticket.Registration.REG_ID' => $this->ID(),
1923
-                ),
1924
-                'order_by' => array('DTT_EVT_start' => 'ASC'),
1925
-            )
1926
-        );
1927
-    }
1928
-
1929
-
1930
-    /**
1931
-     * This method simply returns the check-in status for this registration and the given datetime.
1932
-     * If neither the datetime nor the checkin values are provided as arguments,
1933
-     * then this will return the LATEST check-in status for the registration across all datetimes it belongs to.
1934
-     *
1935
-     * @param  int       $DTT_ID  The ID of the datetime we're checking against
1936
-     *                            (if empty we'll get the primary datetime for
1937
-     *                            this registration (via event) and use it's ID);
1938
-     * @param EE_Checkin $checkin If present, we use the given checkin object rather than the dtt_id.
1939
-     * @return int                Integer representing Check-in status.
1940
-     * @throws EE_Error
1941
-     * @throws InvalidArgumentException
1942
-     * @throws InvalidDataTypeException
1943
-     * @throws InvalidInterfaceException
1944
-     * @throws ReflectionException
1945
-     */
1946
-    public function check_in_status_for_datetime($DTT_ID = 0, $checkin = null)
1947
-    {
1948
-        $checkin_query_params = array(
1949
-            'order_by' => array('CHK_timestamp' => 'DESC'),
1950
-        );
1951
-
1952
-        if ($DTT_ID > 0) {
1953
-            $checkin_query_params[0] = array('DTT_ID' => $DTT_ID);
1954
-        }
1955
-
1956
-        // get checkin object (if exists)
1957
-        $checkin = $checkin instanceof EE_Checkin
1958
-            ? $checkin
1959
-            : $this->get_first_related('Checkin', $checkin_query_params);
1960
-        if ($checkin instanceof EE_Checkin) {
1961
-            if ($checkin->get('CHK_in')) {
1962
-                return EE_Checkin::status_checked_in; // checked in
1963
-            }
1964
-            return EE_Checkin::status_checked_out; // had checked in but is now checked out.
1965
-        }
1966
-        return EE_Checkin::status_checked_never; // never been checked in
1967
-    }
1968
-
1969
-
1970
-    /**
1971
-     * This method returns a localized message for the toggled Check-in message.
1972
-     *
1973
-     * @param  int $DTT_ID include specific datetime to get the correct Check-in message.  If not included or null,
1974
-     *                     then it is assumed Check-in for primary datetime was toggled.
1975
-     * @param bool $error  This just flags that you want an error message returned. This is put in so that the error
1976
-     *                     message can be customized with the attendee name.
1977
-     * @return string internationalized message
1978
-     * @throws EE_Error
1979
-     * @throws InvalidArgumentException
1980
-     * @throws InvalidDataTypeException
1981
-     * @throws InvalidInterfaceException
1982
-     * @throws ReflectionException
1983
-     */
1984
-    public function get_checkin_msg($DTT_ID, $error = false)
1985
-    {
1986
-        // let's get the attendee first so we can include the name of the attendee
1987
-        $attendee = $this->get_first_related('Attendee');
1988
-        if ($attendee instanceof EE_Attendee) {
1989
-            if ($error) {
1990
-                return sprintf(
1991
-                    esc_html__("%s's check-in status was not changed.", "event_espresso"),
1992
-                    $attendee->full_name()
1993
-                );
1994
-            }
1995
-            $cur_status = $this->check_in_status_for_datetime($DTT_ID);
1996
-            // what is the status message going to be?
1997
-            switch ($cur_status) {
1998
-                case EE_Checkin::status_checked_never:
1999
-                    return sprintf(
2000
-                        esc_html__('%s has been removed from Check-in records', 'event_espresso'),
2001
-                        $attendee->full_name()
2002
-                    );
2003
-                    break;
2004
-                case EE_Checkin::status_checked_in:
2005
-                    return sprintf(esc_html__('%s has been checked in', 'event_espresso'), $attendee->full_name());
2006
-                    break;
2007
-                case EE_Checkin::status_checked_out:
2008
-                    return sprintf(esc_html__('%s has been checked out', 'event_espresso'), $attendee->full_name());
2009
-                    break;
2010
-            }
2011
-        }
2012
-        return esc_html__('The check-in status could not be determined.', 'event_espresso');
2013
-    }
2014
-
2015
-
2016
-    /**
2017
-     * Returns the related EE_Transaction to this registration
2018
-     *
2019
-     * @return EE_Transaction
2020
-     * @throws EE_Error
2021
-     * @throws EntityNotFoundException
2022
-     * @throws InvalidArgumentException
2023
-     * @throws InvalidDataTypeException
2024
-     * @throws InvalidInterfaceException
2025
-     * @throws ReflectionException
2026
-     */
2027
-    public function transaction()
2028
-    {
2029
-        $transaction = $this->get_first_related('Transaction');
2030
-        if (! $transaction instanceof \EE_Transaction) {
2031
-            throw new EntityNotFoundException('Transaction ID', $this->transaction_ID());
2032
-        }
2033
-        return $transaction;
2034
-    }
2035
-
2036
-
2037
-    /**
2038
-     * get Registration Code
2039
-     *
2040
-     * @return mixed
2041
-     * @throws EE_Error
2042
-     * @throws InvalidArgumentException
2043
-     * @throws InvalidDataTypeException
2044
-     * @throws InvalidInterfaceException
2045
-     * @throws ReflectionException
2046
-     */
2047
-    public function reg_code()
2048
-    {
2049
-        return $this->get('REG_code');
2050
-    }
2051
-
2052
-
2053
-    /**
2054
-     * @return mixed
2055
-     * @throws EE_Error
2056
-     * @throws InvalidArgumentException
2057
-     * @throws InvalidDataTypeException
2058
-     * @throws InvalidInterfaceException
2059
-     * @throws ReflectionException
2060
-     */
2061
-    public function transaction_ID()
2062
-    {
2063
-        return $this->get('TXN_ID');
2064
-    }
2065
-
2066
-
2067
-    /**
2068
-     * @return int
2069
-     * @throws EE_Error
2070
-     * @throws InvalidArgumentException
2071
-     * @throws InvalidDataTypeException
2072
-     * @throws InvalidInterfaceException
2073
-     * @throws ReflectionException
2074
-     */
2075
-    public function ticket_ID()
2076
-    {
2077
-        return $this->get('TKT_ID');
2078
-    }
2079
-
2080
-
2081
-    /**
2082
-     * Set Registration Code
2083
-     *
2084
-     * @param    string  $REG_code Registration Code
2085
-     * @param    boolean $use_default
2086
-     * @throws EE_Error
2087
-     * @throws InvalidArgumentException
2088
-     * @throws InvalidDataTypeException
2089
-     * @throws InvalidInterfaceException
2090
-     * @throws ReflectionException
2091
-     */
2092
-    public function set_reg_code($REG_code, $use_default = false)
2093
-    {
2094
-        if (empty($REG_code)) {
2095
-            EE_Error::add_error(
2096
-                esc_html__('REG_code can not be empty.', 'event_espresso'),
2097
-                __FILE__,
2098
-                __FUNCTION__,
2099
-                __LINE__
2100
-            );
2101
-            return;
2102
-        }
2103
-        if (! $this->reg_code()) {
2104
-            parent::set('REG_code', $REG_code, $use_default);
2105
-        } else {
2106
-            EE_Error::doing_it_wrong(
2107
-                __CLASS__ . '::' . __FUNCTION__,
2108
-                esc_html__('Can not change a registration REG_code once it has been set.', 'event_espresso'),
2109
-                '4.6.0'
2110
-            );
2111
-        }
2112
-    }
2113
-
2114
-
2115
-    /**
2116
-     * Returns all other registrations in the same group as this registrant who have the same ticket option.
2117
-     * Note, if you want to just get all registrations in the same transaction (group), use:
2118
-     *    $registration->transaction()->registrations();
2119
-     *
2120
-     * @since 4.5.0
2121
-     * @return EE_Registration[] or empty array if this isn't a group registration.
2122
-     * @throws EE_Error
2123
-     * @throws InvalidArgumentException
2124
-     * @throws InvalidDataTypeException
2125
-     * @throws InvalidInterfaceException
2126
-     * @throws ReflectionException
2127
-     */
2128
-    public function get_all_other_registrations_in_group()
2129
-    {
2130
-        if ($this->group_size() < 2) {
2131
-            return array();
2132
-        }
2133
-
2134
-        $query[0] = array(
2135
-            'TXN_ID' => $this->transaction_ID(),
2136
-            'REG_ID' => array('!=', $this->ID()),
2137
-            'TKT_ID' => $this->ticket_ID(),
2138
-        );
2139
-        /** @var EE_Registration[] $registrations */
2140
-        $registrations = $this->get_model()->get_all($query);
2141
-        return $registrations;
2142
-    }
2143
-
2144
-
2145
-    /**
2146
-     * Return the link to the admin details for the object.
2147
-     *
2148
-     * @return string
2149
-     * @throws EE_Error
2150
-     * @throws InvalidArgumentException
2151
-     * @throws InvalidDataTypeException
2152
-     * @throws InvalidInterfaceException
2153
-     * @throws ReflectionException
2154
-     */
2155
-    public function get_admin_details_link()
2156
-    {
2157
-        EE_Registry::instance()->load_helper('URL');
2158
-        return EEH_URL::add_query_args_and_nonce(
2159
-            array(
2160
-                'page'    => 'espresso_registrations',
2161
-                'action'  => 'view_registration',
2162
-                '_REG_ID' => $this->ID(),
2163
-            ),
2164
-            admin_url('admin.php')
2165
-        );
2166
-    }
2167
-
2168
-
2169
-    /**
2170
-     * Returns the link to the editor for the object.  Sometimes this is the same as the details.
2171
-     *
2172
-     * @return string
2173
-     * @throws EE_Error
2174
-     * @throws InvalidArgumentException
2175
-     * @throws InvalidDataTypeException
2176
-     * @throws InvalidInterfaceException
2177
-     * @throws ReflectionException
2178
-     */
2179
-    public function get_admin_edit_link()
2180
-    {
2181
-        return $this->get_admin_details_link();
2182
-    }
2183
-
2184
-
2185
-    /**
2186
-     * Returns the link to a settings page for the object.
2187
-     *
2188
-     * @return string
2189
-     * @throws EE_Error
2190
-     * @throws InvalidArgumentException
2191
-     * @throws InvalidDataTypeException
2192
-     * @throws InvalidInterfaceException
2193
-     * @throws ReflectionException
2194
-     */
2195
-    public function get_admin_settings_link()
2196
-    {
2197
-        return $this->get_admin_details_link();
2198
-    }
2199
-
2200
-
2201
-    /**
2202
-     * Returns the link to the "overview" for the object (typically the "list table" view).
2203
-     *
2204
-     * @return string
2205
-     * @throws EE_Error
2206
-     * @throws InvalidArgumentException
2207
-     * @throws InvalidDataTypeException
2208
-     * @throws InvalidInterfaceException
2209
-     * @throws ReflectionException
2210
-     */
2211
-    public function get_admin_overview_link()
2212
-    {
2213
-        EE_Registry::instance()->load_helper('URL');
2214
-        return EEH_URL::add_query_args_and_nonce(
2215
-            array(
2216
-                'page' => 'espresso_registrations',
2217
-            ),
2218
-            admin_url('admin.php')
2219
-        );
2220
-    }
2221
-
2222
-
2223
-    /**
2224
-     * @param array $query_params
2225
-     * @return EE_Base_Class[]|EE_Registration[]
2226
-     * @throws EE_Error
2227
-     * @throws InvalidArgumentException
2228
-     * @throws InvalidDataTypeException
2229
-     * @throws InvalidInterfaceException
2230
-     * @throws ReflectionException
2231
-     */
2232
-    public function payments($query_params = array())
2233
-    {
2234
-        return $this->get_many_related('Payment', $query_params);
2235
-    }
2236
-
2237
-
2238
-    /**
2239
-     * @param array $query_params
2240
-     * @return EE_Base_Class[]|EE_Registration_Payment[]
2241
-     * @throws EE_Error
2242
-     * @throws InvalidArgumentException
2243
-     * @throws InvalidDataTypeException
2244
-     * @throws InvalidInterfaceException
2245
-     * @throws ReflectionException
2246
-     */
2247
-    public function registration_payments($query_params = array())
2248
-    {
2249
-        return $this->get_many_related('Registration_Payment', $query_params);
2250
-    }
2251
-
2252
-
2253
-    /**
2254
-     * This grabs the payment method corresponding to the last payment made for the amount owing on the registration.
2255
-     * Note: if there are no payments on the registration there will be no payment method returned.
2256
-     *
2257
-     * @return EE_Payment|EE_Payment_Method|null
2258
-     * @throws EE_Error
2259
-     * @throws InvalidArgumentException
2260
-     * @throws InvalidDataTypeException
2261
-     * @throws InvalidInterfaceException
2262
-     */
2263
-    public function payment_method()
2264
-    {
2265
-        return EEM_Payment_Method::instance()->get_last_used_for_registration($this);
2266
-    }
2267
-
2268
-
2269
-    /**
2270
-     * @return \EE_Line_Item
2271
-     * @throws EE_Error
2272
-     * @throws EntityNotFoundException
2273
-     * @throws InvalidArgumentException
2274
-     * @throws InvalidDataTypeException
2275
-     * @throws InvalidInterfaceException
2276
-     * @throws ReflectionException
2277
-     */
2278
-    public function ticket_line_item()
2279
-    {
2280
-        $ticket = $this->ticket();
2281
-        $transaction = $this->transaction();
2282
-        $line_item = null;
2283
-        $ticket_line_items = \EEH_Line_Item::get_line_items_by_object_type_and_IDs(
2284
-            $transaction->total_line_item(),
2285
-            'Ticket',
2286
-            array($ticket->ID())
2287
-        );
2288
-        foreach ($ticket_line_items as $ticket_line_item) {
2289
-            if (
2290
-                $ticket_line_item instanceof \EE_Line_Item
2291
-                && $ticket_line_item->OBJ_type() === 'Ticket'
2292
-                && $ticket_line_item->OBJ_ID() === $ticket->ID()
2293
-            ) {
2294
-                $line_item = $ticket_line_item;
2295
-                break;
2296
-            }
2297
-        }
2298
-        if (! ($line_item instanceof \EE_Line_Item && $line_item->OBJ_type() === 'Ticket')) {
2299
-            throw new EntityNotFoundException('Line Item Ticket ID', $ticket->ID());
2300
-        }
2301
-        return $line_item;
2302
-    }
2303
-
2304
-
2305
-    /**
2306
-     * Soft Deletes this model object.
2307
-     *
2308
-     * @param string $source function name that called this method
2309
-     * @return boolean | int
2310
-     * @throws DomainException
2311
-     * @throws EE_Error
2312
-     * @throws EntityNotFoundException
2313
-     * @throws InvalidArgumentException
2314
-     * @throws InvalidDataTypeException
2315
-     * @throws InvalidInterfaceException
2316
-     * @throws ReflectionException
2317
-     * @throws RuntimeException
2318
-     * @throws UnexpectedEntityException
2319
-     */
2320
-    public function delete()
2321
-    {
2322
-        if ($this->update_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY, $this->status_ID()) === true) {
2323
-            $this->set_status(EEM_Registration::status_id_cancelled);
2324
-        }
2325
-        return parent::delete();
2326
-    }
2327
-
2328
-
2329
-    /**
2330
-     * Restores whatever the previous status was on a registration before it was trashed (if possible)
2331
-     *
2332
-     * @param string $source function name that called this method
2333
-     * @return bool|int
2334
-     * @throws DomainException
2335
-     * @throws EE_Error
2336
-     * @throws EntityNotFoundException
2337
-     * @throws InvalidArgumentException
2338
-     * @throws InvalidDataTypeException
2339
-     * @throws InvalidInterfaceException
2340
-     * @throws ReflectionException
2341
-     * @throws RuntimeException
2342
-     * @throws UnexpectedEntityException
2343
-     */
2344
-    public function restore()
2345
-    {
2346
-        $previous_status = $this->get_extra_meta(
2347
-            EE_Registration::PRE_TRASH_REG_STATUS_KEY,
2348
-            true,
2349
-            EEM_Registration::status_id_cancelled
2350
-        );
2351
-        if ($previous_status) {
2352
-            $this->delete_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY);
2353
-            $this->set_status($previous_status);
2354
-        }
2355
-        return parent::restore();
2356
-    }
2357
-
2358
-
2359
-    /**
2360
-     * possibly toggle Registration status based on comparison of REG_paid vs REG_final_price
2361
-     *
2362
-     * @param  boolean $trigger_set_status_logic EE_Registration::set_status() can trigger additional logic
2363
-     *                                           depending on whether the reg status changes to or from "Approved"
2364
-     * @return boolean whether the Registration status was updated
2365
-     * @throws DomainException
2366
-     * @throws EE_Error
2367
-     * @throws EntityNotFoundException
2368
-     * @throws InvalidArgumentException
2369
-     * @throws InvalidDataTypeException
2370
-     * @throws InvalidInterfaceException
2371
-     * @throws ReflectionException
2372
-     * @throws RuntimeException
2373
-     * @throws UnexpectedEntityException
2374
-     */
2375
-    public function updateStatusBasedOnTotalPaid($trigger_set_status_logic = true)
2376
-    {
2377
-        $paid = $this->paid();
2378
-        $price = $this->final_price();
2379
-        switch (true) {
2380
-            // overpaid or paid
2381
-            case EEH_Money::compare_floats($paid, $price, '>'):
2382
-            case EEH_Money::compare_floats($paid, $price):
2383
-                $new_status = EEM_Registration::status_id_approved;
2384
-                break;
2385
-            //  underpaid
2386
-            case EEH_Money::compare_floats($paid, $price, '<'):
2387
-                $new_status = EEM_Registration::status_id_pending_payment;
2388
-                break;
2389
-            // uhhh Houston...
2390
-            default:
2391
-                throw new RuntimeException(
2392
-                    esc_html__('The total paid calculation for this registration is inaccurate.', 'event_espresso')
2393
-                );
2394
-        }
2395
-        if ($new_status !== $this->status_ID()) {
2396
-            if ($trigger_set_status_logic) {
2397
-                return $this->set_status($new_status);
2398
-            }
2399
-            parent::set('STS_ID', $new_status);
2400
-            return true;
2401
-        }
2402
-        return false;
2403
-    }
2404
-
2405
-
2406
-    /*************************** DEPRECATED ***************************/
2407
-
2408
-
2409
-    /**
2410
-     * @deprecated
2411
-     * @since     4.7.0
2412
-     */
2413
-    public function price_paid()
2414
-    {
2415
-        EE_Error::doing_it_wrong(
2416
-            'EE_Registration::price_paid()',
2417
-            esc_html__(
2418
-                'This method is deprecated, please use EE_Registration::final_price() instead.',
2419
-                'event_espresso'
2420
-            ),
2421
-            '4.7.0'
2422
-        );
2423
-        return $this->final_price();
2424
-    }
2425
-
2426
-
2427
-    /**
2428
-     * @deprecated
2429
-     * @since     4.7.0
2430
-     * @param    float $REG_final_price
2431
-     * @throws EE_Error
2432
-     * @throws EntityNotFoundException
2433
-     * @throws InvalidArgumentException
2434
-     * @throws InvalidDataTypeException
2435
-     * @throws InvalidInterfaceException
2436
-     * @throws ReflectionException
2437
-     * @throws RuntimeException
2438
-     * @throws DomainException
2439
-     */
2440
-    public function set_price_paid($REG_final_price = 0.00)
2441
-    {
2442
-        EE_Error::doing_it_wrong(
2443
-            'EE_Registration::set_price_paid()',
2444
-            esc_html__(
2445
-                'This method is deprecated, please use EE_Registration::set_final_price() instead.',
2446
-                'event_espresso'
2447
-            ),
2448
-            '4.7.0'
2449
-        );
2450
-        $this->set_final_price($REG_final_price);
2451
-    }
2452
-
2453
-
2454
-    /**
2455
-     * @deprecated
2456
-     * @since 4.7.0
2457
-     * @return string
2458
-     * @throws EE_Error
2459
-     * @throws InvalidArgumentException
2460
-     * @throws InvalidDataTypeException
2461
-     * @throws InvalidInterfaceException
2462
-     * @throws ReflectionException
2463
-     */
2464
-    public function pretty_price_paid()
2465
-    {
2466
-        EE_Error::doing_it_wrong(
2467
-            'EE_Registration::pretty_price_paid()',
2468
-            esc_html__(
2469
-                'This method is deprecated, please use EE_Registration::pretty_final_price() instead.',
2470
-                'event_espresso'
2471
-            ),
2472
-            '4.7.0'
2473
-        );
2474
-        return $this->pretty_final_price();
2475
-    }
2476
-
2477
-
2478
-    /**
2479
-     * Gets the primary datetime related to this registration via the related Event to this registration
2480
-     *
2481
-     * @deprecated 4.9.17
2482
-     * @return EE_Datetime
2483
-     * @throws EE_Error
2484
-     * @throws EntityNotFoundException
2485
-     * @throws InvalidArgumentException
2486
-     * @throws InvalidDataTypeException
2487
-     * @throws InvalidInterfaceException
2488
-     * @throws ReflectionException
2489
-     */
2490
-    public function get_related_primary_datetime()
2491
-    {
2492
-        EE_Error::doing_it_wrong(
2493
-            __METHOD__,
2494
-            esc_html__(
2495
-                'Use EE_Registration::get_latest_related_datetime() or EE_Registration::get_earliest_related_datetime()',
2496
-                'event_espresso'
2497
-            ),
2498
-            '4.9.17',
2499
-            '5.0.0'
2500
-        );
2501
-        return $this->event()->primary_datetime();
2502
-    }
2503
-
2504
-    /**
2505
-     * Returns the contact's name (or "Unknown" if there is no contact.)
2506
-     * @since 4.10.12.p
2507
-     * @return string
2508
-     * @throws EE_Error
2509
-     * @throws InvalidArgumentException
2510
-     * @throws InvalidDataTypeException
2511
-     * @throws InvalidInterfaceException
2512
-     * @throws ReflectionException
2513
-     */
2514
-    public function name()
2515
-    {
2516
-        return $this->attendeeName();
2517
-    }
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
+	/**
59
+	 * @param array  $props_n_values          incoming values
60
+	 * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
61
+	 *                                        used.)
62
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
63
+	 *                                        date_format and the second value is the time format
64
+	 * @return EE_Registration
65
+	 * @throws EE_Error
66
+	 * @throws InvalidArgumentException
67
+	 * @throws InvalidDataTypeException
68
+	 * @throws InvalidInterfaceException
69
+	 * @throws ReflectionException
70
+	 */
71
+	public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
72
+	{
73
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
74
+		return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
75
+	}
76
+
77
+
78
+	/**
79
+	 * @param array  $props_n_values  incoming values from the database
80
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
81
+	 *                                the website will be used.
82
+	 * @return EE_Registration
83
+	 * @throws EE_Error
84
+	 * @throws InvalidArgumentException
85
+	 * @throws InvalidDataTypeException
86
+	 * @throws InvalidInterfaceException
87
+	 * @throws ReflectionException
88
+	 */
89
+	public static function new_instance_from_db($props_n_values = array(), $timezone = null)
90
+	{
91
+		return new self($props_n_values, true, $timezone);
92
+	}
93
+
94
+
95
+	/**
96
+	 *        Set Event ID
97
+	 *
98
+	 * @param        int $EVT_ID Event ID
99
+	 * @throws DomainException
100
+	 * @throws EE_Error
101
+	 * @throws EntityNotFoundException
102
+	 * @throws InvalidArgumentException
103
+	 * @throws InvalidDataTypeException
104
+	 * @throws InvalidInterfaceException
105
+	 * @throws ReflectionException
106
+	 * @throws RuntimeException
107
+	 * @throws UnexpectedEntityException
108
+	 */
109
+	public function set_event($EVT_ID = 0)
110
+	{
111
+		$this->set('EVT_ID', $EVT_ID);
112
+	}
113
+
114
+
115
+	/**
116
+	 * Overrides parent set() method so that all calls to set( 'REG_code', $REG_code ) OR set( 'STS_ID', $STS_ID ) can
117
+	 * be routed to internal methods
118
+	 *
119
+	 * @param string $field_name
120
+	 * @param mixed  $field_value
121
+	 * @param bool   $use_default
122
+	 * @throws DomainException
123
+	 * @throws EE_Error
124
+	 * @throws EntityNotFoundException
125
+	 * @throws InvalidArgumentException
126
+	 * @throws InvalidDataTypeException
127
+	 * @throws InvalidInterfaceException
128
+	 * @throws ReflectionException
129
+	 * @throws RuntimeException
130
+	 * @throws UnexpectedEntityException
131
+	 */
132
+	public function set($field_name, $field_value, $use_default = false)
133
+	{
134
+		switch ($field_name) {
135
+			case 'REG_code':
136
+				if (! empty($field_value) && $this->reg_code() === null) {
137
+					$this->set_reg_code($field_value, $use_default);
138
+				}
139
+				break;
140
+			case 'STS_ID':
141
+				$this->set_status($field_value, $use_default);
142
+				break;
143
+			default:
144
+				parent::set($field_name, $field_value, $use_default);
145
+		}
146
+	}
147
+
148
+
149
+	/**
150
+	 * Set Status ID
151
+	 * updates the registration status and ALSO...
152
+	 * calls reserve_registration_space() if the reg status changes TO approved from any other reg status
153
+	 * calls release_registration_space() if the reg status changes FROM approved to any other reg status
154
+	 *
155
+	 * @param string                $new_STS_ID
156
+	 * @param boolean               $use_default
157
+	 * @param ContextInterface|null $context
158
+	 * @return bool
159
+	 * @throws DomainException
160
+	 * @throws EE_Error
161
+	 * @throws EntityNotFoundException
162
+	 * @throws InvalidArgumentException
163
+	 * @throws InvalidDataTypeException
164
+	 * @throws InvalidInterfaceException
165
+	 * @throws ReflectionException
166
+	 * @throws RuntimeException
167
+	 * @throws UnexpectedEntityException
168
+	 */
169
+	public function set_status($new_STS_ID = null, $use_default = false, ContextInterface $context = null)
170
+	{
171
+		// get current REG_Status
172
+		$old_STS_ID = $this->status_ID();
173
+		// if status has changed
174
+		if (
175
+			$old_STS_ID !== $new_STS_ID // and that status has actually changed
176
+			&& ! empty($old_STS_ID) // and that old status is actually set
177
+			&& ! empty($new_STS_ID) // as well as the new status
178
+			&& $this->ID() // ensure registration is in the db
179
+		) {
180
+			// update internal status first
181
+			parent::set('STS_ID', $new_STS_ID, $use_default);
182
+			// THEN handle other changes that occur when reg status changes
183
+			// TO approved
184
+			if ($new_STS_ID === EEM_Registration::status_id_approved) {
185
+				// reserve a space by incrementing ticket and datetime sold values
186
+				$this->reserveRegistrationSpace();
187
+				do_action('AHEE__EE_Registration__set_status__to_approved', $this, $old_STS_ID, $new_STS_ID, $context);
188
+				// OR FROM  approved
189
+			} elseif ($old_STS_ID === EEM_Registration::status_id_approved) {
190
+				// release a space by decrementing ticket and datetime sold values
191
+				$this->releaseRegistrationSpace();
192
+				do_action(
193
+					'AHEE__EE_Registration__set_status__from_approved',
194
+					$this,
195
+					$old_STS_ID,
196
+					$new_STS_ID,
197
+					$context
198
+				);
199
+			}
200
+			// update status
201
+			parent::set('STS_ID', $new_STS_ID, $use_default);
202
+			$this->updateIfCanceledOrReinstated($new_STS_ID, $old_STS_ID, $context);
203
+			if ($this->statusChangeUpdatesTransaction($context)) {
204
+				$this->updateTransactionAfterStatusChange();
205
+			}
206
+			do_action('AHEE__EE_Registration__set_status__after_update', $this, $old_STS_ID, $new_STS_ID, $context);
207
+			return true;
208
+		}
209
+		// even though the old value matches the new value, it's still good to
210
+		// allow the parent set method to have a say
211
+		parent::set('STS_ID', $new_STS_ID, $use_default);
212
+		return true;
213
+	}
214
+
215
+
216
+	/**
217
+	 * update REGs and TXN when cancelled or declined registrations involved
218
+	 *
219
+	 * @param string                $new_STS_ID
220
+	 * @param string                $old_STS_ID
221
+	 * @param ContextInterface|null $context
222
+	 * @throws EE_Error
223
+	 * @throws InvalidArgumentException
224
+	 * @throws InvalidDataTypeException
225
+	 * @throws InvalidInterfaceException
226
+	 * @throws ReflectionException
227
+	 * @throws RuntimeException
228
+	 */
229
+	private function updateIfCanceledOrReinstated($new_STS_ID, $old_STS_ID, ContextInterface $context = null)
230
+	{
231
+		// these reg statuses should not be considered in any calculations involving monies owing
232
+		$closed_reg_statuses = EEM_Registration::closed_reg_statuses();
233
+		// true if registration has been cancelled or declined
234
+		$this->updateIfCanceled(
235
+			$closed_reg_statuses,
236
+			$new_STS_ID,
237
+			$old_STS_ID,
238
+			$context
239
+		);
240
+		$this->updateIfReinstated(
241
+			$closed_reg_statuses,
242
+			$new_STS_ID,
243
+			$old_STS_ID,
244
+			$context
245
+		);
246
+	}
247
+
248
+
249
+	/**
250
+	 * update REGs and TXN when cancelled or declined registrations involved
251
+	 *
252
+	 * @param array                 $closed_reg_statuses
253
+	 * @param string                $new_STS_ID
254
+	 * @param string                $old_STS_ID
255
+	 * @param ContextInterface|null $context
256
+	 * @throws EE_Error
257
+	 * @throws InvalidArgumentException
258
+	 * @throws InvalidDataTypeException
259
+	 * @throws InvalidInterfaceException
260
+	 * @throws ReflectionException
261
+	 * @throws RuntimeException
262
+	 */
263
+	private function updateIfCanceled(
264
+		array $closed_reg_statuses,
265
+		$new_STS_ID,
266
+		$old_STS_ID,
267
+		ContextInterface $context = null
268
+	) {
269
+		// true if registration has been cancelled or declined
270
+		if (
271
+			in_array($new_STS_ID, $closed_reg_statuses, true)
272
+			&& ! in_array($old_STS_ID, $closed_reg_statuses, true)
273
+		) {
274
+			/** @type EE_Registration_Processor $registration_processor */
275
+			$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
276
+			/** @type EE_Transaction_Processor $transaction_processor */
277
+			$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
278
+			// cancelled or declined registration
279
+			$registration_processor->update_registration_after_being_canceled_or_declined(
280
+				$this,
281
+				$closed_reg_statuses
282
+			);
283
+			$transaction_processor->update_transaction_after_canceled_or_declined_registration(
284
+				$this,
285
+				$closed_reg_statuses,
286
+				false
287
+			);
288
+			do_action(
289
+				'AHEE__EE_Registration__set_status__canceled_or_declined',
290
+				$this,
291
+				$old_STS_ID,
292
+				$new_STS_ID,
293
+				$context
294
+			);
295
+			return;
296
+		}
297
+	}
298
+
299
+
300
+	/**
301
+	 * update REGs and TXN when cancelled or declined registrations involved
302
+	 *
303
+	 * @param array                 $closed_reg_statuses
304
+	 * @param string                $new_STS_ID
305
+	 * @param string                $old_STS_ID
306
+	 * @param ContextInterface|null $context
307
+	 * @throws EE_Error
308
+	 * @throws InvalidArgumentException
309
+	 * @throws InvalidDataTypeException
310
+	 * @throws InvalidInterfaceException
311
+	 * @throws ReflectionException
312
+	 * @throws RuntimeException
313
+	 */
314
+	private function updateIfReinstated(
315
+		array $closed_reg_statuses,
316
+		$new_STS_ID,
317
+		$old_STS_ID,
318
+		ContextInterface $context = null
319
+	) {
320
+		// true if reinstating cancelled or declined registration
321
+		if (
322
+			in_array($old_STS_ID, $closed_reg_statuses, true)
323
+			&& ! in_array($new_STS_ID, $closed_reg_statuses, true)
324
+		) {
325
+			/** @type EE_Registration_Processor $registration_processor */
326
+			$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
327
+			/** @type EE_Transaction_Processor $transaction_processor */
328
+			$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
329
+			// reinstating cancelled or declined registration
330
+			$registration_processor->update_canceled_or_declined_registration_after_being_reinstated(
331
+				$this,
332
+				$closed_reg_statuses
333
+			);
334
+			$transaction_processor->update_transaction_after_reinstating_canceled_registration(
335
+				$this,
336
+				$closed_reg_statuses,
337
+				false
338
+			);
339
+			do_action(
340
+				'AHEE__EE_Registration__set_status__after_reinstated',
341
+				$this,
342
+				$old_STS_ID,
343
+				$new_STS_ID,
344
+				$context
345
+			);
346
+		}
347
+	}
348
+
349
+
350
+	/**
351
+	 * @param ContextInterface|null $context
352
+	 * @return bool
353
+	 */
354
+	private function statusChangeUpdatesTransaction(ContextInterface $context = null)
355
+	{
356
+		$contexts_that_do_not_update_transaction = (array) apply_filters(
357
+			'AHEE__EE_Registration__statusChangeUpdatesTransaction__contexts_that_do_not_update_transaction',
358
+			array('spco_reg_step_attendee_information_process_registrations'),
359
+			$context,
360
+			$this
361
+		);
362
+		return ! (
363
+			$context instanceof ContextInterface
364
+			&& in_array($context->slug(), $contexts_that_do_not_update_transaction, true)
365
+		);
366
+	}
367
+
368
+
369
+	/**
370
+	 * @throws EE_Error
371
+	 * @throws EntityNotFoundException
372
+	 * @throws InvalidArgumentException
373
+	 * @throws InvalidDataTypeException
374
+	 * @throws InvalidInterfaceException
375
+	 * @throws ReflectionException
376
+	 * @throws RuntimeException
377
+	 */
378
+	private function updateTransactionAfterStatusChange()
379
+	{
380
+		/** @type EE_Transaction_Payments $transaction_payments */
381
+		$transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
382
+		$transaction_payments->recalculate_transaction_total($this->transaction(), false);
383
+		$this->transaction()->update_status_based_on_total_paid();
384
+	}
385
+
386
+
387
+	/**
388
+	 * get Status ID
389
+	 *
390
+	 * @throws EE_Error
391
+	 * @throws InvalidArgumentException
392
+	 * @throws InvalidDataTypeException
393
+	 * @throws InvalidInterfaceException
394
+	 * @throws ReflectionException
395
+	 */
396
+	public function status_ID()
397
+	{
398
+		return $this->get('STS_ID');
399
+	}
400
+
401
+
402
+	/**
403
+	 * Gets the ticket this registration is for
404
+	 *
405
+	 * @param boolean $include_archived whether to include archived tickets or not.
406
+	 * @return EE_Ticket|EE_Base_Class
407
+	 * @throws EE_Error
408
+	 * @throws InvalidArgumentException
409
+	 * @throws InvalidDataTypeException
410
+	 * @throws InvalidInterfaceException
411
+	 * @throws ReflectionException
412
+	 */
413
+	public function ticket($include_archived = true)
414
+	{
415
+		$query_params = array();
416
+		if ($include_archived) {
417
+			$query_params['default_where_conditions'] = 'none';
418
+		}
419
+		return $this->get_first_related('Ticket', $query_params);
420
+	}
421
+
422
+
423
+	/**
424
+	 * Gets the event this registration is for
425
+	 *
426
+	 * @return EE_Event
427
+	 * @throws EE_Error
428
+	 * @throws EntityNotFoundException
429
+	 * @throws InvalidArgumentException
430
+	 * @throws InvalidDataTypeException
431
+	 * @throws InvalidInterfaceException
432
+	 * @throws ReflectionException
433
+	 */
434
+	public function event()
435
+	{
436
+		$event = $this->get_first_related('Event');
437
+		if (! $event instanceof \EE_Event) {
438
+			throw new EntityNotFoundException('Event ID', $this->event_ID());
439
+		}
440
+		return $event;
441
+	}
442
+
443
+
444
+	/**
445
+	 * Gets the "author" of the registration.  Note that for the purposes of registrations, the author will correspond
446
+	 * with the author of the event this registration is for.
447
+	 *
448
+	 * @since 4.5.0
449
+	 * @return int
450
+	 * @throws EE_Error
451
+	 * @throws EntityNotFoundException
452
+	 * @throws InvalidArgumentException
453
+	 * @throws InvalidDataTypeException
454
+	 * @throws InvalidInterfaceException
455
+	 * @throws ReflectionException
456
+	 */
457
+	public function wp_user()
458
+	{
459
+		$event = $this->event();
460
+		if ($event instanceof EE_Event) {
461
+			return $event->wp_user();
462
+		}
463
+		return 0;
464
+	}
465
+
466
+
467
+	/**
468
+	 * increments this registration's related ticket sold and corresponding datetime sold values
469
+	 *
470
+	 * @return void
471
+	 * @throws DomainException
472
+	 * @throws EE_Error
473
+	 * @throws EntityNotFoundException
474
+	 * @throws InvalidArgumentException
475
+	 * @throws InvalidDataTypeException
476
+	 * @throws InvalidInterfaceException
477
+	 * @throws ReflectionException
478
+	 * @throws UnexpectedEntityException
479
+	 */
480
+	private function reserveRegistrationSpace()
481
+	{
482
+		// reserved ticket and datetime counts will be decremented as sold counts are incremented
483
+		// so stop tracking that this reg has a ticket reserved
484
+		$this->release_reserved_ticket(false, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
485
+		$ticket = $this->ticket();
486
+		$ticket->increaseSold();
487
+		// possibly set event status to sold out
488
+		$this->event()->perform_sold_out_status_check();
489
+	}
490
+
491
+
492
+	/**
493
+	 * decrements (subtracts) this registration's related ticket sold and corresponding datetime sold values
494
+	 *
495
+	 * @return void
496
+	 * @throws DomainException
497
+	 * @throws EE_Error
498
+	 * @throws EntityNotFoundException
499
+	 * @throws InvalidArgumentException
500
+	 * @throws InvalidDataTypeException
501
+	 * @throws InvalidInterfaceException
502
+	 * @throws ReflectionException
503
+	 * @throws UnexpectedEntityException
504
+	 */
505
+	private function releaseRegistrationSpace()
506
+	{
507
+		$ticket = $this->ticket();
508
+		$ticket->decreaseSold();
509
+		// possibly change event status from sold out back to previous status
510
+		$this->event()->perform_sold_out_status_check();
511
+	}
512
+
513
+
514
+	/**
515
+	 * tracks this registration's ticket reservation in extra meta
516
+	 * and can increment related ticket reserved and corresponding datetime reserved values
517
+	 *
518
+	 * @param bool   $update_ticket if true, will increment ticket and datetime reserved count
519
+	 * @param string $source
520
+	 * @return void
521
+	 * @throws EE_Error
522
+	 * @throws InvalidArgumentException
523
+	 * @throws InvalidDataTypeException
524
+	 * @throws InvalidInterfaceException
525
+	 * @throws ReflectionException
526
+	 */
527
+	public function reserve_ticket($update_ticket = false, $source = 'unknown')
528
+	{
529
+		// only reserve ticket if space is not currently reserved
530
+		if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) !== true) {
531
+			$reserved = $this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true);
532
+			if ($reserved && $update_ticket) {
533
+				$ticket = $this->ticket();
534
+				$ticket->increaseReserved(1, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
535
+				$this->update_extra_meta('reserve_ticket', "{$this->ticket_ID()} from {$source}");
536
+				$ticket->save();
537
+			}
538
+		}
539
+	}
540
+
541
+
542
+	/**
543
+	 * stops tracking this registration's ticket reservation in extra meta
544
+	 * decrements (subtracts) related ticket reserved and corresponding datetime reserved values
545
+	 *
546
+	 * @param bool   $update_ticket if true, will decrement ticket and datetime reserved count
547
+	 * @param string $source
548
+	 * @return void
549
+	 * @throws EE_Error
550
+	 * @throws InvalidArgumentException
551
+	 * @throws InvalidDataTypeException
552
+	 * @throws InvalidInterfaceException
553
+	 * @throws ReflectionException
554
+	 */
555
+	public function release_reserved_ticket($update_ticket = false, $source = 'unknown')
556
+	{
557
+		// only release ticket if space is currently reserved
558
+		if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) === true) {
559
+			$reserved = $this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, false);
560
+			if ($reserved && $update_ticket) {
561
+				$ticket = $this->ticket();
562
+				$ticket->decreaseReserved(1, true, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
563
+				$this->update_extra_meta('release_reserved_ticket', "{$this->ticket_ID()} from {$source}");
564
+			}
565
+		}
566
+	}
567
+
568
+
569
+	/**
570
+	 * Set Attendee ID
571
+	 *
572
+	 * @param        int $ATT_ID Attendee ID
573
+	 * @throws DomainException
574
+	 * @throws EE_Error
575
+	 * @throws EntityNotFoundException
576
+	 * @throws InvalidArgumentException
577
+	 * @throws InvalidDataTypeException
578
+	 * @throws InvalidInterfaceException
579
+	 * @throws ReflectionException
580
+	 * @throws RuntimeException
581
+	 * @throws UnexpectedEntityException
582
+	 */
583
+	public function set_attendee_id($ATT_ID = 0)
584
+	{
585
+		$this->set('ATT_ID', $ATT_ID);
586
+	}
587
+
588
+
589
+	/**
590
+	 *        Set Transaction ID
591
+	 *
592
+	 * @param        int $TXN_ID Transaction ID
593
+	 * @throws DomainException
594
+	 * @throws EE_Error
595
+	 * @throws EntityNotFoundException
596
+	 * @throws InvalidArgumentException
597
+	 * @throws InvalidDataTypeException
598
+	 * @throws InvalidInterfaceException
599
+	 * @throws ReflectionException
600
+	 * @throws RuntimeException
601
+	 * @throws UnexpectedEntityException
602
+	 */
603
+	public function set_transaction_id($TXN_ID = 0)
604
+	{
605
+		$this->set('TXN_ID', $TXN_ID);
606
+	}
607
+
608
+
609
+	/**
610
+	 *        Set Session
611
+	 *
612
+	 * @param    string $REG_session PHP Session ID
613
+	 * @throws DomainException
614
+	 * @throws EE_Error
615
+	 * @throws EntityNotFoundException
616
+	 * @throws InvalidArgumentException
617
+	 * @throws InvalidDataTypeException
618
+	 * @throws InvalidInterfaceException
619
+	 * @throws ReflectionException
620
+	 * @throws RuntimeException
621
+	 * @throws UnexpectedEntityException
622
+	 */
623
+	public function set_session($REG_session = '')
624
+	{
625
+		$this->set('REG_session', $REG_session);
626
+	}
627
+
628
+
629
+	/**
630
+	 *        Set Registration URL Link
631
+	 *
632
+	 * @param    string $REG_url_link Registration URL Link
633
+	 * @throws DomainException
634
+	 * @throws EE_Error
635
+	 * @throws EntityNotFoundException
636
+	 * @throws InvalidArgumentException
637
+	 * @throws InvalidDataTypeException
638
+	 * @throws InvalidInterfaceException
639
+	 * @throws ReflectionException
640
+	 * @throws RuntimeException
641
+	 * @throws UnexpectedEntityException
642
+	 */
643
+	public function set_reg_url_link($REG_url_link = '')
644
+	{
645
+		$this->set('REG_url_link', $REG_url_link);
646
+	}
647
+
648
+
649
+	/**
650
+	 *        Set Attendee Counter
651
+	 *
652
+	 * @param        int $REG_count Primary Attendee
653
+	 * @throws DomainException
654
+	 * @throws EE_Error
655
+	 * @throws EntityNotFoundException
656
+	 * @throws InvalidArgumentException
657
+	 * @throws InvalidDataTypeException
658
+	 * @throws InvalidInterfaceException
659
+	 * @throws ReflectionException
660
+	 * @throws RuntimeException
661
+	 * @throws UnexpectedEntityException
662
+	 */
663
+	public function set_count($REG_count = 1)
664
+	{
665
+		$this->set('REG_count', $REG_count);
666
+	}
667
+
668
+
669
+	/**
670
+	 *        Set Group Size
671
+	 *
672
+	 * @param        boolean $REG_group_size Group Registration
673
+	 * @throws DomainException
674
+	 * @throws EE_Error
675
+	 * @throws EntityNotFoundException
676
+	 * @throws InvalidArgumentException
677
+	 * @throws InvalidDataTypeException
678
+	 * @throws InvalidInterfaceException
679
+	 * @throws ReflectionException
680
+	 * @throws RuntimeException
681
+	 * @throws UnexpectedEntityException
682
+	 */
683
+	public function set_group_size($REG_group_size = false)
684
+	{
685
+		$this->set('REG_group_size', $REG_group_size);
686
+	}
687
+
688
+
689
+	/**
690
+	 *    is_not_approved -  convenience method that returns TRUE if REG status ID ==
691
+	 *    EEM_Registration::status_id_not_approved
692
+	 *
693
+	 * @return        boolean
694
+	 * @throws EE_Error
695
+	 * @throws InvalidArgumentException
696
+	 * @throws InvalidDataTypeException
697
+	 * @throws InvalidInterfaceException
698
+	 * @throws ReflectionException
699
+	 */
700
+	public function is_not_approved()
701
+	{
702
+		return $this->status_ID() === EEM_Registration::status_id_not_approved;
703
+	}
704
+
705
+
706
+	/**
707
+	 *    is_pending_payment -  convenience method that returns TRUE if REG status ID ==
708
+	 *    EEM_Registration::status_id_pending_payment
709
+	 *
710
+	 * @return        boolean
711
+	 * @throws EE_Error
712
+	 * @throws InvalidArgumentException
713
+	 * @throws InvalidDataTypeException
714
+	 * @throws InvalidInterfaceException
715
+	 * @throws ReflectionException
716
+	 */
717
+	public function is_pending_payment()
718
+	{
719
+		return $this->status_ID() === EEM_Registration::status_id_pending_payment;
720
+	}
721
+
722
+
723
+	/**
724
+	 *    is_approved -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_approved
725
+	 *
726
+	 * @return        boolean
727
+	 * @throws EE_Error
728
+	 * @throws InvalidArgumentException
729
+	 * @throws InvalidDataTypeException
730
+	 * @throws InvalidInterfaceException
731
+	 * @throws ReflectionException
732
+	 */
733
+	public function is_approved()
734
+	{
735
+		return $this->status_ID() === EEM_Registration::status_id_approved;
736
+	}
737
+
738
+
739
+	/**
740
+	 *    is_cancelled -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_cancelled
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_cancelled()
750
+	{
751
+		return $this->status_ID() === EEM_Registration::status_id_cancelled;
752
+	}
753
+
754
+
755
+	/**
756
+	 *    is_declined -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_declined
757
+	 *
758
+	 * @return        boolean
759
+	 * @throws EE_Error
760
+	 * @throws InvalidArgumentException
761
+	 * @throws InvalidDataTypeException
762
+	 * @throws InvalidInterfaceException
763
+	 * @throws ReflectionException
764
+	 */
765
+	public function is_declined()
766
+	{
767
+		return $this->status_ID() === EEM_Registration::status_id_declined;
768
+	}
769
+
770
+
771
+	/**
772
+	 *    is_incomplete -  convenience method that returns TRUE if REG status ID ==
773
+	 *    EEM_Registration::status_id_incomplete
774
+	 *
775
+	 * @return        boolean
776
+	 * @throws EE_Error
777
+	 * @throws InvalidArgumentException
778
+	 * @throws InvalidDataTypeException
779
+	 * @throws InvalidInterfaceException
780
+	 * @throws ReflectionException
781
+	 */
782
+	public function is_incomplete()
783
+	{
784
+		return $this->status_ID() === EEM_Registration::status_id_incomplete;
785
+	}
786
+
787
+
788
+	/**
789
+	 *        Set Registration Date
790
+	 *
791
+	 * @param        mixed ( int or string ) $REG_date Registration Date - Unix timestamp or string representation of
792
+	 *                                                 Date
793
+	 * @throws DomainException
794
+	 * @throws EE_Error
795
+	 * @throws EntityNotFoundException
796
+	 * @throws InvalidArgumentException
797
+	 * @throws InvalidDataTypeException
798
+	 * @throws InvalidInterfaceException
799
+	 * @throws ReflectionException
800
+	 * @throws RuntimeException
801
+	 * @throws UnexpectedEntityException
802
+	 */
803
+	public function set_reg_date($REG_date = false)
804
+	{
805
+		$this->set('REG_date', $REG_date);
806
+	}
807
+
808
+
809
+	/**
810
+	 *    Set final price owing for this registration after all ticket/price modifications
811
+	 *
812
+	 * @param    float $REG_final_price
813
+	 * @throws DomainException
814
+	 * @throws EE_Error
815
+	 * @throws EntityNotFoundException
816
+	 * @throws InvalidArgumentException
817
+	 * @throws InvalidDataTypeException
818
+	 * @throws InvalidInterfaceException
819
+	 * @throws ReflectionException
820
+	 * @throws RuntimeException
821
+	 * @throws UnexpectedEntityException
822
+	 */
823
+	public function set_final_price($REG_final_price = 0.00)
824
+	{
825
+		$this->set('REG_final_price', $REG_final_price);
826
+	}
827
+
828
+
829
+	/**
830
+	 *    Set amount paid towards this registration's final price
831
+	 *
832
+	 * @param    float $REG_paid
833
+	 * @throws DomainException
834
+	 * @throws EE_Error
835
+	 * @throws EntityNotFoundException
836
+	 * @throws InvalidArgumentException
837
+	 * @throws InvalidDataTypeException
838
+	 * @throws InvalidInterfaceException
839
+	 * @throws ReflectionException
840
+	 * @throws RuntimeException
841
+	 * @throws UnexpectedEntityException
842
+	 */
843
+	public function set_paid($REG_paid = 0.00)
844
+	{
845
+		$this->set('REG_paid', $REG_paid);
846
+	}
847
+
848
+
849
+	/**
850
+	 *        Attendee Is Going
851
+	 *
852
+	 * @param        boolean $REG_att_is_going Attendee Is Going
853
+	 * @throws DomainException
854
+	 * @throws EE_Error
855
+	 * @throws EntityNotFoundException
856
+	 * @throws InvalidArgumentException
857
+	 * @throws InvalidDataTypeException
858
+	 * @throws InvalidInterfaceException
859
+	 * @throws ReflectionException
860
+	 * @throws RuntimeException
861
+	 * @throws UnexpectedEntityException
862
+	 */
863
+	public function set_att_is_going($REG_att_is_going = false)
864
+	{
865
+		$this->set('REG_att_is_going', $REG_att_is_going);
866
+	}
867
+
868
+
869
+	/**
870
+	 * Gets the related attendee
871
+	 *
872
+	 * @return EE_Attendee|EE_Base_Class
873
+	 * @throws EE_Error
874
+	 * @throws InvalidArgumentException
875
+	 * @throws InvalidDataTypeException
876
+	 * @throws InvalidInterfaceException
877
+	 * @throws ReflectionException
878
+	 */
879
+	public function attendee()
880
+	{
881
+		return $this->get_first_related('Attendee');
882
+	}
883
+
884
+	/**
885
+	 * Gets the name of the attendee.
886
+	 * @since 4.10.12.p
887
+	 * @param bool $apply_html_entities set to true if you want to use HTML entities.
888
+	 * @return string
889
+	 * @throws EE_Error
890
+	 * @throws InvalidArgumentException
891
+	 * @throws InvalidDataTypeException
892
+	 * @throws InvalidInterfaceException
893
+	 * @throws ReflectionException
894
+	 */
895
+	public function attendeeName($apply_html_entities = false)
896
+	{
897
+		$attendee = $this->get_first_related('Attendee');
898
+		if ($attendee instanceof EE_Attendee) {
899
+			$attendee_name = $attendee->full_name($apply_html_entities);
900
+		} else {
901
+			$attendee_name = esc_html__('Unknown', 'event_espresso');
902
+		}
903
+		return $attendee_name;
904
+	}
905
+
906
+
907
+	/**
908
+	 *        get Event ID
909
+	 */
910
+	public function event_ID()
911
+	{
912
+		return $this->get('EVT_ID');
913
+	}
914
+
915
+
916
+	/**
917
+	 *        get Event ID
918
+	 */
919
+	public function event_name()
920
+	{
921
+		$event = $this->event_obj();
922
+		if ($event) {
923
+			return $event->name();
924
+		} else {
925
+			return null;
926
+		}
927
+	}
928
+
929
+
930
+	/**
931
+	 * Fetches the event this registration is for
932
+	 *
933
+	 * @return EE_Base_Class|EE_Event
934
+	 * @throws EE_Error
935
+	 * @throws InvalidArgumentException
936
+	 * @throws InvalidDataTypeException
937
+	 * @throws InvalidInterfaceException
938
+	 * @throws ReflectionException
939
+	 */
940
+	public function event_obj()
941
+	{
942
+		return $this->get_first_related('Event');
943
+	}
944
+
945
+
946
+	/**
947
+	 *        get Attendee ID
948
+	 */
949
+	public function attendee_ID()
950
+	{
951
+		return $this->get('ATT_ID');
952
+	}
953
+
954
+
955
+	/**
956
+	 *        get PHP Session ID
957
+	 */
958
+	public function session_ID()
959
+	{
960
+		return $this->get('REG_session');
961
+	}
962
+
963
+
964
+	/**
965
+	 * Gets the string which represents the URL trigger for the receipt template in the message template system.
966
+	 *
967
+	 * @param string $messenger 'pdf' or 'html'.  Default 'html'.
968
+	 * @return string
969
+	 * @throws DomainException
970
+	 * @throws EE_Error
971
+	 * @throws InvalidArgumentException
972
+	 * @throws InvalidDataTypeException
973
+	 * @throws InvalidInterfaceException
974
+	 * @throws ReflectionException
975
+	 */
976
+	public function receipt_url($messenger = 'html')
977
+	{
978
+
979
+		/**
980
+		 * The below will be deprecated one version after this.  We check first if there is a custom receipt template
981
+		 * already in use on old system.  If there is then we just return the standard url for it.
982
+		 *
983
+		 * @since 4.5.0
984
+		 */
985
+		$template_relative_path = 'modules/gateways/Invoice/lib/templates/receipt_body.template.php';
986
+		$has_custom = EEH_Template::locate_template(
987
+			$template_relative_path,
988
+			array(),
989
+			true,
990
+			true,
991
+			true
992
+		);
993
+
994
+		if ($has_custom) {
995
+			return add_query_arg(array('receipt' => 'true'), $this->invoice_url('launch'));
996
+		}
997
+		return apply_filters('FHEE__EE_Registration__receipt_url__receipt_url', '', $this, $messenger, 'receipt');
998
+	}
999
+
1000
+
1001
+	/**
1002
+	 * Gets the string which represents the URL trigger for the invoice template in the message template system.
1003
+	 *
1004
+	 * @param string $messenger 'pdf' or 'html'.  Default 'html'.
1005
+	 * @return string
1006
+	 * @throws DomainException
1007
+	 * @throws EE_Error
1008
+	 * @throws InvalidArgumentException
1009
+	 * @throws InvalidDataTypeException
1010
+	 * @throws InvalidInterfaceException
1011
+	 * @throws ReflectionException
1012
+	 */
1013
+	public function invoice_url($messenger = 'html')
1014
+	{
1015
+		/**
1016
+		 * The below will be deprecated one version after this.  We check first if there is a custom invoice template
1017
+		 * already in use on old system.  If there is then we just return the standard url for it.
1018
+		 *
1019
+		 * @since 4.5.0
1020
+		 */
1021
+		$template_relative_path = 'modules/gateways/Invoice/lib/templates/invoice_body.template.php';
1022
+		$has_custom = EEH_Template::locate_template(
1023
+			$template_relative_path,
1024
+			array(),
1025
+			true,
1026
+			true,
1027
+			true
1028
+		);
1029
+
1030
+		if ($has_custom) {
1031
+			if ($messenger == 'html') {
1032
+				return $this->invoice_url('launch');
1033
+			}
1034
+			$route = $messenger == 'download' || $messenger == 'pdf' ? 'download_invoice' : 'launch_invoice';
1035
+
1036
+			$query_args = array('ee' => $route, 'id' => $this->reg_url_link());
1037
+			if ($messenger == 'html') {
1038
+				$query_args['html'] = true;
1039
+			}
1040
+			return add_query_arg($query_args, get_permalink(EE_Registry::instance()->CFG->core->thank_you_page_id));
1041
+		}
1042
+		return apply_filters('FHEE__EE_Registration__invoice_url__invoice_url', '', $this, $messenger, 'invoice');
1043
+	}
1044
+
1045
+
1046
+	/**
1047
+	 * get Registration URL Link
1048
+	 *
1049
+	 * @return string
1050
+	 * @throws EE_Error
1051
+	 * @throws InvalidArgumentException
1052
+	 * @throws InvalidDataTypeException
1053
+	 * @throws InvalidInterfaceException
1054
+	 * @throws ReflectionException
1055
+	 */
1056
+	public function reg_url_link()
1057
+	{
1058
+		return (string) $this->get('REG_url_link');
1059
+	}
1060
+
1061
+
1062
+	/**
1063
+	 * Echoes out invoice_url()
1064
+	 *
1065
+	 * @param string $type 'download','launch', or 'html' (default is 'launch')
1066
+	 * @return void
1067
+	 * @throws DomainException
1068
+	 * @throws EE_Error
1069
+	 * @throws InvalidArgumentException
1070
+	 * @throws InvalidDataTypeException
1071
+	 * @throws InvalidInterfaceException
1072
+	 * @throws ReflectionException
1073
+	 */
1074
+	public function e_invoice_url($type = 'launch')
1075
+	{
1076
+		echo esc_url_raw($this->invoice_url($type));
1077
+	}
1078
+
1079
+
1080
+	/**
1081
+	 * Echoes out payment_overview_url
1082
+	 */
1083
+	public function e_payment_overview_url()
1084
+	{
1085
+		echo esc_url_raw($this->payment_overview_url());
1086
+	}
1087
+
1088
+
1089
+	/**
1090
+	 * Gets the URL for the checkout payment options reg step
1091
+	 * with this registration's REG_url_link added as a query parameter
1092
+	 *
1093
+	 * @param bool $clear_session Set to true when you want to clear the session on revisiting the
1094
+	 *                            payment overview url.
1095
+	 * @return string
1096
+	 * @throws EE_Error
1097
+	 * @throws InvalidArgumentException
1098
+	 * @throws InvalidDataTypeException
1099
+	 * @throws InvalidInterfaceException
1100
+	 * @throws ReflectionException
1101
+	 */
1102
+	public function payment_overview_url($clear_session = false)
1103
+	{
1104
+		return add_query_arg(
1105
+			(array) apply_filters(
1106
+				'FHEE__EE_Registration__payment_overview_url__query_args',
1107
+				array(
1108
+					'e_reg_url_link' => $this->reg_url_link(),
1109
+					'step'           => 'payment_options',
1110
+					'revisit'        => true,
1111
+					'clear_session'  => (bool) $clear_session,
1112
+				),
1113
+				$this
1114
+			),
1115
+			EE_Registry::instance()->CFG->core->reg_page_url()
1116
+		);
1117
+	}
1118
+
1119
+
1120
+	/**
1121
+	 * Gets the URL for the checkout attendee information reg step
1122
+	 * with this registration's REG_url_link added as a query parameter
1123
+	 *
1124
+	 * @return string
1125
+	 * @throws EE_Error
1126
+	 * @throws InvalidArgumentException
1127
+	 * @throws InvalidDataTypeException
1128
+	 * @throws InvalidInterfaceException
1129
+	 * @throws ReflectionException
1130
+	 */
1131
+	public function edit_attendee_information_url()
1132
+	{
1133
+		return add_query_arg(
1134
+			(array) apply_filters(
1135
+				'FHEE__EE_Registration__edit_attendee_information_url__query_args',
1136
+				array(
1137
+					'e_reg_url_link' => $this->reg_url_link(),
1138
+					'step'           => 'attendee_information',
1139
+					'revisit'        => true,
1140
+				),
1141
+				$this
1142
+			),
1143
+			EE_Registry::instance()->CFG->core->reg_page_url()
1144
+		);
1145
+	}
1146
+
1147
+
1148
+	/**
1149
+	 * Simply generates and returns the appropriate admin_url link to edit this registration
1150
+	 *
1151
+	 * @return string
1152
+	 * @throws EE_Error
1153
+	 * @throws InvalidArgumentException
1154
+	 * @throws InvalidDataTypeException
1155
+	 * @throws InvalidInterfaceException
1156
+	 * @throws ReflectionException
1157
+	 */
1158
+	public function get_admin_edit_url()
1159
+	{
1160
+		return EEH_URL::add_query_args_and_nonce(
1161
+			array(
1162
+				'page'    => 'espresso_registrations',
1163
+				'action'  => 'view_registration',
1164
+				'_REG_ID' => $this->ID(),
1165
+			),
1166
+			admin_url('admin.php')
1167
+		);
1168
+	}
1169
+
1170
+
1171
+	/**
1172
+	 * is_primary_registrant?
1173
+	 *
1174
+	 * @throws EE_Error
1175
+	 * @throws InvalidArgumentException
1176
+	 * @throws InvalidDataTypeException
1177
+	 * @throws InvalidInterfaceException
1178
+	 * @throws ReflectionException
1179
+	 */
1180
+	public function is_primary_registrant()
1181
+	{
1182
+		return (int) $this->get('REG_count') === 1;
1183
+	}
1184
+
1185
+
1186
+	/**
1187
+	 * This returns the primary registration object for this registration group (which may be this object).
1188
+	 *
1189
+	 * @return EE_Registration
1190
+	 * @throws EE_Error
1191
+	 * @throws InvalidArgumentException
1192
+	 * @throws InvalidDataTypeException
1193
+	 * @throws InvalidInterfaceException
1194
+	 * @throws ReflectionException
1195
+	 */
1196
+	public function get_primary_registration()
1197
+	{
1198
+		if ($this->is_primary_registrant()) {
1199
+			return $this;
1200
+		}
1201
+
1202
+		// k reg_count !== 1 so let's get the EE_Registration object matching this txn_id and reg_count == 1
1203
+		/** @var EE_Registration $primary_registrant */
1204
+		$primary_registrant = EEM_Registration::instance()->get_one(
1205
+			array(
1206
+				array(
1207
+					'TXN_ID'    => $this->transaction_ID(),
1208
+					'REG_count' => 1,
1209
+				),
1210
+			)
1211
+		);
1212
+		return $primary_registrant;
1213
+	}
1214
+
1215
+
1216
+	/**
1217
+	 * get  Attendee Number
1218
+	 *
1219
+	 * @throws EE_Error
1220
+	 * @throws InvalidArgumentException
1221
+	 * @throws InvalidDataTypeException
1222
+	 * @throws InvalidInterfaceException
1223
+	 * @throws ReflectionException
1224
+	 */
1225
+	public function count()
1226
+	{
1227
+		return $this->get('REG_count');
1228
+	}
1229
+
1230
+
1231
+	/**
1232
+	 * get Group Size
1233
+	 *
1234
+	 * @throws EE_Error
1235
+	 * @throws InvalidArgumentException
1236
+	 * @throws InvalidDataTypeException
1237
+	 * @throws InvalidInterfaceException
1238
+	 * @throws ReflectionException
1239
+	 */
1240
+	public function group_size()
1241
+	{
1242
+		return $this->get('REG_group_size');
1243
+	}
1244
+
1245
+
1246
+	/**
1247
+	 * get Registration Date
1248
+	 *
1249
+	 * @throws EE_Error
1250
+	 * @throws InvalidArgumentException
1251
+	 * @throws InvalidDataTypeException
1252
+	 * @throws InvalidInterfaceException
1253
+	 * @throws ReflectionException
1254
+	 */
1255
+	public function date()
1256
+	{
1257
+		return $this->get('REG_date');
1258
+	}
1259
+
1260
+
1261
+	/**
1262
+	 * gets a pretty date
1263
+	 *
1264
+	 * @param string $date_format
1265
+	 * @param string $time_format
1266
+	 * @return string
1267
+	 * @throws EE_Error
1268
+	 * @throws InvalidArgumentException
1269
+	 * @throws InvalidDataTypeException
1270
+	 * @throws InvalidInterfaceException
1271
+	 * @throws ReflectionException
1272
+	 */
1273
+	public function pretty_date($date_format = null, $time_format = null)
1274
+	{
1275
+		return $this->get_datetime('REG_date', $date_format, $time_format);
1276
+	}
1277
+
1278
+
1279
+	/**
1280
+	 * final_price
1281
+	 * the registration's share of the transaction total, so that the
1282
+	 * sum of all the transaction's REG_final_prices equal the transaction's total
1283
+	 *
1284
+	 * @return float
1285
+	 * @throws EE_Error
1286
+	 * @throws InvalidArgumentException
1287
+	 * @throws InvalidDataTypeException
1288
+	 * @throws InvalidInterfaceException
1289
+	 * @throws ReflectionException
1290
+	 */
1291
+	public function final_price()
1292
+	{
1293
+		return $this->get('REG_final_price');
1294
+	}
1295
+
1296
+
1297
+	/**
1298
+	 * pretty_final_price
1299
+	 *  final price as formatted string, with correct decimal places and currency symbol
1300
+	 *
1301
+	 * @return string
1302
+	 * @throws EE_Error
1303
+	 * @throws InvalidArgumentException
1304
+	 * @throws InvalidDataTypeException
1305
+	 * @throws InvalidInterfaceException
1306
+	 * @throws ReflectionException
1307
+	 */
1308
+	public function pretty_final_price()
1309
+	{
1310
+		return $this->get_pretty('REG_final_price');
1311
+	}
1312
+
1313
+
1314
+	/**
1315
+	 * get paid (yeah)
1316
+	 *
1317
+	 * @return float
1318
+	 * @throws EE_Error
1319
+	 * @throws InvalidArgumentException
1320
+	 * @throws InvalidDataTypeException
1321
+	 * @throws InvalidInterfaceException
1322
+	 * @throws ReflectionException
1323
+	 */
1324
+	public function paid()
1325
+	{
1326
+		return $this->get('REG_paid');
1327
+	}
1328
+
1329
+
1330
+	/**
1331
+	 * pretty_paid
1332
+	 *
1333
+	 * @return float
1334
+	 * @throws EE_Error
1335
+	 * @throws InvalidArgumentException
1336
+	 * @throws InvalidDataTypeException
1337
+	 * @throws InvalidInterfaceException
1338
+	 * @throws ReflectionException
1339
+	 */
1340
+	public function pretty_paid()
1341
+	{
1342
+		return $this->get_pretty('REG_paid');
1343
+	}
1344
+
1345
+
1346
+	/**
1347
+	 * owes_monies_and_can_pay
1348
+	 * whether or not this registration has monies owing and it's' status allows payment
1349
+	 *
1350
+	 * @param array $requires_payment
1351
+	 * @return bool
1352
+	 * @throws EE_Error
1353
+	 * @throws InvalidArgumentException
1354
+	 * @throws InvalidDataTypeException
1355
+	 * @throws InvalidInterfaceException
1356
+	 * @throws ReflectionException
1357
+	 */
1358
+	public function owes_monies_and_can_pay($requires_payment = array())
1359
+	{
1360
+		// these reg statuses require payment (if event is not free)
1361
+		$requires_payment = ! empty($requires_payment)
1362
+			? $requires_payment
1363
+			: EEM_Registration::reg_statuses_that_allow_payment();
1364
+		if (
1365
+			$this->final_price() !== 0 &&
1366
+			$this->final_price() !== $this->paid() &&
1367
+			in_array($this->status_ID(), $requires_payment)
1368
+		) {
1369
+			return true;
1370
+		}
1371
+		return false;
1372
+	}
1373
+
1374
+
1375
+	/**
1376
+	 * Prints out the return value of $this->pretty_status()
1377
+	 *
1378
+	 * @param bool $show_icons
1379
+	 * @return void
1380
+	 * @throws EE_Error
1381
+	 * @throws InvalidArgumentException
1382
+	 * @throws InvalidDataTypeException
1383
+	 * @throws InvalidInterfaceException
1384
+	 * @throws ReflectionException
1385
+	 */
1386
+	public function e_pretty_status($show_icons = false)
1387
+	{
1388
+		echo wp_kses($this->pretty_status($show_icons), AllowedTags::getAllowedTags());
1389
+	}
1390
+
1391
+
1392
+	/**
1393
+	 * Returns a nice version of the status for displaying to customers
1394
+	 *
1395
+	 * @param bool $show_icons
1396
+	 * @return string
1397
+	 * @throws EE_Error
1398
+	 * @throws InvalidArgumentException
1399
+	 * @throws InvalidDataTypeException
1400
+	 * @throws InvalidInterfaceException
1401
+	 * @throws ReflectionException
1402
+	 */
1403
+	public function pretty_status($show_icons = false)
1404
+	{
1405
+		$status = EEM_Status::instance()->localized_status(
1406
+			array($this->status_ID() => esc_html__('unknown', 'event_espresso')),
1407
+			false,
1408
+			'sentence'
1409
+		);
1410
+		$icon = '';
1411
+		switch ($this->status_ID()) {
1412
+			case EEM_Registration::status_id_approved:
1413
+				$icon = $show_icons
1414
+					? '<span class="dashicons dashicons-star-filled ee-icon-size-16 green-text"></span>'
1415
+					: '';
1416
+				break;
1417
+			case EEM_Registration::status_id_pending_payment:
1418
+				$icon = $show_icons
1419
+					? '<span class="dashicons dashicons-star-half ee-icon-size-16 orange-text"></span>'
1420
+					: '';
1421
+				break;
1422
+			case EEM_Registration::status_id_not_approved:
1423
+				$icon = $show_icons
1424
+					? '<span class="dashicons dashicons-marker ee-icon-size-16 orange-text"></span>'
1425
+					: '';
1426
+				break;
1427
+			case EEM_Registration::status_id_cancelled:
1428
+				$icon = $show_icons
1429
+					? '<span class="dashicons dashicons-no ee-icon-size-16 lt-grey-text"></span>'
1430
+					: '';
1431
+				break;
1432
+			case EEM_Registration::status_id_incomplete:
1433
+				$icon = $show_icons
1434
+					? '<span class="dashicons dashicons-no ee-icon-size-16 lt-orange-text"></span>'
1435
+					: '';
1436
+				break;
1437
+			case EEM_Registration::status_id_declined:
1438
+				$icon = $show_icons
1439
+					? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>'
1440
+					: '';
1441
+				break;
1442
+			case EEM_Registration::status_id_wait_list:
1443
+				$icon = $show_icons
1444
+					? '<span class="dashicons dashicons-clipboard ee-icon-size-16 purple-text"></span>'
1445
+					: '';
1446
+				break;
1447
+		}
1448
+		return $icon . $status[ $this->status_ID() ];
1449
+	}
1450
+
1451
+
1452
+	/**
1453
+	 *        get Attendee Is Going
1454
+	 */
1455
+	public function att_is_going()
1456
+	{
1457
+		return $this->get('REG_att_is_going');
1458
+	}
1459
+
1460
+
1461
+	/**
1462
+	 * Gets related answers
1463
+	 *
1464
+	 * @param array $query_params @see
1465
+	 *                            https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1466
+	 * @return EE_Answer[]|EE_Base_Class[]
1467
+	 * @throws EE_Error
1468
+	 * @throws InvalidArgumentException
1469
+	 * @throws InvalidDataTypeException
1470
+	 * @throws InvalidInterfaceException
1471
+	 * @throws ReflectionException
1472
+	 */
1473
+	public function answers($query_params = null)
1474
+	{
1475
+		return $this->get_many_related('Answer', $query_params);
1476
+	}
1477
+
1478
+
1479
+	/**
1480
+	 * Gets the registration's answer value to the specified question
1481
+	 * (either the question's ID or a question object)
1482
+	 *
1483
+	 * @param EE_Question|int $question
1484
+	 * @param bool            $pretty_value
1485
+	 * @return array|string if pretty_value= true, the result will always be a string
1486
+	 * (because the answer might be an array of answer values, so passing pretty_value=true
1487
+	 * will convert it into some kind of string)
1488
+	 * @throws EE_Error
1489
+	 * @throws InvalidArgumentException
1490
+	 * @throws InvalidDataTypeException
1491
+	 * @throws InvalidInterfaceException
1492
+	 */
1493
+	public function answer_value_to_question($question, $pretty_value = true)
1494
+	{
1495
+		$question_id = EEM_Question::instance()->ensure_is_ID($question);
1496
+		return EEM_Answer::instance()->get_answer_value_to_question($this, $question_id, $pretty_value);
1497
+	}
1498
+
1499
+
1500
+	/**
1501
+	 * question_groups
1502
+	 * returns an array of EE_Question_Group objects for this registration
1503
+	 *
1504
+	 * @return EE_Question_Group[]
1505
+	 * @throws EE_Error
1506
+	 * @throws InvalidArgumentException
1507
+	 * @throws InvalidDataTypeException
1508
+	 * @throws InvalidInterfaceException
1509
+	 * @throws ReflectionException
1510
+	 */
1511
+	public function question_groups()
1512
+	{
1513
+		return EEM_Event::instance()->get_question_groups_for_event($this->event_ID(), $this);
1514
+	}
1515
+
1516
+
1517
+	/**
1518
+	 * count_question_groups
1519
+	 * returns a count of the number of EE_Question_Group objects for this registration
1520
+	 *
1521
+	 * @return int
1522
+	 * @throws EE_Error
1523
+	 * @throws EntityNotFoundException
1524
+	 * @throws InvalidArgumentException
1525
+	 * @throws InvalidDataTypeException
1526
+	 * @throws InvalidInterfaceException
1527
+	 * @throws ReflectionException
1528
+	 */
1529
+	public function count_question_groups()
1530
+	{
1531
+		return EEM_Event::instance()->count_related(
1532
+			$this->event_ID(),
1533
+			'Question_Group',
1534
+			[
1535
+				[
1536
+					'Event_Question_Group.'
1537
+					. EEM_Event_Question_Group::instance()->fieldNameForContext($this->is_primary_registrant()) => true,
1538
+				]
1539
+			]
1540
+		);
1541
+	}
1542
+
1543
+
1544
+	/**
1545
+	 * Returns the registration date in the 'standard' string format
1546
+	 * (function may be improved in the future to allow for different formats and timezones)
1547
+	 *
1548
+	 * @return string
1549
+	 * @throws EE_Error
1550
+	 * @throws InvalidArgumentException
1551
+	 * @throws InvalidDataTypeException
1552
+	 * @throws InvalidInterfaceException
1553
+	 * @throws ReflectionException
1554
+	 */
1555
+	public function reg_date()
1556
+	{
1557
+		return $this->get_datetime('REG_date');
1558
+	}
1559
+
1560
+
1561
+	/**
1562
+	 * Gets the datetime-ticket for this registration (ie, it can be used to isolate
1563
+	 * the ticket this registration purchased, or the datetime they have registered
1564
+	 * to attend)
1565
+	 *
1566
+	 * @return EE_Base_Class|EE_Datetime_Ticket
1567
+	 * @throws EE_Error
1568
+	 * @throws InvalidArgumentException
1569
+	 * @throws InvalidDataTypeException
1570
+	 * @throws InvalidInterfaceException
1571
+	 * @throws ReflectionException
1572
+	 */
1573
+	public function datetime_ticket()
1574
+	{
1575
+		return $this->get_first_related('Datetime_Ticket');
1576
+	}
1577
+
1578
+
1579
+	/**
1580
+	 * Sets the registration's datetime_ticket.
1581
+	 *
1582
+	 * @param EE_Datetime_Ticket $datetime_ticket
1583
+	 * @return EE_Base_Class|EE_Datetime_Ticket
1584
+	 * @throws EE_Error
1585
+	 * @throws InvalidArgumentException
1586
+	 * @throws InvalidDataTypeException
1587
+	 * @throws InvalidInterfaceException
1588
+	 * @throws ReflectionException
1589
+	 */
1590
+	public function set_datetime_ticket($datetime_ticket)
1591
+	{
1592
+		return $this->_add_relation_to($datetime_ticket, 'Datetime_Ticket');
1593
+	}
1594
+
1595
+
1596
+	/**
1597
+	 * Gets deleted
1598
+	 *
1599
+	 * @return bool
1600
+	 * @throws EE_Error
1601
+	 * @throws InvalidArgumentException
1602
+	 * @throws InvalidDataTypeException
1603
+	 * @throws InvalidInterfaceException
1604
+	 * @throws ReflectionException
1605
+	 */
1606
+	public function deleted()
1607
+	{
1608
+		return $this->get('REG_deleted');
1609
+	}
1610
+
1611
+
1612
+	/**
1613
+	 * Sets deleted
1614
+	 *
1615
+	 * @param boolean $deleted
1616
+	 * @return void
1617
+	 * @throws DomainException
1618
+	 * @throws EE_Error
1619
+	 * @throws EntityNotFoundException
1620
+	 * @throws InvalidArgumentException
1621
+	 * @throws InvalidDataTypeException
1622
+	 * @throws InvalidInterfaceException
1623
+	 * @throws ReflectionException
1624
+	 * @throws RuntimeException
1625
+	 * @throws UnexpectedEntityException
1626
+	 */
1627
+	public function set_deleted($deleted)
1628
+	{
1629
+		if ($deleted) {
1630
+			$this->delete();
1631
+		} else {
1632
+			$this->restore();
1633
+		}
1634
+	}
1635
+
1636
+
1637
+	/**
1638
+	 * Get the status object of this object
1639
+	 *
1640
+	 * @return EE_Base_Class|EE_Status
1641
+	 * @throws EE_Error
1642
+	 * @throws InvalidArgumentException
1643
+	 * @throws InvalidDataTypeException
1644
+	 * @throws InvalidInterfaceException
1645
+	 * @throws ReflectionException
1646
+	 */
1647
+	public function status_obj()
1648
+	{
1649
+		return $this->get_first_related('Status');
1650
+	}
1651
+
1652
+
1653
+	/**
1654
+	 * Returns the number of times this registration has checked into any of the datetimes
1655
+	 * its available for
1656
+	 *
1657
+	 * @return int
1658
+	 * @throws EE_Error
1659
+	 * @throws InvalidArgumentException
1660
+	 * @throws InvalidDataTypeException
1661
+	 * @throws InvalidInterfaceException
1662
+	 * @throws ReflectionException
1663
+	 */
1664
+	public function count_checkins()
1665
+	{
1666
+		return $this->get_model()->count_related($this, 'Checkin');
1667
+	}
1668
+
1669
+
1670
+	/**
1671
+	 * Returns the number of current Check-ins this registration is checked into for any of the datetimes the
1672
+	 * registration is for.  Note, this is ONLY checked in (does not include checkedout)
1673
+	 *
1674
+	 * @return int
1675
+	 * @throws EE_Error
1676
+	 * @throws InvalidArgumentException
1677
+	 * @throws InvalidDataTypeException
1678
+	 * @throws InvalidInterfaceException
1679
+	 * @throws ReflectionException
1680
+	 */
1681
+	public function count_checkins_not_checkedout()
1682
+	{
1683
+		return $this->get_model()->count_related($this, 'Checkin', array(array('CHK_in' => 1)));
1684
+	}
1685
+
1686
+
1687
+	/**
1688
+	 * The purpose of this method is simply to check whether this registration can checkin to the given datetime.
1689
+	 *
1690
+	 * @param int | EE_Datetime $DTT_OR_ID      The datetime the registration is being checked against
1691
+	 * @param bool              $check_approved This is used to indicate whether the caller wants can_checkin to also
1692
+	 *                                          consider registration status as well as datetime access.
1693
+	 * @return bool
1694
+	 * @throws EE_Error
1695
+	 * @throws InvalidArgumentException
1696
+	 * @throws InvalidDataTypeException
1697
+	 * @throws InvalidInterfaceException
1698
+	 * @throws ReflectionException
1699
+	 */
1700
+	public function can_checkin($DTT_OR_ID, $check_approved = true)
1701
+	{
1702
+		$DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1703
+		// first check registration status
1704
+		if (! $DTT_ID || ($check_approved && ! $this->is_approved())) {
1705
+			return false;
1706
+		}
1707
+		// is there a datetime ticket that matches this dtt_ID?
1708
+		if (
1709
+			! (EEM_Datetime_Ticket::instance()->exists(
1710
+				array(
1711
+					array(
1712
+						'TKT_ID' => $this->get('TKT_ID'),
1713
+						'DTT_ID' => $DTT_ID,
1714
+					),
1715
+				)
1716
+			))
1717
+		) {
1718
+			return false;
1719
+		}
1720
+
1721
+		// final check is against TKT_uses
1722
+		return $this->verify_can_checkin_against_TKT_uses($DTT_ID);
1723
+	}
1724
+
1725
+
1726
+	/**
1727
+	 * This method verifies whether the user can checkin for the given datetime considering the max uses value set on
1728
+	 * the ticket. To do this,  a query is done to get the count of the datetime records already checked into.  If the
1729
+	 * datetime given does not have a check-in record and checking in for that datetime will exceed the allowed uses,
1730
+	 * then return false.  Otherwise return true.
1731
+	 *
1732
+	 * @param int | EE_Datetime $DTT_OR_ID The datetime the registration is being checked against
1733
+	 * @return bool true means can checkin.  false means cannot checkin.
1734
+	 * @throws EE_Error
1735
+	 * @throws InvalidArgumentException
1736
+	 * @throws InvalidDataTypeException
1737
+	 * @throws InvalidInterfaceException
1738
+	 * @throws ReflectionException
1739
+	 */
1740
+	public function verify_can_checkin_against_TKT_uses($DTT_OR_ID)
1741
+	{
1742
+		$DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1743
+
1744
+		if (! $DTT_ID) {
1745
+			return false;
1746
+		}
1747
+
1748
+		$max_uses = $this->ticket() instanceof EE_Ticket ? $this->ticket()->uses() : EE_INF;
1749
+
1750
+		// if max uses is not set or equals infinity then return true cause its not a factor for whether user can
1751
+		// check-in or not.
1752
+		if (! $max_uses || $max_uses === EE_INF) {
1753
+			return true;
1754
+		}
1755
+
1756
+		// does this datetime have a checkin record?  If so, then the dtt count has already been verified so we can just
1757
+		// go ahead and toggle.
1758
+		if (EEM_Checkin::instance()->exists(array(array('REG_ID' => $this->ID(), 'DTT_ID' => $DTT_ID)))) {
1759
+			return true;
1760
+		}
1761
+
1762
+		// made it here so the last check is whether the number of checkins per unique datetime on this registration
1763
+		// disallows further check-ins.
1764
+		$count_unique_dtt_checkins = EEM_Checkin::instance()->count(
1765
+			array(
1766
+				array(
1767
+					'REG_ID' => $this->ID(),
1768
+					'CHK_in' => true,
1769
+				),
1770
+			),
1771
+			'DTT_ID',
1772
+			true
1773
+		);
1774
+		// checkins have already reached their max number of uses
1775
+		// so registrant can NOT checkin
1776
+		if ($count_unique_dtt_checkins >= $max_uses) {
1777
+			EE_Error::add_error(
1778
+				esc_html__(
1779
+					'Check-in denied because number of datetime uses for the ticket has been reached or exceeded.',
1780
+					'event_espresso'
1781
+				),
1782
+				__FILE__,
1783
+				__FUNCTION__,
1784
+				__LINE__
1785
+			);
1786
+			return false;
1787
+		}
1788
+		return true;
1789
+	}
1790
+
1791
+
1792
+	/**
1793
+	 * toggle Check-in status for this registration
1794
+	 * Check-ins are toggled in the following order:
1795
+	 * never checked in -> checked in
1796
+	 * checked in -> checked out
1797
+	 * checked out -> checked in
1798
+	 *
1799
+	 * @param  int $DTT_ID  include specific datetime to toggle Check-in for.
1800
+	 *                      If not included or null, then it is assumed latest datetime is being toggled.
1801
+	 * @param bool $verify  If true then can_checkin() is used to verify whether the person
1802
+	 *                      can be checked in or not.  Otherwise this forces change in checkin status.
1803
+	 * @return bool|int     the chk_in status toggled to OR false if nothing got changed.
1804
+	 * @throws EE_Error
1805
+	 * @throws InvalidArgumentException
1806
+	 * @throws InvalidDataTypeException
1807
+	 * @throws InvalidInterfaceException
1808
+	 * @throws ReflectionException
1809
+	 */
1810
+	public function toggle_checkin_status($DTT_ID = null, $verify = false)
1811
+	{
1812
+		if (empty($DTT_ID)) {
1813
+			$datetime = $this->get_latest_related_datetime();
1814
+			$DTT_ID = $datetime instanceof EE_Datetime ? $datetime->ID() : 0;
1815
+			// verify the registration can checkin for the given DTT_ID
1816
+		} elseif (! $this->can_checkin($DTT_ID, $verify)) {
1817
+			EE_Error::add_error(
1818
+				sprintf(
1819
+					esc_html__(
1820
+						'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',
1821
+						'event_espresso'
1822
+					),
1823
+					$this->ID(),
1824
+					$DTT_ID
1825
+				),
1826
+				__FILE__,
1827
+				__FUNCTION__,
1828
+				__LINE__
1829
+			);
1830
+			return false;
1831
+		}
1832
+		$status_paths = array(
1833
+			EE_Checkin::status_checked_never => EE_Checkin::status_checked_in,
1834
+			EE_Checkin::status_checked_in    => EE_Checkin::status_checked_out,
1835
+			EE_Checkin::status_checked_out   => EE_Checkin::status_checked_in,
1836
+		);
1837
+		// start by getting the current status so we know what status we'll be changing to.
1838
+		$cur_status = $this->check_in_status_for_datetime($DTT_ID);
1839
+		$status_to = $status_paths[ $cur_status ];
1840
+		// database only records true for checked IN or false for checked OUT
1841
+		// no record ( null ) means checked in NEVER, but we obviously don't save that
1842
+		$new_status = $status_to === EE_Checkin::status_checked_in;
1843
+		// add relation - note Check-ins are always creating new rows
1844
+		// because we are keeping track of Check-ins over time.
1845
+		// Eventually we'll probably want to show a list table
1846
+		// for the individual Check-ins so that they can be managed.
1847
+		$checkin = EE_Checkin::new_instance(
1848
+			array(
1849
+				'REG_ID' => $this->ID(),
1850
+				'DTT_ID' => $DTT_ID,
1851
+				'CHK_in' => $new_status,
1852
+			)
1853
+		);
1854
+		// if the record could not be saved then return false
1855
+		if ($checkin->save() === 0) {
1856
+			if (WP_DEBUG) {
1857
+				global $wpdb;
1858
+				$error = sprintf(
1859
+					esc_html__(
1860
+						'Registration check in update failed because of the following database error: %1$s%2$s',
1861
+						'event_espresso'
1862
+					),
1863
+					'<br />',
1864
+					$wpdb->last_error
1865
+				);
1866
+			} else {
1867
+				$error = esc_html__(
1868
+					'Registration check in update failed because of an unknown database error',
1869
+					'event_espresso'
1870
+				);
1871
+			}
1872
+			EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
1873
+			return false;
1874
+		}
1875
+		// Fire a checked_in and checkout_out action.
1876
+		$checked_status = $status_to === EE_Checkin::status_checked_in ? 'checked_in' : 'checked_out';
1877
+		do_action("AHEE__EE_Registration__toggle_checkin_status__{$checked_status}", $this, $DTT_ID);
1878
+		return $status_to;
1879
+	}
1880
+
1881
+
1882
+	/**
1883
+	 * Returns the latest datetime related to this registration (via the ticket attached to the registration).
1884
+	 * "Latest" is defined by the `DTT_EVT_start` column.
1885
+	 *
1886
+	 * @return EE_Datetime|null
1887
+	 * @throws EE_Error
1888
+	 * @throws InvalidArgumentException
1889
+	 * @throws InvalidDataTypeException
1890
+	 * @throws InvalidInterfaceException
1891
+	 * @throws ReflectionException
1892
+	 */
1893
+	public function get_latest_related_datetime()
1894
+	{
1895
+		return EEM_Datetime::instance()->get_one(
1896
+			array(
1897
+				array(
1898
+					'Ticket.Registration.REG_ID' => $this->ID(),
1899
+				),
1900
+				'order_by' => array('DTT_EVT_start' => 'DESC'),
1901
+			)
1902
+		);
1903
+	}
1904
+
1905
+
1906
+	/**
1907
+	 * Returns the earliest datetime related to this registration (via the ticket attached to the registration).
1908
+	 * "Earliest" is defined by the `DTT_EVT_start` column.
1909
+	 *
1910
+	 * @return EE_Base_Class|EE_Soft_Delete_Base_Class|NULL
1911
+	 * @throws EE_Error
1912
+	 * @throws InvalidArgumentException
1913
+	 * @throws InvalidDataTypeException
1914
+	 * @throws InvalidInterfaceException
1915
+	 * @throws ReflectionException
1916
+	 */
1917
+	public function get_earliest_related_datetime()
1918
+	{
1919
+		return EEM_Datetime::instance()->get_one(
1920
+			array(
1921
+				array(
1922
+					'Ticket.Registration.REG_ID' => $this->ID(),
1923
+				),
1924
+				'order_by' => array('DTT_EVT_start' => 'ASC'),
1925
+			)
1926
+		);
1927
+	}
1928
+
1929
+
1930
+	/**
1931
+	 * This method simply returns the check-in status for this registration and the given datetime.
1932
+	 * If neither the datetime nor the checkin values are provided as arguments,
1933
+	 * then this will return the LATEST check-in status for the registration across all datetimes it belongs to.
1934
+	 *
1935
+	 * @param  int       $DTT_ID  The ID of the datetime we're checking against
1936
+	 *                            (if empty we'll get the primary datetime for
1937
+	 *                            this registration (via event) and use it's ID);
1938
+	 * @param EE_Checkin $checkin If present, we use the given checkin object rather than the dtt_id.
1939
+	 * @return int                Integer representing Check-in status.
1940
+	 * @throws EE_Error
1941
+	 * @throws InvalidArgumentException
1942
+	 * @throws InvalidDataTypeException
1943
+	 * @throws InvalidInterfaceException
1944
+	 * @throws ReflectionException
1945
+	 */
1946
+	public function check_in_status_for_datetime($DTT_ID = 0, $checkin = null)
1947
+	{
1948
+		$checkin_query_params = array(
1949
+			'order_by' => array('CHK_timestamp' => 'DESC'),
1950
+		);
1951
+
1952
+		if ($DTT_ID > 0) {
1953
+			$checkin_query_params[0] = array('DTT_ID' => $DTT_ID);
1954
+		}
1955
+
1956
+		// get checkin object (if exists)
1957
+		$checkin = $checkin instanceof EE_Checkin
1958
+			? $checkin
1959
+			: $this->get_first_related('Checkin', $checkin_query_params);
1960
+		if ($checkin instanceof EE_Checkin) {
1961
+			if ($checkin->get('CHK_in')) {
1962
+				return EE_Checkin::status_checked_in; // checked in
1963
+			}
1964
+			return EE_Checkin::status_checked_out; // had checked in but is now checked out.
1965
+		}
1966
+		return EE_Checkin::status_checked_never; // never been checked in
1967
+	}
1968
+
1969
+
1970
+	/**
1971
+	 * This method returns a localized message for the toggled Check-in message.
1972
+	 *
1973
+	 * @param  int $DTT_ID include specific datetime to get the correct Check-in message.  If not included or null,
1974
+	 *                     then it is assumed Check-in for primary datetime was toggled.
1975
+	 * @param bool $error  This just flags that you want an error message returned. This is put in so that the error
1976
+	 *                     message can be customized with the attendee name.
1977
+	 * @return string internationalized message
1978
+	 * @throws EE_Error
1979
+	 * @throws InvalidArgumentException
1980
+	 * @throws InvalidDataTypeException
1981
+	 * @throws InvalidInterfaceException
1982
+	 * @throws ReflectionException
1983
+	 */
1984
+	public function get_checkin_msg($DTT_ID, $error = false)
1985
+	{
1986
+		// let's get the attendee first so we can include the name of the attendee
1987
+		$attendee = $this->get_first_related('Attendee');
1988
+		if ($attendee instanceof EE_Attendee) {
1989
+			if ($error) {
1990
+				return sprintf(
1991
+					esc_html__("%s's check-in status was not changed.", "event_espresso"),
1992
+					$attendee->full_name()
1993
+				);
1994
+			}
1995
+			$cur_status = $this->check_in_status_for_datetime($DTT_ID);
1996
+			// what is the status message going to be?
1997
+			switch ($cur_status) {
1998
+				case EE_Checkin::status_checked_never:
1999
+					return sprintf(
2000
+						esc_html__('%s has been removed from Check-in records', 'event_espresso'),
2001
+						$attendee->full_name()
2002
+					);
2003
+					break;
2004
+				case EE_Checkin::status_checked_in:
2005
+					return sprintf(esc_html__('%s has been checked in', 'event_espresso'), $attendee->full_name());
2006
+					break;
2007
+				case EE_Checkin::status_checked_out:
2008
+					return sprintf(esc_html__('%s has been checked out', 'event_espresso'), $attendee->full_name());
2009
+					break;
2010
+			}
2011
+		}
2012
+		return esc_html__('The check-in status could not be determined.', 'event_espresso');
2013
+	}
2014
+
2015
+
2016
+	/**
2017
+	 * Returns the related EE_Transaction to this registration
2018
+	 *
2019
+	 * @return EE_Transaction
2020
+	 * @throws EE_Error
2021
+	 * @throws EntityNotFoundException
2022
+	 * @throws InvalidArgumentException
2023
+	 * @throws InvalidDataTypeException
2024
+	 * @throws InvalidInterfaceException
2025
+	 * @throws ReflectionException
2026
+	 */
2027
+	public function transaction()
2028
+	{
2029
+		$transaction = $this->get_first_related('Transaction');
2030
+		if (! $transaction instanceof \EE_Transaction) {
2031
+			throw new EntityNotFoundException('Transaction ID', $this->transaction_ID());
2032
+		}
2033
+		return $transaction;
2034
+	}
2035
+
2036
+
2037
+	/**
2038
+	 * get Registration Code
2039
+	 *
2040
+	 * @return mixed
2041
+	 * @throws EE_Error
2042
+	 * @throws InvalidArgumentException
2043
+	 * @throws InvalidDataTypeException
2044
+	 * @throws InvalidInterfaceException
2045
+	 * @throws ReflectionException
2046
+	 */
2047
+	public function reg_code()
2048
+	{
2049
+		return $this->get('REG_code');
2050
+	}
2051
+
2052
+
2053
+	/**
2054
+	 * @return mixed
2055
+	 * @throws EE_Error
2056
+	 * @throws InvalidArgumentException
2057
+	 * @throws InvalidDataTypeException
2058
+	 * @throws InvalidInterfaceException
2059
+	 * @throws ReflectionException
2060
+	 */
2061
+	public function transaction_ID()
2062
+	{
2063
+		return $this->get('TXN_ID');
2064
+	}
2065
+
2066
+
2067
+	/**
2068
+	 * @return int
2069
+	 * @throws EE_Error
2070
+	 * @throws InvalidArgumentException
2071
+	 * @throws InvalidDataTypeException
2072
+	 * @throws InvalidInterfaceException
2073
+	 * @throws ReflectionException
2074
+	 */
2075
+	public function ticket_ID()
2076
+	{
2077
+		return $this->get('TKT_ID');
2078
+	}
2079
+
2080
+
2081
+	/**
2082
+	 * Set Registration Code
2083
+	 *
2084
+	 * @param    string  $REG_code Registration Code
2085
+	 * @param    boolean $use_default
2086
+	 * @throws EE_Error
2087
+	 * @throws InvalidArgumentException
2088
+	 * @throws InvalidDataTypeException
2089
+	 * @throws InvalidInterfaceException
2090
+	 * @throws ReflectionException
2091
+	 */
2092
+	public function set_reg_code($REG_code, $use_default = false)
2093
+	{
2094
+		if (empty($REG_code)) {
2095
+			EE_Error::add_error(
2096
+				esc_html__('REG_code can not be empty.', 'event_espresso'),
2097
+				__FILE__,
2098
+				__FUNCTION__,
2099
+				__LINE__
2100
+			);
2101
+			return;
2102
+		}
2103
+		if (! $this->reg_code()) {
2104
+			parent::set('REG_code', $REG_code, $use_default);
2105
+		} else {
2106
+			EE_Error::doing_it_wrong(
2107
+				__CLASS__ . '::' . __FUNCTION__,
2108
+				esc_html__('Can not change a registration REG_code once it has been set.', 'event_espresso'),
2109
+				'4.6.0'
2110
+			);
2111
+		}
2112
+	}
2113
+
2114
+
2115
+	/**
2116
+	 * Returns all other registrations in the same group as this registrant who have the same ticket option.
2117
+	 * Note, if you want to just get all registrations in the same transaction (group), use:
2118
+	 *    $registration->transaction()->registrations();
2119
+	 *
2120
+	 * @since 4.5.0
2121
+	 * @return EE_Registration[] or empty array if this isn't a group registration.
2122
+	 * @throws EE_Error
2123
+	 * @throws InvalidArgumentException
2124
+	 * @throws InvalidDataTypeException
2125
+	 * @throws InvalidInterfaceException
2126
+	 * @throws ReflectionException
2127
+	 */
2128
+	public function get_all_other_registrations_in_group()
2129
+	{
2130
+		if ($this->group_size() < 2) {
2131
+			return array();
2132
+		}
2133
+
2134
+		$query[0] = array(
2135
+			'TXN_ID' => $this->transaction_ID(),
2136
+			'REG_ID' => array('!=', $this->ID()),
2137
+			'TKT_ID' => $this->ticket_ID(),
2138
+		);
2139
+		/** @var EE_Registration[] $registrations */
2140
+		$registrations = $this->get_model()->get_all($query);
2141
+		return $registrations;
2142
+	}
2143
+
2144
+
2145
+	/**
2146
+	 * Return the link to the admin details for the object.
2147
+	 *
2148
+	 * @return string
2149
+	 * @throws EE_Error
2150
+	 * @throws InvalidArgumentException
2151
+	 * @throws InvalidDataTypeException
2152
+	 * @throws InvalidInterfaceException
2153
+	 * @throws ReflectionException
2154
+	 */
2155
+	public function get_admin_details_link()
2156
+	{
2157
+		EE_Registry::instance()->load_helper('URL');
2158
+		return EEH_URL::add_query_args_and_nonce(
2159
+			array(
2160
+				'page'    => 'espresso_registrations',
2161
+				'action'  => 'view_registration',
2162
+				'_REG_ID' => $this->ID(),
2163
+			),
2164
+			admin_url('admin.php')
2165
+		);
2166
+	}
2167
+
2168
+
2169
+	/**
2170
+	 * Returns the link to the editor for the object.  Sometimes this is the same as the details.
2171
+	 *
2172
+	 * @return string
2173
+	 * @throws EE_Error
2174
+	 * @throws InvalidArgumentException
2175
+	 * @throws InvalidDataTypeException
2176
+	 * @throws InvalidInterfaceException
2177
+	 * @throws ReflectionException
2178
+	 */
2179
+	public function get_admin_edit_link()
2180
+	{
2181
+		return $this->get_admin_details_link();
2182
+	}
2183
+
2184
+
2185
+	/**
2186
+	 * Returns the link to a settings page for the object.
2187
+	 *
2188
+	 * @return string
2189
+	 * @throws EE_Error
2190
+	 * @throws InvalidArgumentException
2191
+	 * @throws InvalidDataTypeException
2192
+	 * @throws InvalidInterfaceException
2193
+	 * @throws ReflectionException
2194
+	 */
2195
+	public function get_admin_settings_link()
2196
+	{
2197
+		return $this->get_admin_details_link();
2198
+	}
2199
+
2200
+
2201
+	/**
2202
+	 * Returns the link to the "overview" for the object (typically the "list table" view).
2203
+	 *
2204
+	 * @return string
2205
+	 * @throws EE_Error
2206
+	 * @throws InvalidArgumentException
2207
+	 * @throws InvalidDataTypeException
2208
+	 * @throws InvalidInterfaceException
2209
+	 * @throws ReflectionException
2210
+	 */
2211
+	public function get_admin_overview_link()
2212
+	{
2213
+		EE_Registry::instance()->load_helper('URL');
2214
+		return EEH_URL::add_query_args_and_nonce(
2215
+			array(
2216
+				'page' => 'espresso_registrations',
2217
+			),
2218
+			admin_url('admin.php')
2219
+		);
2220
+	}
2221
+
2222
+
2223
+	/**
2224
+	 * @param array $query_params
2225
+	 * @return EE_Base_Class[]|EE_Registration[]
2226
+	 * @throws EE_Error
2227
+	 * @throws InvalidArgumentException
2228
+	 * @throws InvalidDataTypeException
2229
+	 * @throws InvalidInterfaceException
2230
+	 * @throws ReflectionException
2231
+	 */
2232
+	public function payments($query_params = array())
2233
+	{
2234
+		return $this->get_many_related('Payment', $query_params);
2235
+	}
2236
+
2237
+
2238
+	/**
2239
+	 * @param array $query_params
2240
+	 * @return EE_Base_Class[]|EE_Registration_Payment[]
2241
+	 * @throws EE_Error
2242
+	 * @throws InvalidArgumentException
2243
+	 * @throws InvalidDataTypeException
2244
+	 * @throws InvalidInterfaceException
2245
+	 * @throws ReflectionException
2246
+	 */
2247
+	public function registration_payments($query_params = array())
2248
+	{
2249
+		return $this->get_many_related('Registration_Payment', $query_params);
2250
+	}
2251
+
2252
+
2253
+	/**
2254
+	 * This grabs the payment method corresponding to the last payment made for the amount owing on the registration.
2255
+	 * Note: if there are no payments on the registration there will be no payment method returned.
2256
+	 *
2257
+	 * @return EE_Payment|EE_Payment_Method|null
2258
+	 * @throws EE_Error
2259
+	 * @throws InvalidArgumentException
2260
+	 * @throws InvalidDataTypeException
2261
+	 * @throws InvalidInterfaceException
2262
+	 */
2263
+	public function payment_method()
2264
+	{
2265
+		return EEM_Payment_Method::instance()->get_last_used_for_registration($this);
2266
+	}
2267
+
2268
+
2269
+	/**
2270
+	 * @return \EE_Line_Item
2271
+	 * @throws EE_Error
2272
+	 * @throws EntityNotFoundException
2273
+	 * @throws InvalidArgumentException
2274
+	 * @throws InvalidDataTypeException
2275
+	 * @throws InvalidInterfaceException
2276
+	 * @throws ReflectionException
2277
+	 */
2278
+	public function ticket_line_item()
2279
+	{
2280
+		$ticket = $this->ticket();
2281
+		$transaction = $this->transaction();
2282
+		$line_item = null;
2283
+		$ticket_line_items = \EEH_Line_Item::get_line_items_by_object_type_and_IDs(
2284
+			$transaction->total_line_item(),
2285
+			'Ticket',
2286
+			array($ticket->ID())
2287
+		);
2288
+		foreach ($ticket_line_items as $ticket_line_item) {
2289
+			if (
2290
+				$ticket_line_item instanceof \EE_Line_Item
2291
+				&& $ticket_line_item->OBJ_type() === 'Ticket'
2292
+				&& $ticket_line_item->OBJ_ID() === $ticket->ID()
2293
+			) {
2294
+				$line_item = $ticket_line_item;
2295
+				break;
2296
+			}
2297
+		}
2298
+		if (! ($line_item instanceof \EE_Line_Item && $line_item->OBJ_type() === 'Ticket')) {
2299
+			throw new EntityNotFoundException('Line Item Ticket ID', $ticket->ID());
2300
+		}
2301
+		return $line_item;
2302
+	}
2303
+
2304
+
2305
+	/**
2306
+	 * Soft Deletes this model object.
2307
+	 *
2308
+	 * @param string $source function name that called this method
2309
+	 * @return boolean | int
2310
+	 * @throws DomainException
2311
+	 * @throws EE_Error
2312
+	 * @throws EntityNotFoundException
2313
+	 * @throws InvalidArgumentException
2314
+	 * @throws InvalidDataTypeException
2315
+	 * @throws InvalidInterfaceException
2316
+	 * @throws ReflectionException
2317
+	 * @throws RuntimeException
2318
+	 * @throws UnexpectedEntityException
2319
+	 */
2320
+	public function delete()
2321
+	{
2322
+		if ($this->update_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY, $this->status_ID()) === true) {
2323
+			$this->set_status(EEM_Registration::status_id_cancelled);
2324
+		}
2325
+		return parent::delete();
2326
+	}
2327
+
2328
+
2329
+	/**
2330
+	 * Restores whatever the previous status was on a registration before it was trashed (if possible)
2331
+	 *
2332
+	 * @param string $source function name that called this method
2333
+	 * @return bool|int
2334
+	 * @throws DomainException
2335
+	 * @throws EE_Error
2336
+	 * @throws EntityNotFoundException
2337
+	 * @throws InvalidArgumentException
2338
+	 * @throws InvalidDataTypeException
2339
+	 * @throws InvalidInterfaceException
2340
+	 * @throws ReflectionException
2341
+	 * @throws RuntimeException
2342
+	 * @throws UnexpectedEntityException
2343
+	 */
2344
+	public function restore()
2345
+	{
2346
+		$previous_status = $this->get_extra_meta(
2347
+			EE_Registration::PRE_TRASH_REG_STATUS_KEY,
2348
+			true,
2349
+			EEM_Registration::status_id_cancelled
2350
+		);
2351
+		if ($previous_status) {
2352
+			$this->delete_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY);
2353
+			$this->set_status($previous_status);
2354
+		}
2355
+		return parent::restore();
2356
+	}
2357
+
2358
+
2359
+	/**
2360
+	 * possibly toggle Registration status based on comparison of REG_paid vs REG_final_price
2361
+	 *
2362
+	 * @param  boolean $trigger_set_status_logic EE_Registration::set_status() can trigger additional logic
2363
+	 *                                           depending on whether the reg status changes to or from "Approved"
2364
+	 * @return boolean whether the Registration status was updated
2365
+	 * @throws DomainException
2366
+	 * @throws EE_Error
2367
+	 * @throws EntityNotFoundException
2368
+	 * @throws InvalidArgumentException
2369
+	 * @throws InvalidDataTypeException
2370
+	 * @throws InvalidInterfaceException
2371
+	 * @throws ReflectionException
2372
+	 * @throws RuntimeException
2373
+	 * @throws UnexpectedEntityException
2374
+	 */
2375
+	public function updateStatusBasedOnTotalPaid($trigger_set_status_logic = true)
2376
+	{
2377
+		$paid = $this->paid();
2378
+		$price = $this->final_price();
2379
+		switch (true) {
2380
+			// overpaid or paid
2381
+			case EEH_Money::compare_floats($paid, $price, '>'):
2382
+			case EEH_Money::compare_floats($paid, $price):
2383
+				$new_status = EEM_Registration::status_id_approved;
2384
+				break;
2385
+			//  underpaid
2386
+			case EEH_Money::compare_floats($paid, $price, '<'):
2387
+				$new_status = EEM_Registration::status_id_pending_payment;
2388
+				break;
2389
+			// uhhh Houston...
2390
+			default:
2391
+				throw new RuntimeException(
2392
+					esc_html__('The total paid calculation for this registration is inaccurate.', 'event_espresso')
2393
+				);
2394
+		}
2395
+		if ($new_status !== $this->status_ID()) {
2396
+			if ($trigger_set_status_logic) {
2397
+				return $this->set_status($new_status);
2398
+			}
2399
+			parent::set('STS_ID', $new_status);
2400
+			return true;
2401
+		}
2402
+		return false;
2403
+	}
2404
+
2405
+
2406
+	/*************************** DEPRECATED ***************************/
2407
+
2408
+
2409
+	/**
2410
+	 * @deprecated
2411
+	 * @since     4.7.0
2412
+	 */
2413
+	public function price_paid()
2414
+	{
2415
+		EE_Error::doing_it_wrong(
2416
+			'EE_Registration::price_paid()',
2417
+			esc_html__(
2418
+				'This method is deprecated, please use EE_Registration::final_price() instead.',
2419
+				'event_espresso'
2420
+			),
2421
+			'4.7.0'
2422
+		);
2423
+		return $this->final_price();
2424
+	}
2425
+
2426
+
2427
+	/**
2428
+	 * @deprecated
2429
+	 * @since     4.7.0
2430
+	 * @param    float $REG_final_price
2431
+	 * @throws EE_Error
2432
+	 * @throws EntityNotFoundException
2433
+	 * @throws InvalidArgumentException
2434
+	 * @throws InvalidDataTypeException
2435
+	 * @throws InvalidInterfaceException
2436
+	 * @throws ReflectionException
2437
+	 * @throws RuntimeException
2438
+	 * @throws DomainException
2439
+	 */
2440
+	public function set_price_paid($REG_final_price = 0.00)
2441
+	{
2442
+		EE_Error::doing_it_wrong(
2443
+			'EE_Registration::set_price_paid()',
2444
+			esc_html__(
2445
+				'This method is deprecated, please use EE_Registration::set_final_price() instead.',
2446
+				'event_espresso'
2447
+			),
2448
+			'4.7.0'
2449
+		);
2450
+		$this->set_final_price($REG_final_price);
2451
+	}
2452
+
2453
+
2454
+	/**
2455
+	 * @deprecated
2456
+	 * @since 4.7.0
2457
+	 * @return string
2458
+	 * @throws EE_Error
2459
+	 * @throws InvalidArgumentException
2460
+	 * @throws InvalidDataTypeException
2461
+	 * @throws InvalidInterfaceException
2462
+	 * @throws ReflectionException
2463
+	 */
2464
+	public function pretty_price_paid()
2465
+	{
2466
+		EE_Error::doing_it_wrong(
2467
+			'EE_Registration::pretty_price_paid()',
2468
+			esc_html__(
2469
+				'This method is deprecated, please use EE_Registration::pretty_final_price() instead.',
2470
+				'event_espresso'
2471
+			),
2472
+			'4.7.0'
2473
+		);
2474
+		return $this->pretty_final_price();
2475
+	}
2476
+
2477
+
2478
+	/**
2479
+	 * Gets the primary datetime related to this registration via the related Event to this registration
2480
+	 *
2481
+	 * @deprecated 4.9.17
2482
+	 * @return EE_Datetime
2483
+	 * @throws EE_Error
2484
+	 * @throws EntityNotFoundException
2485
+	 * @throws InvalidArgumentException
2486
+	 * @throws InvalidDataTypeException
2487
+	 * @throws InvalidInterfaceException
2488
+	 * @throws ReflectionException
2489
+	 */
2490
+	public function get_related_primary_datetime()
2491
+	{
2492
+		EE_Error::doing_it_wrong(
2493
+			__METHOD__,
2494
+			esc_html__(
2495
+				'Use EE_Registration::get_latest_related_datetime() or EE_Registration::get_earliest_related_datetime()',
2496
+				'event_espresso'
2497
+			),
2498
+			'4.9.17',
2499
+			'5.0.0'
2500
+		);
2501
+		return $this->event()->primary_datetime();
2502
+	}
2503
+
2504
+	/**
2505
+	 * Returns the contact's name (or "Unknown" if there is no contact.)
2506
+	 * @since 4.10.12.p
2507
+	 * @return string
2508
+	 * @throws EE_Error
2509
+	 * @throws InvalidArgumentException
2510
+	 * @throws InvalidDataTypeException
2511
+	 * @throws InvalidInterfaceException
2512
+	 * @throws ReflectionException
2513
+	 */
2514
+	public function name()
2515
+	{
2516
+		return $this->attendeeName();
2517
+	}
2518 2518
 }
Please login to merge, or discard this patch.
espresso.php 1 patch
Indentation   +80 added lines, -80 removed lines patch added patch discarded remove patch
@@ -38,103 +38,103 @@
 block discarded – undo
38 38
  * @since           4.0
39 39
  */
40 40
 if (function_exists('espresso_version')) {
41
-    if (! function_exists('espresso_duplicate_plugin_error')) {
42
-        /**
43
-         *    espresso_duplicate_plugin_error
44
-         *    displays if more than one version of EE is activated at the same time
45
-         */
46
-        function espresso_duplicate_plugin_error()
47
-        {
48
-            ?>
41
+	if (! function_exists('espresso_duplicate_plugin_error')) {
42
+		/**
43
+		 *    espresso_duplicate_plugin_error
44
+		 *    displays if more than one version of EE is activated at the same time
45
+		 */
46
+		function espresso_duplicate_plugin_error()
47
+		{
48
+			?>
49 49
             <div class="error">
50 50
                 <p>
51 51
                     <?php
52
-                    echo esc_html__(
53
-                        'Can not run multiple versions of Event Espresso! One version has been automatically deactivated. Please verify that you have the correct version you want still active.',
54
-                        'event_espresso'
55
-                    ); ?>
52
+					echo esc_html__(
53
+						'Can not run multiple versions of Event Espresso! One version has been automatically deactivated. Please verify that you have the correct version you want still active.',
54
+						'event_espresso'
55
+					); ?>
56 56
                 </p>
57 57
             </div>
58 58
             <?php
59
-            espresso_deactivate_plugin(plugin_basename(__FILE__));
60
-        }
61
-    }
62
-    add_action('admin_notices', 'espresso_duplicate_plugin_error', 1);
59
+			espresso_deactivate_plugin(plugin_basename(__FILE__));
60
+		}
61
+	}
62
+	add_action('admin_notices', 'espresso_duplicate_plugin_error', 1);
63 63
 } else {
64
-    define('EE_MIN_PHP_VER_REQUIRED', '5.6.2');
65
-    if (! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) {
66
-        /**
67
-         * espresso_minimum_php_version_error
68
-         *
69
-         * @return void
70
-         */
71
-        function espresso_minimum_php_version_error()
72
-        {
73
-            ?>
64
+	define('EE_MIN_PHP_VER_REQUIRED', '5.6.2');
65
+	if (! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) {
66
+		/**
67
+		 * espresso_minimum_php_version_error
68
+		 *
69
+		 * @return void
70
+		 */
71
+		function espresso_minimum_php_version_error()
72
+		{
73
+			?>
74 74
             <div class="error">
75 75
                 <p>
76 76
                     <?php
77
-                    printf(
78
-                        esc_html__(
79
-                            'We\'re sorry, but Event Espresso requires PHP version %1$s or greater in order to operate. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.',
80
-                            'event_espresso'
81
-                        ),
82
-                        EE_MIN_PHP_VER_REQUIRED,
83
-                        PHP_VERSION,
84
-                        '<br/>',
85
-                        '<a href="http://php.net/downloads.php">http://php.net/downloads.php</a>'
86
-                    );
87
-                    ?>
77
+					printf(
78
+						esc_html__(
79
+							'We\'re sorry, but Event Espresso requires PHP version %1$s or greater in order to operate. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.',
80
+							'event_espresso'
81
+						),
82
+						EE_MIN_PHP_VER_REQUIRED,
83
+						PHP_VERSION,
84
+						'<br/>',
85
+						'<a href="http://php.net/downloads.php">http://php.net/downloads.php</a>'
86
+					);
87
+					?>
88 88
                 </p>
89 89
             </div>
90 90
             <?php
91
-            espresso_deactivate_plugin(plugin_basename(__FILE__));
92
-        }
91
+			espresso_deactivate_plugin(plugin_basename(__FILE__));
92
+		}
93 93
 
94
-        add_action('admin_notices', 'espresso_minimum_php_version_error', 1);
95
-    } else {
96
-        define('EVENT_ESPRESSO_MAIN_FILE', __FILE__);
97
-        /**
98
-         * espresso_version
99
-         * Returns the plugin version
100
-         *
101
-         * @return string
102
-         */
103
-        function espresso_version()
104
-        {
105
-            return apply_filters('FHEE__espresso__espresso_version', '4.10.38.rc.000');
106
-        }
94
+		add_action('admin_notices', 'espresso_minimum_php_version_error', 1);
95
+	} else {
96
+		define('EVENT_ESPRESSO_MAIN_FILE', __FILE__);
97
+		/**
98
+		 * espresso_version
99
+		 * Returns the plugin version
100
+		 *
101
+		 * @return string
102
+		 */
103
+		function espresso_version()
104
+		{
105
+			return apply_filters('FHEE__espresso__espresso_version', '4.10.38.rc.000');
106
+		}
107 107
 
108
-        /**
109
-         * espresso_plugin_activation
110
-         * adds a wp-option to indicate that EE has been activated via the WP admin plugins page
111
-         */
112
-        function espresso_plugin_activation()
113
-        {
114
-            update_option('ee_espresso_activation', true);
115
-        }
108
+		/**
109
+		 * espresso_plugin_activation
110
+		 * adds a wp-option to indicate that EE has been activated via the WP admin plugins page
111
+		 */
112
+		function espresso_plugin_activation()
113
+		{
114
+			update_option('ee_espresso_activation', true);
115
+		}
116 116
 
117
-        register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation');
117
+		register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation');
118 118
 
119
-        require_once __DIR__ . '/core/bootstrap_espresso.php';
120
-        bootstrap_espresso();
121
-    }
119
+		require_once __DIR__ . '/core/bootstrap_espresso.php';
120
+		bootstrap_espresso();
121
+	}
122 122
 }
123 123
 if (! function_exists('espresso_deactivate_plugin')) {
124
-    /**
125
-     *    deactivate_plugin
126
-     * usage:  espresso_deactivate_plugin( plugin_basename( __FILE__ ));
127
-     *
128
-     * @access public
129
-     * @param string $plugin_basename - the results of plugin_basename( __FILE__ ) for the plugin's main file
130
-     * @return    void
131
-     */
132
-    function espresso_deactivate_plugin($plugin_basename = '')
133
-    {
134
-        if (! function_exists('deactivate_plugins')) {
135
-            require_once ABSPATH . 'wp-admin/includes/plugin.php';
136
-        }
137
-        unset($_GET['activate'], $_REQUEST['activate']);
138
-        deactivate_plugins($plugin_basename);
139
-    }
124
+	/**
125
+	 *    deactivate_plugin
126
+	 * usage:  espresso_deactivate_plugin( plugin_basename( __FILE__ ));
127
+	 *
128
+	 * @access public
129
+	 * @param string $plugin_basename - the results of plugin_basename( __FILE__ ) for the plugin's main file
130
+	 * @return    void
131
+	 */
132
+	function espresso_deactivate_plugin($plugin_basename = '')
133
+	{
134
+		if (! function_exists('deactivate_plugins')) {
135
+			require_once ABSPATH . 'wp-admin/includes/plugin.php';
136
+		}
137
+		unset($_GET['activate'], $_REQUEST['activate']);
138
+		deactivate_plugins($plugin_basename);
139
+	}
140 140
 }
141 141
\ No newline at end of file
Please login to merge, or discard this patch.
core/db_models/EEM_Soft_Delete_Base.model.php 2 patches
Indentation   +347 added lines, -347 removed lines patch added patch discarded remove patch
@@ -26,351 +26,351 @@
 block discarded – undo
26 26
  */
27 27
 abstract class EEM_Soft_Delete_Base extends EEM_Base
28 28
 {
29
-    /**
30
-     * @param null $timezone
31
-     */
32
-    protected function __construct($timezone = null)
33
-    {
34
-        if (! $this->_default_where_conditions_strategy instanceof EE_Default_Where_Conditions) {
35
-            $this->_default_where_conditions_strategy = new EE_Soft_Delete_Where_Conditions();
36
-        }
37
-        parent::__construct($timezone);
38
-    }
39
-
40
-
41
-
42
-    /**
43
-     * Searches for field on this model of type 'deleted_flag'. if it is found,
44
-     * returns it's name.
45
-     *
46
-     * @return string
47
-     * @throws EE_Error
48
-     */
49
-    public function deleted_field_name()
50
-    {
51
-        $field = $this->get_a_field_of_type('EE_Trashed_Flag_Field');
52
-        if ($field) {
53
-            return $field->get_name();
54
-        } else {
55
-            throw new EE_Error(sprintf(esc_html__(
56
-                'We are trying to find the deleted flag field on %s, but none was found. Are you sure there is a field of type EE_Trashed_Flag_Field in %s constructor?',
57
-                'event_espresso'
58
-            ), get_class($this), get_class($this)));
59
-        }
60
-    }
61
-
62
-
63
-
64
-    /**
65
-     * Gets one item that's been deleted, according to $query_params
66
-     *
67
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
68
-     * @return EE_Soft_Delete_Base_Class
69
-     */
70
-    public function get_one_deleted($query_params = array())
71
-    {
72
-        $query_params = $this->_alter_query_params_so_only_trashed_items_included($query_params);
73
-        return parent::get_one($query_params);
74
-    }
75
-
76
-
77
-
78
-    /**
79
-     * Gets one item from the DB, regardless of whether it's been soft-deleted or not
80
-     *
81
-     * @param array $query_params like EEM_base::get_all's $query_params
82
-     * @return EE_Soft_Delete_Base_Class
83
-     */
84
-    public function get_one_deleted_or_undeleted($query_params = array())
85
-    {
86
-        $query_params = $this->_alter_query_params_so_deleted_and_undeleted_items_included($query_params);
87
-        return parent::get_one($query_params);
88
-    }
89
-
90
-
91
-
92
-    /**
93
-     * Gets the item indicated by its ID. But if it's soft-deleted, pretends it doesn't exist.
94
-     *
95
-     * @param int|string $id
96
-     * @return EE_Soft_Delete_Base_Class
97
-     */
98
-    public function get_one_by_ID_but_ignore_deleted($id)
99
-    {
100
-        return $this->get_one(
101
-            $this->alter_query_params_to_restrict_by_ID(
102
-                $id,
103
-                array('default_where_conditions' => 'default')
104
-            )
105
-        );
106
-    }
107
-
108
-
109
-
110
-    /**
111
-     * Counts all the deleted/trashed items
112
-     *
113
-     * @param array  $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
114
-     * @param string $field_to_count
115
-     * @param bool   $distinct     if we want to only count the distinct values for the column then you can trigger that by the setting $distinct to TRUE;
116
-     * @return int
117
-     */
118
-    public function count_deleted($query_params = null, $field_to_count = null, $distinct = false)
119
-    {
120
-        $query_params = $this->_alter_query_params_so_only_trashed_items_included($query_params);
121
-        return parent::count($query_params, $field_to_count, $distinct);
122
-    }
123
-
124
-
125
-
126
-    /**
127
-     * Alters the query params so that only trashed/soft-deleted items are considered
128
-     *
129
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
130
-     * @return array @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
131
-     */
132
-    protected function _alter_query_params_so_only_trashed_items_included($query_params)
133
-    {
134
-        $deletedFlagFieldName = $this->deleted_field_name();
135
-        $query_params[0][ $deletedFlagFieldName ] = true;
136
-        return $query_params;
137
-    }
138
-
139
-
140
-
141
-    /**
142
-     * Alters the query params so that only trashed/soft-deleted items are considered
143
-     *
144
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
145
-     * @return array @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
146
-     */
147
-    public function alter_query_params_so_only_trashed_items_included($query_params)
148
-    {
149
-        return $this->_alter_query_params_so_only_trashed_items_included($query_params);
150
-    }
151
-
152
-
153
-
154
-    /**
155
-     * Alters the query params so each item's deleted status is ignored.
156
-     *
157
-     * @param array $query_params
158
-     * @return array
159
-     */
160
-    public function alter_query_params_so_deleted_and_undeleted_items_included($query_params = array())
161
-    {
162
-        return $this->_alter_query_params_so_deleted_and_undeleted_items_included($query_params);
163
-    }
164
-
165
-
166
-
167
-    /**
168
-     * Alters the query params so each item's deleted status is ignored.
169
-     *
170
-     * @param array $query_params
171
-     * @return array
172
-     */
173
-    protected function _alter_query_params_so_deleted_and_undeleted_items_included($query_params)
174
-    {
175
-        if (! isset($query_params['default_where_conditions'])) {
176
-            $query_params['default_where_conditions'] = 'minimum';
177
-        }
178
-        return $query_params;
179
-    }
180
-
181
-
182
-
183
-    /**
184
-     * Counts all deleted and undeleted items
185
-     *
186
-     * @param array  $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
187
-     * @param string $field_to_count
188
-     * @param bool   $distinct     if we want to only count the distinct values for the column then you can trigger that by the setting $distinct to TRUE;
189
-     * @return int
190
-     */
191
-    public function count_deleted_and_undeleted($query_params = null, $field_to_count = null, $distinct = false)
192
-    {
193
-        $query_params = $this->_alter_query_params_so_deleted_and_undeleted_items_included($query_params);
194
-        return parent::count($query_params, $field_to_count, $distinct);
195
-    }
196
-
197
-
198
-
199
-    /**
200
-     * Sum all the deleted items.
201
-     *
202
-     * @param array  $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
203
-     * @param string $field_to_sum
204
-     * @return int
205
-     */
206
-    public function sum_deleted($query_params = null, $field_to_sum = null)
207
-    {
208
-        $query_params = $this->_alter_query_params_so_only_trashed_items_included($query_params);
209
-        return parent::sum($query_params, $field_to_sum);
210
-    }
211
-
212
-
213
-
214
-    /**
215
-     * Sums all the deleted and undeleted items.
216
-     *
217
-     * @param array  $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
218
-     * @param string $field_to_sum
219
-     * @return int
220
-     */
221
-    public function sum_deleted_and_undeleted($query_params = null, $field_to_sum = null)
222
-    {
223
-        $query_params = $this->_alter_query_params_so_deleted_and_undeleted_items_included($query_params);
224
-        parent::sum($query_params, $field_to_sum);
225
-    }
226
-
227
-
228
-
229
-    /**
230
-     * Gets all deleted and undeleted mode objects from the db that meet the criteria, regardless of
231
-     * whether they've been soft-deleted or not
232
-     *
233
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
234
-     * @return EE_Soft_Delete_Base_Class[]
235
-     */
236
-    public function get_all_deleted_and_undeleted($query_params = array())
237
-    {
238
-        $query_params = $this->_alter_query_params_so_deleted_and_undeleted_items_included($query_params);
239
-        return parent::get_all($query_params);
240
-    }
241
-
242
-
243
-
244
-    /**
245
-     * For 'soft deletable' models, gets all which ARE deleted, according to conditions specified in $query_params.
246
-     *
247
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
248
-     * @return EE_Soft_Delete_Base_Class[]
249
-     */
250
-    public function get_all_deleted($query_params = array())
251
-    {
252
-        $query_params = $this->_alter_query_params_so_only_trashed_items_included($query_params);
253
-        return parent::get_all($query_params);
254
-    }
255
-
256
-
257
-
258
-    /**
259
-     * Permanently deletes the selected rows. When selecting rows for deletion, ignores
260
-     * whether they've been soft-deleted or not. (ie, you don't have to soft-delete objects
261
-     * before you can permanently delete them).
262
-     * Because this will cause a real deletion, related models may block this deletion (ie, add an error
263
-     * and abort the delete)
264
-     *
265
-     * @param array   $query_params   @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
266
-     * @param boolean $allow_blocking if TRUE, matched objects will only be deleted if there is no related model info
267
-     *                                that blocks it (ie, there' sno other data that depends on this data); if false, deletes regardless of other objects
268
-     *                                which may depend on it. Its generally advisable to always leave this as TRUE, otherwise you could easily corrupt your DB
269
-     * @return int                    number of rows deleted
270
-     * @throws EE_Error
271
-     */
272
-    public function delete_permanently($query_params, $allow_blocking = true)
273
-    {
274
-        $query_params = $this->_alter_query_params_so_deleted_and_undeleted_items_included($query_params);
275
-        return parent::delete_permanently($query_params, $allow_blocking);
276
-    }
277
-
278
-
279
-
280
-    /**
281
-     * Restores a particular item by its ID (primary key). Ignores the fact whether the item
282
-     * has been soft-deleted or not.
283
-     *
284
-     * @param mixed $ID int if primary key is an int, string otherwise
285
-     * @return boolean success
286
-     */
287
-    public function restore_by_ID($ID = false)
288
-    {
289
-        return $this->delete_or_restore_by_ID(false, $ID);
290
-    }
291
-
292
-
293
-    /**
294
-     * For deleting or restoring a particular item. Note that this model is a SOFT-DELETABLE model! However,
295
-     * this function will ignore whether the items have been soft-deleted or not.
296
-     *
297
-     * @param boolean $delete true for delete, false for restore
298
-     * @param mixed   $ID     int if primary key is an int, string otherwise
299
-     * @return bool
300
-     * @throws EE_Error
301
-     */
302
-    public function delete_or_restore_by_ID($delete = true, $ID = false)
303
-    {
304
-        // returns false if entity doesn't have an ID or if delete/restore action failed
305
-        return $ID && $this->delete_or_restore($delete, $this->alter_query_params_to_restrict_by_ID($ID));
306
-    }
307
-
308
-
309
-
310
-    /**
311
-     * Overrides parent's 'delete' method to instead do a soft delete on all rows that
312
-     * meet the criteria in $where_col_n_values. This particular function ignores whether the items have been soft-deleted or not.
313
-     * Note: because this item will be soft-deleted only,
314
-     * doesn't block because of model dependencies
315
-     *
316
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
317
-     * @param bool  $block_deletes
318
-     * @return bool
319
-     */
320
-    public function delete($query_params = array(), $block_deletes = false)
321
-    {
322
-        // no matter what, we WON'T block soft deletes.
323
-        return $this->delete_or_restore(true, $query_params);
324
-    }
325
-
326
-
327
-
328
-    /**
329
-     * 'Un-deletes' the chosen items. Note that this model is a SOFT-DELETABLE model! That means that, by default, trashed/soft-deleted
330
-     * items are ignored in queries. However, this particular function ignores whether the items have been soft-deleted or not.
331
-     *
332
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
333
-     * @return bool
334
-     */
335
-    public function restore($query_params = array())
336
-    {
337
-        return $this->delete_or_restore(false, $query_params);
338
-    }
339
-
340
-
341
-    /**
342
-     * Performs deletes or restores on items. Both soft-deleted and non-soft-deleted items considered.
343
-     *
344
-     * @param boolean $delete       true to indicate deletion, false to indicate restoration
345
-     * @param array $query_params
346
-     * @return boolean
347
-     * @throws EE_Error
348
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
349
-     */
350
-    public function delete_or_restore($delete = true, $query_params = array())
351
-    {
352
-        $deletedFlagFieldName = $this->deleted_field_name();
353
-        $query_params = $this->_alter_query_params_so_deleted_and_undeleted_items_included($query_params);
354
-        return (bool) $this->update([$deletedFlagFieldName => $delete], $query_params);
355
-    }
356
-
357
-
358
-
359
-    /**
360
-     * Updates all the items of this model which match the $query params, regardless of whether
361
-     * they've been soft-deleted or not
362
-     *
363
-     * @param array   $fields_n_values         like EEM_Base::update's $fields_n_value
364
-     * @param array   $query_params            like EEM_base::get_all's $query_params
365
-     * @param boolean $keep_model_objs_in_sync if TRUE, makes sure we ALSO update model objects
366
-     *                                         in this model's entity map according to $fields_n_values that match $query_params. This
367
-     *                                         obviously has some overhead, so you can disable it by setting this to FALSE, but
368
-     *                                         be aware that model objects being used could get out-of-sync with the database
369
-     * @return int number of items updated
370
-     */
371
-    public function update_deleted_and_undeleted($fields_n_values, $query_params, $keep_model_objs_in_sync = true)
372
-    {
373
-        $query_params = $this->_alter_query_params_so_deleted_and_undeleted_items_included($query_params);
374
-        return $this->update($fields_n_values, $query_params, $keep_model_objs_in_sync);
375
-    }
29
+	/**
30
+	 * @param null $timezone
31
+	 */
32
+	protected function __construct($timezone = null)
33
+	{
34
+		if (! $this->_default_where_conditions_strategy instanceof EE_Default_Where_Conditions) {
35
+			$this->_default_where_conditions_strategy = new EE_Soft_Delete_Where_Conditions();
36
+		}
37
+		parent::__construct($timezone);
38
+	}
39
+
40
+
41
+
42
+	/**
43
+	 * Searches for field on this model of type 'deleted_flag'. if it is found,
44
+	 * returns it's name.
45
+	 *
46
+	 * @return string
47
+	 * @throws EE_Error
48
+	 */
49
+	public function deleted_field_name()
50
+	{
51
+		$field = $this->get_a_field_of_type('EE_Trashed_Flag_Field');
52
+		if ($field) {
53
+			return $field->get_name();
54
+		} else {
55
+			throw new EE_Error(sprintf(esc_html__(
56
+				'We are trying to find the deleted flag field on %s, but none was found. Are you sure there is a field of type EE_Trashed_Flag_Field in %s constructor?',
57
+				'event_espresso'
58
+			), get_class($this), get_class($this)));
59
+		}
60
+	}
61
+
62
+
63
+
64
+	/**
65
+	 * Gets one item that's been deleted, according to $query_params
66
+	 *
67
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
68
+	 * @return EE_Soft_Delete_Base_Class
69
+	 */
70
+	public function get_one_deleted($query_params = array())
71
+	{
72
+		$query_params = $this->_alter_query_params_so_only_trashed_items_included($query_params);
73
+		return parent::get_one($query_params);
74
+	}
75
+
76
+
77
+
78
+	/**
79
+	 * Gets one item from the DB, regardless of whether it's been soft-deleted or not
80
+	 *
81
+	 * @param array $query_params like EEM_base::get_all's $query_params
82
+	 * @return EE_Soft_Delete_Base_Class
83
+	 */
84
+	public function get_one_deleted_or_undeleted($query_params = array())
85
+	{
86
+		$query_params = $this->_alter_query_params_so_deleted_and_undeleted_items_included($query_params);
87
+		return parent::get_one($query_params);
88
+	}
89
+
90
+
91
+
92
+	/**
93
+	 * Gets the item indicated by its ID. But if it's soft-deleted, pretends it doesn't exist.
94
+	 *
95
+	 * @param int|string $id
96
+	 * @return EE_Soft_Delete_Base_Class
97
+	 */
98
+	public function get_one_by_ID_but_ignore_deleted($id)
99
+	{
100
+		return $this->get_one(
101
+			$this->alter_query_params_to_restrict_by_ID(
102
+				$id,
103
+				array('default_where_conditions' => 'default')
104
+			)
105
+		);
106
+	}
107
+
108
+
109
+
110
+	/**
111
+	 * Counts all the deleted/trashed items
112
+	 *
113
+	 * @param array  $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
114
+	 * @param string $field_to_count
115
+	 * @param bool   $distinct     if we want to only count the distinct values for the column then you can trigger that by the setting $distinct to TRUE;
116
+	 * @return int
117
+	 */
118
+	public function count_deleted($query_params = null, $field_to_count = null, $distinct = false)
119
+	{
120
+		$query_params = $this->_alter_query_params_so_only_trashed_items_included($query_params);
121
+		return parent::count($query_params, $field_to_count, $distinct);
122
+	}
123
+
124
+
125
+
126
+	/**
127
+	 * Alters the query params so that only trashed/soft-deleted items are considered
128
+	 *
129
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
130
+	 * @return array @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
131
+	 */
132
+	protected function _alter_query_params_so_only_trashed_items_included($query_params)
133
+	{
134
+		$deletedFlagFieldName = $this->deleted_field_name();
135
+		$query_params[0][ $deletedFlagFieldName ] = true;
136
+		return $query_params;
137
+	}
138
+
139
+
140
+
141
+	/**
142
+	 * Alters the query params so that only trashed/soft-deleted items are considered
143
+	 *
144
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
145
+	 * @return array @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
146
+	 */
147
+	public function alter_query_params_so_only_trashed_items_included($query_params)
148
+	{
149
+		return $this->_alter_query_params_so_only_trashed_items_included($query_params);
150
+	}
151
+
152
+
153
+
154
+	/**
155
+	 * Alters the query params so each item's deleted status is ignored.
156
+	 *
157
+	 * @param array $query_params
158
+	 * @return array
159
+	 */
160
+	public function alter_query_params_so_deleted_and_undeleted_items_included($query_params = array())
161
+	{
162
+		return $this->_alter_query_params_so_deleted_and_undeleted_items_included($query_params);
163
+	}
164
+
165
+
166
+
167
+	/**
168
+	 * Alters the query params so each item's deleted status is ignored.
169
+	 *
170
+	 * @param array $query_params
171
+	 * @return array
172
+	 */
173
+	protected function _alter_query_params_so_deleted_and_undeleted_items_included($query_params)
174
+	{
175
+		if (! isset($query_params['default_where_conditions'])) {
176
+			$query_params['default_where_conditions'] = 'minimum';
177
+		}
178
+		return $query_params;
179
+	}
180
+
181
+
182
+
183
+	/**
184
+	 * Counts all deleted and undeleted items
185
+	 *
186
+	 * @param array  $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
187
+	 * @param string $field_to_count
188
+	 * @param bool   $distinct     if we want to only count the distinct values for the column then you can trigger that by the setting $distinct to TRUE;
189
+	 * @return int
190
+	 */
191
+	public function count_deleted_and_undeleted($query_params = null, $field_to_count = null, $distinct = false)
192
+	{
193
+		$query_params = $this->_alter_query_params_so_deleted_and_undeleted_items_included($query_params);
194
+		return parent::count($query_params, $field_to_count, $distinct);
195
+	}
196
+
197
+
198
+
199
+	/**
200
+	 * Sum all the deleted items.
201
+	 *
202
+	 * @param array  $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
203
+	 * @param string $field_to_sum
204
+	 * @return int
205
+	 */
206
+	public function sum_deleted($query_params = null, $field_to_sum = null)
207
+	{
208
+		$query_params = $this->_alter_query_params_so_only_trashed_items_included($query_params);
209
+		return parent::sum($query_params, $field_to_sum);
210
+	}
211
+
212
+
213
+
214
+	/**
215
+	 * Sums all the deleted and undeleted items.
216
+	 *
217
+	 * @param array  $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
218
+	 * @param string $field_to_sum
219
+	 * @return int
220
+	 */
221
+	public function sum_deleted_and_undeleted($query_params = null, $field_to_sum = null)
222
+	{
223
+		$query_params = $this->_alter_query_params_so_deleted_and_undeleted_items_included($query_params);
224
+		parent::sum($query_params, $field_to_sum);
225
+	}
226
+
227
+
228
+
229
+	/**
230
+	 * Gets all deleted and undeleted mode objects from the db that meet the criteria, regardless of
231
+	 * whether they've been soft-deleted or not
232
+	 *
233
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
234
+	 * @return EE_Soft_Delete_Base_Class[]
235
+	 */
236
+	public function get_all_deleted_and_undeleted($query_params = array())
237
+	{
238
+		$query_params = $this->_alter_query_params_so_deleted_and_undeleted_items_included($query_params);
239
+		return parent::get_all($query_params);
240
+	}
241
+
242
+
243
+
244
+	/**
245
+	 * For 'soft deletable' models, gets all which ARE deleted, according to conditions specified in $query_params.
246
+	 *
247
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
248
+	 * @return EE_Soft_Delete_Base_Class[]
249
+	 */
250
+	public function get_all_deleted($query_params = array())
251
+	{
252
+		$query_params = $this->_alter_query_params_so_only_trashed_items_included($query_params);
253
+		return parent::get_all($query_params);
254
+	}
255
+
256
+
257
+
258
+	/**
259
+	 * Permanently deletes the selected rows. When selecting rows for deletion, ignores
260
+	 * whether they've been soft-deleted or not. (ie, you don't have to soft-delete objects
261
+	 * before you can permanently delete them).
262
+	 * Because this will cause a real deletion, related models may block this deletion (ie, add an error
263
+	 * and abort the delete)
264
+	 *
265
+	 * @param array   $query_params   @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
266
+	 * @param boolean $allow_blocking if TRUE, matched objects will only be deleted if there is no related model info
267
+	 *                                that blocks it (ie, there' sno other data that depends on this data); if false, deletes regardless of other objects
268
+	 *                                which may depend on it. Its generally advisable to always leave this as TRUE, otherwise you could easily corrupt your DB
269
+	 * @return int                    number of rows deleted
270
+	 * @throws EE_Error
271
+	 */
272
+	public function delete_permanently($query_params, $allow_blocking = true)
273
+	{
274
+		$query_params = $this->_alter_query_params_so_deleted_and_undeleted_items_included($query_params);
275
+		return parent::delete_permanently($query_params, $allow_blocking);
276
+	}
277
+
278
+
279
+
280
+	/**
281
+	 * Restores a particular item by its ID (primary key). Ignores the fact whether the item
282
+	 * has been soft-deleted or not.
283
+	 *
284
+	 * @param mixed $ID int if primary key is an int, string otherwise
285
+	 * @return boolean success
286
+	 */
287
+	public function restore_by_ID($ID = false)
288
+	{
289
+		return $this->delete_or_restore_by_ID(false, $ID);
290
+	}
291
+
292
+
293
+	/**
294
+	 * For deleting or restoring a particular item. Note that this model is a SOFT-DELETABLE model! However,
295
+	 * this function will ignore whether the items have been soft-deleted or not.
296
+	 *
297
+	 * @param boolean $delete true for delete, false for restore
298
+	 * @param mixed   $ID     int if primary key is an int, string otherwise
299
+	 * @return bool
300
+	 * @throws EE_Error
301
+	 */
302
+	public function delete_or_restore_by_ID($delete = true, $ID = false)
303
+	{
304
+		// returns false if entity doesn't have an ID or if delete/restore action failed
305
+		return $ID && $this->delete_or_restore($delete, $this->alter_query_params_to_restrict_by_ID($ID));
306
+	}
307
+
308
+
309
+
310
+	/**
311
+	 * Overrides parent's 'delete' method to instead do a soft delete on all rows that
312
+	 * meet the criteria in $where_col_n_values. This particular function ignores whether the items have been soft-deleted or not.
313
+	 * Note: because this item will be soft-deleted only,
314
+	 * doesn't block because of model dependencies
315
+	 *
316
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
317
+	 * @param bool  $block_deletes
318
+	 * @return bool
319
+	 */
320
+	public function delete($query_params = array(), $block_deletes = false)
321
+	{
322
+		// no matter what, we WON'T block soft deletes.
323
+		return $this->delete_or_restore(true, $query_params);
324
+	}
325
+
326
+
327
+
328
+	/**
329
+	 * 'Un-deletes' the chosen items. Note that this model is a SOFT-DELETABLE model! That means that, by default, trashed/soft-deleted
330
+	 * items are ignored in queries. However, this particular function ignores whether the items have been soft-deleted or not.
331
+	 *
332
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
333
+	 * @return bool
334
+	 */
335
+	public function restore($query_params = array())
336
+	{
337
+		return $this->delete_or_restore(false, $query_params);
338
+	}
339
+
340
+
341
+	/**
342
+	 * Performs deletes or restores on items. Both soft-deleted and non-soft-deleted items considered.
343
+	 *
344
+	 * @param boolean $delete       true to indicate deletion, false to indicate restoration
345
+	 * @param array $query_params
346
+	 * @return boolean
347
+	 * @throws EE_Error
348
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
349
+	 */
350
+	public function delete_or_restore($delete = true, $query_params = array())
351
+	{
352
+		$deletedFlagFieldName = $this->deleted_field_name();
353
+		$query_params = $this->_alter_query_params_so_deleted_and_undeleted_items_included($query_params);
354
+		return (bool) $this->update([$deletedFlagFieldName => $delete], $query_params);
355
+	}
356
+
357
+
358
+
359
+	/**
360
+	 * Updates all the items of this model which match the $query params, regardless of whether
361
+	 * they've been soft-deleted or not
362
+	 *
363
+	 * @param array   $fields_n_values         like EEM_Base::update's $fields_n_value
364
+	 * @param array   $query_params            like EEM_base::get_all's $query_params
365
+	 * @param boolean $keep_model_objs_in_sync if TRUE, makes sure we ALSO update model objects
366
+	 *                                         in this model's entity map according to $fields_n_values that match $query_params. This
367
+	 *                                         obviously has some overhead, so you can disable it by setting this to FALSE, but
368
+	 *                                         be aware that model objects being used could get out-of-sync with the database
369
+	 * @return int number of items updated
370
+	 */
371
+	public function update_deleted_and_undeleted($fields_n_values, $query_params, $keep_model_objs_in_sync = true)
372
+	{
373
+		$query_params = $this->_alter_query_params_so_deleted_and_undeleted_items_included($query_params);
374
+		return $this->update($fields_n_values, $query_params, $keep_model_objs_in_sync);
375
+	}
376 376
 }
Please login to merge, or discard this patch.
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -31,7 +31,7 @@  discard block
 block discarded – undo
31 31
      */
32 32
     protected function __construct($timezone = null)
33 33
     {
34
-        if (! $this->_default_where_conditions_strategy instanceof EE_Default_Where_Conditions) {
34
+        if ( ! $this->_default_where_conditions_strategy instanceof EE_Default_Where_Conditions) {
35 35
             $this->_default_where_conditions_strategy = new EE_Soft_Delete_Where_Conditions();
36 36
         }
37 37
         parent::__construct($timezone);
@@ -132,7 +132,7 @@  discard block
 block discarded – undo
132 132
     protected function _alter_query_params_so_only_trashed_items_included($query_params)
133 133
     {
134 134
         $deletedFlagFieldName = $this->deleted_field_name();
135
-        $query_params[0][ $deletedFlagFieldName ] = true;
135
+        $query_params[0][$deletedFlagFieldName] = true;
136 136
         return $query_params;
137 137
     }
138 138
 
@@ -172,7 +172,7 @@  discard block
 block discarded – undo
172 172
      */
173 173
     protected function _alter_query_params_so_deleted_and_undeleted_items_included($query_params)
174 174
     {
175
-        if (! isset($query_params['default_where_conditions'])) {
175
+        if ( ! isset($query_params['default_where_conditions'])) {
176 176
             $query_params['default_where_conditions'] = 'minimum';
177 177
         }
178 178
         return $query_params;
Please login to merge, or discard this patch.
core/EE_System.core.php 1 patch
Indentation   +1358 added lines, -1358 removed lines patch added patch discarded remove patch
@@ -26,1362 +26,1362 @@
 block discarded – undo
26 26
  */
27 27
 final class EE_System implements ResettableInterface
28 28
 {
29
-    /**
30
-     * indicates this is a 'normal' request. Ie, not activation, nor upgrade, nor activation.
31
-     * So examples of this would be a normal GET request on the frontend or backend, or a POST, etc
32
-     */
33
-    const req_type_normal = 0;
34
-
35
-    /**
36
-     * Indicates this is a brand new installation of EE so we should install
37
-     * tables and default data etc
38
-     */
39
-    const req_type_new_activation = 1;
40
-
41
-    /**
42
-     * we've detected that EE has been reactivated (or EE was activated during maintenance mode,
43
-     * and we just exited maintenance mode). We MUST check the database is setup properly
44
-     * and that default data is setup too
45
-     */
46
-    const req_type_reactivation = 2;
47
-
48
-    /**
49
-     * indicates that EE has been upgraded since its previous request.
50
-     * We may have data migration scripts to call and will want to trigger maintenance mode
51
-     */
52
-    const req_type_upgrade = 3;
53
-
54
-    /**
55
-     * TODO  will detect that EE has been DOWNGRADED. We probably don't want to run in this case...
56
-     */
57
-    const req_type_downgrade = 4;
58
-
59
-    /**
60
-     * @deprecated since version 4.6.0.dev.006
61
-     * Now whenever a new_activation is detected the request type is still just
62
-     * new_activation (same for reactivation, upgrade, downgrade etc), but if we'r ein maintenance mode
63
-     * EE_System::initialize_db_if_no_migrations_required and EE_Addon::initialize_db_if_no_migrations_required
64
-     * will instead enqueue that EE plugin's db initialization for when we're taken out of maintenance mode.
65
-     * (Specifically, when the migration manager indicates migrations are finished
66
-     * EE_Data_Migration_Manager::initialize_db_for_enqueued_ee_plugins() will be called)
67
-     */
68
-    const req_type_activation_but_not_installed = 5;
69
-
70
-    /**
71
-     * option prefix for recording the activation history (like core's "espresso_db_update") of addons
72
-     */
73
-    const addon_activation_history_option_prefix = 'ee_addon_activation_history_';
74
-
75
-    /**
76
-     * @var EE_System $_instance
77
-     */
78
-    private static $_instance;
79
-
80
-    /**
81
-     * @var EE_Registry $registry
82
-     */
83
-    private $registry;
84
-
85
-    /**
86
-     * @var LoaderInterface $loader
87
-     */
88
-    private $loader;
89
-
90
-    /**
91
-     * @var EE_Capabilities $capabilities
92
-     */
93
-    private $capabilities;
94
-
95
-    /**
96
-     * @var RequestInterface $request
97
-     */
98
-    private $request;
99
-
100
-    /**
101
-     * @var EE_Maintenance_Mode $maintenance_mode
102
-     */
103
-    private $maintenance_mode;
104
-
105
-    /**
106
-     * Stores which type of request this is, options being one of the constants on EE_System starting with req_type_*.
107
-     * It can be a brand-new activation, a reactivation, an upgrade, a downgrade, or a normal request.
108
-     *
109
-     * @var int $_req_type
110
-     */
111
-    private $_req_type;
112
-
113
-    /**
114
-     * Whether or not there was a non-micro version change in EE core version during this request
115
-     *
116
-     * @var boolean $_major_version_change
117
-     */
118
-    private $_major_version_change = false;
119
-
120
-    /**
121
-     * A Context DTO dedicated solely to identifying the current request type.
122
-     *
123
-     * @var RequestTypeContextCheckerInterface $request_type
124
-     */
125
-    private $request_type;
126
-
127
-    /**
128
-     * @param EventEspresso\core\domain\services\custom_post_types\RegisterCustomPostTypes
129
-     */
130
-    private $register_custom_post_types;
131
-
132
-    /**
133
-     * @param EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomies
134
-     */
135
-    private $register_custom_taxonomies;
136
-
137
-    /**
138
-     * @param EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomyTerms
139
-     */
140
-    private $register_custom_taxonomy_terms;
141
-
142
-    /**
143
-     * @singleton method used to instantiate class object
144
-     * @param EE_Registry|null         $registry
145
-     * @param LoaderInterface|null     $loader
146
-     * @param RequestInterface|null    $request
147
-     * @param EE_Maintenance_Mode|null $maintenance_mode
148
-     * @return EE_System
149
-     */
150
-    public static function instance(
151
-        EE_Registry $registry = null,
152
-        LoaderInterface $loader = null,
153
-        RequestInterface $request = null,
154
-        EE_Maintenance_Mode $maintenance_mode = null
155
-    ) {
156
-        // check if class object is instantiated
157
-        if (! self::$_instance instanceof EE_System) {
158
-            self::$_instance = new self($registry, $loader, $request, $maintenance_mode);
159
-        }
160
-        return self::$_instance;
161
-    }
162
-
163
-
164
-    /**
165
-     * resets the instance and returns it
166
-     *
167
-     * @return EE_System
168
-     */
169
-    public static function reset()
170
-    {
171
-        self::$_instance->_req_type = null;
172
-        // make sure none of the old hooks are left hanging around
173
-        remove_all_actions('AHEE__EE_System__perform_activations_upgrades_and_migrations');
174
-        // we need to reset the migration manager in order for it to detect DMSs properly
175
-        EE_Data_Migration_Manager::reset();
176
-        self::instance()->detect_activations_or_upgrades();
177
-        self::instance()->perform_activations_upgrades_and_migrations();
178
-        return self::instance();
179
-    }
180
-
181
-
182
-    /**
183
-     * sets hooks for running rest of system
184
-     * provides "AHEE__EE_System__construct__complete" hook for EE Addons to use as their starting point
185
-     * starting EE Addons from any other point may lead to problems
186
-     *
187
-     * @param EE_Registry         $registry
188
-     * @param LoaderInterface     $loader
189
-     * @param RequestInterface    $request
190
-     * @param EE_Maintenance_Mode $maintenance_mode
191
-     */
192
-    private function __construct(
193
-        EE_Registry $registry,
194
-        LoaderInterface $loader,
195
-        RequestInterface $request,
196
-        EE_Maintenance_Mode $maintenance_mode
197
-    ) {
198
-        $this->registry = $registry;
199
-        $this->loader = $loader;
200
-        $this->request = $request;
201
-        $this->maintenance_mode = $maintenance_mode;
202
-        do_action('AHEE__EE_System__construct__begin', $this);
203
-        add_action(
204
-            'AHEE__EE_Bootstrap__load_espresso_addons',
205
-            array($this, 'loadCapabilities'),
206
-            5
207
-        );
208
-        add_action(
209
-            'AHEE__EE_Bootstrap__load_espresso_addons',
210
-            array($this, 'loadCommandBus'),
211
-            7
212
-        );
213
-        add_action(
214
-            'AHEE__EE_Bootstrap__load_espresso_addons',
215
-            array($this, 'loadPluginApi'),
216
-            9
217
-        );
218
-        // allow addons to load first so that they can register autoloaders, set hooks for running DMS's, etc
219
-        add_action(
220
-            'AHEE__EE_Bootstrap__load_espresso_addons',
221
-            array($this, 'load_espresso_addons')
222
-        );
223
-        // when an ee addon is activated, we want to call the core hook(s) again
224
-        // because the newly-activated addon didn't get a chance to run at all
225
-        add_action('activate_plugin', array($this, 'load_espresso_addons'), 1);
226
-        // detect whether install or upgrade
227
-        add_action(
228
-            'AHEE__EE_Bootstrap__detect_activations_or_upgrades',
229
-            array($this, 'detect_activations_or_upgrades'),
230
-            3
231
-        );
232
-        // load EE_Config, EE_Textdomain, etc
233
-        add_action(
234
-            'AHEE__EE_Bootstrap__load_core_configuration',
235
-            array($this, 'load_core_configuration'),
236
-            5
237
-        );
238
-        // load specifications for matching routes to current request
239
-        add_action(
240
-            'AHEE__EE_Bootstrap__load_core_configuration',
241
-            array($this, 'loadRouteMatchSpecifications')
242
-        );
243
-        // load specifications for custom post types
244
-        add_action(
245
-            'AHEE__EE_Bootstrap__load_core_configuration',
246
-            array($this, 'loadCustomPostTypes')
247
-        );
248
-        // load EE_Config, EE_Textdomain, etc
249
-        add_action(
250
-            'AHEE__EE_Bootstrap__register_shortcodes_modules_and_widgets',
251
-            array($this, 'register_shortcodes_modules_and_widgets'),
252
-            7
253
-        );
254
-        // you wanna get going? I wanna get going... let's get going!
255
-        add_action(
256
-            'AHEE__EE_Bootstrap__brew_espresso',
257
-            array($this, 'brew_espresso'),
258
-            9
259
-        );
260
-        // other housekeeping
261
-        // exclude EE critical pages from wp_list_pages
262
-        add_filter(
263
-            'wp_list_pages_excludes',
264
-            array($this, 'remove_pages_from_wp_list_pages'),
265
-            10
266
-        );
267
-        // ALL EE Addons should use the following hook point to attach their initial setup too
268
-        // it's extremely important for EE Addons to register any class autoloaders so that they can be available when the EE_Config loads
269
-        do_action('AHEE__EE_System__construct__complete', $this);
270
-    }
271
-
272
-
273
-    /**
274
-     * load and setup EE_Capabilities
275
-     *
276
-     * @return void
277
-     * @throws EE_Error
278
-     */
279
-    public function loadCapabilities()
280
-    {
281
-        $this->capabilities = $this->loader->getShared('EE_Capabilities');
282
-        add_action(
283
-            'AHEE__EE_Capabilities__init_caps__before_initialization',
284
-            function () {
285
-                LoaderFactory::getLoader()->getShared('EE_Payment_Method_Manager');
286
-            }
287
-        );
288
-    }
289
-
290
-
291
-    /**
292
-     * create and cache the CommandBus, and also add middleware
293
-     * The CapChecker middleware requires the use of EE_Capabilities
294
-     * which is why we need to load the CommandBus after Caps are set up
295
-     * CommandBus middleware operate FIFO - First In First Out
296
-     * so LocateMovedCommands will run first in order to return any new commands
297
-     *
298
-     * @return void
299
-     * @throws EE_Error
300
-     */
301
-    public function loadCommandBus()
302
-    {
303
-        $this->loader->getShared(
304
-            'CommandBusInterface',
305
-            array(
306
-                null,
307
-                apply_filters(
308
-                    'FHEE__EE_Load_Espresso_Core__handle_request__CommandBus_middleware',
309
-                    array(
310
-                        $this->loader->getShared('EventEspresso\core\services\commands\middleware\LocateMovedCommands'),
311
-                        $this->loader->getShared('EventEspresso\core\services\commands\middleware\CapChecker'),
312
-                        $this->loader->getShared('EventEspresso\core\services\commands\middleware\AddActionHook'),
313
-                    )
314
-                ),
315
-            )
316
-        );
317
-    }
318
-
319
-
320
-    /**
321
-     * @return void
322
-     * @throws EE_Error
323
-     */
324
-    public function loadPluginApi()
325
-    {
326
-        // set autoloaders for all of the classes implementing EEI_Plugin_API
327
-        // which provide helpers for EE plugin authors to more easily register certain components with EE.
328
-        EEH_Autoloader::instance()->register_autoloaders_for_each_file_in_folder(EE_LIBRARIES . 'plugin_api');
329
-    }
330
-
331
-
332
-    /**
333
-     * @param string $addon_name
334
-     * @param string $version_constant
335
-     * @param string $min_version_required
336
-     * @param string $load_callback
337
-     * @param string $plugin_file_constant
338
-     * @return void
339
-     */
340
-    private function deactivateIncompatibleAddon(
341
-        $addon_name,
342
-        $version_constant,
343
-        $min_version_required,
344
-        $load_callback,
345
-        $plugin_file_constant
346
-    ) {
347
-        if (! defined($version_constant)) {
348
-            return;
349
-        }
350
-        $addon_version = constant($version_constant);
351
-        if ($addon_version && version_compare($addon_version, $min_version_required, '<')) {
352
-            remove_action('AHEE__EE_System__load_espresso_addons', $load_callback);
353
-            if (! function_exists('deactivate_plugins')) {
354
-                require_once ABSPATH . 'wp-admin/includes/plugin.php';
355
-            }
356
-            deactivate_plugins(plugin_basename(constant($plugin_file_constant)));
357
-            $this->request->unSetRequestParams(['activate', 'activate-multi'], true);
358
-            EE_Error::add_error(
359
-                sprintf(
360
-                    esc_html__(
361
-                        'We\'re sorry, but the Event Espresso %1$s addon was deactivated because version %2$s or higher is required with this version of Event Espresso core.',
362
-                        'event_espresso'
363
-                    ),
364
-                    $addon_name,
365
-                    $min_version_required
366
-                ),
367
-                __FILE__,
368
-                __FUNCTION__ . "({$addon_name})",
369
-                __LINE__
370
-            );
371
-            EE_Error::get_notices(false, true);
372
-        }
373
-    }
374
-
375
-
376
-    /**
377
-     * load_espresso_addons
378
-     * allow addons to load first so that they can set hooks for running DMS's, etc
379
-     * this is hooked into both:
380
-     *    'AHEE__EE_Bootstrap__load_core_configuration'
381
-     *        which runs during the WP 'plugins_loaded' action at priority 5
382
-     *    and the WP 'activate_plugin' hook point
383
-     *
384
-     * @access public
385
-     * @return void
386
-     */
387
-    public function load_espresso_addons()
388
-    {
389
-        $this->deactivateIncompatibleAddon(
390
-            'Wait Lists',
391
-            'EE_WAIT_LISTS_VERSION',
392
-            '1.0.0.beta.074',
393
-            'load_espresso_wait_lists',
394
-            'EE_WAIT_LISTS_PLUGIN_FILE'
395
-        );
396
-        $this->deactivateIncompatibleAddon(
397
-            'Automated Upcoming Event Notifications',
398
-            'EE_AUTOMATED_UPCOMING_EVENT_NOTIFICATION_VERSION',
399
-            '1.0.0.beta.091',
400
-            'load_espresso_automated_upcoming_event_notification',
401
-            'EE_AUTOMATED_UPCOMING_EVENT_NOTIFICATION_PLUGIN_FILE'
402
-        );
403
-        do_action('AHEE__EE_System__load_espresso_addons');
404
-        // if the WP API basic auth plugin isn't already loaded, load it now.
405
-        // We want it for mobile apps. Just include the entire plugin
406
-        // also, don't load the basic auth when a plugin is getting activated, because
407
-        // it could be the basic auth plugin, and it doesn't check if its methods are already defined
408
-        // and causes a fatal error
409
-        if (
410
-            ($this->request->isWordPressApi() || $this->request->isApi())
411
-            && $this->request->getRequestParam('activate') !== 'true'
412
-            && ! function_exists('json_basic_auth_handler')
413
-            && ! function_exists('json_basic_auth_error')
414
-            && ! in_array(
415
-                $this->request->getRequestParam('action'),
416
-                array('activate', 'activate-selected'),
417
-                true
418
-            )
419
-        ) {
420
-            include_once EE_THIRD_PARTY . 'wp-api-basic-auth/basic-auth.php';
421
-        }
422
-        do_action('AHEE__EE_System__load_espresso_addons__complete');
423
-    }
424
-
425
-
426
-    /**
427
-     * detect_activations_or_upgrades
428
-     * Checks for activation or upgrade of core first;
429
-     * then also checks if any registered addons have been activated or upgraded
430
-     * This is hooked into 'AHEE__EE_Bootstrap__detect_activations_or_upgrades'
431
-     * which runs during the WP 'plugins_loaded' action at priority 3
432
-     *
433
-     * @access public
434
-     * @return void
435
-     */
436
-    public function detect_activations_or_upgrades()
437
-    {
438
-        // first off: let's make sure to handle core
439
-        $this->detect_if_activation_or_upgrade();
440
-        foreach ($this->registry->addons as $addon) {
441
-            if ($addon instanceof EE_Addon) {
442
-                // detect teh request type for that addon
443
-                $addon->detect_req_type();
444
-            }
445
-        }
446
-    }
447
-
448
-
449
-    /**
450
-     * detect_if_activation_or_upgrade
451
-     * Takes care of detecting whether this is a brand new install or code upgrade,
452
-     * and either setting up the DB or setting up maintenance mode etc.
453
-     *
454
-     * @access public
455
-     * @return void
456
-     */
457
-    public function detect_if_activation_or_upgrade()
458
-    {
459
-        do_action('AHEE__EE_System___detect_if_activation_or_upgrade__begin');
460
-        // check if db has been updated, or if its a brand-new installation
461
-        $espresso_db_update = $this->fix_espresso_db_upgrade_option();
462
-        $request_type = $this->detect_req_type($espresso_db_update);
463
-        // EEH_Debug_Tools::printr( $request_type, '$request_type', __FILE__, __LINE__ );
464
-        switch ($request_type) {
465
-            case EE_System::req_type_new_activation:
466
-                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__new_activation');
467
-                $this->_handle_core_version_change($espresso_db_update);
468
-                break;
469
-            case EE_System::req_type_reactivation:
470
-                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__reactivation');
471
-                $this->_handle_core_version_change($espresso_db_update);
472
-                break;
473
-            case EE_System::req_type_upgrade:
474
-                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__upgrade');
475
-                // migrations may be required now that we've upgraded
476
-                $this->maintenance_mode->set_maintenance_mode_if_db_old();
477
-                $this->_handle_core_version_change($espresso_db_update);
478
-                break;
479
-            case EE_System::req_type_downgrade:
480
-                do_action('AHEE__EE_System__detect_if_activation_or_upgrade__downgrade');
481
-                // its possible migrations are no longer required
482
-                $this->maintenance_mode->set_maintenance_mode_if_db_old();
483
-                $this->_handle_core_version_change($espresso_db_update);
484
-                break;
485
-            case EE_System::req_type_normal:
486
-            default:
487
-                break;
488
-        }
489
-        do_action('AHEE__EE_System__detect_if_activation_or_upgrade__complete');
490
-    }
491
-
492
-
493
-    /**
494
-     * Updates the list of installed versions and sets hooks for
495
-     * initializing the database later during the request
496
-     *
497
-     * @param array $espresso_db_update
498
-     */
499
-    private function _handle_core_version_change($espresso_db_update)
500
-    {
501
-        $this->update_list_of_installed_versions($espresso_db_update);
502
-        // get ready to verify the DB is ok (provided we aren't in maintenance mode, of course)
503
-        add_action(
504
-            'AHEE__EE_System__perform_activations_upgrades_and_migrations',
505
-            array($this, 'initialize_db_if_no_migrations_required')
506
-        );
507
-    }
508
-
509
-
510
-    /**
511
-     * standardizes the wp option 'espresso_db_upgrade' which actually stores
512
-     * information about what versions of EE have been installed and activated,
513
-     * NOT necessarily the state of the database
514
-     *
515
-     * @param mixed $espresso_db_update           the value of the WordPress option.
516
-     *                                            If not supplied, fetches it from the options table
517
-     * @return array the correct value of 'espresso_db_upgrade', after saving it, if it needed correction
518
-     */
519
-    private function fix_espresso_db_upgrade_option($espresso_db_update = null)
520
-    {
521
-        do_action('FHEE__EE_System__manage_fix_espresso_db_upgrade_option__begin', $espresso_db_update);
522
-        if (! $espresso_db_update) {
523
-            $espresso_db_update = get_option('espresso_db_update');
524
-        }
525
-        // check that option is an array
526
-        if (! is_array($espresso_db_update)) {
527
-            // if option is FALSE, then it never existed
528
-            if ($espresso_db_update === false) {
529
-                // make $espresso_db_update an array and save option with autoload OFF
530
-                $espresso_db_update = array();
531
-                add_option('espresso_db_update', $espresso_db_update, '', 'no');
532
-            } else {
533
-                // option is NOT FALSE but also is NOT an array, so make it an array and save it
534
-                $espresso_db_update = array($espresso_db_update => array());
535
-                update_option('espresso_db_update', $espresso_db_update);
536
-            }
537
-        } else {
538
-            $corrected_db_update = array();
539
-            // if IS an array, but is it an array where KEYS are version numbers, and values are arrays?
540
-            foreach ($espresso_db_update as $should_be_version_string => $should_be_array) {
541
-                if (is_int($should_be_version_string) && ! is_array($should_be_array)) {
542
-                    // the key is an int, and the value IS NOT an array
543
-                    // so it must be numerically-indexed, where values are versions installed...
544
-                    // fix it!
545
-                    $version_string = $should_be_array;
546
-                    $corrected_db_update[ $version_string ] = array('unknown-date');
547
-                } else {
548
-                    // ok it checks out
549
-                    $corrected_db_update[ $should_be_version_string ] = $should_be_array;
550
-                }
551
-            }
552
-            $espresso_db_update = $corrected_db_update;
553
-            update_option('espresso_db_update', $espresso_db_update);
554
-        }
555
-        do_action('FHEE__EE_System__manage_fix_espresso_db_upgrade_option__complete', $espresso_db_update);
556
-        return $espresso_db_update;
557
-    }
558
-
559
-
560
-    /**
561
-     * Does the traditional work of setting up the plugin's database and adding default data.
562
-     * If migration script/process did not exist, this is what would happen on every activation/reactivation/upgrade.
563
-     * NOTE: if we're in maintenance mode (which would be the case if we detect there are data
564
-     * migration scripts that need to be run and a version change happens), enqueues core for database initialization,
565
-     * so that it will be done when migrations are finished
566
-     *
567
-     * @param boolean $initialize_addons_too if true, we double-check addons' database tables etc too;
568
-     * @param boolean $verify_schema         if true will re-check the database tables have the correct schema.
569
-     *                                       This is a resource-intensive job
570
-     *                                       so we prefer to only do it when necessary
571
-     * @return void
572
-     * @throws EE_Error
573
-     */
574
-    public function initialize_db_if_no_migrations_required($initialize_addons_too = false, $verify_schema = true)
575
-    {
576
-        $request_type = $this->detect_req_type();
577
-        // only initialize system if we're not in maintenance mode.
578
-        if ($this->maintenance_mode->level() !== EE_Maintenance_Mode::level_2_complete_maintenance) {
579
-            /** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
580
-            $rewrite_rules = $this->loader->getShared(
581
-                'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
582
-            );
583
-            $rewrite_rules->flush();
584
-            if ($verify_schema) {
585
-                EEH_Activation::initialize_db_and_folders();
586
-            }
587
-            EEH_Activation::initialize_db_content();
588
-            EEH_Activation::system_initialization();
589
-            if ($initialize_addons_too) {
590
-                $this->initialize_addons();
591
-            }
592
-        } else {
593
-            EE_Data_Migration_Manager::instance()->enqueue_db_initialization_for('Core');
594
-        }
595
-        if (
596
-            $request_type === EE_System::req_type_new_activation
597
-            || $request_type === EE_System::req_type_reactivation
598
-            || (
599
-                $request_type === EE_System::req_type_upgrade
600
-                && $this->is_major_version_change()
601
-            )
602
-        ) {
603
-            add_action('AHEE__EE_System__initialize_last', array($this, 'redirect_to_about_ee'), 9);
604
-        }
605
-    }
606
-
607
-
608
-    /**
609
-     * Initializes the db for all registered addons
610
-     *
611
-     * @throws EE_Error
612
-     */
613
-    public function initialize_addons()
614
-    {
615
-        // foreach registered addon, make sure its db is up-to-date too
616
-        foreach ($this->registry->addons as $addon) {
617
-            if ($addon instanceof EE_Addon) {
618
-                $addon->initialize_db_if_no_migrations_required();
619
-            }
620
-        }
621
-    }
622
-
623
-
624
-    /**
625
-     * Adds the current code version to the saved wp option which stores a list of all ee versions ever installed.
626
-     *
627
-     * @param    array  $version_history
628
-     * @param    string $current_version_to_add version to be added to the version history
629
-     * @return    boolean success as to whether or not this option was changed
630
-     */
631
-    public function update_list_of_installed_versions($version_history = null, $current_version_to_add = null)
632
-    {
633
-        if (! $version_history) {
634
-            $version_history = $this->fix_espresso_db_upgrade_option($version_history);
635
-        }
636
-        if ($current_version_to_add === null) {
637
-            $current_version_to_add = espresso_version();
638
-        }
639
-        $version_history[ $current_version_to_add ][] = date('Y-m-d H:i:s', time());
640
-        // re-save
641
-        return update_option('espresso_db_update', $version_history);
642
-    }
643
-
644
-
645
-    /**
646
-     * Detects if the current version indicated in the has existed in the list of
647
-     * previously-installed versions of EE (espresso_db_update). Does NOT modify it (ie, no side-effect)
648
-     *
649
-     * @param array $espresso_db_update array from the wp option stored under the name 'espresso_db_update'.
650
-     *                                  If not supplied, fetches it from the options table.
651
-     *                                  Also, caches its result so later parts of the code can also know whether
652
-     *                                  there's been an update or not. This way we can add the current version to
653
-     *                                  espresso_db_update, but still know if this is a new install or not
654
-     * @return int one of the constants on EE_System::req_type_
655
-     */
656
-    public function detect_req_type($espresso_db_update = null)
657
-    {
658
-        if ($this->_req_type === null) {
659
-            $espresso_db_update = ! empty($espresso_db_update)
660
-                ? $espresso_db_update
661
-                : $this->fix_espresso_db_upgrade_option();
662
-            $this->_req_type = EE_System::detect_req_type_given_activation_history(
663
-                $espresso_db_update,
664
-                'ee_espresso_activation',
665
-                espresso_version()
666
-            );
667
-            $this->_major_version_change = $this->_detect_major_version_change($espresso_db_update);
668
-            $this->request->setIsActivation($this->_req_type !== EE_System::req_type_normal);
669
-        }
670
-        return $this->_req_type;
671
-    }
672
-
673
-
674
-    /**
675
-     * Returns whether or not there was a non-micro version change (ie, change in either
676
-     * the first or second number in the version. Eg 4.9.0.rc.001 to 4.10.0.rc.000,
677
-     * but not 4.9.0.rc.0001 to 4.9.1.rc.0001
678
-     *
679
-     * @param $activation_history
680
-     * @return bool
681
-     */
682
-    private function _detect_major_version_change($activation_history)
683
-    {
684
-        $previous_version = EE_System::_get_most_recently_active_version_from_activation_history($activation_history);
685
-        $previous_version_parts = explode('.', $previous_version);
686
-        $current_version_parts = explode('.', espresso_version());
687
-        return isset($previous_version_parts[0], $previous_version_parts[1], $current_version_parts[0], $current_version_parts[1])
688
-               && ($previous_version_parts[0] !== $current_version_parts[0]
689
-                   || $previous_version_parts[1] !== $current_version_parts[1]
690
-               );
691
-    }
692
-
693
-
694
-    /**
695
-     * Returns true if either the major or minor version of EE changed during this request.
696
-     * Eg 4.9.0.rc.001 to 4.10.0.rc.000, but not 4.9.0.rc.0001 to 4.9.1.rc.0001
697
-     *
698
-     * @return bool
699
-     */
700
-    public function is_major_version_change()
701
-    {
702
-        return $this->_major_version_change;
703
-    }
704
-
705
-
706
-    /**
707
-     * Determines the request type for any ee addon, given three piece of info: the current array of activation
708
-     * histories (for core that' 'espresso_db_update' wp option); the name of the WordPress option which is temporarily
709
-     * set upon activation of the plugin (for core it's 'ee_espresso_activation'); and the version that this plugin was
710
-     * just activated to (for core that will always be espresso_version())
711
-     *
712
-     * @param array  $activation_history_for_addon     the option's value which stores the activation history for this
713
-     *                                                 ee plugin. for core that's 'espresso_db_update'
714
-     * @param string $activation_indicator_option_name the name of the WordPress option that is temporarily set to
715
-     *                                                 indicate that this plugin was just activated
716
-     * @param string $version_to_upgrade_to            the version that was just upgraded to (for core that will be
717
-     *                                                 espresso_version())
718
-     * @return int one of the constants on EE_System::req_type_*
719
-     */
720
-    public static function detect_req_type_given_activation_history(
721
-        $activation_history_for_addon,
722
-        $activation_indicator_option_name,
723
-        $version_to_upgrade_to
724
-    ) {
725
-        $version_is_higher = self::_new_version_is_higher($activation_history_for_addon, $version_to_upgrade_to);
726
-        if ($activation_history_for_addon) {
727
-            // it exists, so this isn't a completely new install
728
-            // check if this version already in that list of previously installed versions
729
-            if (! isset($activation_history_for_addon[ $version_to_upgrade_to ])) {
730
-                // it a version we haven't seen before
731
-                if ($version_is_higher === 1) {
732
-                    $req_type = EE_System::req_type_upgrade;
733
-                } else {
734
-                    $req_type = EE_System::req_type_downgrade;
735
-                }
736
-                delete_option($activation_indicator_option_name);
737
-            } else {
738
-                // its not an update. maybe a reactivation?
739
-                if (get_option($activation_indicator_option_name, false)) {
740
-                    if ($version_is_higher === -1) {
741
-                        $req_type = EE_System::req_type_downgrade;
742
-                    } elseif ($version_is_higher === 0) {
743
-                        // we've seen this version before, but it's an activation. must be a reactivation
744
-                        $req_type = EE_System::req_type_reactivation;
745
-                    } else {// $version_is_higher === 1
746
-                        $req_type = EE_System::req_type_upgrade;
747
-                    }
748
-                    delete_option($activation_indicator_option_name);
749
-                } else {
750
-                    // we've seen this version before and the activation indicate doesn't show it was just activated
751
-                    if ($version_is_higher === -1) {
752
-                        $req_type = EE_System::req_type_downgrade;
753
-                    } elseif ($version_is_higher === 0) {
754
-                        // we've seen this version before and it's not an activation. its normal request
755
-                        $req_type = EE_System::req_type_normal;
756
-                    } else {// $version_is_higher === 1
757
-                        $req_type = EE_System::req_type_upgrade;
758
-                    }
759
-                }
760
-            }
761
-        } else {
762
-            // brand new install
763
-            $req_type = EE_System::req_type_new_activation;
764
-            delete_option($activation_indicator_option_name);
765
-        }
766
-        return $req_type;
767
-    }
768
-
769
-
770
-    /**
771
-     * Detects if the $version_to_upgrade_to is higher than the most recent version in
772
-     * the $activation_history_for_addon
773
-     *
774
-     * @param array  $activation_history_for_addon (keys are versions, values are arrays of times activated,
775
-     *                                             sometimes containing 'unknown-date'
776
-     * @param string $version_to_upgrade_to        (current version)
777
-     * @return int results of version_compare( $version_to_upgrade_to, $most_recently_active_version ).
778
-     *                                             ie, -1 if $version_to_upgrade_to is LOWER (downgrade);
779
-     *                                             0 if $version_to_upgrade_to MATCHES (reactivation or normal request);
780
-     *                                             1 if $version_to_upgrade_to is HIGHER (upgrade) ;
781
-     */
782
-    private static function _new_version_is_higher($activation_history_for_addon, $version_to_upgrade_to)
783
-    {
784
-        // find the most recently-activated version
785
-        $most_recently_active_version =
786
-            EE_System::_get_most_recently_active_version_from_activation_history($activation_history_for_addon);
787
-        return version_compare($version_to_upgrade_to, $most_recently_active_version);
788
-    }
789
-
790
-
791
-    /**
792
-     * Gets the most recently active version listed in the activation history,
793
-     * and if none are found (ie, it's a brand new install) returns '0.0.0.dev.000'.
794
-     *
795
-     * @param array $activation_history  (keys are versions, values are arrays of times activated,
796
-     *                                   sometimes containing 'unknown-date'
797
-     * @return string
798
-     */
799
-    private static function _get_most_recently_active_version_from_activation_history($activation_history)
800
-    {
801
-        $most_recently_active_version_activation = '1970-01-01 00:00:00';
802
-        $most_recently_active_version = '0.0.0.dev.000';
803
-        if (is_array($activation_history)) {
804
-            foreach ($activation_history as $version => $times_activated) {
805
-                // check there is a record of when this version was activated. Otherwise,
806
-                // mark it as unknown
807
-                if (! $times_activated) {
808
-                    $times_activated = array('unknown-date');
809
-                }
810
-                if (is_string($times_activated)) {
811
-                    $times_activated = array($times_activated);
812
-                }
813
-                foreach ($times_activated as $an_activation) {
814
-                    if (
815
-                        $an_activation !== 'unknown-date'
816
-                        && $an_activation
817
-                           > $most_recently_active_version_activation
818
-                    ) {
819
-                        $most_recently_active_version = $version;
820
-                        $most_recently_active_version_activation = $an_activation === 'unknown-date'
821
-                            ? '1970-01-01 00:00:00'
822
-                            : $an_activation;
823
-                    }
824
-                }
825
-            }
826
-        }
827
-        return $most_recently_active_version;
828
-    }
829
-
830
-
831
-    /**
832
-     * This redirects to the about EE page after activation
833
-     *
834
-     * @return void
835
-     */
836
-    public function redirect_to_about_ee()
837
-    {
838
-        $notices = EE_Error::get_notices(false);
839
-        // if current user is an admin and it's not an ajax or rest request
840
-        if (
841
-            ! isset($notices['errors'])
842
-            && $this->request->isAdmin()
843
-            && apply_filters(
844
-                'FHEE__EE_System__redirect_to_about_ee__do_redirect',
845
-                $this->capabilities->current_user_can('manage_options', 'espresso_about_default')
846
-            )
847
-        ) {
848
-            $query_params = array('page' => 'espresso_about');
849
-            if (EE_System::instance()->detect_req_type() === EE_System::req_type_new_activation) {
850
-                $query_params['new_activation'] = true;
851
-            }
852
-            if (EE_System::instance()->detect_req_type() === EE_System::req_type_reactivation) {
853
-                $query_params['reactivation'] = true;
854
-            }
855
-            $url = add_query_arg($query_params, admin_url('admin.php'));
856
-            wp_safe_redirect($url);
857
-            exit();
858
-        }
859
-    }
860
-
861
-
862
-    /**
863
-     * load_core_configuration
864
-     * this is hooked into 'AHEE__EE_Bootstrap__load_core_configuration'
865
-     * which runs during the WP 'plugins_loaded' action at priority 5
866
-     *
867
-     * @return void
868
-     * @throws ReflectionException
869
-     * @throws Exception
870
-     */
871
-    public function load_core_configuration()
872
-    {
873
-        do_action('AHEE__EE_System__load_core_configuration__begin', $this);
874
-        $this->loader->getShared('EE_Load_Textdomain');
875
-        // load textdomain
876
-        EE_Load_Textdomain::load_textdomain();
877
-        // load caf stuff a chance to play during the activation process too.
878
-        $this->_maybe_brew_regular();
879
-        // load and setup EE_Config and EE_Network_Config
880
-        $config = $this->loader->getShared('EE_Config');
881
-        $this->loader->getShared('EE_Network_Config');
882
-        // setup autoloaders
883
-        // enable logging?
884
-        $this->loader->getShared('EventEspresso\core\services\orm\TrashLogger');
885
-        if ($config->admin->use_remote_logging) {
886
-            $this->loader->getShared('EE_Log');
887
-        }
888
-        // check for activation errors
889
-        $activation_errors = get_option('ee_plugin_activation_errors', false);
890
-        if ($activation_errors) {
891
-            EE_Error::add_error($activation_errors, __FILE__, __FUNCTION__, __LINE__);
892
-            update_option('ee_plugin_activation_errors', false);
893
-        }
894
-        // get model names
895
-        $this->_parse_model_names();
896
-        // configure custom post type definitions
897
-        $this->loader->getShared('EventEspresso\core\domain\entities\custom_post_types\CustomTaxonomyDefinitions');
898
-        $this->loader->getShared('EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions');
899
-        do_action('AHEE__EE_System__load_core_configuration__complete', $this);
900
-    }
901
-
902
-
903
-    /**
904
-     * cycles through all of the models/*.model.php files, and assembles an array of model names
905
-     *
906
-     * @return void
907
-     * @throws ReflectionException
908
-     */
909
-    private function _parse_model_names()
910
-    {
911
-        // get all the files in the EE_MODELS folder that end in .model.php
912
-        $models = glob(EE_MODELS . '*.model.php');
913
-        $model_names = array();
914
-        $non_abstract_db_models = array();
915
-        foreach ($models as $model) {
916
-            // get model classname
917
-            $classname = EEH_File::get_classname_from_filepath_with_standard_filename($model);
918
-            $short_name = str_replace('EEM_', '', $classname);
919
-            $reflectionClass = new ReflectionClass($classname);
920
-            if ($reflectionClass->isSubclassOf('EEM_Base') && ! $reflectionClass->isAbstract()) {
921
-                $non_abstract_db_models[ $short_name ] = $classname;
922
-            }
923
-            $model_names[ $short_name ] = $classname;
924
-        }
925
-        $this->registry->models = apply_filters('FHEE__EE_System__parse_model_names', $model_names);
926
-        $this->registry->non_abstract_db_models = apply_filters(
927
-            'FHEE__EE_System__parse_implemented_model_names',
928
-            $non_abstract_db_models
929
-        );
930
-    }
931
-
932
-
933
-    /**
934
-     * The purpose of this method is to simply check for a file named "caffeinated/brewing_regular.php" for any hooks
935
-     * that need to be setup before our EE_System launches.
936
-     *
937
-     * @return void
938
-     * @throws DomainException
939
-     * @throws InvalidArgumentException
940
-     * @throws InvalidDataTypeException
941
-     * @throws InvalidInterfaceException
942
-     * @throws InvalidClassException
943
-     * @throws InvalidFilePathException
944
-     */
945
-    private function _maybe_brew_regular()
946
-    {
947
-        /** @var Domain $domain */
948
-        $domain = DomainFactory::getShared(
949
-            new FullyQualifiedName(
950
-                'EventEspresso\core\domain\Domain'
951
-            ),
952
-            array(
953
-                new FilePath(EVENT_ESPRESSO_MAIN_FILE),
954
-                Version::fromString(espresso_version()),
955
-            )
956
-        );
957
-        if ($domain->isCaffeinated()) {
958
-            require_once EE_CAFF_PATH . 'brewing_regular.php';
959
-        }
960
-    }
961
-
962
-
963
-    /**
964
-     * @since 4.9.71.p
965
-     * @throws Exception
966
-     */
967
-    public function loadRouteMatchSpecifications()
968
-    {
969
-        try {
970
-            $this->loader->getShared(
971
-                'EventEspresso\core\services\route_match\RouteMatchSpecificationManager'
972
-            );
973
-        } catch (Exception $exception) {
974
-            new ExceptionStackTraceDisplay($exception);
975
-        }
976
-        do_action('AHEE__EE_System__loadRouteMatchSpecifications');
977
-    }
978
-
979
-
980
-    /**
981
-     * loading CPT related classes earlier so that their definitions are available
982
-     * but not performing any actual registration with WP core until load_CPTs_and_session() is called
983
-     *
984
-     * @since   4.10.21.p
985
-     */
986
-    public function loadCustomPostTypes()
987
-    {
988
-        $this->register_custom_taxonomies = $this->loader->getShared(
989
-            'EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomies'
990
-        );
991
-        $this->register_custom_post_types = $this->loader->getShared(
992
-            'EventEspresso\core\domain\services\custom_post_types\RegisterCustomPostTypes'
993
-        );
994
-        $this->register_custom_taxonomy_terms = $this->loader->getShared(
995
-            'EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomyTerms'
996
-        );
997
-        // integrate WP_Query with the EE models
998
-        $this->loader->getShared('EE_CPT_Strategy');
999
-        // load legacy EE_Request_Handler in case add-ons still need it
1000
-        $this->loader->getShared('EE_Request_Handler');
1001
-    }
1002
-
1003
-
1004
-    /**
1005
-     * register_shortcodes_modules_and_widgets
1006
-     * generate lists of shortcodes and modules, then verify paths and classes
1007
-     * This is hooked into 'AHEE__EE_Bootstrap__register_shortcodes_modules_and_widgets'
1008
-     * which runs during the WP 'plugins_loaded' action at priority 7
1009
-     *
1010
-     * @access public
1011
-     * @return void
1012
-     * @throws Exception
1013
-     */
1014
-    public function register_shortcodes_modules_and_widgets()
1015
-    {
1016
-        if ($this->request->isFrontend() || $this->request->isIframe() || $this->request->isAjax()) {
1017
-            // load, register, and add shortcodes the new way
1018
-            $this->loader->getShared('EventEspresso\core\services\shortcodes\ShortcodesManager');
1019
-        }
1020
-        do_action('AHEE__EE_System__register_shortcodes_modules_and_widgets');
1021
-        // check for addons using old hook point
1022
-        if (has_action('AHEE__EE_System__register_shortcodes_modules_and_addons')) {
1023
-            $this->_incompatible_addon_error();
1024
-        }
1025
-    }
1026
-
1027
-
1028
-    /**
1029
-     * _incompatible_addon_error
1030
-     *
1031
-     * @access public
1032
-     * @return void
1033
-     */
1034
-    private function _incompatible_addon_error()
1035
-    {
1036
-        // get array of classes hooking into here
1037
-        $class_names = EEH_Class_Tools::get_class_names_for_all_callbacks_on_hook(
1038
-            'AHEE__EE_System__register_shortcodes_modules_and_addons'
1039
-        );
1040
-        if (! empty($class_names)) {
1041
-            $msg = esc_html__(
1042
-                'The following plugins, addons, or modules appear to be incompatible with this version of Event Espresso and were automatically deactivated to avoid fatal errors:',
1043
-                'event_espresso'
1044
-            );
1045
-            $msg .= '<ul>';
1046
-            foreach ($class_names as $class_name) {
1047
-                $msg .= '<li><b>Event Espresso - '
1048
-                        . str_replace(
1049
-                            array('EE_', 'EEM_', 'EED_', 'EES_', 'EEW_'),
1050
-                            '',
1051
-                            $class_name
1052
-                        ) . '</b></li>';
1053
-            }
1054
-            $msg .= '</ul>';
1055
-            $msg .= esc_html__(
1056
-                'Compatibility issues can be avoided and/or resolved by keeping addons and plugins updated to the latest version.',
1057
-                'event_espresso'
1058
-            );
1059
-            // save list of incompatible addons to wp-options for later use
1060
-            add_option('ee_incompatible_addons', $class_names, '', 'no');
1061
-            if (is_admin()) {
1062
-                EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1063
-            }
1064
-        }
1065
-    }
1066
-
1067
-
1068
-    /**
1069
-     * brew_espresso
1070
-     * begins the process of setting hooks for initializing EE in the correct order
1071
-     * This is happening on the 'AHEE__EE_Bootstrap__brew_espresso' hook point
1072
-     * which runs during the WP 'plugins_loaded' action at priority 9
1073
-     *
1074
-     * @return void
1075
-     */
1076
-    public function brew_espresso()
1077
-    {
1078
-        do_action('AHEE__EE_System__brew_espresso__begin', $this);
1079
-        // load some final core systems
1080
-        add_action('init', array($this, 'set_hooks_for_core'), 1);
1081
-        add_action('init', array($this, 'perform_activations_upgrades_and_migrations'), 3);
1082
-        add_action('init', array($this, 'load_CPTs_and_session'), 5);
1083
-        add_action('init', array($this, 'load_controllers'), 7);
1084
-        add_action('init', array($this, 'core_loaded_and_ready'), 9);
1085
-        add_action('init', array($this, 'initialize'), 10);
1086
-        add_action('init', array($this, 'initialize_last'), 100);
1087
-        if (is_admin() && apply_filters('FHEE__EE_System__brew_espresso__load_pue', true)) {
1088
-            // pew pew pew
1089
-            $this->loader->getShared('EventEspresso\core\services\licensing\LicenseService');
1090
-            do_action('AHEE__EE_System__brew_espresso__after_pue_init');
1091
-        }
1092
-        do_action('AHEE__EE_System__brew_espresso__complete', $this);
1093
-    }
1094
-
1095
-
1096
-    /**
1097
-     *    set_hooks_for_core
1098
-     *
1099
-     * @access public
1100
-     * @return    void
1101
-     * @throws EE_Error
1102
-     */
1103
-    public function set_hooks_for_core()
1104
-    {
1105
-        $this->_deactivate_incompatible_addons();
1106
-        do_action('AHEE__EE_System__set_hooks_for_core');
1107
-        $this->loader->getShared('EventEspresso\core\domain\values\session\SessionLifespan');
1108
-        // caps need to be initialized on every request so that capability maps are set.
1109
-        // @see https://events.codebasehq.com/projects/event-espresso/tickets/8674
1110
-        $this->registry->CAP->init_caps();
1111
-    }
1112
-
1113
-
1114
-    /**
1115
-     * Using the information gathered in EE_System::_incompatible_addon_error,
1116
-     * deactivates any addons considered incompatible with the current version of EE
1117
-     */
1118
-    private function _deactivate_incompatible_addons()
1119
-    {
1120
-        $incompatible_addons = get_option('ee_incompatible_addons', array());
1121
-        if (! empty($incompatible_addons)) {
1122
-            $active_plugins = get_option('active_plugins', array());
1123
-            foreach ($active_plugins as $active_plugin) {
1124
-                foreach ($incompatible_addons as $incompatible_addon) {
1125
-                    if (strpos($active_plugin, $incompatible_addon) !== false) {
1126
-                        $this->request->unSetRequestParams(['activate'], true);
1127
-                        espresso_deactivate_plugin($active_plugin);
1128
-                    }
1129
-                }
1130
-            }
1131
-        }
1132
-    }
1133
-
1134
-
1135
-    /**
1136
-     *    perform_activations_upgrades_and_migrations
1137
-     *
1138
-     * @access public
1139
-     * @return    void
1140
-     */
1141
-    public function perform_activations_upgrades_and_migrations()
1142
-    {
1143
-        do_action('AHEE__EE_System__perform_activations_upgrades_and_migrations');
1144
-    }
1145
-
1146
-
1147
-    /**
1148
-     * @return void
1149
-     * @throws DomainException
1150
-     */
1151
-    public function load_CPTs_and_session()
1152
-    {
1153
-        do_action('AHEE__EE_System__load_CPTs_and_session__start');
1154
-        $this->register_custom_taxonomies->registerCustomTaxonomies();
1155
-        $this->register_custom_post_types->registerCustomPostTypes();
1156
-        $this->register_custom_taxonomy_terms->registerCustomTaxonomyTerms();
1157
-        // load legacy Custom Post Types and Taxonomies
1158
-        $this->loader->getShared('EE_Register_CPTs');
1159
-        do_action('AHEE__EE_System__load_CPTs_and_session__complete');
1160
-    }
1161
-
1162
-
1163
-    /**
1164
-     * load_controllers
1165
-     * this is the best place to load any additional controllers that needs access to EE core.
1166
-     * it is expected that all basic core EE systems, that are not dependant on the current request are loaded at this
1167
-     * time
1168
-     *
1169
-     * @access public
1170
-     * @return void
1171
-     */
1172
-    public function load_controllers()
1173
-    {
1174
-        do_action('AHEE__EE_System__load_controllers__start');
1175
-        // let's get it started
1176
-        if (
1177
-            ! $this->maintenance_mode->level()
1178
-            && ($this->request->isFrontend() || $this->request->isFrontAjax())
1179
-        ) {
1180
-            do_action('AHEE__EE_System__load_controllers__load_front_controllers');
1181
-            $this->loader->getShared('EE_Front_Controller');
1182
-        } elseif ($this->request->isAdmin() || $this->request->isAdminAjax()) {
1183
-            do_action('AHEE__EE_System__load_controllers__load_admin_controllers');
1184
-            $this->loader->getShared('EE_Admin');
1185
-        } elseif ($this->request->isWordPressHeartbeat()) {
1186
-            $this->loader->getShared('EventEspresso\core\domain\services\admin\ajax\WordpressHeartbeat');
1187
-        }
1188
-        do_action('AHEE__EE_System__load_controllers__complete');
1189
-    }
1190
-
1191
-
1192
-    /**
1193
-     * core_loaded_and_ready
1194
-     * all of the basic EE core should be loaded at this point and available regardless of M-Mode
1195
-     *
1196
-     * @access public
1197
-     * @return void
1198
-     * @throws Exception
1199
-     */
1200
-    public function core_loaded_and_ready()
1201
-    {
1202
-        if (
1203
-            $this->request->isAdmin()
1204
-            || $this->request->isFrontend()
1205
-            || $this->request->isIframe()
1206
-            || $this->request->isWordPressApi()
1207
-        ) {
1208
-            try {
1209
-                $this->loader->getShared('EventEspresso\core\services\assets\I18nRegistry', [[]]);
1210
-                $this->loader->getShared('EventEspresso\core\services\assets\Registry');
1211
-                $this->loader->getShared('EventEspresso\core\domain\services\assets\CoreAssetManager');
1212
-                if ($this->canLoadBlocks()) {
1213
-                    $this->loader->getShared(
1214
-                        'EventEspresso\core\services\editor\BlockRegistrationManager'
1215
-                    );
1216
-                }
1217
-            } catch (Exception $exception) {
1218
-                new ExceptionStackTraceDisplay($exception);
1219
-            }
1220
-        }
1221
-        if (
1222
-            $this->request->isAdmin()
1223
-            || $this->request->isEeAjax()
1224
-            || $this->request->isFrontend()
1225
-        ) {
1226
-            $this->loader->getShared('EE_Session');
1227
-        }
1228
-        do_action('AHEE__EE_System__core_loaded_and_ready');
1229
-        // always load template tags, because it's faster than checking if it's a front-end request, and many page
1230
-        // builders require these even on the front-end
1231
-        require_once EE_PUBLIC . 'template_tags.php';
1232
-        do_action('AHEE__EE_System__set_hooks_for_shortcodes_modules_and_addons');
1233
-    }
1234
-
1235
-
1236
-    /**
1237
-     * initialize
1238
-     * this is the best place to begin initializing client code
1239
-     *
1240
-     * @access public
1241
-     * @return void
1242
-     */
1243
-    public function initialize()
1244
-    {
1245
-        do_action('AHEE__EE_System__initialize');
1246
-        add_filter(
1247
-            'safe_style_css',
1248
-            function ($styles) {
1249
-                $styles[] = 'display';
1250
-                $styles[] = 'visibility';
1251
-                $styles[] = 'position';
1252
-                $styles[] = 'top';
1253
-                $styles[] = 'right';
1254
-                $styles[] = 'bottom';
1255
-                $styles[] = 'left';
1256
-                $styles[] = 'resize';
1257
-                $styles[] = 'max-width';
1258
-                $styles[] = 'max-height';
1259
-                return $styles;
1260
-            }
1261
-        );
1262
-    }
1263
-
1264
-
1265
-    /**
1266
-     * initialize_last
1267
-     * this is run really late during the WP init hook point, and ensures that mostly everything else that needs to
1268
-     * initialize has done so
1269
-     *
1270
-     * @access public
1271
-     * @return void
1272
-     */
1273
-    public function initialize_last()
1274
-    {
1275
-        do_action('AHEE__EE_System__initialize_last');
1276
-        /** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
1277
-        $rewrite_rules = $this->loader->getShared(
1278
-            'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
1279
-        );
1280
-        $rewrite_rules->flushRewriteRules();
1281
-        add_action('admin_bar_init', array($this, 'addEspressoToolbar'));
1282
-        if (
1283
-            ($this->request->isAjax() || $this->request->isAdmin())
1284
-            && $this->maintenance_mode->models_can_query()
1285
-        ) {
1286
-            $this->loader->getShared('EventEspresso\core\services\privacy\export\PersonalDataExporterManager');
1287
-            $this->loader->getShared('EventEspresso\core\services\privacy\erasure\PersonalDataEraserManager');
1288
-        }
1289
-    }
1290
-
1291
-
1292
-    /**
1293
-     * @return void
1294
-     * @throws EE_Error
1295
-     */
1296
-    public function addEspressoToolbar()
1297
-    {
1298
-        $this->loader->getShared(
1299
-            'EventEspresso\core\domain\services\admin\AdminToolBar',
1300
-            array($this->registry->CAP)
1301
-        );
1302
-    }
1303
-
1304
-
1305
-    /**
1306
-     * do_not_cache
1307
-     * sets no cache headers and defines no cache constants for WP plugins
1308
-     *
1309
-     * @access public
1310
-     * @return void
1311
-     */
1312
-    public static function do_not_cache()
1313
-    {
1314
-        // set no cache constants
1315
-        if (! defined('DONOTCACHEPAGE')) {
1316
-            define('DONOTCACHEPAGE', true);
1317
-        }
1318
-        if (! defined('DONOTCACHCEOBJECT')) {
1319
-            define('DONOTCACHCEOBJECT', true);
1320
-        }
1321
-        if (! defined('DONOTCACHEDB')) {
1322
-            define('DONOTCACHEDB', true);
1323
-        }
1324
-        // add no cache headers
1325
-        add_action('send_headers', array('EE_System', 'nocache_headers'), 10);
1326
-        // plus a little extra for nginx and Google Chrome
1327
-        add_filter('nocache_headers', array('EE_System', 'extra_nocache_headers'), 10, 1);
1328
-        // prevent browsers from prefetching of the rel='next' link, because it may contain content that interferes with the registration process
1329
-        remove_action('wp_head', 'adjacent_posts_rel_link_wp_head');
1330
-    }
1331
-
1332
-
1333
-    /**
1334
-     *    extra_nocache_headers
1335
-     *
1336
-     * @access    public
1337
-     * @param $headers
1338
-     * @return    array
1339
-     */
1340
-    public static function extra_nocache_headers($headers)
1341
-    {
1342
-        // for NGINX
1343
-        $headers['X-Accel-Expires'] = 0;
1344
-        // plus extra for Google Chrome since it doesn't seem to respect "no-cache", but WILL respect "no-store"
1345
-        $headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0';
1346
-        return $headers;
1347
-    }
1348
-
1349
-
1350
-    /**
1351
-     *    nocache_headers
1352
-     *
1353
-     * @access    public
1354
-     * @return    void
1355
-     */
1356
-    public static function nocache_headers()
1357
-    {
1358
-        nocache_headers();
1359
-    }
1360
-
1361
-
1362
-    /**
1363
-     * simply hooks into "wp_list_pages_exclude" filter (for wp_list_pages method) and makes sure EE critical pages are
1364
-     * never returned with the function.
1365
-     *
1366
-     * @param  array $exclude_array any existing pages being excluded are in this array.
1367
-     * @return array
1368
-     */
1369
-    public function remove_pages_from_wp_list_pages($exclude_array)
1370
-    {
1371
-        return array_merge($exclude_array, $this->registry->CFG->core->get_critical_pages_array());
1372
-    }
1373
-
1374
-
1375
-    /**
1376
-     * Return whether blocks can be registered/loaded or not.
1377
-     * @return bool
1378
-     */
1379
-    private function canLoadBlocks()
1380
-    {
1381
-        return apply_filters('FHEE__EE_System__canLoadBlocks', true)
1382
-               && function_exists('register_block_type')
1383
-               // don't load blocks if in the Divi page builder editor context
1384
-               // @see https://github.com/eventespresso/event-espresso-core/issues/814
1385
-               && ! $this->request->getRequestParam('et_fb', false);
1386
-    }
29
+	/**
30
+	 * indicates this is a 'normal' request. Ie, not activation, nor upgrade, nor activation.
31
+	 * So examples of this would be a normal GET request on the frontend or backend, or a POST, etc
32
+	 */
33
+	const req_type_normal = 0;
34
+
35
+	/**
36
+	 * Indicates this is a brand new installation of EE so we should install
37
+	 * tables and default data etc
38
+	 */
39
+	const req_type_new_activation = 1;
40
+
41
+	/**
42
+	 * we've detected that EE has been reactivated (or EE was activated during maintenance mode,
43
+	 * and we just exited maintenance mode). We MUST check the database is setup properly
44
+	 * and that default data is setup too
45
+	 */
46
+	const req_type_reactivation = 2;
47
+
48
+	/**
49
+	 * indicates that EE has been upgraded since its previous request.
50
+	 * We may have data migration scripts to call and will want to trigger maintenance mode
51
+	 */
52
+	const req_type_upgrade = 3;
53
+
54
+	/**
55
+	 * TODO  will detect that EE has been DOWNGRADED. We probably don't want to run in this case...
56
+	 */
57
+	const req_type_downgrade = 4;
58
+
59
+	/**
60
+	 * @deprecated since version 4.6.0.dev.006
61
+	 * Now whenever a new_activation is detected the request type is still just
62
+	 * new_activation (same for reactivation, upgrade, downgrade etc), but if we'r ein maintenance mode
63
+	 * EE_System::initialize_db_if_no_migrations_required and EE_Addon::initialize_db_if_no_migrations_required
64
+	 * will instead enqueue that EE plugin's db initialization for when we're taken out of maintenance mode.
65
+	 * (Specifically, when the migration manager indicates migrations are finished
66
+	 * EE_Data_Migration_Manager::initialize_db_for_enqueued_ee_plugins() will be called)
67
+	 */
68
+	const req_type_activation_but_not_installed = 5;
69
+
70
+	/**
71
+	 * option prefix for recording the activation history (like core's "espresso_db_update") of addons
72
+	 */
73
+	const addon_activation_history_option_prefix = 'ee_addon_activation_history_';
74
+
75
+	/**
76
+	 * @var EE_System $_instance
77
+	 */
78
+	private static $_instance;
79
+
80
+	/**
81
+	 * @var EE_Registry $registry
82
+	 */
83
+	private $registry;
84
+
85
+	/**
86
+	 * @var LoaderInterface $loader
87
+	 */
88
+	private $loader;
89
+
90
+	/**
91
+	 * @var EE_Capabilities $capabilities
92
+	 */
93
+	private $capabilities;
94
+
95
+	/**
96
+	 * @var RequestInterface $request
97
+	 */
98
+	private $request;
99
+
100
+	/**
101
+	 * @var EE_Maintenance_Mode $maintenance_mode
102
+	 */
103
+	private $maintenance_mode;
104
+
105
+	/**
106
+	 * Stores which type of request this is, options being one of the constants on EE_System starting with req_type_*.
107
+	 * It can be a brand-new activation, a reactivation, an upgrade, a downgrade, or a normal request.
108
+	 *
109
+	 * @var int $_req_type
110
+	 */
111
+	private $_req_type;
112
+
113
+	/**
114
+	 * Whether or not there was a non-micro version change in EE core version during this request
115
+	 *
116
+	 * @var boolean $_major_version_change
117
+	 */
118
+	private $_major_version_change = false;
119
+
120
+	/**
121
+	 * A Context DTO dedicated solely to identifying the current request type.
122
+	 *
123
+	 * @var RequestTypeContextCheckerInterface $request_type
124
+	 */
125
+	private $request_type;
126
+
127
+	/**
128
+	 * @param EventEspresso\core\domain\services\custom_post_types\RegisterCustomPostTypes
129
+	 */
130
+	private $register_custom_post_types;
131
+
132
+	/**
133
+	 * @param EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomies
134
+	 */
135
+	private $register_custom_taxonomies;
136
+
137
+	/**
138
+	 * @param EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomyTerms
139
+	 */
140
+	private $register_custom_taxonomy_terms;
141
+
142
+	/**
143
+	 * @singleton method used to instantiate class object
144
+	 * @param EE_Registry|null         $registry
145
+	 * @param LoaderInterface|null     $loader
146
+	 * @param RequestInterface|null    $request
147
+	 * @param EE_Maintenance_Mode|null $maintenance_mode
148
+	 * @return EE_System
149
+	 */
150
+	public static function instance(
151
+		EE_Registry $registry = null,
152
+		LoaderInterface $loader = null,
153
+		RequestInterface $request = null,
154
+		EE_Maintenance_Mode $maintenance_mode = null
155
+	) {
156
+		// check if class object is instantiated
157
+		if (! self::$_instance instanceof EE_System) {
158
+			self::$_instance = new self($registry, $loader, $request, $maintenance_mode);
159
+		}
160
+		return self::$_instance;
161
+	}
162
+
163
+
164
+	/**
165
+	 * resets the instance and returns it
166
+	 *
167
+	 * @return EE_System
168
+	 */
169
+	public static function reset()
170
+	{
171
+		self::$_instance->_req_type = null;
172
+		// make sure none of the old hooks are left hanging around
173
+		remove_all_actions('AHEE__EE_System__perform_activations_upgrades_and_migrations');
174
+		// we need to reset the migration manager in order for it to detect DMSs properly
175
+		EE_Data_Migration_Manager::reset();
176
+		self::instance()->detect_activations_or_upgrades();
177
+		self::instance()->perform_activations_upgrades_and_migrations();
178
+		return self::instance();
179
+	}
180
+
181
+
182
+	/**
183
+	 * sets hooks for running rest of system
184
+	 * provides "AHEE__EE_System__construct__complete" hook for EE Addons to use as their starting point
185
+	 * starting EE Addons from any other point may lead to problems
186
+	 *
187
+	 * @param EE_Registry         $registry
188
+	 * @param LoaderInterface     $loader
189
+	 * @param RequestInterface    $request
190
+	 * @param EE_Maintenance_Mode $maintenance_mode
191
+	 */
192
+	private function __construct(
193
+		EE_Registry $registry,
194
+		LoaderInterface $loader,
195
+		RequestInterface $request,
196
+		EE_Maintenance_Mode $maintenance_mode
197
+	) {
198
+		$this->registry = $registry;
199
+		$this->loader = $loader;
200
+		$this->request = $request;
201
+		$this->maintenance_mode = $maintenance_mode;
202
+		do_action('AHEE__EE_System__construct__begin', $this);
203
+		add_action(
204
+			'AHEE__EE_Bootstrap__load_espresso_addons',
205
+			array($this, 'loadCapabilities'),
206
+			5
207
+		);
208
+		add_action(
209
+			'AHEE__EE_Bootstrap__load_espresso_addons',
210
+			array($this, 'loadCommandBus'),
211
+			7
212
+		);
213
+		add_action(
214
+			'AHEE__EE_Bootstrap__load_espresso_addons',
215
+			array($this, 'loadPluginApi'),
216
+			9
217
+		);
218
+		// allow addons to load first so that they can register autoloaders, set hooks for running DMS's, etc
219
+		add_action(
220
+			'AHEE__EE_Bootstrap__load_espresso_addons',
221
+			array($this, 'load_espresso_addons')
222
+		);
223
+		// when an ee addon is activated, we want to call the core hook(s) again
224
+		// because the newly-activated addon didn't get a chance to run at all
225
+		add_action('activate_plugin', array($this, 'load_espresso_addons'), 1);
226
+		// detect whether install or upgrade
227
+		add_action(
228
+			'AHEE__EE_Bootstrap__detect_activations_or_upgrades',
229
+			array($this, 'detect_activations_or_upgrades'),
230
+			3
231
+		);
232
+		// load EE_Config, EE_Textdomain, etc
233
+		add_action(
234
+			'AHEE__EE_Bootstrap__load_core_configuration',
235
+			array($this, 'load_core_configuration'),
236
+			5
237
+		);
238
+		// load specifications for matching routes to current request
239
+		add_action(
240
+			'AHEE__EE_Bootstrap__load_core_configuration',
241
+			array($this, 'loadRouteMatchSpecifications')
242
+		);
243
+		// load specifications for custom post types
244
+		add_action(
245
+			'AHEE__EE_Bootstrap__load_core_configuration',
246
+			array($this, 'loadCustomPostTypes')
247
+		);
248
+		// load EE_Config, EE_Textdomain, etc
249
+		add_action(
250
+			'AHEE__EE_Bootstrap__register_shortcodes_modules_and_widgets',
251
+			array($this, 'register_shortcodes_modules_and_widgets'),
252
+			7
253
+		);
254
+		// you wanna get going? I wanna get going... let's get going!
255
+		add_action(
256
+			'AHEE__EE_Bootstrap__brew_espresso',
257
+			array($this, 'brew_espresso'),
258
+			9
259
+		);
260
+		// other housekeeping
261
+		// exclude EE critical pages from wp_list_pages
262
+		add_filter(
263
+			'wp_list_pages_excludes',
264
+			array($this, 'remove_pages_from_wp_list_pages'),
265
+			10
266
+		);
267
+		// ALL EE Addons should use the following hook point to attach their initial setup too
268
+		// it's extremely important for EE Addons to register any class autoloaders so that they can be available when the EE_Config loads
269
+		do_action('AHEE__EE_System__construct__complete', $this);
270
+	}
271
+
272
+
273
+	/**
274
+	 * load and setup EE_Capabilities
275
+	 *
276
+	 * @return void
277
+	 * @throws EE_Error
278
+	 */
279
+	public function loadCapabilities()
280
+	{
281
+		$this->capabilities = $this->loader->getShared('EE_Capabilities');
282
+		add_action(
283
+			'AHEE__EE_Capabilities__init_caps__before_initialization',
284
+			function () {
285
+				LoaderFactory::getLoader()->getShared('EE_Payment_Method_Manager');
286
+			}
287
+		);
288
+	}
289
+
290
+
291
+	/**
292
+	 * create and cache the CommandBus, and also add middleware
293
+	 * The CapChecker middleware requires the use of EE_Capabilities
294
+	 * which is why we need to load the CommandBus after Caps are set up
295
+	 * CommandBus middleware operate FIFO - First In First Out
296
+	 * so LocateMovedCommands will run first in order to return any new commands
297
+	 *
298
+	 * @return void
299
+	 * @throws EE_Error
300
+	 */
301
+	public function loadCommandBus()
302
+	{
303
+		$this->loader->getShared(
304
+			'CommandBusInterface',
305
+			array(
306
+				null,
307
+				apply_filters(
308
+					'FHEE__EE_Load_Espresso_Core__handle_request__CommandBus_middleware',
309
+					array(
310
+						$this->loader->getShared('EventEspresso\core\services\commands\middleware\LocateMovedCommands'),
311
+						$this->loader->getShared('EventEspresso\core\services\commands\middleware\CapChecker'),
312
+						$this->loader->getShared('EventEspresso\core\services\commands\middleware\AddActionHook'),
313
+					)
314
+				),
315
+			)
316
+		);
317
+	}
318
+
319
+
320
+	/**
321
+	 * @return void
322
+	 * @throws EE_Error
323
+	 */
324
+	public function loadPluginApi()
325
+	{
326
+		// set autoloaders for all of the classes implementing EEI_Plugin_API
327
+		// which provide helpers for EE plugin authors to more easily register certain components with EE.
328
+		EEH_Autoloader::instance()->register_autoloaders_for_each_file_in_folder(EE_LIBRARIES . 'plugin_api');
329
+	}
330
+
331
+
332
+	/**
333
+	 * @param string $addon_name
334
+	 * @param string $version_constant
335
+	 * @param string $min_version_required
336
+	 * @param string $load_callback
337
+	 * @param string $plugin_file_constant
338
+	 * @return void
339
+	 */
340
+	private function deactivateIncompatibleAddon(
341
+		$addon_name,
342
+		$version_constant,
343
+		$min_version_required,
344
+		$load_callback,
345
+		$plugin_file_constant
346
+	) {
347
+		if (! defined($version_constant)) {
348
+			return;
349
+		}
350
+		$addon_version = constant($version_constant);
351
+		if ($addon_version && version_compare($addon_version, $min_version_required, '<')) {
352
+			remove_action('AHEE__EE_System__load_espresso_addons', $load_callback);
353
+			if (! function_exists('deactivate_plugins')) {
354
+				require_once ABSPATH . 'wp-admin/includes/plugin.php';
355
+			}
356
+			deactivate_plugins(plugin_basename(constant($plugin_file_constant)));
357
+			$this->request->unSetRequestParams(['activate', 'activate-multi'], true);
358
+			EE_Error::add_error(
359
+				sprintf(
360
+					esc_html__(
361
+						'We\'re sorry, but the Event Espresso %1$s addon was deactivated because version %2$s or higher is required with this version of Event Espresso core.',
362
+						'event_espresso'
363
+					),
364
+					$addon_name,
365
+					$min_version_required
366
+				),
367
+				__FILE__,
368
+				__FUNCTION__ . "({$addon_name})",
369
+				__LINE__
370
+			);
371
+			EE_Error::get_notices(false, true);
372
+		}
373
+	}
374
+
375
+
376
+	/**
377
+	 * load_espresso_addons
378
+	 * allow addons to load first so that they can set hooks for running DMS's, etc
379
+	 * this is hooked into both:
380
+	 *    'AHEE__EE_Bootstrap__load_core_configuration'
381
+	 *        which runs during the WP 'plugins_loaded' action at priority 5
382
+	 *    and the WP 'activate_plugin' hook point
383
+	 *
384
+	 * @access public
385
+	 * @return void
386
+	 */
387
+	public function load_espresso_addons()
388
+	{
389
+		$this->deactivateIncompatibleAddon(
390
+			'Wait Lists',
391
+			'EE_WAIT_LISTS_VERSION',
392
+			'1.0.0.beta.074',
393
+			'load_espresso_wait_lists',
394
+			'EE_WAIT_LISTS_PLUGIN_FILE'
395
+		);
396
+		$this->deactivateIncompatibleAddon(
397
+			'Automated Upcoming Event Notifications',
398
+			'EE_AUTOMATED_UPCOMING_EVENT_NOTIFICATION_VERSION',
399
+			'1.0.0.beta.091',
400
+			'load_espresso_automated_upcoming_event_notification',
401
+			'EE_AUTOMATED_UPCOMING_EVENT_NOTIFICATION_PLUGIN_FILE'
402
+		);
403
+		do_action('AHEE__EE_System__load_espresso_addons');
404
+		// if the WP API basic auth plugin isn't already loaded, load it now.
405
+		// We want it for mobile apps. Just include the entire plugin
406
+		// also, don't load the basic auth when a plugin is getting activated, because
407
+		// it could be the basic auth plugin, and it doesn't check if its methods are already defined
408
+		// and causes a fatal error
409
+		if (
410
+			($this->request->isWordPressApi() || $this->request->isApi())
411
+			&& $this->request->getRequestParam('activate') !== 'true'
412
+			&& ! function_exists('json_basic_auth_handler')
413
+			&& ! function_exists('json_basic_auth_error')
414
+			&& ! in_array(
415
+				$this->request->getRequestParam('action'),
416
+				array('activate', 'activate-selected'),
417
+				true
418
+			)
419
+		) {
420
+			include_once EE_THIRD_PARTY . 'wp-api-basic-auth/basic-auth.php';
421
+		}
422
+		do_action('AHEE__EE_System__load_espresso_addons__complete');
423
+	}
424
+
425
+
426
+	/**
427
+	 * detect_activations_or_upgrades
428
+	 * Checks for activation or upgrade of core first;
429
+	 * then also checks if any registered addons have been activated or upgraded
430
+	 * This is hooked into 'AHEE__EE_Bootstrap__detect_activations_or_upgrades'
431
+	 * which runs during the WP 'plugins_loaded' action at priority 3
432
+	 *
433
+	 * @access public
434
+	 * @return void
435
+	 */
436
+	public function detect_activations_or_upgrades()
437
+	{
438
+		// first off: let's make sure to handle core
439
+		$this->detect_if_activation_or_upgrade();
440
+		foreach ($this->registry->addons as $addon) {
441
+			if ($addon instanceof EE_Addon) {
442
+				// detect teh request type for that addon
443
+				$addon->detect_req_type();
444
+			}
445
+		}
446
+	}
447
+
448
+
449
+	/**
450
+	 * detect_if_activation_or_upgrade
451
+	 * Takes care of detecting whether this is a brand new install or code upgrade,
452
+	 * and either setting up the DB or setting up maintenance mode etc.
453
+	 *
454
+	 * @access public
455
+	 * @return void
456
+	 */
457
+	public function detect_if_activation_or_upgrade()
458
+	{
459
+		do_action('AHEE__EE_System___detect_if_activation_or_upgrade__begin');
460
+		// check if db has been updated, or if its a brand-new installation
461
+		$espresso_db_update = $this->fix_espresso_db_upgrade_option();
462
+		$request_type = $this->detect_req_type($espresso_db_update);
463
+		// EEH_Debug_Tools::printr( $request_type, '$request_type', __FILE__, __LINE__ );
464
+		switch ($request_type) {
465
+			case EE_System::req_type_new_activation:
466
+				do_action('AHEE__EE_System__detect_if_activation_or_upgrade__new_activation');
467
+				$this->_handle_core_version_change($espresso_db_update);
468
+				break;
469
+			case EE_System::req_type_reactivation:
470
+				do_action('AHEE__EE_System__detect_if_activation_or_upgrade__reactivation');
471
+				$this->_handle_core_version_change($espresso_db_update);
472
+				break;
473
+			case EE_System::req_type_upgrade:
474
+				do_action('AHEE__EE_System__detect_if_activation_or_upgrade__upgrade');
475
+				// migrations may be required now that we've upgraded
476
+				$this->maintenance_mode->set_maintenance_mode_if_db_old();
477
+				$this->_handle_core_version_change($espresso_db_update);
478
+				break;
479
+			case EE_System::req_type_downgrade:
480
+				do_action('AHEE__EE_System__detect_if_activation_or_upgrade__downgrade');
481
+				// its possible migrations are no longer required
482
+				$this->maintenance_mode->set_maintenance_mode_if_db_old();
483
+				$this->_handle_core_version_change($espresso_db_update);
484
+				break;
485
+			case EE_System::req_type_normal:
486
+			default:
487
+				break;
488
+		}
489
+		do_action('AHEE__EE_System__detect_if_activation_or_upgrade__complete');
490
+	}
491
+
492
+
493
+	/**
494
+	 * Updates the list of installed versions and sets hooks for
495
+	 * initializing the database later during the request
496
+	 *
497
+	 * @param array $espresso_db_update
498
+	 */
499
+	private function _handle_core_version_change($espresso_db_update)
500
+	{
501
+		$this->update_list_of_installed_versions($espresso_db_update);
502
+		// get ready to verify the DB is ok (provided we aren't in maintenance mode, of course)
503
+		add_action(
504
+			'AHEE__EE_System__perform_activations_upgrades_and_migrations',
505
+			array($this, 'initialize_db_if_no_migrations_required')
506
+		);
507
+	}
508
+
509
+
510
+	/**
511
+	 * standardizes the wp option 'espresso_db_upgrade' which actually stores
512
+	 * information about what versions of EE have been installed and activated,
513
+	 * NOT necessarily the state of the database
514
+	 *
515
+	 * @param mixed $espresso_db_update           the value of the WordPress option.
516
+	 *                                            If not supplied, fetches it from the options table
517
+	 * @return array the correct value of 'espresso_db_upgrade', after saving it, if it needed correction
518
+	 */
519
+	private function fix_espresso_db_upgrade_option($espresso_db_update = null)
520
+	{
521
+		do_action('FHEE__EE_System__manage_fix_espresso_db_upgrade_option__begin', $espresso_db_update);
522
+		if (! $espresso_db_update) {
523
+			$espresso_db_update = get_option('espresso_db_update');
524
+		}
525
+		// check that option is an array
526
+		if (! is_array($espresso_db_update)) {
527
+			// if option is FALSE, then it never existed
528
+			if ($espresso_db_update === false) {
529
+				// make $espresso_db_update an array and save option with autoload OFF
530
+				$espresso_db_update = array();
531
+				add_option('espresso_db_update', $espresso_db_update, '', 'no');
532
+			} else {
533
+				// option is NOT FALSE but also is NOT an array, so make it an array and save it
534
+				$espresso_db_update = array($espresso_db_update => array());
535
+				update_option('espresso_db_update', $espresso_db_update);
536
+			}
537
+		} else {
538
+			$corrected_db_update = array();
539
+			// if IS an array, but is it an array where KEYS are version numbers, and values are arrays?
540
+			foreach ($espresso_db_update as $should_be_version_string => $should_be_array) {
541
+				if (is_int($should_be_version_string) && ! is_array($should_be_array)) {
542
+					// the key is an int, and the value IS NOT an array
543
+					// so it must be numerically-indexed, where values are versions installed...
544
+					// fix it!
545
+					$version_string = $should_be_array;
546
+					$corrected_db_update[ $version_string ] = array('unknown-date');
547
+				} else {
548
+					// ok it checks out
549
+					$corrected_db_update[ $should_be_version_string ] = $should_be_array;
550
+				}
551
+			}
552
+			$espresso_db_update = $corrected_db_update;
553
+			update_option('espresso_db_update', $espresso_db_update);
554
+		}
555
+		do_action('FHEE__EE_System__manage_fix_espresso_db_upgrade_option__complete', $espresso_db_update);
556
+		return $espresso_db_update;
557
+	}
558
+
559
+
560
+	/**
561
+	 * Does the traditional work of setting up the plugin's database and adding default data.
562
+	 * If migration script/process did not exist, this is what would happen on every activation/reactivation/upgrade.
563
+	 * NOTE: if we're in maintenance mode (which would be the case if we detect there are data
564
+	 * migration scripts that need to be run and a version change happens), enqueues core for database initialization,
565
+	 * so that it will be done when migrations are finished
566
+	 *
567
+	 * @param boolean $initialize_addons_too if true, we double-check addons' database tables etc too;
568
+	 * @param boolean $verify_schema         if true will re-check the database tables have the correct schema.
569
+	 *                                       This is a resource-intensive job
570
+	 *                                       so we prefer to only do it when necessary
571
+	 * @return void
572
+	 * @throws EE_Error
573
+	 */
574
+	public function initialize_db_if_no_migrations_required($initialize_addons_too = false, $verify_schema = true)
575
+	{
576
+		$request_type = $this->detect_req_type();
577
+		// only initialize system if we're not in maintenance mode.
578
+		if ($this->maintenance_mode->level() !== EE_Maintenance_Mode::level_2_complete_maintenance) {
579
+			/** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
580
+			$rewrite_rules = $this->loader->getShared(
581
+				'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
582
+			);
583
+			$rewrite_rules->flush();
584
+			if ($verify_schema) {
585
+				EEH_Activation::initialize_db_and_folders();
586
+			}
587
+			EEH_Activation::initialize_db_content();
588
+			EEH_Activation::system_initialization();
589
+			if ($initialize_addons_too) {
590
+				$this->initialize_addons();
591
+			}
592
+		} else {
593
+			EE_Data_Migration_Manager::instance()->enqueue_db_initialization_for('Core');
594
+		}
595
+		if (
596
+			$request_type === EE_System::req_type_new_activation
597
+			|| $request_type === EE_System::req_type_reactivation
598
+			|| (
599
+				$request_type === EE_System::req_type_upgrade
600
+				&& $this->is_major_version_change()
601
+			)
602
+		) {
603
+			add_action('AHEE__EE_System__initialize_last', array($this, 'redirect_to_about_ee'), 9);
604
+		}
605
+	}
606
+
607
+
608
+	/**
609
+	 * Initializes the db for all registered addons
610
+	 *
611
+	 * @throws EE_Error
612
+	 */
613
+	public function initialize_addons()
614
+	{
615
+		// foreach registered addon, make sure its db is up-to-date too
616
+		foreach ($this->registry->addons as $addon) {
617
+			if ($addon instanceof EE_Addon) {
618
+				$addon->initialize_db_if_no_migrations_required();
619
+			}
620
+		}
621
+	}
622
+
623
+
624
+	/**
625
+	 * Adds the current code version to the saved wp option which stores a list of all ee versions ever installed.
626
+	 *
627
+	 * @param    array  $version_history
628
+	 * @param    string $current_version_to_add version to be added to the version history
629
+	 * @return    boolean success as to whether or not this option was changed
630
+	 */
631
+	public function update_list_of_installed_versions($version_history = null, $current_version_to_add = null)
632
+	{
633
+		if (! $version_history) {
634
+			$version_history = $this->fix_espresso_db_upgrade_option($version_history);
635
+		}
636
+		if ($current_version_to_add === null) {
637
+			$current_version_to_add = espresso_version();
638
+		}
639
+		$version_history[ $current_version_to_add ][] = date('Y-m-d H:i:s', time());
640
+		// re-save
641
+		return update_option('espresso_db_update', $version_history);
642
+	}
643
+
644
+
645
+	/**
646
+	 * Detects if the current version indicated in the has existed in the list of
647
+	 * previously-installed versions of EE (espresso_db_update). Does NOT modify it (ie, no side-effect)
648
+	 *
649
+	 * @param array $espresso_db_update array from the wp option stored under the name 'espresso_db_update'.
650
+	 *                                  If not supplied, fetches it from the options table.
651
+	 *                                  Also, caches its result so later parts of the code can also know whether
652
+	 *                                  there's been an update or not. This way we can add the current version to
653
+	 *                                  espresso_db_update, but still know if this is a new install or not
654
+	 * @return int one of the constants on EE_System::req_type_
655
+	 */
656
+	public function detect_req_type($espresso_db_update = null)
657
+	{
658
+		if ($this->_req_type === null) {
659
+			$espresso_db_update = ! empty($espresso_db_update)
660
+				? $espresso_db_update
661
+				: $this->fix_espresso_db_upgrade_option();
662
+			$this->_req_type = EE_System::detect_req_type_given_activation_history(
663
+				$espresso_db_update,
664
+				'ee_espresso_activation',
665
+				espresso_version()
666
+			);
667
+			$this->_major_version_change = $this->_detect_major_version_change($espresso_db_update);
668
+			$this->request->setIsActivation($this->_req_type !== EE_System::req_type_normal);
669
+		}
670
+		return $this->_req_type;
671
+	}
672
+
673
+
674
+	/**
675
+	 * Returns whether or not there was a non-micro version change (ie, change in either
676
+	 * the first or second number in the version. Eg 4.9.0.rc.001 to 4.10.0.rc.000,
677
+	 * but not 4.9.0.rc.0001 to 4.9.1.rc.0001
678
+	 *
679
+	 * @param $activation_history
680
+	 * @return bool
681
+	 */
682
+	private function _detect_major_version_change($activation_history)
683
+	{
684
+		$previous_version = EE_System::_get_most_recently_active_version_from_activation_history($activation_history);
685
+		$previous_version_parts = explode('.', $previous_version);
686
+		$current_version_parts = explode('.', espresso_version());
687
+		return isset($previous_version_parts[0], $previous_version_parts[1], $current_version_parts[0], $current_version_parts[1])
688
+			   && ($previous_version_parts[0] !== $current_version_parts[0]
689
+				   || $previous_version_parts[1] !== $current_version_parts[1]
690
+			   );
691
+	}
692
+
693
+
694
+	/**
695
+	 * Returns true if either the major or minor version of EE changed during this request.
696
+	 * Eg 4.9.0.rc.001 to 4.10.0.rc.000, but not 4.9.0.rc.0001 to 4.9.1.rc.0001
697
+	 *
698
+	 * @return bool
699
+	 */
700
+	public function is_major_version_change()
701
+	{
702
+		return $this->_major_version_change;
703
+	}
704
+
705
+
706
+	/**
707
+	 * Determines the request type for any ee addon, given three piece of info: the current array of activation
708
+	 * histories (for core that' 'espresso_db_update' wp option); the name of the WordPress option which is temporarily
709
+	 * set upon activation of the plugin (for core it's 'ee_espresso_activation'); and the version that this plugin was
710
+	 * just activated to (for core that will always be espresso_version())
711
+	 *
712
+	 * @param array  $activation_history_for_addon     the option's value which stores the activation history for this
713
+	 *                                                 ee plugin. for core that's 'espresso_db_update'
714
+	 * @param string $activation_indicator_option_name the name of the WordPress option that is temporarily set to
715
+	 *                                                 indicate that this plugin was just activated
716
+	 * @param string $version_to_upgrade_to            the version that was just upgraded to (for core that will be
717
+	 *                                                 espresso_version())
718
+	 * @return int one of the constants on EE_System::req_type_*
719
+	 */
720
+	public static function detect_req_type_given_activation_history(
721
+		$activation_history_for_addon,
722
+		$activation_indicator_option_name,
723
+		$version_to_upgrade_to
724
+	) {
725
+		$version_is_higher = self::_new_version_is_higher($activation_history_for_addon, $version_to_upgrade_to);
726
+		if ($activation_history_for_addon) {
727
+			// it exists, so this isn't a completely new install
728
+			// check if this version already in that list of previously installed versions
729
+			if (! isset($activation_history_for_addon[ $version_to_upgrade_to ])) {
730
+				// it a version we haven't seen before
731
+				if ($version_is_higher === 1) {
732
+					$req_type = EE_System::req_type_upgrade;
733
+				} else {
734
+					$req_type = EE_System::req_type_downgrade;
735
+				}
736
+				delete_option($activation_indicator_option_name);
737
+			} else {
738
+				// its not an update. maybe a reactivation?
739
+				if (get_option($activation_indicator_option_name, false)) {
740
+					if ($version_is_higher === -1) {
741
+						$req_type = EE_System::req_type_downgrade;
742
+					} elseif ($version_is_higher === 0) {
743
+						// we've seen this version before, but it's an activation. must be a reactivation
744
+						$req_type = EE_System::req_type_reactivation;
745
+					} else {// $version_is_higher === 1
746
+						$req_type = EE_System::req_type_upgrade;
747
+					}
748
+					delete_option($activation_indicator_option_name);
749
+				} else {
750
+					// we've seen this version before and the activation indicate doesn't show it was just activated
751
+					if ($version_is_higher === -1) {
752
+						$req_type = EE_System::req_type_downgrade;
753
+					} elseif ($version_is_higher === 0) {
754
+						// we've seen this version before and it's not an activation. its normal request
755
+						$req_type = EE_System::req_type_normal;
756
+					} else {// $version_is_higher === 1
757
+						$req_type = EE_System::req_type_upgrade;
758
+					}
759
+				}
760
+			}
761
+		} else {
762
+			// brand new install
763
+			$req_type = EE_System::req_type_new_activation;
764
+			delete_option($activation_indicator_option_name);
765
+		}
766
+		return $req_type;
767
+	}
768
+
769
+
770
+	/**
771
+	 * Detects if the $version_to_upgrade_to is higher than the most recent version in
772
+	 * the $activation_history_for_addon
773
+	 *
774
+	 * @param array  $activation_history_for_addon (keys are versions, values are arrays of times activated,
775
+	 *                                             sometimes containing 'unknown-date'
776
+	 * @param string $version_to_upgrade_to        (current version)
777
+	 * @return int results of version_compare( $version_to_upgrade_to, $most_recently_active_version ).
778
+	 *                                             ie, -1 if $version_to_upgrade_to is LOWER (downgrade);
779
+	 *                                             0 if $version_to_upgrade_to MATCHES (reactivation or normal request);
780
+	 *                                             1 if $version_to_upgrade_to is HIGHER (upgrade) ;
781
+	 */
782
+	private static function _new_version_is_higher($activation_history_for_addon, $version_to_upgrade_to)
783
+	{
784
+		// find the most recently-activated version
785
+		$most_recently_active_version =
786
+			EE_System::_get_most_recently_active_version_from_activation_history($activation_history_for_addon);
787
+		return version_compare($version_to_upgrade_to, $most_recently_active_version);
788
+	}
789
+
790
+
791
+	/**
792
+	 * Gets the most recently active version listed in the activation history,
793
+	 * and if none are found (ie, it's a brand new install) returns '0.0.0.dev.000'.
794
+	 *
795
+	 * @param array $activation_history  (keys are versions, values are arrays of times activated,
796
+	 *                                   sometimes containing 'unknown-date'
797
+	 * @return string
798
+	 */
799
+	private static function _get_most_recently_active_version_from_activation_history($activation_history)
800
+	{
801
+		$most_recently_active_version_activation = '1970-01-01 00:00:00';
802
+		$most_recently_active_version = '0.0.0.dev.000';
803
+		if (is_array($activation_history)) {
804
+			foreach ($activation_history as $version => $times_activated) {
805
+				// check there is a record of when this version was activated. Otherwise,
806
+				// mark it as unknown
807
+				if (! $times_activated) {
808
+					$times_activated = array('unknown-date');
809
+				}
810
+				if (is_string($times_activated)) {
811
+					$times_activated = array($times_activated);
812
+				}
813
+				foreach ($times_activated as $an_activation) {
814
+					if (
815
+						$an_activation !== 'unknown-date'
816
+						&& $an_activation
817
+						   > $most_recently_active_version_activation
818
+					) {
819
+						$most_recently_active_version = $version;
820
+						$most_recently_active_version_activation = $an_activation === 'unknown-date'
821
+							? '1970-01-01 00:00:00'
822
+							: $an_activation;
823
+					}
824
+				}
825
+			}
826
+		}
827
+		return $most_recently_active_version;
828
+	}
829
+
830
+
831
+	/**
832
+	 * This redirects to the about EE page after activation
833
+	 *
834
+	 * @return void
835
+	 */
836
+	public function redirect_to_about_ee()
837
+	{
838
+		$notices = EE_Error::get_notices(false);
839
+		// if current user is an admin and it's not an ajax or rest request
840
+		if (
841
+			! isset($notices['errors'])
842
+			&& $this->request->isAdmin()
843
+			&& apply_filters(
844
+				'FHEE__EE_System__redirect_to_about_ee__do_redirect',
845
+				$this->capabilities->current_user_can('manage_options', 'espresso_about_default')
846
+			)
847
+		) {
848
+			$query_params = array('page' => 'espresso_about');
849
+			if (EE_System::instance()->detect_req_type() === EE_System::req_type_new_activation) {
850
+				$query_params['new_activation'] = true;
851
+			}
852
+			if (EE_System::instance()->detect_req_type() === EE_System::req_type_reactivation) {
853
+				$query_params['reactivation'] = true;
854
+			}
855
+			$url = add_query_arg($query_params, admin_url('admin.php'));
856
+			wp_safe_redirect($url);
857
+			exit();
858
+		}
859
+	}
860
+
861
+
862
+	/**
863
+	 * load_core_configuration
864
+	 * this is hooked into 'AHEE__EE_Bootstrap__load_core_configuration'
865
+	 * which runs during the WP 'plugins_loaded' action at priority 5
866
+	 *
867
+	 * @return void
868
+	 * @throws ReflectionException
869
+	 * @throws Exception
870
+	 */
871
+	public function load_core_configuration()
872
+	{
873
+		do_action('AHEE__EE_System__load_core_configuration__begin', $this);
874
+		$this->loader->getShared('EE_Load_Textdomain');
875
+		// load textdomain
876
+		EE_Load_Textdomain::load_textdomain();
877
+		// load caf stuff a chance to play during the activation process too.
878
+		$this->_maybe_brew_regular();
879
+		// load and setup EE_Config and EE_Network_Config
880
+		$config = $this->loader->getShared('EE_Config');
881
+		$this->loader->getShared('EE_Network_Config');
882
+		// setup autoloaders
883
+		// enable logging?
884
+		$this->loader->getShared('EventEspresso\core\services\orm\TrashLogger');
885
+		if ($config->admin->use_remote_logging) {
886
+			$this->loader->getShared('EE_Log');
887
+		}
888
+		// check for activation errors
889
+		$activation_errors = get_option('ee_plugin_activation_errors', false);
890
+		if ($activation_errors) {
891
+			EE_Error::add_error($activation_errors, __FILE__, __FUNCTION__, __LINE__);
892
+			update_option('ee_plugin_activation_errors', false);
893
+		}
894
+		// get model names
895
+		$this->_parse_model_names();
896
+		// configure custom post type definitions
897
+		$this->loader->getShared('EventEspresso\core\domain\entities\custom_post_types\CustomTaxonomyDefinitions');
898
+		$this->loader->getShared('EventEspresso\core\domain\entities\custom_post_types\CustomPostTypeDefinitions');
899
+		do_action('AHEE__EE_System__load_core_configuration__complete', $this);
900
+	}
901
+
902
+
903
+	/**
904
+	 * cycles through all of the models/*.model.php files, and assembles an array of model names
905
+	 *
906
+	 * @return void
907
+	 * @throws ReflectionException
908
+	 */
909
+	private function _parse_model_names()
910
+	{
911
+		// get all the files in the EE_MODELS folder that end in .model.php
912
+		$models = glob(EE_MODELS . '*.model.php');
913
+		$model_names = array();
914
+		$non_abstract_db_models = array();
915
+		foreach ($models as $model) {
916
+			// get model classname
917
+			$classname = EEH_File::get_classname_from_filepath_with_standard_filename($model);
918
+			$short_name = str_replace('EEM_', '', $classname);
919
+			$reflectionClass = new ReflectionClass($classname);
920
+			if ($reflectionClass->isSubclassOf('EEM_Base') && ! $reflectionClass->isAbstract()) {
921
+				$non_abstract_db_models[ $short_name ] = $classname;
922
+			}
923
+			$model_names[ $short_name ] = $classname;
924
+		}
925
+		$this->registry->models = apply_filters('FHEE__EE_System__parse_model_names', $model_names);
926
+		$this->registry->non_abstract_db_models = apply_filters(
927
+			'FHEE__EE_System__parse_implemented_model_names',
928
+			$non_abstract_db_models
929
+		);
930
+	}
931
+
932
+
933
+	/**
934
+	 * The purpose of this method is to simply check for a file named "caffeinated/brewing_regular.php" for any hooks
935
+	 * that need to be setup before our EE_System launches.
936
+	 *
937
+	 * @return void
938
+	 * @throws DomainException
939
+	 * @throws InvalidArgumentException
940
+	 * @throws InvalidDataTypeException
941
+	 * @throws InvalidInterfaceException
942
+	 * @throws InvalidClassException
943
+	 * @throws InvalidFilePathException
944
+	 */
945
+	private function _maybe_brew_regular()
946
+	{
947
+		/** @var Domain $domain */
948
+		$domain = DomainFactory::getShared(
949
+			new FullyQualifiedName(
950
+				'EventEspresso\core\domain\Domain'
951
+			),
952
+			array(
953
+				new FilePath(EVENT_ESPRESSO_MAIN_FILE),
954
+				Version::fromString(espresso_version()),
955
+			)
956
+		);
957
+		if ($domain->isCaffeinated()) {
958
+			require_once EE_CAFF_PATH . 'brewing_regular.php';
959
+		}
960
+	}
961
+
962
+
963
+	/**
964
+	 * @since 4.9.71.p
965
+	 * @throws Exception
966
+	 */
967
+	public function loadRouteMatchSpecifications()
968
+	{
969
+		try {
970
+			$this->loader->getShared(
971
+				'EventEspresso\core\services\route_match\RouteMatchSpecificationManager'
972
+			);
973
+		} catch (Exception $exception) {
974
+			new ExceptionStackTraceDisplay($exception);
975
+		}
976
+		do_action('AHEE__EE_System__loadRouteMatchSpecifications');
977
+	}
978
+
979
+
980
+	/**
981
+	 * loading CPT related classes earlier so that their definitions are available
982
+	 * but not performing any actual registration with WP core until load_CPTs_and_session() is called
983
+	 *
984
+	 * @since   4.10.21.p
985
+	 */
986
+	public function loadCustomPostTypes()
987
+	{
988
+		$this->register_custom_taxonomies = $this->loader->getShared(
989
+			'EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomies'
990
+		);
991
+		$this->register_custom_post_types = $this->loader->getShared(
992
+			'EventEspresso\core\domain\services\custom_post_types\RegisterCustomPostTypes'
993
+		);
994
+		$this->register_custom_taxonomy_terms = $this->loader->getShared(
995
+			'EventEspresso\core\domain\services\custom_post_types\RegisterCustomTaxonomyTerms'
996
+		);
997
+		// integrate WP_Query with the EE models
998
+		$this->loader->getShared('EE_CPT_Strategy');
999
+		// load legacy EE_Request_Handler in case add-ons still need it
1000
+		$this->loader->getShared('EE_Request_Handler');
1001
+	}
1002
+
1003
+
1004
+	/**
1005
+	 * register_shortcodes_modules_and_widgets
1006
+	 * generate lists of shortcodes and modules, then verify paths and classes
1007
+	 * This is hooked into 'AHEE__EE_Bootstrap__register_shortcodes_modules_and_widgets'
1008
+	 * which runs during the WP 'plugins_loaded' action at priority 7
1009
+	 *
1010
+	 * @access public
1011
+	 * @return void
1012
+	 * @throws Exception
1013
+	 */
1014
+	public function register_shortcodes_modules_and_widgets()
1015
+	{
1016
+		if ($this->request->isFrontend() || $this->request->isIframe() || $this->request->isAjax()) {
1017
+			// load, register, and add shortcodes the new way
1018
+			$this->loader->getShared('EventEspresso\core\services\shortcodes\ShortcodesManager');
1019
+		}
1020
+		do_action('AHEE__EE_System__register_shortcodes_modules_and_widgets');
1021
+		// check for addons using old hook point
1022
+		if (has_action('AHEE__EE_System__register_shortcodes_modules_and_addons')) {
1023
+			$this->_incompatible_addon_error();
1024
+		}
1025
+	}
1026
+
1027
+
1028
+	/**
1029
+	 * _incompatible_addon_error
1030
+	 *
1031
+	 * @access public
1032
+	 * @return void
1033
+	 */
1034
+	private function _incompatible_addon_error()
1035
+	{
1036
+		// get array of classes hooking into here
1037
+		$class_names = EEH_Class_Tools::get_class_names_for_all_callbacks_on_hook(
1038
+			'AHEE__EE_System__register_shortcodes_modules_and_addons'
1039
+		);
1040
+		if (! empty($class_names)) {
1041
+			$msg = esc_html__(
1042
+				'The following plugins, addons, or modules appear to be incompatible with this version of Event Espresso and were automatically deactivated to avoid fatal errors:',
1043
+				'event_espresso'
1044
+			);
1045
+			$msg .= '<ul>';
1046
+			foreach ($class_names as $class_name) {
1047
+				$msg .= '<li><b>Event Espresso - '
1048
+						. str_replace(
1049
+							array('EE_', 'EEM_', 'EED_', 'EES_', 'EEW_'),
1050
+							'',
1051
+							$class_name
1052
+						) . '</b></li>';
1053
+			}
1054
+			$msg .= '</ul>';
1055
+			$msg .= esc_html__(
1056
+				'Compatibility issues can be avoided and/or resolved by keeping addons and plugins updated to the latest version.',
1057
+				'event_espresso'
1058
+			);
1059
+			// save list of incompatible addons to wp-options for later use
1060
+			add_option('ee_incompatible_addons', $class_names, '', 'no');
1061
+			if (is_admin()) {
1062
+				EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
1063
+			}
1064
+		}
1065
+	}
1066
+
1067
+
1068
+	/**
1069
+	 * brew_espresso
1070
+	 * begins the process of setting hooks for initializing EE in the correct order
1071
+	 * This is happening on the 'AHEE__EE_Bootstrap__brew_espresso' hook point
1072
+	 * which runs during the WP 'plugins_loaded' action at priority 9
1073
+	 *
1074
+	 * @return void
1075
+	 */
1076
+	public function brew_espresso()
1077
+	{
1078
+		do_action('AHEE__EE_System__brew_espresso__begin', $this);
1079
+		// load some final core systems
1080
+		add_action('init', array($this, 'set_hooks_for_core'), 1);
1081
+		add_action('init', array($this, 'perform_activations_upgrades_and_migrations'), 3);
1082
+		add_action('init', array($this, 'load_CPTs_and_session'), 5);
1083
+		add_action('init', array($this, 'load_controllers'), 7);
1084
+		add_action('init', array($this, 'core_loaded_and_ready'), 9);
1085
+		add_action('init', array($this, 'initialize'), 10);
1086
+		add_action('init', array($this, 'initialize_last'), 100);
1087
+		if (is_admin() && apply_filters('FHEE__EE_System__brew_espresso__load_pue', true)) {
1088
+			// pew pew pew
1089
+			$this->loader->getShared('EventEspresso\core\services\licensing\LicenseService');
1090
+			do_action('AHEE__EE_System__brew_espresso__after_pue_init');
1091
+		}
1092
+		do_action('AHEE__EE_System__brew_espresso__complete', $this);
1093
+	}
1094
+
1095
+
1096
+	/**
1097
+	 *    set_hooks_for_core
1098
+	 *
1099
+	 * @access public
1100
+	 * @return    void
1101
+	 * @throws EE_Error
1102
+	 */
1103
+	public function set_hooks_for_core()
1104
+	{
1105
+		$this->_deactivate_incompatible_addons();
1106
+		do_action('AHEE__EE_System__set_hooks_for_core');
1107
+		$this->loader->getShared('EventEspresso\core\domain\values\session\SessionLifespan');
1108
+		// caps need to be initialized on every request so that capability maps are set.
1109
+		// @see https://events.codebasehq.com/projects/event-espresso/tickets/8674
1110
+		$this->registry->CAP->init_caps();
1111
+	}
1112
+
1113
+
1114
+	/**
1115
+	 * Using the information gathered in EE_System::_incompatible_addon_error,
1116
+	 * deactivates any addons considered incompatible with the current version of EE
1117
+	 */
1118
+	private function _deactivate_incompatible_addons()
1119
+	{
1120
+		$incompatible_addons = get_option('ee_incompatible_addons', array());
1121
+		if (! empty($incompatible_addons)) {
1122
+			$active_plugins = get_option('active_plugins', array());
1123
+			foreach ($active_plugins as $active_plugin) {
1124
+				foreach ($incompatible_addons as $incompatible_addon) {
1125
+					if (strpos($active_plugin, $incompatible_addon) !== false) {
1126
+						$this->request->unSetRequestParams(['activate'], true);
1127
+						espresso_deactivate_plugin($active_plugin);
1128
+					}
1129
+				}
1130
+			}
1131
+		}
1132
+	}
1133
+
1134
+
1135
+	/**
1136
+	 *    perform_activations_upgrades_and_migrations
1137
+	 *
1138
+	 * @access public
1139
+	 * @return    void
1140
+	 */
1141
+	public function perform_activations_upgrades_and_migrations()
1142
+	{
1143
+		do_action('AHEE__EE_System__perform_activations_upgrades_and_migrations');
1144
+	}
1145
+
1146
+
1147
+	/**
1148
+	 * @return void
1149
+	 * @throws DomainException
1150
+	 */
1151
+	public function load_CPTs_and_session()
1152
+	{
1153
+		do_action('AHEE__EE_System__load_CPTs_and_session__start');
1154
+		$this->register_custom_taxonomies->registerCustomTaxonomies();
1155
+		$this->register_custom_post_types->registerCustomPostTypes();
1156
+		$this->register_custom_taxonomy_terms->registerCustomTaxonomyTerms();
1157
+		// load legacy Custom Post Types and Taxonomies
1158
+		$this->loader->getShared('EE_Register_CPTs');
1159
+		do_action('AHEE__EE_System__load_CPTs_and_session__complete');
1160
+	}
1161
+
1162
+
1163
+	/**
1164
+	 * load_controllers
1165
+	 * this is the best place to load any additional controllers that needs access to EE core.
1166
+	 * it is expected that all basic core EE systems, that are not dependant on the current request are loaded at this
1167
+	 * time
1168
+	 *
1169
+	 * @access public
1170
+	 * @return void
1171
+	 */
1172
+	public function load_controllers()
1173
+	{
1174
+		do_action('AHEE__EE_System__load_controllers__start');
1175
+		// let's get it started
1176
+		if (
1177
+			! $this->maintenance_mode->level()
1178
+			&& ($this->request->isFrontend() || $this->request->isFrontAjax())
1179
+		) {
1180
+			do_action('AHEE__EE_System__load_controllers__load_front_controllers');
1181
+			$this->loader->getShared('EE_Front_Controller');
1182
+		} elseif ($this->request->isAdmin() || $this->request->isAdminAjax()) {
1183
+			do_action('AHEE__EE_System__load_controllers__load_admin_controllers');
1184
+			$this->loader->getShared('EE_Admin');
1185
+		} elseif ($this->request->isWordPressHeartbeat()) {
1186
+			$this->loader->getShared('EventEspresso\core\domain\services\admin\ajax\WordpressHeartbeat');
1187
+		}
1188
+		do_action('AHEE__EE_System__load_controllers__complete');
1189
+	}
1190
+
1191
+
1192
+	/**
1193
+	 * core_loaded_and_ready
1194
+	 * all of the basic EE core should be loaded at this point and available regardless of M-Mode
1195
+	 *
1196
+	 * @access public
1197
+	 * @return void
1198
+	 * @throws Exception
1199
+	 */
1200
+	public function core_loaded_and_ready()
1201
+	{
1202
+		if (
1203
+			$this->request->isAdmin()
1204
+			|| $this->request->isFrontend()
1205
+			|| $this->request->isIframe()
1206
+			|| $this->request->isWordPressApi()
1207
+		) {
1208
+			try {
1209
+				$this->loader->getShared('EventEspresso\core\services\assets\I18nRegistry', [[]]);
1210
+				$this->loader->getShared('EventEspresso\core\services\assets\Registry');
1211
+				$this->loader->getShared('EventEspresso\core\domain\services\assets\CoreAssetManager');
1212
+				if ($this->canLoadBlocks()) {
1213
+					$this->loader->getShared(
1214
+						'EventEspresso\core\services\editor\BlockRegistrationManager'
1215
+					);
1216
+				}
1217
+			} catch (Exception $exception) {
1218
+				new ExceptionStackTraceDisplay($exception);
1219
+			}
1220
+		}
1221
+		if (
1222
+			$this->request->isAdmin()
1223
+			|| $this->request->isEeAjax()
1224
+			|| $this->request->isFrontend()
1225
+		) {
1226
+			$this->loader->getShared('EE_Session');
1227
+		}
1228
+		do_action('AHEE__EE_System__core_loaded_and_ready');
1229
+		// always load template tags, because it's faster than checking if it's a front-end request, and many page
1230
+		// builders require these even on the front-end
1231
+		require_once EE_PUBLIC . 'template_tags.php';
1232
+		do_action('AHEE__EE_System__set_hooks_for_shortcodes_modules_and_addons');
1233
+	}
1234
+
1235
+
1236
+	/**
1237
+	 * initialize
1238
+	 * this is the best place to begin initializing client code
1239
+	 *
1240
+	 * @access public
1241
+	 * @return void
1242
+	 */
1243
+	public function initialize()
1244
+	{
1245
+		do_action('AHEE__EE_System__initialize');
1246
+		add_filter(
1247
+			'safe_style_css',
1248
+			function ($styles) {
1249
+				$styles[] = 'display';
1250
+				$styles[] = 'visibility';
1251
+				$styles[] = 'position';
1252
+				$styles[] = 'top';
1253
+				$styles[] = 'right';
1254
+				$styles[] = 'bottom';
1255
+				$styles[] = 'left';
1256
+				$styles[] = 'resize';
1257
+				$styles[] = 'max-width';
1258
+				$styles[] = 'max-height';
1259
+				return $styles;
1260
+			}
1261
+		);
1262
+	}
1263
+
1264
+
1265
+	/**
1266
+	 * initialize_last
1267
+	 * this is run really late during the WP init hook point, and ensures that mostly everything else that needs to
1268
+	 * initialize has done so
1269
+	 *
1270
+	 * @access public
1271
+	 * @return void
1272
+	 */
1273
+	public function initialize_last()
1274
+	{
1275
+		do_action('AHEE__EE_System__initialize_last');
1276
+		/** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
1277
+		$rewrite_rules = $this->loader->getShared(
1278
+			'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
1279
+		);
1280
+		$rewrite_rules->flushRewriteRules();
1281
+		add_action('admin_bar_init', array($this, 'addEspressoToolbar'));
1282
+		if (
1283
+			($this->request->isAjax() || $this->request->isAdmin())
1284
+			&& $this->maintenance_mode->models_can_query()
1285
+		) {
1286
+			$this->loader->getShared('EventEspresso\core\services\privacy\export\PersonalDataExporterManager');
1287
+			$this->loader->getShared('EventEspresso\core\services\privacy\erasure\PersonalDataEraserManager');
1288
+		}
1289
+	}
1290
+
1291
+
1292
+	/**
1293
+	 * @return void
1294
+	 * @throws EE_Error
1295
+	 */
1296
+	public function addEspressoToolbar()
1297
+	{
1298
+		$this->loader->getShared(
1299
+			'EventEspresso\core\domain\services\admin\AdminToolBar',
1300
+			array($this->registry->CAP)
1301
+		);
1302
+	}
1303
+
1304
+
1305
+	/**
1306
+	 * do_not_cache
1307
+	 * sets no cache headers and defines no cache constants for WP plugins
1308
+	 *
1309
+	 * @access public
1310
+	 * @return void
1311
+	 */
1312
+	public static function do_not_cache()
1313
+	{
1314
+		// set no cache constants
1315
+		if (! defined('DONOTCACHEPAGE')) {
1316
+			define('DONOTCACHEPAGE', true);
1317
+		}
1318
+		if (! defined('DONOTCACHCEOBJECT')) {
1319
+			define('DONOTCACHCEOBJECT', true);
1320
+		}
1321
+		if (! defined('DONOTCACHEDB')) {
1322
+			define('DONOTCACHEDB', true);
1323
+		}
1324
+		// add no cache headers
1325
+		add_action('send_headers', array('EE_System', 'nocache_headers'), 10);
1326
+		// plus a little extra for nginx and Google Chrome
1327
+		add_filter('nocache_headers', array('EE_System', 'extra_nocache_headers'), 10, 1);
1328
+		// prevent browsers from prefetching of the rel='next' link, because it may contain content that interferes with the registration process
1329
+		remove_action('wp_head', 'adjacent_posts_rel_link_wp_head');
1330
+	}
1331
+
1332
+
1333
+	/**
1334
+	 *    extra_nocache_headers
1335
+	 *
1336
+	 * @access    public
1337
+	 * @param $headers
1338
+	 * @return    array
1339
+	 */
1340
+	public static function extra_nocache_headers($headers)
1341
+	{
1342
+		// for NGINX
1343
+		$headers['X-Accel-Expires'] = 0;
1344
+		// plus extra for Google Chrome since it doesn't seem to respect "no-cache", but WILL respect "no-store"
1345
+		$headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0';
1346
+		return $headers;
1347
+	}
1348
+
1349
+
1350
+	/**
1351
+	 *    nocache_headers
1352
+	 *
1353
+	 * @access    public
1354
+	 * @return    void
1355
+	 */
1356
+	public static function nocache_headers()
1357
+	{
1358
+		nocache_headers();
1359
+	}
1360
+
1361
+
1362
+	/**
1363
+	 * simply hooks into "wp_list_pages_exclude" filter (for wp_list_pages method) and makes sure EE critical pages are
1364
+	 * never returned with the function.
1365
+	 *
1366
+	 * @param  array $exclude_array any existing pages being excluded are in this array.
1367
+	 * @return array
1368
+	 */
1369
+	public function remove_pages_from_wp_list_pages($exclude_array)
1370
+	{
1371
+		return array_merge($exclude_array, $this->registry->CFG->core->get_critical_pages_array());
1372
+	}
1373
+
1374
+
1375
+	/**
1376
+	 * Return whether blocks can be registered/loaded or not.
1377
+	 * @return bool
1378
+	 */
1379
+	private function canLoadBlocks()
1380
+	{
1381
+		return apply_filters('FHEE__EE_System__canLoadBlocks', true)
1382
+			   && function_exists('register_block_type')
1383
+			   // don't load blocks if in the Divi page builder editor context
1384
+			   // @see https://github.com/eventespresso/event-espresso-core/issues/814
1385
+			   && ! $this->request->getRequestParam('et_fb', false);
1386
+	}
1387 1387
 }
Please login to merge, or discard this patch.
core/services/orm/TrashLogger.php 2 patches
Indentation   +93 added lines, -93 removed lines patch added patch discarded remove patch
@@ -16,97 +16,97 @@
 block discarded – undo
16 16
  */
17 17
 class TrashLogger
18 18
 {
19
-    /**
20
-     * extra meta key for tracking when entities are trashed and by who
21
-     *
22
-     * @type string
23
-     */
24
-    const EXTRA_META_KEY_ENTITY_TRASHED = 'entity-trashed';
25
-
26
-    /**
27
-     * extra meta key for tracking when entities are restored and by who
28
-     *
29
-     * @type string
30
-     */
31
-    const EXTRA_META_KEY_ENTITY_RESTORED = 'entity-restored';
32
-
33
-    /**
34
-     * extra meta key for tracking when entities are deleted and by who
35
-     *
36
-     * @type string
37
-     */
38
-    const EXTRA_META_KEY_ENTITY_DELETED = 'entity-deleted';
39
-
40
-
41
-    public function __construct()
42
-    {
43
-        add_action('AHEE__EE_Soft_Delete_Base_Class__delete_or_restore__after', [$this, 'logSoftDelete'], 10, 3);
44
-        add_action('AHEE__EE_Base_Class__delete_permanently__end', [$this, 'logHardDelete'], 10, 2);
45
-    }
46
-
47
-
48
-    /**
49
-     * @param EE_Soft_Delete_Base_Class $entity
50
-     * @param bool                      $delete
51
-     * @param bool                      $result
52
-     * @throws EE_Error
53
-     * @throws ReflectionException
54
-     */
55
-    public function logSoftDelete(EE_Soft_Delete_Base_Class $entity, bool $delete, bool $result)
56
-    {
57
-        // which base meta key to use... trashed or restored?
58
-        $action = $delete
59
-            ? TrashLogger::EXTRA_META_KEY_ENTITY_TRASHED
60
-            : TrashLogger::EXTRA_META_KEY_ENTITY_RESTORED;
61
-        $this->logDelete($entity, $action, $result);
62
-    }
63
-
64
-
65
-    /**
66
-     * @param EE_Base_Class $entity
67
-     * @param bool          $result
68
-     * @throws EE_Error
69
-     * @throws ReflectionException
70
-     */
71
-    public function logHardDelete(EE_Base_Class $entity, bool $result)
72
-    {
73
-        $this->logDelete($entity, TrashLogger::EXTRA_META_KEY_ENTITY_DELETED, $result);
74
-    }
75
-
76
-
77
-    /**
78
-     * converts entity class like 'EE_Registration' to 'registration'
79
-     *
80
-     * @param EE_Base_Class $entity
81
-     * @return string
82
-     */
83
-    private function getEntityClass(EE_Base_Class $entity): string
84
-    {
85
-        return strtolower(str_replace('EE_', '', get_class($entity)));
86
-    }
87
-
88
-
89
-    /**
90
-     * @param EE_Base_Class $entity
91
-     * @param string        $action
92
-     * @param bool          $result
93
-     * @throws EE_Error
94
-     * @throws ReflectionException
95
-     */
96
-    private function logDelete(EE_Base_Class $entity, string $action, bool $result)
97
-    {
98
-        // if trash/restore/delete was not successful, then get out
99
-        if (! $result) {
100
-            return;
101
-        }
102
-
103
-        // convert 'entity-deleted' to  'registration-deleted'
104
-        $key = str_replace('entity', $this->getEntityClass($entity), $action);
105
-
106
-        $current_user = wp_get_current_user();
107
-        $user_name    = $current_user->ID ? $current_user->display_name : 'unknown user';
108
-        $timestamp    = date("D M j, Y @ g:i:s a", current_time('timestamp'));
109
-
110
-        $entity->add_extra_meta($key, "by $user_name on $timestamp");
111
-    }
19
+	/**
20
+	 * extra meta key for tracking when entities are trashed and by who
21
+	 *
22
+	 * @type string
23
+	 */
24
+	const EXTRA_META_KEY_ENTITY_TRASHED = 'entity-trashed';
25
+
26
+	/**
27
+	 * extra meta key for tracking when entities are restored and by who
28
+	 *
29
+	 * @type string
30
+	 */
31
+	const EXTRA_META_KEY_ENTITY_RESTORED = 'entity-restored';
32
+
33
+	/**
34
+	 * extra meta key for tracking when entities are deleted and by who
35
+	 *
36
+	 * @type string
37
+	 */
38
+	const EXTRA_META_KEY_ENTITY_DELETED = 'entity-deleted';
39
+
40
+
41
+	public function __construct()
42
+	{
43
+		add_action('AHEE__EE_Soft_Delete_Base_Class__delete_or_restore__after', [$this, 'logSoftDelete'], 10, 3);
44
+		add_action('AHEE__EE_Base_Class__delete_permanently__end', [$this, 'logHardDelete'], 10, 2);
45
+	}
46
+
47
+
48
+	/**
49
+	 * @param EE_Soft_Delete_Base_Class $entity
50
+	 * @param bool                      $delete
51
+	 * @param bool                      $result
52
+	 * @throws EE_Error
53
+	 * @throws ReflectionException
54
+	 */
55
+	public function logSoftDelete(EE_Soft_Delete_Base_Class $entity, bool $delete, bool $result)
56
+	{
57
+		// which base meta key to use... trashed or restored?
58
+		$action = $delete
59
+			? TrashLogger::EXTRA_META_KEY_ENTITY_TRASHED
60
+			: TrashLogger::EXTRA_META_KEY_ENTITY_RESTORED;
61
+		$this->logDelete($entity, $action, $result);
62
+	}
63
+
64
+
65
+	/**
66
+	 * @param EE_Base_Class $entity
67
+	 * @param bool          $result
68
+	 * @throws EE_Error
69
+	 * @throws ReflectionException
70
+	 */
71
+	public function logHardDelete(EE_Base_Class $entity, bool $result)
72
+	{
73
+		$this->logDelete($entity, TrashLogger::EXTRA_META_KEY_ENTITY_DELETED, $result);
74
+	}
75
+
76
+
77
+	/**
78
+	 * converts entity class like 'EE_Registration' to 'registration'
79
+	 *
80
+	 * @param EE_Base_Class $entity
81
+	 * @return string
82
+	 */
83
+	private function getEntityClass(EE_Base_Class $entity): string
84
+	{
85
+		return strtolower(str_replace('EE_', '', get_class($entity)));
86
+	}
87
+
88
+
89
+	/**
90
+	 * @param EE_Base_Class $entity
91
+	 * @param string        $action
92
+	 * @param bool          $result
93
+	 * @throws EE_Error
94
+	 * @throws ReflectionException
95
+	 */
96
+	private function logDelete(EE_Base_Class $entity, string $action, bool $result)
97
+	{
98
+		// if trash/restore/delete was not successful, then get out
99
+		if (! $result) {
100
+			return;
101
+		}
102
+
103
+		// convert 'entity-deleted' to  'registration-deleted'
104
+		$key = str_replace('entity', $this->getEntityClass($entity), $action);
105
+
106
+		$current_user = wp_get_current_user();
107
+		$user_name    = $current_user->ID ? $current_user->display_name : 'unknown user';
108
+		$timestamp    = date("D M j, Y @ g:i:s a", current_time('timestamp'));
109
+
110
+		$entity->add_extra_meta($key, "by $user_name on $timestamp");
111
+	}
112 112
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -96,7 +96,7 @@
 block discarded – undo
96 96
     private function logDelete(EE_Base_Class $entity, string $action, bool $result)
97 97
     {
98 98
         // if trash/restore/delete was not successful, then get out
99
-        if (! $result) {
99
+        if ( ! $result) {
100 100
             return;
101 101
         }
102 102
 
Please login to merge, or discard this patch.
core/db_classes/EE_Transaction.class.php 2 patches
Indentation   +1706 added lines, -1706 removed lines patch added patch discarded remove patch
@@ -13,1710 +13,1710 @@
 block discarded – undo
13 13
  */
14 14
 class EE_Transaction extends EE_Base_Class implements EEI_Transaction
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
-     * txn status upon initial construction.
24
-     *
25
-     * @var string
26
-     */
27
-    protected $_old_txn_status;
28
-
29
-
30
-    /**
31
-     * @param array  $props_n_values          incoming values
32
-     * @param string $timezone                incoming timezone
33
-     *                                        (if not set the timezone set for the website will be used.)
34
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
35
-     *                                        date_format and the second value is the time format
36
-     * @return EE_Transaction
37
-     * @throws EE_Error
38
-     * @throws InvalidArgumentException
39
-     * @throws InvalidDataTypeException
40
-     * @throws InvalidInterfaceException
41
-     * @throws ReflectionException
42
-     */
43
-    public static function new_instance($props_n_values = [], $timezone = null, $date_formats = [])
44
-    {
45
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
46
-        $txn        = $has_object
47
-            ? $has_object
48
-            : new self($props_n_values, false, $timezone, $date_formats);
49
-        if (! $has_object) {
50
-            $txn->set_old_txn_status($txn->status_ID());
51
-        }
52
-        return $txn;
53
-    }
54
-
55
-
56
-    /**
57
-     * @param array  $props_n_values  incoming values from the database
58
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
59
-     *                                the website will be used.
60
-     * @return EE_Transaction
61
-     * @throws EE_Error
62
-     * @throws InvalidArgumentException
63
-     * @throws InvalidDataTypeException
64
-     * @throws InvalidInterfaceException
65
-     * @throws ReflectionException
66
-     */
67
-    public static function new_instance_from_db($props_n_values = [], $timezone = null)
68
-    {
69
-        $txn = new self($props_n_values, true, $timezone);
70
-        $txn->set_old_txn_status($txn->status_ID());
71
-        return $txn;
72
-    }
73
-
74
-
75
-    /**
76
-     * Sets a meta field indicating that this TXN is locked and should not be updated in the db.
77
-     * If a lock has already been set, then we will attempt to remove it in case it has expired.
78
-     * If that also fails, then an exception is thrown.
79
-     *
80
-     * @throws EE_Error
81
-     * @throws InvalidArgumentException
82
-     * @throws InvalidDataTypeException
83
-     * @throws InvalidInterfaceException
84
-     * @throws ReflectionException
85
-     */
86
-    public function lock()
87
-    {
88
-        // attempt to set lock, but if that fails...
89
-        if (! $this->add_extra_meta('lock', time(), true)) {
90
-            // then attempt to remove the lock in case it is expired
91
-            if ($this->_remove_expired_lock()) {
92
-                // if removal was successful, then try setting lock again
93
-                $this->lock();
94
-            } else {
95
-                // but if the lock can not be removed, then throw an exception
96
-                throw new EE_Error(
97
-                    sprintf(
98
-                        esc_html__(
99
-                            '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.',
100
-                            'event_espresso'
101
-                        ),
102
-                        $this->ID()
103
-                    )
104
-                );
105
-            }
106
-        }
107
-    }
108
-
109
-
110
-    /**
111
-     * removes transaction lock applied in EE_Transaction::lock()
112
-     *
113
-     * @return int
114
-     * @throws EE_Error
115
-     * @throws InvalidArgumentException
116
-     * @throws InvalidDataTypeException
117
-     * @throws InvalidInterfaceException
118
-     * @throws ReflectionException
119
-     */
120
-    public function unlock()
121
-    {
122
-        return $this->delete_extra_meta('lock');
123
-    }
124
-
125
-
126
-    /**
127
-     * Decides whether or not now is the right time to update the transaction.
128
-     * This is useful because we don't always know if it is safe to update the transaction
129
-     * and its related data. why?
130
-     * because it's possible that the transaction is being used in another
131
-     * request and could overwrite anything we save.
132
-     * So we want to only update the txn once we know that won't happen.
133
-     * We also check that the lock isn't expired, and remove it if it is
134
-     *
135
-     * @return boolean
136
-     * @throws EE_Error
137
-     * @throws InvalidArgumentException
138
-     * @throws InvalidDataTypeException
139
-     * @throws InvalidInterfaceException
140
-     * @throws ReflectionException
141
-     */
142
-    public function is_locked()
143
-    {
144
-        // if TXN is not locked, then return false immediately
145
-        if (! $this->_get_lock()) {
146
-            return false;
147
-        }
148
-        // if not, then let's try and remove the lock in case it's expired...
149
-        // _remove_expired_lock() returns 0 when lock is valid (ie: removed = false)
150
-        // and a positive number if the lock was removed (ie: number of locks deleted),
151
-        // so we need to return the opposite
152
-        return ! $this->_remove_expired_lock() ? true : false;
153
-    }
154
-
155
-
156
-    /**
157
-     * Gets the meta field indicating that this TXN is locked
158
-     *
159
-     * @return int
160
-     * @throws EE_Error
161
-     * @throws InvalidArgumentException
162
-     * @throws InvalidDataTypeException
163
-     * @throws InvalidInterfaceException
164
-     * @throws ReflectionException
165
-     */
166
-    protected function _get_lock()
167
-    {
168
-        return (int) $this->get_extra_meta('lock', true, 0);
169
-    }
170
-
171
-
172
-    /**
173
-     * If the lock on this transaction is expired, then we want to remove it so that the transaction can be updated
174
-     *
175
-     * @return int
176
-     * @throws EE_Error
177
-     * @throws InvalidArgumentException
178
-     * @throws InvalidDataTypeException
179
-     * @throws InvalidInterfaceException
180
-     * @throws ReflectionException
181
-     */
182
-    protected function _remove_expired_lock()
183
-    {
184
-        $locked = $this->_get_lock();
185
-        if ($locked && time() - EE_Transaction::LOCK_EXPIRATION > $locked) {
186
-            return $this->unlock();
187
-        }
188
-        return 0;
189
-    }
190
-
191
-
192
-    /**
193
-     * Set transaction total
194
-     *
195
-     * @param float $total total value of transaction
196
-     * @throws EE_Error
197
-     * @throws InvalidArgumentException
198
-     * @throws InvalidDataTypeException
199
-     * @throws InvalidInterfaceException
200
-     * @throws ReflectionException
201
-     */
202
-    public function set_total($total = 0.00)
203
-    {
204
-        $this->set('TXN_total', (float) $total);
205
-    }
206
-
207
-
208
-    /**
209
-     * Set Total Amount Paid to Date
210
-     *
211
-     * @param float $total_paid total amount paid to date (sum of all payments)
212
-     * @throws EE_Error
213
-     * @throws InvalidArgumentException
214
-     * @throws InvalidDataTypeException
215
-     * @throws InvalidInterfaceException
216
-     * @throws ReflectionException
217
-     */
218
-    public function set_paid($total_paid = 0.00)
219
-    {
220
-        $this->set('TXN_paid', (float) $total_paid);
221
-    }
222
-
223
-
224
-    /**
225
-     * Set transaction status
226
-     *
227
-     * @param string $status        whether the transaction is open, declined, accepted,
228
-     *                              or any number of custom values that can be set
229
-     * @throws EE_Error
230
-     * @throws InvalidArgumentException
231
-     * @throws InvalidDataTypeException
232
-     * @throws InvalidInterfaceException
233
-     * @throws ReflectionException
234
-     */
235
-    public function set_status($status = '')
236
-    {
237
-        $this->set('STS_ID', $status);
238
-    }
239
-
240
-
241
-    /**
242
-     * Set hash salt
243
-     *
244
-     * @param string $hash_salt required for some payment gateways
245
-     * @throws EE_Error
246
-     * @throws InvalidArgumentException
247
-     * @throws InvalidDataTypeException
248
-     * @throws InvalidInterfaceException
249
-     * @throws ReflectionException
250
-     */
251
-    public function set_hash_salt($hash_salt = '')
252
-    {
253
-        $this->set('TXN_hash_salt', $hash_salt);
254
-    }
255
-
256
-
257
-    /**
258
-     * Sets TXN_reg_steps array
259
-     *
260
-     * @param array $txn_reg_steps
261
-     * @throws EE_Error
262
-     * @throws InvalidArgumentException
263
-     * @throws InvalidDataTypeException
264
-     * @throws InvalidInterfaceException
265
-     * @throws ReflectionException
266
-     */
267
-    public function set_reg_steps(array $txn_reg_steps)
268
-    {
269
-        $this->set('TXN_reg_steps', $txn_reg_steps);
270
-    }
271
-
272
-
273
-    /**
274
-     * Gets TXN_reg_steps
275
-     *
276
-     * @return array
277
-     * @throws EE_Error
278
-     * @throws InvalidArgumentException
279
-     * @throws InvalidDataTypeException
280
-     * @throws InvalidInterfaceException
281
-     * @throws ReflectionException
282
-     */
283
-    public function reg_steps()
284
-    {
285
-        $TXN_reg_steps = $this->get('TXN_reg_steps');
286
-        return is_array($TXN_reg_steps) ? $TXN_reg_steps : [];
287
-    }
288
-
289
-
290
-    /**
291
-     * @return string of transaction's total cost, with currency symbol and decimal
292
-     * @throws EE_Error
293
-     * @throws InvalidArgumentException
294
-     * @throws InvalidDataTypeException
295
-     * @throws InvalidInterfaceException
296
-     * @throws ReflectionException
297
-     */
298
-    public function pretty_total()
299
-    {
300
-        return $this->get_pretty('TXN_total');
301
-    }
302
-
303
-
304
-    /**
305
-     * Gets the amount paid in a pretty string (formatted and with currency symbol)
306
-     *
307
-     * @return string
308
-     * @throws EE_Error
309
-     * @throws InvalidArgumentException
310
-     * @throws InvalidDataTypeException
311
-     * @throws InvalidInterfaceException
312
-     * @throws ReflectionException
313
-     */
314
-    public function pretty_paid()
315
-    {
316
-        return $this->get_pretty('TXN_paid');
317
-    }
318
-
319
-
320
-    /**
321
-     * calculate the amount remaining for this transaction and return;
322
-     *
323
-     * @return float amount remaining
324
-     * @throws EE_Error
325
-     * @throws InvalidArgumentException
326
-     * @throws InvalidDataTypeException
327
-     * @throws InvalidInterfaceException
328
-     * @throws ReflectionException
329
-     */
330
-    public function remaining()
331
-    {
332
-        return $this->total() - $this->paid();
333
-    }
334
-
335
-
336
-    /**
337
-     * get Transaction Total
338
-     *
339
-     * @return float
340
-     * @throws EE_Error
341
-     * @throws InvalidArgumentException
342
-     * @throws InvalidDataTypeException
343
-     * @throws InvalidInterfaceException
344
-     * @throws ReflectionException
345
-     */
346
-    public function total()
347
-    {
348
-        return (float) $this->get('TXN_total');
349
-    }
350
-
351
-
352
-    /**
353
-     * get Total Amount Paid to Date
354
-     *
355
-     * @return float
356
-     * @throws EE_Error
357
-     * @throws InvalidArgumentException
358
-     * @throws InvalidDataTypeException
359
-     * @throws InvalidInterfaceException
360
-     * @throws ReflectionException
361
-     */
362
-    public function paid()
363
-    {
364
-        return (float) $this->get('TXN_paid');
365
-    }
366
-
367
-
368
-    /**
369
-     * @return mixed|null
370
-     * @throws EE_Error
371
-     * @throws InvalidArgumentException
372
-     * @throws InvalidDataTypeException
373
-     * @throws InvalidInterfaceException
374
-     * @throws ReflectionException
375
-     */
376
-    public function get_cart_session()
377
-    {
378
-        $session_data = (array) $this->get('TXN_session_data');
379
-        return isset($session_data['cart']) && $session_data['cart'] instanceof EE_Cart
380
-            ? $session_data['cart']
381
-            : null;
382
-    }
383
-
384
-
385
-    /**
386
-     * get Transaction session data
387
-     *
388
-     * @return array|mixed
389
-     * @throws EE_Error
390
-     * @throws InvalidArgumentException
391
-     * @throws InvalidDataTypeException
392
-     * @throws InvalidInterfaceException
393
-     * @throws ReflectionException
394
-     */
395
-    public function session_data()
396
-    {
397
-        $session_data = $this->get('TXN_session_data');
398
-        if (empty($session_data)) {
399
-            $session_data = [
400
-                'id'            => null,
401
-                'user_id'       => null,
402
-                'ip_address'    => null,
403
-                'user_agent'    => null,
404
-                'init_access'   => null,
405
-                'last_access'   => null,
406
-                'pages_visited' => [],
407
-            ];
408
-        }
409
-        return $session_data;
410
-    }
411
-
412
-
413
-    /**
414
-     * Set session data within the TXN object
415
-     *
416
-     * @param EE_Session|array $session_data
417
-     * @throws EE_Error
418
-     * @throws InvalidArgumentException
419
-     * @throws InvalidDataTypeException
420
-     * @throws InvalidInterfaceException
421
-     * @throws ReflectionException
422
-     */
423
-    public function set_txn_session_data($session_data)
424
-    {
425
-        if ($session_data instanceof EE_Session) {
426
-            $this->set('TXN_session_data', $session_data->get_session_data(null, true));
427
-        } else {
428
-            $this->set('TXN_session_data', $session_data);
429
-        }
430
-    }
431
-
432
-
433
-    /**
434
-     * get Transaction hash salt
435
-     *
436
-     * @return mixed
437
-     * @throws EE_Error
438
-     * @throws InvalidArgumentException
439
-     * @throws InvalidDataTypeException
440
-     * @throws InvalidInterfaceException
441
-     * @throws ReflectionException
442
-     */
443
-    public function hash_salt_()
444
-    {
445
-        return $this->get('TXN_hash_salt');
446
-    }
447
-
448
-
449
-    /**
450
-     * Returns the transaction datetime as either:
451
-     *            - unix timestamp format ($format = false, $gmt = true)
452
-     *            - formatted date string including the UTC (timezone) offset ($format = true ($gmt
453
-     *              has no affect with this option)), this also may include a timezone abbreviation if the
454
-     *              set timezone in this class differs from what the timezone is on the blog.
455
-     *            - formatted date string including the UTC (timezone) offset (default).
456
-     *
457
-     * @param boolean $format   - whether to return a unix timestamp (default) or formatted date string
458
-     * @param boolean $gmt      - whether to return a unix timestamp with UTC offset applied (default)
459
-     *                          or no UTC offset applied
460
-     * @return string | int
461
-     * @throws EE_Error
462
-     * @throws InvalidArgumentException
463
-     * @throws InvalidDataTypeException
464
-     * @throws InvalidInterfaceException
465
-     * @throws ReflectionException
466
-     */
467
-    public function datetime($format = false, $gmt = false)
468
-    {
469
-        if ($format) {
470
-            return $this->get_pretty('TXN_timestamp');
471
-        }
472
-        if ($gmt) {
473
-            return $this->get_raw('TXN_timestamp');
474
-        }
475
-        return $this->get('TXN_timestamp');
476
-    }
477
-
478
-
479
-    /**
480
-     * Gets registrations on this transaction
481
-     *
482
-     * @param array   $query_params array of query parameters
483
-     * @param boolean $get_cached   TRUE to retrieve cached registrations or FALSE to pull from the db
484
-     * @return EE_Base_Class[]|EE_Registration[]
485
-     * @throws EE_Error
486
-     * @throws InvalidArgumentException
487
-     * @throws InvalidDataTypeException
488
-     * @throws InvalidInterfaceException
489
-     * @throws ReflectionException
490
-     */
491
-    public function registrations($query_params = [], $get_cached = false)
492
-    {
493
-        $query_params = (empty($query_params) || ! is_array($query_params))
494
-            ? [
495
-                'order_by' => [
496
-                    'Event.EVT_name'     => 'ASC',
497
-                    'Attendee.ATT_lname' => 'ASC',
498
-                    'Attendee.ATT_fname' => 'ASC',
499
-                ],
500
-            ]
501
-            : $query_params;
502
-        $query_params = $get_cached ? [] : $query_params;
503
-        return $this->get_many_related('Registration', $query_params);
504
-    }
505
-
506
-
507
-    /**
508
-     * Gets all the attendees for this transaction (handy for use with EE_Attendee's get_registrations_for_event
509
-     * function for getting attendees and how many registrations they each have for an event)
510
-     *
511
-     * @return mixed EE_Attendee[] by default, int if $output is set to 'COUNT'
512
-     * @throws EE_Error
513
-     * @throws InvalidArgumentException
514
-     * @throws InvalidDataTypeException
515
-     * @throws InvalidInterfaceException
516
-     * @throws ReflectionException
517
-     */
518
-    public function attendees()
519
-    {
520
-        return $this->get_many_related('Attendee', [['Registration.Transaction.TXN_ID' => $this->ID()]]);
521
-    }
522
-
523
-
524
-    /**
525
-     * Gets payments for this transaction. Unlike other such functions, order by 'DESC' by default
526
-     *
527
-     * @param array $query_params @see
528
-     *                            https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
529
-     * @return EE_Base_Class[]|EE_Payment[]
530
-     * @throws EE_Error
531
-     * @throws InvalidArgumentException
532
-     * @throws InvalidDataTypeException
533
-     * @throws InvalidInterfaceException
534
-     * @throws ReflectionException
535
-     */
536
-    public function payments($query_params = [])
537
-    {
538
-        return $this->get_many_related('Payment', $query_params);
539
-    }
540
-
541
-
542
-    /**
543
-     * gets only approved payments for this transaction
544
-     *
545
-     * @return EE_Base_Class[]|EE_Payment[]
546
-     * @throws EE_Error
547
-     * @throws InvalidArgumentException
548
-     * @throws ReflectionException
549
-     * @throws InvalidDataTypeException
550
-     * @throws InvalidInterfaceException
551
-     */
552
-    public function approved_payments()
553
-    {
554
-        EE_Registry::instance()->load_model('Payment');
555
-        return $this->get_many_related(
556
-            'Payment',
557
-            [
558
-                ['STS_ID' => EEM_Payment::status_id_approved],
559
-                'order_by' => ['PAY_timestamp' => 'DESC'],
560
-            ]
561
-        );
562
-    }
563
-
564
-
565
-    /**
566
-     * Gets all payments which have not been approved
567
-     *
568
-     * @return EE_Base_Class[]|EEI_Payment[]
569
-     * @throws EE_Error if a model is misconfigured somehow
570
-     * @throws InvalidArgumentException
571
-     * @throws InvalidDataTypeException
572
-     * @throws InvalidInterfaceException
573
-     * @throws ReflectionException
574
-     */
575
-    public function pending_payments()
576
-    {
577
-        return $this->get_many_related(
578
-            'Payment',
579
-            [
580
-                [
581
-                    'STS_ID' => EEM_Payment::status_id_pending,
582
-                ],
583
-                'order_by' => [
584
-                    'PAY_timestamp' => 'DESC',
585
-                ],
586
-            ]
587
-        );
588
-    }
589
-
590
-
591
-    /**
592
-     * echoes $this->pretty_status()
593
-     *
594
-     * @param bool $show_icons
595
-     * @throws EE_Error
596
-     * @throws InvalidArgumentException
597
-     * @throws InvalidDataTypeException
598
-     * @throws InvalidInterfaceException
599
-     * @throws ReflectionException
600
-     */
601
-    public function e_pretty_status($show_icons = false)
602
-    {
603
-        echo wp_kses($this->pretty_status($show_icons), AllowedTags::getAllowedTags());
604
-    }
605
-
606
-
607
-    /**
608
-     * returns a pretty version of the status, good for displaying to users
609
-     *
610
-     * @param bool $show_icons
611
-     * @return string
612
-     * @throws EE_Error
613
-     * @throws InvalidArgumentException
614
-     * @throws InvalidDataTypeException
615
-     * @throws InvalidInterfaceException
616
-     * @throws ReflectionException
617
-     */
618
-    public function pretty_status($show_icons = false)
619
-    {
620
-        $status = EEM_Status::instance()->localized_status(
621
-            [$this->status_ID() => esc_html__('unknown', 'event_espresso')],
622
-            false,
623
-            'sentence'
624
-        );
625
-        $icon   = '';
626
-        switch ($this->status_ID()) {
627
-            case EEM_Transaction::complete_status_code:
628
-                $icon = $show_icons ? '<span class="dashicons dashicons-yes ee-icon-size-24 green-text"></span>' : '';
629
-                break;
630
-            case EEM_Transaction::incomplete_status_code:
631
-                $icon = $show_icons ? '<span class="dashicons dashicons-marker ee-icon-size-16 lt-blue-text"></span>'
632
-                    : '';
633
-                break;
634
-            case EEM_Transaction::abandoned_status_code:
635
-                $icon = $show_icons ? '<span class="dashicons dashicons-marker ee-icon-size-16 red-text"></span>' : '';
636
-                break;
637
-            case EEM_Transaction::failed_status_code:
638
-                $icon = $show_icons ? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>' : '';
639
-                break;
640
-            case EEM_Transaction::overpaid_status_code:
641
-                $icon = $show_icons ? '<span class="dashicons dashicons-plus ee-icon-size-16 orange-text"></span>' : '';
642
-                break;
643
-        }
644
-        return $icon . $status[ $this->status_ID() ];
645
-    }
646
-
647
-
648
-    /**
649
-     * get Transaction Status
650
-     *
651
-     * @return mixed
652
-     * @throws EE_Error
653
-     * @throws InvalidArgumentException
654
-     * @throws InvalidDataTypeException
655
-     * @throws InvalidInterfaceException
656
-     * @throws ReflectionException
657
-     */
658
-    public function status_ID()
659
-    {
660
-        return $this->get('STS_ID');
661
-    }
662
-
663
-
664
-    /**
665
-     * Returns TRUE or FALSE for whether or not this transaction cost any money
666
-     *
667
-     * @return boolean
668
-     * @throws EE_Error
669
-     * @throws InvalidArgumentException
670
-     * @throws InvalidDataTypeException
671
-     * @throws InvalidInterfaceException
672
-     * @throws ReflectionException
673
-     */
674
-    public function is_free()
675
-    {
676
-        return EEH_Money::compare_floats($this->get('TXN_total'), 0, '==');
677
-    }
678
-
679
-
680
-    /**
681
-     * Returns whether this transaction is complete
682
-     * Useful in templates and other logic for deciding if we should ask for another payment...
683
-     *
684
-     * @return boolean
685
-     * @throws EE_Error
686
-     * @throws InvalidArgumentException
687
-     * @throws InvalidDataTypeException
688
-     * @throws InvalidInterfaceException
689
-     * @throws ReflectionException
690
-     */
691
-    public function is_completed()
692
-    {
693
-        return $this->status_ID() === EEM_Transaction::complete_status_code;
694
-    }
695
-
696
-
697
-    /**
698
-     * Returns whether this transaction is incomplete
699
-     * Useful in templates and other logic for deciding if we should ask for another payment...
700
-     *
701
-     * @return boolean
702
-     * @throws EE_Error
703
-     * @throws InvalidArgumentException
704
-     * @throws InvalidDataTypeException
705
-     * @throws InvalidInterfaceException
706
-     * @throws ReflectionException
707
-     */
708
-    public function is_incomplete()
709
-    {
710
-        return $this->status_ID() === EEM_Transaction::incomplete_status_code;
711
-    }
712
-
713
-
714
-    /**
715
-     * Returns whether this transaction is overpaid
716
-     * Useful in templates and other logic for deciding if monies need to be refunded
717
-     *
718
-     * @return boolean
719
-     * @throws EE_Error
720
-     * @throws InvalidArgumentException
721
-     * @throws InvalidDataTypeException
722
-     * @throws InvalidInterfaceException
723
-     * @throws ReflectionException
724
-     */
725
-    public function is_overpaid()
726
-    {
727
-        return $this->status_ID() === EEM_Transaction::overpaid_status_code;
728
-    }
729
-
730
-
731
-    /**
732
-     * Returns whether this transaction was abandoned
733
-     * meaning that the transaction/registration process was somehow interrupted and never completed
734
-     * but that contact information exists for at least one registrant
735
-     *
736
-     * @return boolean
737
-     * @throws EE_Error
738
-     * @throws InvalidArgumentException
739
-     * @throws InvalidDataTypeException
740
-     * @throws InvalidInterfaceException
741
-     * @throws ReflectionException
742
-     */
743
-    public function is_abandoned()
744
-    {
745
-        return $this->status_ID() === EEM_Transaction::abandoned_status_code;
746
-    }
747
-
748
-
749
-    /**
750
-     * Returns whether this transaction failed
751
-     * meaning that the transaction/registration process was somehow interrupted and never completed
752
-     * and that NO contact information exists for any registrants
753
-     *
754
-     * @return boolean
755
-     * @throws EE_Error
756
-     * @throws InvalidArgumentException
757
-     * @throws InvalidDataTypeException
758
-     * @throws InvalidInterfaceException
759
-     * @throws ReflectionException
760
-     */
761
-    public function failed()
762
-    {
763
-        return $this->status_ID() === EEM_Transaction::failed_status_code;
764
-    }
765
-
766
-
767
-    /**
768
-     * This returns the url for the invoice of this transaction
769
-     *
770
-     * @param string $type 'html' or 'pdf' (default is pdf)
771
-     * @return string
772
-     * @throws DomainException
773
-     * @throws EE_Error
774
-     * @throws InvalidArgumentException
775
-     * @throws InvalidDataTypeException
776
-     * @throws InvalidInterfaceException
777
-     * @throws ReflectionException
778
-     */
779
-    public function invoice_url($type = 'html')
780
-    {
781
-        $REG = $this->primary_registration();
782
-        if (! $REG instanceof EE_Registration) {
783
-            return '';
784
-        }
785
-        return $REG->invoice_url($type);
786
-    }
787
-
788
-
789
-    /**
790
-     * Gets the primary registration only
791
-     *
792
-     * @return EE_Base_Class|EE_Registration
793
-     * @throws EE_Error
794
-     * @throws InvalidArgumentException
795
-     * @throws InvalidDataTypeException
796
-     * @throws InvalidInterfaceException
797
-     * @throws ReflectionException
798
-     */
799
-    public function primary_registration()
800
-    {
801
-        $registrations = (array) $this->get_many_related(
802
-            'Registration',
803
-            [['REG_count' => EEM_Registration::PRIMARY_REGISTRANT_COUNT]]
804
-        );
805
-        foreach ($registrations as $registration) {
806
-            // valid registration that is NOT cancelled or declined ?
807
-            if (
808
-                $registration instanceof EE_Registration
809
-                && ! in_array($registration->status_ID(), EEM_Registration::closed_reg_statuses(), true)
810
-            ) {
811
-                return $registration;
812
-            }
813
-        }
814
-        // nothing valid found, so just return first thing from array of results
815
-        return reset($registrations);
816
-    }
817
-
818
-
819
-    /**
820
-     * Gets the URL for viewing the receipt
821
-     *
822
-     * @param string $type 'pdf' or 'html' (default is 'html')
823
-     * @return string
824
-     * @throws DomainException
825
-     * @throws EE_Error
826
-     * @throws InvalidArgumentException
827
-     * @throws InvalidDataTypeException
828
-     * @throws InvalidInterfaceException
829
-     * @throws ReflectionException
830
-     */
831
-    public function receipt_url($type = 'html')
832
-    {
833
-        $REG = $this->primary_registration();
834
-        if (! $REG instanceof EE_Registration) {
835
-            return '';
836
-        }
837
-        return $REG->receipt_url($type);
838
-    }
839
-
840
-
841
-    /**
842
-     * Gets the URL of the thank you page with this registration REG_url_link added as
843
-     * a query parameter
844
-     *
845
-     * @return string
846
-     * @throws EE_Error
847
-     * @throws InvalidArgumentException
848
-     * @throws InvalidDataTypeException
849
-     * @throws InvalidInterfaceException
850
-     * @throws ReflectionException
851
-     */
852
-    public function payment_overview_url()
853
-    {
854
-        $primary_registration = $this->primary_registration();
855
-        return $primary_registration instanceof EE_Registration ? $primary_registration->payment_overview_url() : false;
856
-    }
857
-
858
-
859
-    /**
860
-     * @return string
861
-     * @throws EE_Error
862
-     * @throws InvalidArgumentException
863
-     * @throws InvalidDataTypeException
864
-     * @throws InvalidInterfaceException
865
-     * @throws ReflectionException
866
-     */
867
-    public function gateway_response_on_transaction()
868
-    {
869
-        $payment = $this->get_first_related('Payment');
870
-        return $payment instanceof EE_Payment ? $payment->gateway_response() : '';
871
-    }
872
-
873
-
874
-    /**
875
-     * Get the status object of this object
876
-     *
877
-     * @return EE_Base_Class|EE_Status
878
-     * @throws EE_Error
879
-     * @throws InvalidArgumentException
880
-     * @throws InvalidDataTypeException
881
-     * @throws InvalidInterfaceException
882
-     * @throws ReflectionException
883
-     */
884
-    public function status_obj()
885
-    {
886
-        return $this->get_first_related('Status');
887
-    }
888
-
889
-
890
-    /**
891
-     * Gets all the extra meta info on this payment
892
-     *
893
-     * @param array $query_params
894
-     * @return EE_Base_Class[]|EE_Extra_Meta
895
-     * @throws EE_Error
896
-     * @throws InvalidArgumentException
897
-     * @throws InvalidDataTypeException
898
-     * @throws InvalidInterfaceException
899
-     * @throws ReflectionException
900
-     * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
901
-     */
902
-    public function extra_meta($query_params = [])
903
-    {
904
-        return $this->get_many_related('Extra_Meta', $query_params);
905
-    }
906
-
907
-
908
-    /**
909
-     * Wrapper for _add_relation_to
910
-     *
911
-     * @param EE_Registration $registration
912
-     * @return EE_Base_Class the relation was added to
913
-     * @throws EE_Error
914
-     * @throws InvalidArgumentException
915
-     * @throws InvalidDataTypeException
916
-     * @throws InvalidInterfaceException
917
-     * @throws ReflectionException
918
-     */
919
-    public function add_registration(EE_Registration $registration)
920
-    {
921
-        return $this->_add_relation_to($registration, 'Registration');
922
-    }
923
-
924
-
925
-    /**
926
-     * Removes the given registration from being related (even before saving this transaction).
927
-     * If an ID/index is provided and this transaction isn't saved yet, removes it from list of cached relations
928
-     *
929
-     * @param int $registration_or_id
930
-     * @return EE_Base_Class that was removed from being related
931
-     * @throws EE_Error
932
-     * @throws InvalidArgumentException
933
-     * @throws InvalidDataTypeException
934
-     * @throws InvalidInterfaceException
935
-     * @throws ReflectionException
936
-     */
937
-    public function remove_registration_with_id($registration_or_id)
938
-    {
939
-        return $this->_remove_relation_to($registration_or_id, 'Registration');
940
-    }
941
-
942
-
943
-    /**
944
-     * Gets all the line items which are for ACTUAL items
945
-     *
946
-     * @return EE_Line_Item[]
947
-     * @throws EE_Error
948
-     * @throws InvalidArgumentException
949
-     * @throws InvalidDataTypeException
950
-     * @throws InvalidInterfaceException
951
-     * @throws ReflectionException
952
-     */
953
-    public function items_purchased()
954
-    {
955
-        return $this->line_items([['LIN_type' => EEM_Line_Item::type_line_item]]);
956
-    }
957
-
958
-
959
-    /**
960
-     * Wrapper for _add_relation_to
961
-     *
962
-     * @param EE_Line_Item $line_item
963
-     * @return EE_Base_Class the relation was added to
964
-     * @throws EE_Error
965
-     * @throws InvalidArgumentException
966
-     * @throws InvalidDataTypeException
967
-     * @throws InvalidInterfaceException
968
-     * @throws ReflectionException
969
-     */
970
-    public function add_line_item(EE_Line_Item $line_item)
971
-    {
972
-        return $this->_add_relation_to($line_item, 'Line_Item');
973
-    }
974
-
975
-
976
-    /**
977
-     * Gets ALL the line items related to this transaction (unstructured)
978
-     *
979
-     * @param array $query_params
980
-     * @return EE_Base_Class[]|EE_Line_Item[]
981
-     * @throws EE_Error
982
-     * @throws InvalidArgumentException
983
-     * @throws InvalidDataTypeException
984
-     * @throws InvalidInterfaceException
985
-     * @throws ReflectionException
986
-     */
987
-    public function line_items($query_params = [])
988
-    {
989
-        return $this->get_many_related('Line_Item', $query_params);
990
-    }
991
-
992
-
993
-    /**
994
-     * Gets all the line items which are taxes on the total
995
-     *
996
-     * @return EE_Line_Item[]
997
-     * @throws EE_Error
998
-     * @throws InvalidArgumentException
999
-     * @throws InvalidDataTypeException
1000
-     * @throws InvalidInterfaceException
1001
-     * @throws ReflectionException
1002
-     */
1003
-    public function tax_items()
1004
-    {
1005
-        return $this->line_items([['LIN_type' => EEM_Line_Item::type_tax]]);
1006
-    }
1007
-
1008
-
1009
-    /**
1010
-     * Gets the total line item (which is a parent of all other related line items,
1011
-     * meaning it takes them all into account on its total)
1012
-     *
1013
-     * @param bool $create_if_not_found
1014
-     * @return \EE_Line_Item
1015
-     * @throws EE_Error
1016
-     * @throws InvalidArgumentException
1017
-     * @throws InvalidDataTypeException
1018
-     * @throws InvalidInterfaceException
1019
-     * @throws ReflectionException
1020
-     */
1021
-    public function total_line_item($create_if_not_found = true)
1022
-    {
1023
-        $item = $this->get_first_related('Line_Item', [['LIN_type' => EEM_Line_Item::type_total]]);
1024
-        if (! $item && $create_if_not_found) {
1025
-            $item = EEH_Line_Item::create_total_line_item($this);
1026
-        }
1027
-        return $item;
1028
-    }
1029
-
1030
-
1031
-    /**
1032
-     * Returns the total amount of tax on this transaction
1033
-     * (assumes there's only one tax subtotal line item)
1034
-     *
1035
-     * @return float
1036
-     * @throws EE_Error
1037
-     * @throws InvalidArgumentException
1038
-     * @throws InvalidDataTypeException
1039
-     * @throws InvalidInterfaceException
1040
-     * @throws ReflectionException
1041
-     */
1042
-    public function tax_total()
1043
-    {
1044
-        $tax_line_item = $this->tax_total_line_item();
1045
-        if ($tax_line_item) {
1046
-            return (float) $tax_line_item->total();
1047
-        }
1048
-        return (float) 0;
1049
-    }
1050
-
1051
-
1052
-    /**
1053
-     * Gets the tax subtotal line item (assumes there's only one)
1054
-     *
1055
-     * @return EE_Line_Item
1056
-     * @throws EE_Error
1057
-     * @throws InvalidArgumentException
1058
-     * @throws InvalidDataTypeException
1059
-     * @throws InvalidInterfaceException
1060
-     * @throws ReflectionException
1061
-     */
1062
-    public function tax_total_line_item()
1063
-    {
1064
-        return EEH_Line_Item::get_taxes_subtotal($this->total_line_item());
1065
-    }
1066
-
1067
-
1068
-    /**
1069
-     * Gets the array of billing info for the gateway and for this transaction's primary registration's attendee.
1070
-     *
1071
-     * @return EE_Form_Section_Proper
1072
-     * @throws EE_Error
1073
-     * @throws InvalidArgumentException
1074
-     * @throws InvalidDataTypeException
1075
-     * @throws InvalidInterfaceException
1076
-     * @throws ReflectionException
1077
-     */
1078
-    public function billing_info()
1079
-    {
1080
-        $payment_method = $this->payment_method();
1081
-        if (! $payment_method) {
1082
-            EE_Error::add_error(
1083
-                esc_html__(
1084
-                    'Could not find billing info for transaction because no gateway has been used for it yet',
1085
-                    'event_espresso'
1086
-                ),
1087
-                __FILE__,
1088
-                __FUNCTION__,
1089
-                __LINE__
1090
-            );
1091
-            return null;
1092
-        }
1093
-        $primary_reg = $this->primary_registration();
1094
-        if (! $primary_reg) {
1095
-            EE_Error::add_error(
1096
-                esc_html__(
1097
-                    'Cannot get billing info for gateway %s on transaction because no primary registration exists',
1098
-                    'event_espresso'
1099
-                ),
1100
-                __FILE__,
1101
-                __FUNCTION__,
1102
-                __LINE__
1103
-            );
1104
-            return null;
1105
-        }
1106
-        $attendee = $primary_reg->attendee();
1107
-        if (! $attendee) {
1108
-            EE_Error::add_error(
1109
-                esc_html__(
1110
-                    'Cannot get billing info for gateway %s on transaction because the primary registration has no attendee exists',
1111
-                    'event_espresso'
1112
-                ),
1113
-                __FILE__,
1114
-                __FUNCTION__,
1115
-                __LINE__
1116
-            );
1117
-            return null;
1118
-        }
1119
-        return $attendee->billing_info_for_payment_method($payment_method);
1120
-    }
1121
-
1122
-
1123
-    /**
1124
-     * Gets PMD_ID
1125
-     *
1126
-     * @return int
1127
-     * @throws EE_Error
1128
-     * @throws InvalidArgumentException
1129
-     * @throws InvalidDataTypeException
1130
-     * @throws InvalidInterfaceException
1131
-     * @throws ReflectionException
1132
-     */
1133
-    public function payment_method_ID()
1134
-    {
1135
-        return $this->get('PMD_ID');
1136
-    }
1137
-
1138
-
1139
-    /**
1140
-     * Sets PMD_ID
1141
-     *
1142
-     * @param int $PMD_ID
1143
-     * @throws EE_Error
1144
-     * @throws InvalidArgumentException
1145
-     * @throws InvalidDataTypeException
1146
-     * @throws InvalidInterfaceException
1147
-     * @throws ReflectionException
1148
-     */
1149
-    public function set_payment_method_ID($PMD_ID)
1150
-    {
1151
-        $this->set('PMD_ID', $PMD_ID);
1152
-    }
1153
-
1154
-
1155
-    /**
1156
-     * Gets the last-used payment method on this transaction
1157
-     * (we COULD just use the last-made payment, but some payment methods, namely
1158
-     * offline ones, dont' create payments)
1159
-     *
1160
-     * @return EE_Payment_Method
1161
-     * @throws EE_Error
1162
-     * @throws InvalidArgumentException
1163
-     * @throws InvalidDataTypeException
1164
-     * @throws InvalidInterfaceException
1165
-     * @throws ReflectionException
1166
-     */
1167
-    public function payment_method()
1168
-    {
1169
-        $pm = $this->get_first_related('Payment_Method');
1170
-        if ($pm instanceof EE_Payment_Method) {
1171
-            return $pm;
1172
-        }
1173
-        $last_payment = $this->last_payment();
1174
-        if ($last_payment instanceof EE_Payment && $last_payment->payment_method()) {
1175
-            return $last_payment->payment_method();
1176
-        }
1177
-        return null;
1178
-    }
1179
-
1180
-
1181
-    /**
1182
-     * Gets the last payment made
1183
-     *
1184
-     * @return EE_Base_Class|EE_Payment
1185
-     * @throws EE_Error
1186
-     * @throws InvalidArgumentException
1187
-     * @throws InvalidDataTypeException
1188
-     * @throws InvalidInterfaceException
1189
-     * @throws ReflectionException
1190
-     */
1191
-    public function last_payment()
1192
-    {
1193
-        return $this->get_first_related('Payment', ['order_by' => ['PAY_ID' => 'desc']]);
1194
-    }
1195
-
1196
-
1197
-    /**
1198
-     * Gets all the line items which are unrelated to tickets on this transaction
1199
-     *
1200
-     * @return EE_Line_Item[]
1201
-     * @throws EE_Error
1202
-     * @throws InvalidArgumentException
1203
-     * @throws InvalidDataTypeException
1204
-     * @throws InvalidInterfaceException
1205
-     * @throws ReflectionException
1206
-     */
1207
-    public function non_ticket_line_items()
1208
-    {
1209
-        return EEM_Line_Item::instance()->get_all_non_ticket_line_items_for_transaction($this->ID());
1210
-    }
1211
-
1212
-
1213
-    /**
1214
-     * possibly toggles TXN status
1215
-     *
1216
-     * @param boolean $update whether to save the TXN
1217
-     * @return bool whether the TXN was saved
1218
-     * @throws EE_Error
1219
-     * @throws InvalidArgumentException
1220
-     * @throws InvalidDataTypeException
1221
-     * @throws InvalidInterfaceException
1222
-     * @throws ReflectionException
1223
-     * @throws RuntimeException
1224
-     */
1225
-    public function update_status_based_on_total_paid($update = true)
1226
-    {
1227
-        // set transaction status based on comparison of TXN_paid vs TXN_total
1228
-        if (EEH_Money::compare_floats($this->paid(), $this->total(), '>')) {
1229
-            $new_txn_status = EEM_Transaction::overpaid_status_code;
1230
-        } elseif (EEH_Money::compare_floats($this->paid(), $this->total())) {
1231
-            $new_txn_status = EEM_Transaction::complete_status_code;
1232
-        } elseif (EEH_Money::compare_floats($this->paid(), $this->total(), '<')) {
1233
-            $new_txn_status = EEM_Transaction::incomplete_status_code;
1234
-        } else {
1235
-            throw new RuntimeException(
1236
-                esc_html__('The total paid calculation for this transaction is inaccurate.', 'event_espresso')
1237
-            );
1238
-        }
1239
-        if ($new_txn_status !== $this->status_ID()) {
1240
-            $this->set_status($new_txn_status);
1241
-            if ($update) {
1242
-                return (bool) $this->save();
1243
-            }
1244
-        }
1245
-        return false;
1246
-    }
1247
-
1248
-
1249
-    /**
1250
-     * Updates the transaction's status and total_paid based on all the payments
1251
-     * that apply to it
1252
-     *
1253
-     * @return array|bool
1254
-     * @throws EE_Error
1255
-     * @throws InvalidArgumentException
1256
-     * @throws ReflectionException
1257
-     * @throws InvalidDataTypeException
1258
-     * @throws InvalidInterfaceException
1259
-     * @deprecated
1260
-     */
1261
-    public function update_based_on_payments()
1262
-    {
1263
-        EE_Error::doing_it_wrong(
1264
-            __CLASS__ . '::' . __FUNCTION__,
1265
-            sprintf(
1266
-                esc_html__('This method is deprecated. Please use "%s" instead', 'event_espresso'),
1267
-                'EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()'
1268
-            ),
1269
-            '4.6.0'
1270
-        );
1271
-        /** @type EE_Transaction_Processor $transaction_processor */
1272
-        $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
1273
-        return $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment($this);
1274
-    }
1275
-
1276
-
1277
-    /**
1278
-     * @return string
1279
-     */
1280
-    public function old_txn_status()
1281
-    {
1282
-        return $this->_old_txn_status;
1283
-    }
1284
-
1285
-
1286
-    /**
1287
-     * @param string $old_txn_status
1288
-     */
1289
-    public function set_old_txn_status($old_txn_status)
1290
-    {
1291
-        // only set the first time
1292
-        if ($this->_old_txn_status === null) {
1293
-            $this->_old_txn_status = $old_txn_status;
1294
-        }
1295
-    }
1296
-
1297
-
1298
-    /**
1299
-     * reg_status_updated
1300
-     *
1301
-     * @return bool
1302
-     * @throws EE_Error
1303
-     * @throws InvalidArgumentException
1304
-     * @throws InvalidDataTypeException
1305
-     * @throws InvalidInterfaceException
1306
-     * @throws ReflectionException
1307
-     */
1308
-    public function txn_status_updated()
1309
-    {
1310
-        return $this->status_ID() !== $this->_old_txn_status && $this->_old_txn_status !== null;
1311
-    }
1312
-
1313
-
1314
-    /**
1315
-     * _reg_steps_completed
1316
-     * if $check_all is TRUE, then returns TRUE if ALL reg steps have been marked as completed,
1317
-     * if a $reg_step_slug is provided, then this step will be skipped when testing for completion
1318
-     * if $check_all is FALSE and a $reg_step_slug is provided, then ONLY that reg step will be tested for completion
1319
-     *
1320
-     * @param string $reg_step_slug
1321
-     * @param bool   $check_all
1322
-     * @return bool|int
1323
-     * @throws EE_Error
1324
-     * @throws InvalidArgumentException
1325
-     * @throws InvalidDataTypeException
1326
-     * @throws InvalidInterfaceException
1327
-     * @throws ReflectionException
1328
-     */
1329
-    private function _reg_steps_completed($reg_step_slug = '', $check_all = true)
1330
-    {
1331
-        $reg_steps = $this->reg_steps();
1332
-        if (! is_array($reg_steps) || empty($reg_steps)) {
1333
-            return false;
1334
-        }
1335
-        // loop thru reg steps array)
1336
-        foreach ($reg_steps as $slug => $reg_step_completed) {
1337
-            // if NOT checking ALL steps (only checking one step)
1338
-            if (! $check_all) {
1339
-                // and this is the one
1340
-                if ($slug === $reg_step_slug) {
1341
-                    return $reg_step_completed;
1342
-                }
1343
-                // skip to next reg step in loop
1344
-                continue;
1345
-            }
1346
-            // $check_all must be true, else we would never have gotten to this point
1347
-            if ($slug === $reg_step_slug) {
1348
-                // if we reach this point, then we are testing either:
1349
-                // all_reg_steps_completed_except() or
1350
-                // all_reg_steps_completed_except_final_step(),
1351
-                // and since this is the reg step EXCEPTION being tested
1352
-                // we want to return true (yes true) if this reg step is NOT completed
1353
-                // ie: "is everything completed except the final step?"
1354
-                // "that is correct... the final step is not completed, but all others are."
1355
-                return $reg_step_completed !== true;
1356
-            }
1357
-            if ($reg_step_completed !== true) {
1358
-                // if any reg step is NOT completed, then ALL steps are not completed
1359
-                return false;
1360
-            }
1361
-        }
1362
-        return true;
1363
-    }
1364
-
1365
-
1366
-    /**
1367
-     * all_reg_steps_completed
1368
-     * returns:
1369
-     *    true if ALL reg steps have been marked as completed
1370
-     *        or false if any step is not completed
1371
-     *
1372
-     * @return bool
1373
-     * @throws EE_Error
1374
-     * @throws InvalidArgumentException
1375
-     * @throws InvalidDataTypeException
1376
-     * @throws InvalidInterfaceException
1377
-     * @throws ReflectionException
1378
-     */
1379
-    public function all_reg_steps_completed()
1380
-    {
1381
-        return $this->_reg_steps_completed();
1382
-    }
1383
-
1384
-
1385
-    /**
1386
-     * all_reg_steps_completed_except
1387
-     * returns:
1388
-     *        true if ALL reg steps, except a particular step that you wish to skip over, have been marked as completed
1389
-     *        or false if any other step is not completed
1390
-     *        or false if ALL steps are completed including the exception you are testing !!!
1391
-     *
1392
-     * @param string $exception
1393
-     * @return bool
1394
-     * @throws EE_Error
1395
-     * @throws InvalidArgumentException
1396
-     * @throws InvalidDataTypeException
1397
-     * @throws InvalidInterfaceException
1398
-     * @throws ReflectionException
1399
-     */
1400
-    public function all_reg_steps_completed_except($exception = '')
1401
-    {
1402
-        return $this->_reg_steps_completed($exception);
1403
-    }
1404
-
1405
-
1406
-    /**
1407
-     * all_reg_steps_completed_except
1408
-     * returns:
1409
-     *        true if ALL reg steps, except the final step, have been marked as completed
1410
-     *        or false if any step is not completed
1411
-     *    or false if ALL steps are completed including the final step !!!
1412
-     *
1413
-     * @return bool
1414
-     * @throws EE_Error
1415
-     * @throws InvalidArgumentException
1416
-     * @throws InvalidDataTypeException
1417
-     * @throws InvalidInterfaceException
1418
-     * @throws ReflectionException
1419
-     */
1420
-    public function all_reg_steps_completed_except_final_step()
1421
-    {
1422
-        return $this->_reg_steps_completed('finalize_registration');
1423
-    }
1424
-
1425
-
1426
-    /**
1427
-     * reg_step_completed
1428
-     * returns:
1429
-     *    true if a specific reg step has been marked as completed
1430
-     *    a Unix timestamp if it has been initialized but not yet completed,
1431
-     *    or false if it has not yet been initialized
1432
-     *
1433
-     * @param string $reg_step_slug
1434
-     * @return bool|int
1435
-     * @throws EE_Error
1436
-     * @throws InvalidArgumentException
1437
-     * @throws InvalidDataTypeException
1438
-     * @throws InvalidInterfaceException
1439
-     * @throws ReflectionException
1440
-     */
1441
-    public function reg_step_completed($reg_step_slug)
1442
-    {
1443
-        return $this->_reg_steps_completed($reg_step_slug, false);
1444
-    }
1445
-
1446
-
1447
-    /**
1448
-     * completed_final_reg_step
1449
-     * returns:
1450
-     *    true if the finalize_registration reg step has been marked as completed
1451
-     *    a Unix timestamp if it has been initialized but not yet completed,
1452
-     *    or false if it has not yet been initialized
1453
-     *
1454
-     * @return bool|int
1455
-     * @throws EE_Error
1456
-     * @throws InvalidArgumentException
1457
-     * @throws InvalidDataTypeException
1458
-     * @throws InvalidInterfaceException
1459
-     * @throws ReflectionException
1460
-     */
1461
-    public function final_reg_step_completed()
1462
-    {
1463
-        return $this->_reg_steps_completed('finalize_registration', false);
1464
-    }
1465
-
1466
-
1467
-    /**
1468
-     * set_reg_step_initiated
1469
-     * given a valid TXN_reg_step, this sets it's value to a unix timestamp
1470
-     *
1471
-     * @param string $reg_step_slug
1472
-     * @return boolean
1473
-     * @throws EE_Error
1474
-     * @throws InvalidArgumentException
1475
-     * @throws InvalidDataTypeException
1476
-     * @throws InvalidInterfaceException
1477
-     * @throws ReflectionException
1478
-     */
1479
-    public function set_reg_step_initiated($reg_step_slug)
1480
-    {
1481
-        return $this->_set_reg_step_completed_status($reg_step_slug, time());
1482
-    }
1483
-
1484
-
1485
-    /**
1486
-     * set_reg_step_completed
1487
-     * given a valid TXN_reg_step, this sets the step as completed
1488
-     *
1489
-     * @param string $reg_step_slug
1490
-     * @return boolean
1491
-     * @throws EE_Error
1492
-     * @throws InvalidArgumentException
1493
-     * @throws InvalidDataTypeException
1494
-     * @throws InvalidInterfaceException
1495
-     * @throws ReflectionException
1496
-     */
1497
-    public function set_reg_step_completed($reg_step_slug)
1498
-    {
1499
-        return $this->_set_reg_step_completed_status($reg_step_slug, true);
1500
-    }
1501
-
1502
-
1503
-    /**
1504
-     * set_reg_step_completed
1505
-     * given a valid TXN_reg_step slug, this sets the step as NOT completed
1506
-     *
1507
-     * @param string $reg_step_slug
1508
-     * @return boolean
1509
-     * @throws EE_Error
1510
-     * @throws InvalidArgumentException
1511
-     * @throws InvalidDataTypeException
1512
-     * @throws InvalidInterfaceException
1513
-     * @throws ReflectionException
1514
-     */
1515
-    public function set_reg_step_not_completed($reg_step_slug)
1516
-    {
1517
-        return $this->_set_reg_step_completed_status($reg_step_slug, false);
1518
-    }
1519
-
1520
-
1521
-    /**
1522
-     * set_reg_step_completed
1523
-     * given a valid reg step slug, this sets the TXN_reg_step completed status which is either:
1524
-     *
1525
-     * @param string      $reg_step_slug
1526
-     * @param boolean|int $status
1527
-     * @return boolean
1528
-     * @throws EE_Error
1529
-     * @throws InvalidArgumentException
1530
-     * @throws InvalidDataTypeException
1531
-     * @throws InvalidInterfaceException
1532
-     * @throws ReflectionException
1533
-     */
1534
-    private function _set_reg_step_completed_status($reg_step_slug, $status)
1535
-    {
1536
-        // validate status
1537
-        $status = is_bool($status) || is_int($status) ? $status : false;
1538
-        // get reg steps array
1539
-        $txn_reg_steps = $this->reg_steps();
1540
-        // if reg step does NOT exist
1541
-        if (! isset($txn_reg_steps[ $reg_step_slug ])) {
1542
-            return false;
1543
-        }
1544
-        // if  we're trying to complete a step that is already completed
1545
-        if ($txn_reg_steps[ $reg_step_slug ] === true) {
1546
-            return true;
1547
-        }
1548
-        // if  we're trying to complete a step that hasn't even started
1549
-        if ($status === true && $txn_reg_steps[ $reg_step_slug ] === false) {
1550
-            return false;
1551
-        }
1552
-        // if current status value matches the incoming value (no change)
1553
-        // type casting as int means values should collapse to either 0, 1, or a timestamp like 1234567890
1554
-        if ((int) $txn_reg_steps[ $reg_step_slug ] === (int) $status) {
1555
-            // this will happen in cases where multiple AJAX requests occur during the same step
1556
-            return true;
1557
-        }
1558
-        // if we're trying to set a start time, but it has already been set...
1559
-        if (is_numeric($status) && is_numeric($txn_reg_steps[ $reg_step_slug ])) {
1560
-            // skip the update below, but don't return FALSE so that errors won't be displayed
1561
-            return true;
1562
-        }
1563
-        // update completed status
1564
-        $txn_reg_steps[ $reg_step_slug ] = $status;
1565
-        $this->set_reg_steps($txn_reg_steps);
1566
-        $this->save();
1567
-        return true;
1568
-    }
1569
-
1570
-
1571
-    /**
1572
-     * remove_reg_step
1573
-     * given a valid TXN_reg_step slug, this will remove (unset)
1574
-     * the reg step from the TXN reg step array
1575
-     *
1576
-     * @param string $reg_step_slug
1577
-     * @return void
1578
-     * @throws EE_Error
1579
-     * @throws InvalidArgumentException
1580
-     * @throws InvalidDataTypeException
1581
-     * @throws InvalidInterfaceException
1582
-     * @throws ReflectionException
1583
-     */
1584
-    public function remove_reg_step($reg_step_slug)
1585
-    {
1586
-        // get reg steps array
1587
-        $txn_reg_steps = $this->reg_steps();
1588
-        unset($txn_reg_steps[ $reg_step_slug ]);
1589
-        $this->set_reg_steps($txn_reg_steps);
1590
-    }
1591
-
1592
-
1593
-    /**
1594
-     * toggle_failed_transaction_status
1595
-     * upgrades a TXNs status from failed to abandoned,
1596
-     * meaning that contact information has been captured for at least one registrant
1597
-     *
1598
-     * @param bool $save
1599
-     * @return bool
1600
-     * @throws EE_Error
1601
-     * @throws InvalidArgumentException
1602
-     * @throws InvalidDataTypeException
1603
-     * @throws InvalidInterfaceException
1604
-     * @throws ReflectionException
1605
-     */
1606
-    public function toggle_failed_transaction_status($save = true)
1607
-    {
1608
-        // if TXN status is still set as "failed"...
1609
-        if ($this->status_ID() === EEM_Transaction::failed_status_code) {
1610
-            $this->set_status(EEM_Transaction::abandoned_status_code);
1611
-            if ($save) {
1612
-                $this->save();
1613
-            }
1614
-            return true;
1615
-        }
1616
-        return false;
1617
-    }
1618
-
1619
-
1620
-    /**
1621
-     * toggle_abandoned_transaction_status
1622
-     * upgrades a TXNs status from failed or abandoned to incomplete
1623
-     *
1624
-     * @return bool
1625
-     * @throws EE_Error
1626
-     * @throws InvalidArgumentException
1627
-     * @throws InvalidDataTypeException
1628
-     * @throws InvalidInterfaceException
1629
-     * @throws ReflectionException
1630
-     */
1631
-    public function toggle_abandoned_transaction_status()
1632
-    {
1633
-        // if TXN status has not been updated already due to a payment, and is still set as "failed" or "abandoned"...
1634
-        $txn_status = $this->status_ID();
1635
-        if (
1636
-            $txn_status === EEM_Transaction::failed_status_code
1637
-            || $txn_status === EEM_Transaction::abandoned_status_code
1638
-        ) {
1639
-            // if a contact record for the primary registrant has been created
1640
-            if (
1641
-                $this->primary_registration() instanceof EE_Registration
1642
-                && $this->primary_registration()->attendee() instanceof EE_Attendee
1643
-            ) {
1644
-                $this->set_status(EEM_Transaction::incomplete_status_code);
1645
-            } else {
1646
-                // no contact record? yer abandoned!
1647
-                $this->set_status(EEM_Transaction::abandoned_status_code);
1648
-            }
1649
-            return true;
1650
-        }
1651
-        return false;
1652
-    }
1653
-
1654
-
1655
-    /**
1656
-     * checks if an Abandoned TXN has any related payments, and if so,
1657
-     * updates the TXN status based on the amount paid
1658
-     *
1659
-     * @throws EE_Error
1660
-     * @throws InvalidArgumentException
1661
-     * @throws InvalidDataTypeException
1662
-     * @throws InvalidInterfaceException
1663
-     * @throws ReflectionException
1664
-     * @throws RuntimeException
1665
-     * @throws ReflectionException
1666
-     */
1667
-    public function verify_abandoned_transaction_status()
1668
-    {
1669
-        if ($this->status_ID() !== EEM_Transaction::abandoned_status_code) {
1670
-            return;
1671
-        }
1672
-        $payments = $this->get_many_related('Payment');
1673
-        if (! empty($payments)) {
1674
-            foreach ($payments as $payment) {
1675
-                if ($payment instanceof EE_Payment) {
1676
-                    // kk this TXN should NOT be abandoned
1677
-                    $this->update_status_based_on_total_paid();
1678
-                    if (! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) {
1679
-                        EE_Error::add_attention(
1680
-                            sprintf(
1681
-                                esc_html__(
1682
-                                    '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.',
1683
-                                    'event_espresso'
1684
-                                ),
1685
-                                $this->ID(),
1686
-                                $this->pretty_status()
1687
-                            )
1688
-                        );
1689
-                    }
1690
-                    // get final reg step status
1691
-                    $finalized = $this->final_reg_step_completed();
1692
-                    // if the 'finalize_registration' step has been initiated (has a timestamp)
1693
-                    // but has not yet been fully completed (TRUE)
1694
-                    if (is_int($finalized) && $finalized !== false && $finalized !== true) {
1695
-                        $this->set_reg_step_completed('finalize_registration');
1696
-                        $this->save();
1697
-                    }
1698
-                }
1699
-            }
1700
-        }
1701
-    }
1702
-
1703
-
1704
-    /**
1705
-     * @throws EE_Error
1706
-     * @throws InvalidArgumentException
1707
-     * @throws InvalidDataTypeException
1708
-     * @throws InvalidInterfaceException
1709
-     * @throws ReflectionException
1710
-     * @throws RuntimeException
1711
-     * @since 4.10.4.p
1712
-     */
1713
-    public function recalculateLineItems()
1714
-    {
1715
-        $total_line_item = $this->total_line_item(false);
1716
-        if ($total_line_item instanceof EE_Line_Item) {
1717
-            EEH_Line_Item::resetIsTaxableForTickets($total_line_item);
1718
-            return EEH_Line_Item::apply_taxes($total_line_item, true);
1719
-        }
1720
-        return false;
1721
-    }
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
+	 * txn status upon initial construction.
24
+	 *
25
+	 * @var string
26
+	 */
27
+	protected $_old_txn_status;
28
+
29
+
30
+	/**
31
+	 * @param array  $props_n_values          incoming values
32
+	 * @param string $timezone                incoming timezone
33
+	 *                                        (if not set the timezone set for the website will be used.)
34
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
35
+	 *                                        date_format and the second value is the time format
36
+	 * @return EE_Transaction
37
+	 * @throws EE_Error
38
+	 * @throws InvalidArgumentException
39
+	 * @throws InvalidDataTypeException
40
+	 * @throws InvalidInterfaceException
41
+	 * @throws ReflectionException
42
+	 */
43
+	public static function new_instance($props_n_values = [], $timezone = null, $date_formats = [])
44
+	{
45
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
46
+		$txn        = $has_object
47
+			? $has_object
48
+			: new self($props_n_values, false, $timezone, $date_formats);
49
+		if (! $has_object) {
50
+			$txn->set_old_txn_status($txn->status_ID());
51
+		}
52
+		return $txn;
53
+	}
54
+
55
+
56
+	/**
57
+	 * @param array  $props_n_values  incoming values from the database
58
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
59
+	 *                                the website will be used.
60
+	 * @return EE_Transaction
61
+	 * @throws EE_Error
62
+	 * @throws InvalidArgumentException
63
+	 * @throws InvalidDataTypeException
64
+	 * @throws InvalidInterfaceException
65
+	 * @throws ReflectionException
66
+	 */
67
+	public static function new_instance_from_db($props_n_values = [], $timezone = null)
68
+	{
69
+		$txn = new self($props_n_values, true, $timezone);
70
+		$txn->set_old_txn_status($txn->status_ID());
71
+		return $txn;
72
+	}
73
+
74
+
75
+	/**
76
+	 * Sets a meta field indicating that this TXN is locked and should not be updated in the db.
77
+	 * If a lock has already been set, then we will attempt to remove it in case it has expired.
78
+	 * If that also fails, then an exception is thrown.
79
+	 *
80
+	 * @throws EE_Error
81
+	 * @throws InvalidArgumentException
82
+	 * @throws InvalidDataTypeException
83
+	 * @throws InvalidInterfaceException
84
+	 * @throws ReflectionException
85
+	 */
86
+	public function lock()
87
+	{
88
+		// attempt to set lock, but if that fails...
89
+		if (! $this->add_extra_meta('lock', time(), true)) {
90
+			// then attempt to remove the lock in case it is expired
91
+			if ($this->_remove_expired_lock()) {
92
+				// if removal was successful, then try setting lock again
93
+				$this->lock();
94
+			} else {
95
+				// but if the lock can not be removed, then throw an exception
96
+				throw new EE_Error(
97
+					sprintf(
98
+						esc_html__(
99
+							'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.',
100
+							'event_espresso'
101
+						),
102
+						$this->ID()
103
+					)
104
+				);
105
+			}
106
+		}
107
+	}
108
+
109
+
110
+	/**
111
+	 * removes transaction lock applied in EE_Transaction::lock()
112
+	 *
113
+	 * @return int
114
+	 * @throws EE_Error
115
+	 * @throws InvalidArgumentException
116
+	 * @throws InvalidDataTypeException
117
+	 * @throws InvalidInterfaceException
118
+	 * @throws ReflectionException
119
+	 */
120
+	public function unlock()
121
+	{
122
+		return $this->delete_extra_meta('lock');
123
+	}
124
+
125
+
126
+	/**
127
+	 * Decides whether or not now is the right time to update the transaction.
128
+	 * This is useful because we don't always know if it is safe to update the transaction
129
+	 * and its related data. why?
130
+	 * because it's possible that the transaction is being used in another
131
+	 * request and could overwrite anything we save.
132
+	 * So we want to only update the txn once we know that won't happen.
133
+	 * We also check that the lock isn't expired, and remove it if it is
134
+	 *
135
+	 * @return boolean
136
+	 * @throws EE_Error
137
+	 * @throws InvalidArgumentException
138
+	 * @throws InvalidDataTypeException
139
+	 * @throws InvalidInterfaceException
140
+	 * @throws ReflectionException
141
+	 */
142
+	public function is_locked()
143
+	{
144
+		// if TXN is not locked, then return false immediately
145
+		if (! $this->_get_lock()) {
146
+			return false;
147
+		}
148
+		// if not, then let's try and remove the lock in case it's expired...
149
+		// _remove_expired_lock() returns 0 when lock is valid (ie: removed = false)
150
+		// and a positive number if the lock was removed (ie: number of locks deleted),
151
+		// so we need to return the opposite
152
+		return ! $this->_remove_expired_lock() ? true : false;
153
+	}
154
+
155
+
156
+	/**
157
+	 * Gets the meta field indicating that this TXN is locked
158
+	 *
159
+	 * @return int
160
+	 * @throws EE_Error
161
+	 * @throws InvalidArgumentException
162
+	 * @throws InvalidDataTypeException
163
+	 * @throws InvalidInterfaceException
164
+	 * @throws ReflectionException
165
+	 */
166
+	protected function _get_lock()
167
+	{
168
+		return (int) $this->get_extra_meta('lock', true, 0);
169
+	}
170
+
171
+
172
+	/**
173
+	 * If the lock on this transaction is expired, then we want to remove it so that the transaction can be updated
174
+	 *
175
+	 * @return int
176
+	 * @throws EE_Error
177
+	 * @throws InvalidArgumentException
178
+	 * @throws InvalidDataTypeException
179
+	 * @throws InvalidInterfaceException
180
+	 * @throws ReflectionException
181
+	 */
182
+	protected function _remove_expired_lock()
183
+	{
184
+		$locked = $this->_get_lock();
185
+		if ($locked && time() - EE_Transaction::LOCK_EXPIRATION > $locked) {
186
+			return $this->unlock();
187
+		}
188
+		return 0;
189
+	}
190
+
191
+
192
+	/**
193
+	 * Set transaction total
194
+	 *
195
+	 * @param float $total total value of transaction
196
+	 * @throws EE_Error
197
+	 * @throws InvalidArgumentException
198
+	 * @throws InvalidDataTypeException
199
+	 * @throws InvalidInterfaceException
200
+	 * @throws ReflectionException
201
+	 */
202
+	public function set_total($total = 0.00)
203
+	{
204
+		$this->set('TXN_total', (float) $total);
205
+	}
206
+
207
+
208
+	/**
209
+	 * Set Total Amount Paid to Date
210
+	 *
211
+	 * @param float $total_paid total amount paid to date (sum of all payments)
212
+	 * @throws EE_Error
213
+	 * @throws InvalidArgumentException
214
+	 * @throws InvalidDataTypeException
215
+	 * @throws InvalidInterfaceException
216
+	 * @throws ReflectionException
217
+	 */
218
+	public function set_paid($total_paid = 0.00)
219
+	{
220
+		$this->set('TXN_paid', (float) $total_paid);
221
+	}
222
+
223
+
224
+	/**
225
+	 * Set transaction status
226
+	 *
227
+	 * @param string $status        whether the transaction is open, declined, accepted,
228
+	 *                              or any number of custom values that can be set
229
+	 * @throws EE_Error
230
+	 * @throws InvalidArgumentException
231
+	 * @throws InvalidDataTypeException
232
+	 * @throws InvalidInterfaceException
233
+	 * @throws ReflectionException
234
+	 */
235
+	public function set_status($status = '')
236
+	{
237
+		$this->set('STS_ID', $status);
238
+	}
239
+
240
+
241
+	/**
242
+	 * Set hash salt
243
+	 *
244
+	 * @param string $hash_salt required for some payment gateways
245
+	 * @throws EE_Error
246
+	 * @throws InvalidArgumentException
247
+	 * @throws InvalidDataTypeException
248
+	 * @throws InvalidInterfaceException
249
+	 * @throws ReflectionException
250
+	 */
251
+	public function set_hash_salt($hash_salt = '')
252
+	{
253
+		$this->set('TXN_hash_salt', $hash_salt);
254
+	}
255
+
256
+
257
+	/**
258
+	 * Sets TXN_reg_steps array
259
+	 *
260
+	 * @param array $txn_reg_steps
261
+	 * @throws EE_Error
262
+	 * @throws InvalidArgumentException
263
+	 * @throws InvalidDataTypeException
264
+	 * @throws InvalidInterfaceException
265
+	 * @throws ReflectionException
266
+	 */
267
+	public function set_reg_steps(array $txn_reg_steps)
268
+	{
269
+		$this->set('TXN_reg_steps', $txn_reg_steps);
270
+	}
271
+
272
+
273
+	/**
274
+	 * Gets TXN_reg_steps
275
+	 *
276
+	 * @return array
277
+	 * @throws EE_Error
278
+	 * @throws InvalidArgumentException
279
+	 * @throws InvalidDataTypeException
280
+	 * @throws InvalidInterfaceException
281
+	 * @throws ReflectionException
282
+	 */
283
+	public function reg_steps()
284
+	{
285
+		$TXN_reg_steps = $this->get('TXN_reg_steps');
286
+		return is_array($TXN_reg_steps) ? $TXN_reg_steps : [];
287
+	}
288
+
289
+
290
+	/**
291
+	 * @return string of transaction's total cost, with currency symbol and decimal
292
+	 * @throws EE_Error
293
+	 * @throws InvalidArgumentException
294
+	 * @throws InvalidDataTypeException
295
+	 * @throws InvalidInterfaceException
296
+	 * @throws ReflectionException
297
+	 */
298
+	public function pretty_total()
299
+	{
300
+		return $this->get_pretty('TXN_total');
301
+	}
302
+
303
+
304
+	/**
305
+	 * Gets the amount paid in a pretty string (formatted and with currency symbol)
306
+	 *
307
+	 * @return string
308
+	 * @throws EE_Error
309
+	 * @throws InvalidArgumentException
310
+	 * @throws InvalidDataTypeException
311
+	 * @throws InvalidInterfaceException
312
+	 * @throws ReflectionException
313
+	 */
314
+	public function pretty_paid()
315
+	{
316
+		return $this->get_pretty('TXN_paid');
317
+	}
318
+
319
+
320
+	/**
321
+	 * calculate the amount remaining for this transaction and return;
322
+	 *
323
+	 * @return float amount remaining
324
+	 * @throws EE_Error
325
+	 * @throws InvalidArgumentException
326
+	 * @throws InvalidDataTypeException
327
+	 * @throws InvalidInterfaceException
328
+	 * @throws ReflectionException
329
+	 */
330
+	public function remaining()
331
+	{
332
+		return $this->total() - $this->paid();
333
+	}
334
+
335
+
336
+	/**
337
+	 * get Transaction Total
338
+	 *
339
+	 * @return float
340
+	 * @throws EE_Error
341
+	 * @throws InvalidArgumentException
342
+	 * @throws InvalidDataTypeException
343
+	 * @throws InvalidInterfaceException
344
+	 * @throws ReflectionException
345
+	 */
346
+	public function total()
347
+	{
348
+		return (float) $this->get('TXN_total');
349
+	}
350
+
351
+
352
+	/**
353
+	 * get Total Amount Paid to Date
354
+	 *
355
+	 * @return float
356
+	 * @throws EE_Error
357
+	 * @throws InvalidArgumentException
358
+	 * @throws InvalidDataTypeException
359
+	 * @throws InvalidInterfaceException
360
+	 * @throws ReflectionException
361
+	 */
362
+	public function paid()
363
+	{
364
+		return (float) $this->get('TXN_paid');
365
+	}
366
+
367
+
368
+	/**
369
+	 * @return mixed|null
370
+	 * @throws EE_Error
371
+	 * @throws InvalidArgumentException
372
+	 * @throws InvalidDataTypeException
373
+	 * @throws InvalidInterfaceException
374
+	 * @throws ReflectionException
375
+	 */
376
+	public function get_cart_session()
377
+	{
378
+		$session_data = (array) $this->get('TXN_session_data');
379
+		return isset($session_data['cart']) && $session_data['cart'] instanceof EE_Cart
380
+			? $session_data['cart']
381
+			: null;
382
+	}
383
+
384
+
385
+	/**
386
+	 * get Transaction session data
387
+	 *
388
+	 * @return array|mixed
389
+	 * @throws EE_Error
390
+	 * @throws InvalidArgumentException
391
+	 * @throws InvalidDataTypeException
392
+	 * @throws InvalidInterfaceException
393
+	 * @throws ReflectionException
394
+	 */
395
+	public function session_data()
396
+	{
397
+		$session_data = $this->get('TXN_session_data');
398
+		if (empty($session_data)) {
399
+			$session_data = [
400
+				'id'            => null,
401
+				'user_id'       => null,
402
+				'ip_address'    => null,
403
+				'user_agent'    => null,
404
+				'init_access'   => null,
405
+				'last_access'   => null,
406
+				'pages_visited' => [],
407
+			];
408
+		}
409
+		return $session_data;
410
+	}
411
+
412
+
413
+	/**
414
+	 * Set session data within the TXN object
415
+	 *
416
+	 * @param EE_Session|array $session_data
417
+	 * @throws EE_Error
418
+	 * @throws InvalidArgumentException
419
+	 * @throws InvalidDataTypeException
420
+	 * @throws InvalidInterfaceException
421
+	 * @throws ReflectionException
422
+	 */
423
+	public function set_txn_session_data($session_data)
424
+	{
425
+		if ($session_data instanceof EE_Session) {
426
+			$this->set('TXN_session_data', $session_data->get_session_data(null, true));
427
+		} else {
428
+			$this->set('TXN_session_data', $session_data);
429
+		}
430
+	}
431
+
432
+
433
+	/**
434
+	 * get Transaction hash salt
435
+	 *
436
+	 * @return mixed
437
+	 * @throws EE_Error
438
+	 * @throws InvalidArgumentException
439
+	 * @throws InvalidDataTypeException
440
+	 * @throws InvalidInterfaceException
441
+	 * @throws ReflectionException
442
+	 */
443
+	public function hash_salt_()
444
+	{
445
+		return $this->get('TXN_hash_salt');
446
+	}
447
+
448
+
449
+	/**
450
+	 * Returns the transaction datetime as either:
451
+	 *            - unix timestamp format ($format = false, $gmt = true)
452
+	 *            - formatted date string including the UTC (timezone) offset ($format = true ($gmt
453
+	 *              has no affect with this option)), this also may include a timezone abbreviation if the
454
+	 *              set timezone in this class differs from what the timezone is on the blog.
455
+	 *            - formatted date string including the UTC (timezone) offset (default).
456
+	 *
457
+	 * @param boolean $format   - whether to return a unix timestamp (default) or formatted date string
458
+	 * @param boolean $gmt      - whether to return a unix timestamp with UTC offset applied (default)
459
+	 *                          or no UTC offset applied
460
+	 * @return string | int
461
+	 * @throws EE_Error
462
+	 * @throws InvalidArgumentException
463
+	 * @throws InvalidDataTypeException
464
+	 * @throws InvalidInterfaceException
465
+	 * @throws ReflectionException
466
+	 */
467
+	public function datetime($format = false, $gmt = false)
468
+	{
469
+		if ($format) {
470
+			return $this->get_pretty('TXN_timestamp');
471
+		}
472
+		if ($gmt) {
473
+			return $this->get_raw('TXN_timestamp');
474
+		}
475
+		return $this->get('TXN_timestamp');
476
+	}
477
+
478
+
479
+	/**
480
+	 * Gets registrations on this transaction
481
+	 *
482
+	 * @param array   $query_params array of query parameters
483
+	 * @param boolean $get_cached   TRUE to retrieve cached registrations or FALSE to pull from the db
484
+	 * @return EE_Base_Class[]|EE_Registration[]
485
+	 * @throws EE_Error
486
+	 * @throws InvalidArgumentException
487
+	 * @throws InvalidDataTypeException
488
+	 * @throws InvalidInterfaceException
489
+	 * @throws ReflectionException
490
+	 */
491
+	public function registrations($query_params = [], $get_cached = false)
492
+	{
493
+		$query_params = (empty($query_params) || ! is_array($query_params))
494
+			? [
495
+				'order_by' => [
496
+					'Event.EVT_name'     => 'ASC',
497
+					'Attendee.ATT_lname' => 'ASC',
498
+					'Attendee.ATT_fname' => 'ASC',
499
+				],
500
+			]
501
+			: $query_params;
502
+		$query_params = $get_cached ? [] : $query_params;
503
+		return $this->get_many_related('Registration', $query_params);
504
+	}
505
+
506
+
507
+	/**
508
+	 * Gets all the attendees for this transaction (handy for use with EE_Attendee's get_registrations_for_event
509
+	 * function for getting attendees and how many registrations they each have for an event)
510
+	 *
511
+	 * @return mixed EE_Attendee[] by default, int if $output is set to 'COUNT'
512
+	 * @throws EE_Error
513
+	 * @throws InvalidArgumentException
514
+	 * @throws InvalidDataTypeException
515
+	 * @throws InvalidInterfaceException
516
+	 * @throws ReflectionException
517
+	 */
518
+	public function attendees()
519
+	{
520
+		return $this->get_many_related('Attendee', [['Registration.Transaction.TXN_ID' => $this->ID()]]);
521
+	}
522
+
523
+
524
+	/**
525
+	 * Gets payments for this transaction. Unlike other such functions, order by 'DESC' by default
526
+	 *
527
+	 * @param array $query_params @see
528
+	 *                            https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
529
+	 * @return EE_Base_Class[]|EE_Payment[]
530
+	 * @throws EE_Error
531
+	 * @throws InvalidArgumentException
532
+	 * @throws InvalidDataTypeException
533
+	 * @throws InvalidInterfaceException
534
+	 * @throws ReflectionException
535
+	 */
536
+	public function payments($query_params = [])
537
+	{
538
+		return $this->get_many_related('Payment', $query_params);
539
+	}
540
+
541
+
542
+	/**
543
+	 * gets only approved payments for this transaction
544
+	 *
545
+	 * @return EE_Base_Class[]|EE_Payment[]
546
+	 * @throws EE_Error
547
+	 * @throws InvalidArgumentException
548
+	 * @throws ReflectionException
549
+	 * @throws InvalidDataTypeException
550
+	 * @throws InvalidInterfaceException
551
+	 */
552
+	public function approved_payments()
553
+	{
554
+		EE_Registry::instance()->load_model('Payment');
555
+		return $this->get_many_related(
556
+			'Payment',
557
+			[
558
+				['STS_ID' => EEM_Payment::status_id_approved],
559
+				'order_by' => ['PAY_timestamp' => 'DESC'],
560
+			]
561
+		);
562
+	}
563
+
564
+
565
+	/**
566
+	 * Gets all payments which have not been approved
567
+	 *
568
+	 * @return EE_Base_Class[]|EEI_Payment[]
569
+	 * @throws EE_Error if a model is misconfigured somehow
570
+	 * @throws InvalidArgumentException
571
+	 * @throws InvalidDataTypeException
572
+	 * @throws InvalidInterfaceException
573
+	 * @throws ReflectionException
574
+	 */
575
+	public function pending_payments()
576
+	{
577
+		return $this->get_many_related(
578
+			'Payment',
579
+			[
580
+				[
581
+					'STS_ID' => EEM_Payment::status_id_pending,
582
+				],
583
+				'order_by' => [
584
+					'PAY_timestamp' => 'DESC',
585
+				],
586
+			]
587
+		);
588
+	}
589
+
590
+
591
+	/**
592
+	 * echoes $this->pretty_status()
593
+	 *
594
+	 * @param bool $show_icons
595
+	 * @throws EE_Error
596
+	 * @throws InvalidArgumentException
597
+	 * @throws InvalidDataTypeException
598
+	 * @throws InvalidInterfaceException
599
+	 * @throws ReflectionException
600
+	 */
601
+	public function e_pretty_status($show_icons = false)
602
+	{
603
+		echo wp_kses($this->pretty_status($show_icons), AllowedTags::getAllowedTags());
604
+	}
605
+
606
+
607
+	/**
608
+	 * returns a pretty version of the status, good for displaying to users
609
+	 *
610
+	 * @param bool $show_icons
611
+	 * @return string
612
+	 * @throws EE_Error
613
+	 * @throws InvalidArgumentException
614
+	 * @throws InvalidDataTypeException
615
+	 * @throws InvalidInterfaceException
616
+	 * @throws ReflectionException
617
+	 */
618
+	public function pretty_status($show_icons = false)
619
+	{
620
+		$status = EEM_Status::instance()->localized_status(
621
+			[$this->status_ID() => esc_html__('unknown', 'event_espresso')],
622
+			false,
623
+			'sentence'
624
+		);
625
+		$icon   = '';
626
+		switch ($this->status_ID()) {
627
+			case EEM_Transaction::complete_status_code:
628
+				$icon = $show_icons ? '<span class="dashicons dashicons-yes ee-icon-size-24 green-text"></span>' : '';
629
+				break;
630
+			case EEM_Transaction::incomplete_status_code:
631
+				$icon = $show_icons ? '<span class="dashicons dashicons-marker ee-icon-size-16 lt-blue-text"></span>'
632
+					: '';
633
+				break;
634
+			case EEM_Transaction::abandoned_status_code:
635
+				$icon = $show_icons ? '<span class="dashicons dashicons-marker ee-icon-size-16 red-text"></span>' : '';
636
+				break;
637
+			case EEM_Transaction::failed_status_code:
638
+				$icon = $show_icons ? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>' : '';
639
+				break;
640
+			case EEM_Transaction::overpaid_status_code:
641
+				$icon = $show_icons ? '<span class="dashicons dashicons-plus ee-icon-size-16 orange-text"></span>' : '';
642
+				break;
643
+		}
644
+		return $icon . $status[ $this->status_ID() ];
645
+	}
646
+
647
+
648
+	/**
649
+	 * get Transaction Status
650
+	 *
651
+	 * @return mixed
652
+	 * @throws EE_Error
653
+	 * @throws InvalidArgumentException
654
+	 * @throws InvalidDataTypeException
655
+	 * @throws InvalidInterfaceException
656
+	 * @throws ReflectionException
657
+	 */
658
+	public function status_ID()
659
+	{
660
+		return $this->get('STS_ID');
661
+	}
662
+
663
+
664
+	/**
665
+	 * Returns TRUE or FALSE for whether or not this transaction cost any money
666
+	 *
667
+	 * @return boolean
668
+	 * @throws EE_Error
669
+	 * @throws InvalidArgumentException
670
+	 * @throws InvalidDataTypeException
671
+	 * @throws InvalidInterfaceException
672
+	 * @throws ReflectionException
673
+	 */
674
+	public function is_free()
675
+	{
676
+		return EEH_Money::compare_floats($this->get('TXN_total'), 0, '==');
677
+	}
678
+
679
+
680
+	/**
681
+	 * Returns whether this transaction is complete
682
+	 * Useful in templates and other logic for deciding if we should ask for another payment...
683
+	 *
684
+	 * @return boolean
685
+	 * @throws EE_Error
686
+	 * @throws InvalidArgumentException
687
+	 * @throws InvalidDataTypeException
688
+	 * @throws InvalidInterfaceException
689
+	 * @throws ReflectionException
690
+	 */
691
+	public function is_completed()
692
+	{
693
+		return $this->status_ID() === EEM_Transaction::complete_status_code;
694
+	}
695
+
696
+
697
+	/**
698
+	 * Returns whether this transaction is incomplete
699
+	 * Useful in templates and other logic for deciding if we should ask for another payment...
700
+	 *
701
+	 * @return boolean
702
+	 * @throws EE_Error
703
+	 * @throws InvalidArgumentException
704
+	 * @throws InvalidDataTypeException
705
+	 * @throws InvalidInterfaceException
706
+	 * @throws ReflectionException
707
+	 */
708
+	public function is_incomplete()
709
+	{
710
+		return $this->status_ID() === EEM_Transaction::incomplete_status_code;
711
+	}
712
+
713
+
714
+	/**
715
+	 * Returns whether this transaction is overpaid
716
+	 * Useful in templates and other logic for deciding if monies need to be refunded
717
+	 *
718
+	 * @return boolean
719
+	 * @throws EE_Error
720
+	 * @throws InvalidArgumentException
721
+	 * @throws InvalidDataTypeException
722
+	 * @throws InvalidInterfaceException
723
+	 * @throws ReflectionException
724
+	 */
725
+	public function is_overpaid()
726
+	{
727
+		return $this->status_ID() === EEM_Transaction::overpaid_status_code;
728
+	}
729
+
730
+
731
+	/**
732
+	 * Returns whether this transaction was abandoned
733
+	 * meaning that the transaction/registration process was somehow interrupted and never completed
734
+	 * but that contact information exists for at least one registrant
735
+	 *
736
+	 * @return boolean
737
+	 * @throws EE_Error
738
+	 * @throws InvalidArgumentException
739
+	 * @throws InvalidDataTypeException
740
+	 * @throws InvalidInterfaceException
741
+	 * @throws ReflectionException
742
+	 */
743
+	public function is_abandoned()
744
+	{
745
+		return $this->status_ID() === EEM_Transaction::abandoned_status_code;
746
+	}
747
+
748
+
749
+	/**
750
+	 * Returns whether this transaction failed
751
+	 * meaning that the transaction/registration process was somehow interrupted and never completed
752
+	 * and that NO contact information exists for any registrants
753
+	 *
754
+	 * @return boolean
755
+	 * @throws EE_Error
756
+	 * @throws InvalidArgumentException
757
+	 * @throws InvalidDataTypeException
758
+	 * @throws InvalidInterfaceException
759
+	 * @throws ReflectionException
760
+	 */
761
+	public function failed()
762
+	{
763
+		return $this->status_ID() === EEM_Transaction::failed_status_code;
764
+	}
765
+
766
+
767
+	/**
768
+	 * This returns the url for the invoice of this transaction
769
+	 *
770
+	 * @param string $type 'html' or 'pdf' (default is pdf)
771
+	 * @return string
772
+	 * @throws DomainException
773
+	 * @throws EE_Error
774
+	 * @throws InvalidArgumentException
775
+	 * @throws InvalidDataTypeException
776
+	 * @throws InvalidInterfaceException
777
+	 * @throws ReflectionException
778
+	 */
779
+	public function invoice_url($type = 'html')
780
+	{
781
+		$REG = $this->primary_registration();
782
+		if (! $REG instanceof EE_Registration) {
783
+			return '';
784
+		}
785
+		return $REG->invoice_url($type);
786
+	}
787
+
788
+
789
+	/**
790
+	 * Gets the primary registration only
791
+	 *
792
+	 * @return EE_Base_Class|EE_Registration
793
+	 * @throws EE_Error
794
+	 * @throws InvalidArgumentException
795
+	 * @throws InvalidDataTypeException
796
+	 * @throws InvalidInterfaceException
797
+	 * @throws ReflectionException
798
+	 */
799
+	public function primary_registration()
800
+	{
801
+		$registrations = (array) $this->get_many_related(
802
+			'Registration',
803
+			[['REG_count' => EEM_Registration::PRIMARY_REGISTRANT_COUNT]]
804
+		);
805
+		foreach ($registrations as $registration) {
806
+			// valid registration that is NOT cancelled or declined ?
807
+			if (
808
+				$registration instanceof EE_Registration
809
+				&& ! in_array($registration->status_ID(), EEM_Registration::closed_reg_statuses(), true)
810
+			) {
811
+				return $registration;
812
+			}
813
+		}
814
+		// nothing valid found, so just return first thing from array of results
815
+		return reset($registrations);
816
+	}
817
+
818
+
819
+	/**
820
+	 * Gets the URL for viewing the receipt
821
+	 *
822
+	 * @param string $type 'pdf' or 'html' (default is 'html')
823
+	 * @return string
824
+	 * @throws DomainException
825
+	 * @throws EE_Error
826
+	 * @throws InvalidArgumentException
827
+	 * @throws InvalidDataTypeException
828
+	 * @throws InvalidInterfaceException
829
+	 * @throws ReflectionException
830
+	 */
831
+	public function receipt_url($type = 'html')
832
+	{
833
+		$REG = $this->primary_registration();
834
+		if (! $REG instanceof EE_Registration) {
835
+			return '';
836
+		}
837
+		return $REG->receipt_url($type);
838
+	}
839
+
840
+
841
+	/**
842
+	 * Gets the URL of the thank you page with this registration REG_url_link added as
843
+	 * a query parameter
844
+	 *
845
+	 * @return string
846
+	 * @throws EE_Error
847
+	 * @throws InvalidArgumentException
848
+	 * @throws InvalidDataTypeException
849
+	 * @throws InvalidInterfaceException
850
+	 * @throws ReflectionException
851
+	 */
852
+	public function payment_overview_url()
853
+	{
854
+		$primary_registration = $this->primary_registration();
855
+		return $primary_registration instanceof EE_Registration ? $primary_registration->payment_overview_url() : false;
856
+	}
857
+
858
+
859
+	/**
860
+	 * @return string
861
+	 * @throws EE_Error
862
+	 * @throws InvalidArgumentException
863
+	 * @throws InvalidDataTypeException
864
+	 * @throws InvalidInterfaceException
865
+	 * @throws ReflectionException
866
+	 */
867
+	public function gateway_response_on_transaction()
868
+	{
869
+		$payment = $this->get_first_related('Payment');
870
+		return $payment instanceof EE_Payment ? $payment->gateway_response() : '';
871
+	}
872
+
873
+
874
+	/**
875
+	 * Get the status object of this object
876
+	 *
877
+	 * @return EE_Base_Class|EE_Status
878
+	 * @throws EE_Error
879
+	 * @throws InvalidArgumentException
880
+	 * @throws InvalidDataTypeException
881
+	 * @throws InvalidInterfaceException
882
+	 * @throws ReflectionException
883
+	 */
884
+	public function status_obj()
885
+	{
886
+		return $this->get_first_related('Status');
887
+	}
888
+
889
+
890
+	/**
891
+	 * Gets all the extra meta info on this payment
892
+	 *
893
+	 * @param array $query_params
894
+	 * @return EE_Base_Class[]|EE_Extra_Meta
895
+	 * @throws EE_Error
896
+	 * @throws InvalidArgumentException
897
+	 * @throws InvalidDataTypeException
898
+	 * @throws InvalidInterfaceException
899
+	 * @throws ReflectionException
900
+	 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
901
+	 */
902
+	public function extra_meta($query_params = [])
903
+	{
904
+		return $this->get_many_related('Extra_Meta', $query_params);
905
+	}
906
+
907
+
908
+	/**
909
+	 * Wrapper for _add_relation_to
910
+	 *
911
+	 * @param EE_Registration $registration
912
+	 * @return EE_Base_Class the relation was added to
913
+	 * @throws EE_Error
914
+	 * @throws InvalidArgumentException
915
+	 * @throws InvalidDataTypeException
916
+	 * @throws InvalidInterfaceException
917
+	 * @throws ReflectionException
918
+	 */
919
+	public function add_registration(EE_Registration $registration)
920
+	{
921
+		return $this->_add_relation_to($registration, 'Registration');
922
+	}
923
+
924
+
925
+	/**
926
+	 * Removes the given registration from being related (even before saving this transaction).
927
+	 * If an ID/index is provided and this transaction isn't saved yet, removes it from list of cached relations
928
+	 *
929
+	 * @param int $registration_or_id
930
+	 * @return EE_Base_Class that was removed from being related
931
+	 * @throws EE_Error
932
+	 * @throws InvalidArgumentException
933
+	 * @throws InvalidDataTypeException
934
+	 * @throws InvalidInterfaceException
935
+	 * @throws ReflectionException
936
+	 */
937
+	public function remove_registration_with_id($registration_or_id)
938
+	{
939
+		return $this->_remove_relation_to($registration_or_id, 'Registration');
940
+	}
941
+
942
+
943
+	/**
944
+	 * Gets all the line items which are for ACTUAL items
945
+	 *
946
+	 * @return EE_Line_Item[]
947
+	 * @throws EE_Error
948
+	 * @throws InvalidArgumentException
949
+	 * @throws InvalidDataTypeException
950
+	 * @throws InvalidInterfaceException
951
+	 * @throws ReflectionException
952
+	 */
953
+	public function items_purchased()
954
+	{
955
+		return $this->line_items([['LIN_type' => EEM_Line_Item::type_line_item]]);
956
+	}
957
+
958
+
959
+	/**
960
+	 * Wrapper for _add_relation_to
961
+	 *
962
+	 * @param EE_Line_Item $line_item
963
+	 * @return EE_Base_Class the relation was added to
964
+	 * @throws EE_Error
965
+	 * @throws InvalidArgumentException
966
+	 * @throws InvalidDataTypeException
967
+	 * @throws InvalidInterfaceException
968
+	 * @throws ReflectionException
969
+	 */
970
+	public function add_line_item(EE_Line_Item $line_item)
971
+	{
972
+		return $this->_add_relation_to($line_item, 'Line_Item');
973
+	}
974
+
975
+
976
+	/**
977
+	 * Gets ALL the line items related to this transaction (unstructured)
978
+	 *
979
+	 * @param array $query_params
980
+	 * @return EE_Base_Class[]|EE_Line_Item[]
981
+	 * @throws EE_Error
982
+	 * @throws InvalidArgumentException
983
+	 * @throws InvalidDataTypeException
984
+	 * @throws InvalidInterfaceException
985
+	 * @throws ReflectionException
986
+	 */
987
+	public function line_items($query_params = [])
988
+	{
989
+		return $this->get_many_related('Line_Item', $query_params);
990
+	}
991
+
992
+
993
+	/**
994
+	 * Gets all the line items which are taxes on the total
995
+	 *
996
+	 * @return EE_Line_Item[]
997
+	 * @throws EE_Error
998
+	 * @throws InvalidArgumentException
999
+	 * @throws InvalidDataTypeException
1000
+	 * @throws InvalidInterfaceException
1001
+	 * @throws ReflectionException
1002
+	 */
1003
+	public function tax_items()
1004
+	{
1005
+		return $this->line_items([['LIN_type' => EEM_Line_Item::type_tax]]);
1006
+	}
1007
+
1008
+
1009
+	/**
1010
+	 * Gets the total line item (which is a parent of all other related line items,
1011
+	 * meaning it takes them all into account on its total)
1012
+	 *
1013
+	 * @param bool $create_if_not_found
1014
+	 * @return \EE_Line_Item
1015
+	 * @throws EE_Error
1016
+	 * @throws InvalidArgumentException
1017
+	 * @throws InvalidDataTypeException
1018
+	 * @throws InvalidInterfaceException
1019
+	 * @throws ReflectionException
1020
+	 */
1021
+	public function total_line_item($create_if_not_found = true)
1022
+	{
1023
+		$item = $this->get_first_related('Line_Item', [['LIN_type' => EEM_Line_Item::type_total]]);
1024
+		if (! $item && $create_if_not_found) {
1025
+			$item = EEH_Line_Item::create_total_line_item($this);
1026
+		}
1027
+		return $item;
1028
+	}
1029
+
1030
+
1031
+	/**
1032
+	 * Returns the total amount of tax on this transaction
1033
+	 * (assumes there's only one tax subtotal line item)
1034
+	 *
1035
+	 * @return float
1036
+	 * @throws EE_Error
1037
+	 * @throws InvalidArgumentException
1038
+	 * @throws InvalidDataTypeException
1039
+	 * @throws InvalidInterfaceException
1040
+	 * @throws ReflectionException
1041
+	 */
1042
+	public function tax_total()
1043
+	{
1044
+		$tax_line_item = $this->tax_total_line_item();
1045
+		if ($tax_line_item) {
1046
+			return (float) $tax_line_item->total();
1047
+		}
1048
+		return (float) 0;
1049
+	}
1050
+
1051
+
1052
+	/**
1053
+	 * Gets the tax subtotal line item (assumes there's only one)
1054
+	 *
1055
+	 * @return EE_Line_Item
1056
+	 * @throws EE_Error
1057
+	 * @throws InvalidArgumentException
1058
+	 * @throws InvalidDataTypeException
1059
+	 * @throws InvalidInterfaceException
1060
+	 * @throws ReflectionException
1061
+	 */
1062
+	public function tax_total_line_item()
1063
+	{
1064
+		return EEH_Line_Item::get_taxes_subtotal($this->total_line_item());
1065
+	}
1066
+
1067
+
1068
+	/**
1069
+	 * Gets the array of billing info for the gateway and for this transaction's primary registration's attendee.
1070
+	 *
1071
+	 * @return EE_Form_Section_Proper
1072
+	 * @throws EE_Error
1073
+	 * @throws InvalidArgumentException
1074
+	 * @throws InvalidDataTypeException
1075
+	 * @throws InvalidInterfaceException
1076
+	 * @throws ReflectionException
1077
+	 */
1078
+	public function billing_info()
1079
+	{
1080
+		$payment_method = $this->payment_method();
1081
+		if (! $payment_method) {
1082
+			EE_Error::add_error(
1083
+				esc_html__(
1084
+					'Could not find billing info for transaction because no gateway has been used for it yet',
1085
+					'event_espresso'
1086
+				),
1087
+				__FILE__,
1088
+				__FUNCTION__,
1089
+				__LINE__
1090
+			);
1091
+			return null;
1092
+		}
1093
+		$primary_reg = $this->primary_registration();
1094
+		if (! $primary_reg) {
1095
+			EE_Error::add_error(
1096
+				esc_html__(
1097
+					'Cannot get billing info for gateway %s on transaction because no primary registration exists',
1098
+					'event_espresso'
1099
+				),
1100
+				__FILE__,
1101
+				__FUNCTION__,
1102
+				__LINE__
1103
+			);
1104
+			return null;
1105
+		}
1106
+		$attendee = $primary_reg->attendee();
1107
+		if (! $attendee) {
1108
+			EE_Error::add_error(
1109
+				esc_html__(
1110
+					'Cannot get billing info for gateway %s on transaction because the primary registration has no attendee exists',
1111
+					'event_espresso'
1112
+				),
1113
+				__FILE__,
1114
+				__FUNCTION__,
1115
+				__LINE__
1116
+			);
1117
+			return null;
1118
+		}
1119
+		return $attendee->billing_info_for_payment_method($payment_method);
1120
+	}
1121
+
1122
+
1123
+	/**
1124
+	 * Gets PMD_ID
1125
+	 *
1126
+	 * @return int
1127
+	 * @throws EE_Error
1128
+	 * @throws InvalidArgumentException
1129
+	 * @throws InvalidDataTypeException
1130
+	 * @throws InvalidInterfaceException
1131
+	 * @throws ReflectionException
1132
+	 */
1133
+	public function payment_method_ID()
1134
+	{
1135
+		return $this->get('PMD_ID');
1136
+	}
1137
+
1138
+
1139
+	/**
1140
+	 * Sets PMD_ID
1141
+	 *
1142
+	 * @param int $PMD_ID
1143
+	 * @throws EE_Error
1144
+	 * @throws InvalidArgumentException
1145
+	 * @throws InvalidDataTypeException
1146
+	 * @throws InvalidInterfaceException
1147
+	 * @throws ReflectionException
1148
+	 */
1149
+	public function set_payment_method_ID($PMD_ID)
1150
+	{
1151
+		$this->set('PMD_ID', $PMD_ID);
1152
+	}
1153
+
1154
+
1155
+	/**
1156
+	 * Gets the last-used payment method on this transaction
1157
+	 * (we COULD just use the last-made payment, but some payment methods, namely
1158
+	 * offline ones, dont' create payments)
1159
+	 *
1160
+	 * @return EE_Payment_Method
1161
+	 * @throws EE_Error
1162
+	 * @throws InvalidArgumentException
1163
+	 * @throws InvalidDataTypeException
1164
+	 * @throws InvalidInterfaceException
1165
+	 * @throws ReflectionException
1166
+	 */
1167
+	public function payment_method()
1168
+	{
1169
+		$pm = $this->get_first_related('Payment_Method');
1170
+		if ($pm instanceof EE_Payment_Method) {
1171
+			return $pm;
1172
+		}
1173
+		$last_payment = $this->last_payment();
1174
+		if ($last_payment instanceof EE_Payment && $last_payment->payment_method()) {
1175
+			return $last_payment->payment_method();
1176
+		}
1177
+		return null;
1178
+	}
1179
+
1180
+
1181
+	/**
1182
+	 * Gets the last payment made
1183
+	 *
1184
+	 * @return EE_Base_Class|EE_Payment
1185
+	 * @throws EE_Error
1186
+	 * @throws InvalidArgumentException
1187
+	 * @throws InvalidDataTypeException
1188
+	 * @throws InvalidInterfaceException
1189
+	 * @throws ReflectionException
1190
+	 */
1191
+	public function last_payment()
1192
+	{
1193
+		return $this->get_first_related('Payment', ['order_by' => ['PAY_ID' => 'desc']]);
1194
+	}
1195
+
1196
+
1197
+	/**
1198
+	 * Gets all the line items which are unrelated to tickets on this transaction
1199
+	 *
1200
+	 * @return EE_Line_Item[]
1201
+	 * @throws EE_Error
1202
+	 * @throws InvalidArgumentException
1203
+	 * @throws InvalidDataTypeException
1204
+	 * @throws InvalidInterfaceException
1205
+	 * @throws ReflectionException
1206
+	 */
1207
+	public function non_ticket_line_items()
1208
+	{
1209
+		return EEM_Line_Item::instance()->get_all_non_ticket_line_items_for_transaction($this->ID());
1210
+	}
1211
+
1212
+
1213
+	/**
1214
+	 * possibly toggles TXN status
1215
+	 *
1216
+	 * @param boolean $update whether to save the TXN
1217
+	 * @return bool whether the TXN was saved
1218
+	 * @throws EE_Error
1219
+	 * @throws InvalidArgumentException
1220
+	 * @throws InvalidDataTypeException
1221
+	 * @throws InvalidInterfaceException
1222
+	 * @throws ReflectionException
1223
+	 * @throws RuntimeException
1224
+	 */
1225
+	public function update_status_based_on_total_paid($update = true)
1226
+	{
1227
+		// set transaction status based on comparison of TXN_paid vs TXN_total
1228
+		if (EEH_Money::compare_floats($this->paid(), $this->total(), '>')) {
1229
+			$new_txn_status = EEM_Transaction::overpaid_status_code;
1230
+		} elseif (EEH_Money::compare_floats($this->paid(), $this->total())) {
1231
+			$new_txn_status = EEM_Transaction::complete_status_code;
1232
+		} elseif (EEH_Money::compare_floats($this->paid(), $this->total(), '<')) {
1233
+			$new_txn_status = EEM_Transaction::incomplete_status_code;
1234
+		} else {
1235
+			throw new RuntimeException(
1236
+				esc_html__('The total paid calculation for this transaction is inaccurate.', 'event_espresso')
1237
+			);
1238
+		}
1239
+		if ($new_txn_status !== $this->status_ID()) {
1240
+			$this->set_status($new_txn_status);
1241
+			if ($update) {
1242
+				return (bool) $this->save();
1243
+			}
1244
+		}
1245
+		return false;
1246
+	}
1247
+
1248
+
1249
+	/**
1250
+	 * Updates the transaction's status and total_paid based on all the payments
1251
+	 * that apply to it
1252
+	 *
1253
+	 * @return array|bool
1254
+	 * @throws EE_Error
1255
+	 * @throws InvalidArgumentException
1256
+	 * @throws ReflectionException
1257
+	 * @throws InvalidDataTypeException
1258
+	 * @throws InvalidInterfaceException
1259
+	 * @deprecated
1260
+	 */
1261
+	public function update_based_on_payments()
1262
+	{
1263
+		EE_Error::doing_it_wrong(
1264
+			__CLASS__ . '::' . __FUNCTION__,
1265
+			sprintf(
1266
+				esc_html__('This method is deprecated. Please use "%s" instead', 'event_espresso'),
1267
+				'EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()'
1268
+			),
1269
+			'4.6.0'
1270
+		);
1271
+		/** @type EE_Transaction_Processor $transaction_processor */
1272
+		$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
1273
+		return $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment($this);
1274
+	}
1275
+
1276
+
1277
+	/**
1278
+	 * @return string
1279
+	 */
1280
+	public function old_txn_status()
1281
+	{
1282
+		return $this->_old_txn_status;
1283
+	}
1284
+
1285
+
1286
+	/**
1287
+	 * @param string $old_txn_status
1288
+	 */
1289
+	public function set_old_txn_status($old_txn_status)
1290
+	{
1291
+		// only set the first time
1292
+		if ($this->_old_txn_status === null) {
1293
+			$this->_old_txn_status = $old_txn_status;
1294
+		}
1295
+	}
1296
+
1297
+
1298
+	/**
1299
+	 * reg_status_updated
1300
+	 *
1301
+	 * @return bool
1302
+	 * @throws EE_Error
1303
+	 * @throws InvalidArgumentException
1304
+	 * @throws InvalidDataTypeException
1305
+	 * @throws InvalidInterfaceException
1306
+	 * @throws ReflectionException
1307
+	 */
1308
+	public function txn_status_updated()
1309
+	{
1310
+		return $this->status_ID() !== $this->_old_txn_status && $this->_old_txn_status !== null;
1311
+	}
1312
+
1313
+
1314
+	/**
1315
+	 * _reg_steps_completed
1316
+	 * if $check_all is TRUE, then returns TRUE if ALL reg steps have been marked as completed,
1317
+	 * if a $reg_step_slug is provided, then this step will be skipped when testing for completion
1318
+	 * if $check_all is FALSE and a $reg_step_slug is provided, then ONLY that reg step will be tested for completion
1319
+	 *
1320
+	 * @param string $reg_step_slug
1321
+	 * @param bool   $check_all
1322
+	 * @return bool|int
1323
+	 * @throws EE_Error
1324
+	 * @throws InvalidArgumentException
1325
+	 * @throws InvalidDataTypeException
1326
+	 * @throws InvalidInterfaceException
1327
+	 * @throws ReflectionException
1328
+	 */
1329
+	private function _reg_steps_completed($reg_step_slug = '', $check_all = true)
1330
+	{
1331
+		$reg_steps = $this->reg_steps();
1332
+		if (! is_array($reg_steps) || empty($reg_steps)) {
1333
+			return false;
1334
+		}
1335
+		// loop thru reg steps array)
1336
+		foreach ($reg_steps as $slug => $reg_step_completed) {
1337
+			// if NOT checking ALL steps (only checking one step)
1338
+			if (! $check_all) {
1339
+				// and this is the one
1340
+				if ($slug === $reg_step_slug) {
1341
+					return $reg_step_completed;
1342
+				}
1343
+				// skip to next reg step in loop
1344
+				continue;
1345
+			}
1346
+			// $check_all must be true, else we would never have gotten to this point
1347
+			if ($slug === $reg_step_slug) {
1348
+				// if we reach this point, then we are testing either:
1349
+				// all_reg_steps_completed_except() or
1350
+				// all_reg_steps_completed_except_final_step(),
1351
+				// and since this is the reg step EXCEPTION being tested
1352
+				// we want to return true (yes true) if this reg step is NOT completed
1353
+				// ie: "is everything completed except the final step?"
1354
+				// "that is correct... the final step is not completed, but all others are."
1355
+				return $reg_step_completed !== true;
1356
+			}
1357
+			if ($reg_step_completed !== true) {
1358
+				// if any reg step is NOT completed, then ALL steps are not completed
1359
+				return false;
1360
+			}
1361
+		}
1362
+		return true;
1363
+	}
1364
+
1365
+
1366
+	/**
1367
+	 * all_reg_steps_completed
1368
+	 * returns:
1369
+	 *    true if ALL reg steps have been marked as completed
1370
+	 *        or false if any step is not completed
1371
+	 *
1372
+	 * @return bool
1373
+	 * @throws EE_Error
1374
+	 * @throws InvalidArgumentException
1375
+	 * @throws InvalidDataTypeException
1376
+	 * @throws InvalidInterfaceException
1377
+	 * @throws ReflectionException
1378
+	 */
1379
+	public function all_reg_steps_completed()
1380
+	{
1381
+		return $this->_reg_steps_completed();
1382
+	}
1383
+
1384
+
1385
+	/**
1386
+	 * all_reg_steps_completed_except
1387
+	 * returns:
1388
+	 *        true if ALL reg steps, except a particular step that you wish to skip over, have been marked as completed
1389
+	 *        or false if any other step is not completed
1390
+	 *        or false if ALL steps are completed including the exception you are testing !!!
1391
+	 *
1392
+	 * @param string $exception
1393
+	 * @return bool
1394
+	 * @throws EE_Error
1395
+	 * @throws InvalidArgumentException
1396
+	 * @throws InvalidDataTypeException
1397
+	 * @throws InvalidInterfaceException
1398
+	 * @throws ReflectionException
1399
+	 */
1400
+	public function all_reg_steps_completed_except($exception = '')
1401
+	{
1402
+		return $this->_reg_steps_completed($exception);
1403
+	}
1404
+
1405
+
1406
+	/**
1407
+	 * all_reg_steps_completed_except
1408
+	 * returns:
1409
+	 *        true if ALL reg steps, except the final step, have been marked as completed
1410
+	 *        or false if any step is not completed
1411
+	 *    or false if ALL steps are completed including the final step !!!
1412
+	 *
1413
+	 * @return bool
1414
+	 * @throws EE_Error
1415
+	 * @throws InvalidArgumentException
1416
+	 * @throws InvalidDataTypeException
1417
+	 * @throws InvalidInterfaceException
1418
+	 * @throws ReflectionException
1419
+	 */
1420
+	public function all_reg_steps_completed_except_final_step()
1421
+	{
1422
+		return $this->_reg_steps_completed('finalize_registration');
1423
+	}
1424
+
1425
+
1426
+	/**
1427
+	 * reg_step_completed
1428
+	 * returns:
1429
+	 *    true if a specific reg step has been marked as completed
1430
+	 *    a Unix timestamp if it has been initialized but not yet completed,
1431
+	 *    or false if it has not yet been initialized
1432
+	 *
1433
+	 * @param string $reg_step_slug
1434
+	 * @return bool|int
1435
+	 * @throws EE_Error
1436
+	 * @throws InvalidArgumentException
1437
+	 * @throws InvalidDataTypeException
1438
+	 * @throws InvalidInterfaceException
1439
+	 * @throws ReflectionException
1440
+	 */
1441
+	public function reg_step_completed($reg_step_slug)
1442
+	{
1443
+		return $this->_reg_steps_completed($reg_step_slug, false);
1444
+	}
1445
+
1446
+
1447
+	/**
1448
+	 * completed_final_reg_step
1449
+	 * returns:
1450
+	 *    true if the finalize_registration reg step has been marked as completed
1451
+	 *    a Unix timestamp if it has been initialized but not yet completed,
1452
+	 *    or false if it has not yet been initialized
1453
+	 *
1454
+	 * @return bool|int
1455
+	 * @throws EE_Error
1456
+	 * @throws InvalidArgumentException
1457
+	 * @throws InvalidDataTypeException
1458
+	 * @throws InvalidInterfaceException
1459
+	 * @throws ReflectionException
1460
+	 */
1461
+	public function final_reg_step_completed()
1462
+	{
1463
+		return $this->_reg_steps_completed('finalize_registration', false);
1464
+	}
1465
+
1466
+
1467
+	/**
1468
+	 * set_reg_step_initiated
1469
+	 * given a valid TXN_reg_step, this sets it's value to a unix timestamp
1470
+	 *
1471
+	 * @param string $reg_step_slug
1472
+	 * @return boolean
1473
+	 * @throws EE_Error
1474
+	 * @throws InvalidArgumentException
1475
+	 * @throws InvalidDataTypeException
1476
+	 * @throws InvalidInterfaceException
1477
+	 * @throws ReflectionException
1478
+	 */
1479
+	public function set_reg_step_initiated($reg_step_slug)
1480
+	{
1481
+		return $this->_set_reg_step_completed_status($reg_step_slug, time());
1482
+	}
1483
+
1484
+
1485
+	/**
1486
+	 * set_reg_step_completed
1487
+	 * given a valid TXN_reg_step, this sets the step as completed
1488
+	 *
1489
+	 * @param string $reg_step_slug
1490
+	 * @return boolean
1491
+	 * @throws EE_Error
1492
+	 * @throws InvalidArgumentException
1493
+	 * @throws InvalidDataTypeException
1494
+	 * @throws InvalidInterfaceException
1495
+	 * @throws ReflectionException
1496
+	 */
1497
+	public function set_reg_step_completed($reg_step_slug)
1498
+	{
1499
+		return $this->_set_reg_step_completed_status($reg_step_slug, true);
1500
+	}
1501
+
1502
+
1503
+	/**
1504
+	 * set_reg_step_completed
1505
+	 * given a valid TXN_reg_step slug, this sets the step as NOT completed
1506
+	 *
1507
+	 * @param string $reg_step_slug
1508
+	 * @return boolean
1509
+	 * @throws EE_Error
1510
+	 * @throws InvalidArgumentException
1511
+	 * @throws InvalidDataTypeException
1512
+	 * @throws InvalidInterfaceException
1513
+	 * @throws ReflectionException
1514
+	 */
1515
+	public function set_reg_step_not_completed($reg_step_slug)
1516
+	{
1517
+		return $this->_set_reg_step_completed_status($reg_step_slug, false);
1518
+	}
1519
+
1520
+
1521
+	/**
1522
+	 * set_reg_step_completed
1523
+	 * given a valid reg step slug, this sets the TXN_reg_step completed status which is either:
1524
+	 *
1525
+	 * @param string      $reg_step_slug
1526
+	 * @param boolean|int $status
1527
+	 * @return boolean
1528
+	 * @throws EE_Error
1529
+	 * @throws InvalidArgumentException
1530
+	 * @throws InvalidDataTypeException
1531
+	 * @throws InvalidInterfaceException
1532
+	 * @throws ReflectionException
1533
+	 */
1534
+	private function _set_reg_step_completed_status($reg_step_slug, $status)
1535
+	{
1536
+		// validate status
1537
+		$status = is_bool($status) || is_int($status) ? $status : false;
1538
+		// get reg steps array
1539
+		$txn_reg_steps = $this->reg_steps();
1540
+		// if reg step does NOT exist
1541
+		if (! isset($txn_reg_steps[ $reg_step_slug ])) {
1542
+			return false;
1543
+		}
1544
+		// if  we're trying to complete a step that is already completed
1545
+		if ($txn_reg_steps[ $reg_step_slug ] === true) {
1546
+			return true;
1547
+		}
1548
+		// if  we're trying to complete a step that hasn't even started
1549
+		if ($status === true && $txn_reg_steps[ $reg_step_slug ] === false) {
1550
+			return false;
1551
+		}
1552
+		// if current status value matches the incoming value (no change)
1553
+		// type casting as int means values should collapse to either 0, 1, or a timestamp like 1234567890
1554
+		if ((int) $txn_reg_steps[ $reg_step_slug ] === (int) $status) {
1555
+			// this will happen in cases where multiple AJAX requests occur during the same step
1556
+			return true;
1557
+		}
1558
+		// if we're trying to set a start time, but it has already been set...
1559
+		if (is_numeric($status) && is_numeric($txn_reg_steps[ $reg_step_slug ])) {
1560
+			// skip the update below, but don't return FALSE so that errors won't be displayed
1561
+			return true;
1562
+		}
1563
+		// update completed status
1564
+		$txn_reg_steps[ $reg_step_slug ] = $status;
1565
+		$this->set_reg_steps($txn_reg_steps);
1566
+		$this->save();
1567
+		return true;
1568
+	}
1569
+
1570
+
1571
+	/**
1572
+	 * remove_reg_step
1573
+	 * given a valid TXN_reg_step slug, this will remove (unset)
1574
+	 * the reg step from the TXN reg step array
1575
+	 *
1576
+	 * @param string $reg_step_slug
1577
+	 * @return void
1578
+	 * @throws EE_Error
1579
+	 * @throws InvalidArgumentException
1580
+	 * @throws InvalidDataTypeException
1581
+	 * @throws InvalidInterfaceException
1582
+	 * @throws ReflectionException
1583
+	 */
1584
+	public function remove_reg_step($reg_step_slug)
1585
+	{
1586
+		// get reg steps array
1587
+		$txn_reg_steps = $this->reg_steps();
1588
+		unset($txn_reg_steps[ $reg_step_slug ]);
1589
+		$this->set_reg_steps($txn_reg_steps);
1590
+	}
1591
+
1592
+
1593
+	/**
1594
+	 * toggle_failed_transaction_status
1595
+	 * upgrades a TXNs status from failed to abandoned,
1596
+	 * meaning that contact information has been captured for at least one registrant
1597
+	 *
1598
+	 * @param bool $save
1599
+	 * @return bool
1600
+	 * @throws EE_Error
1601
+	 * @throws InvalidArgumentException
1602
+	 * @throws InvalidDataTypeException
1603
+	 * @throws InvalidInterfaceException
1604
+	 * @throws ReflectionException
1605
+	 */
1606
+	public function toggle_failed_transaction_status($save = true)
1607
+	{
1608
+		// if TXN status is still set as "failed"...
1609
+		if ($this->status_ID() === EEM_Transaction::failed_status_code) {
1610
+			$this->set_status(EEM_Transaction::abandoned_status_code);
1611
+			if ($save) {
1612
+				$this->save();
1613
+			}
1614
+			return true;
1615
+		}
1616
+		return false;
1617
+	}
1618
+
1619
+
1620
+	/**
1621
+	 * toggle_abandoned_transaction_status
1622
+	 * upgrades a TXNs status from failed or abandoned to incomplete
1623
+	 *
1624
+	 * @return bool
1625
+	 * @throws EE_Error
1626
+	 * @throws InvalidArgumentException
1627
+	 * @throws InvalidDataTypeException
1628
+	 * @throws InvalidInterfaceException
1629
+	 * @throws ReflectionException
1630
+	 */
1631
+	public function toggle_abandoned_transaction_status()
1632
+	{
1633
+		// if TXN status has not been updated already due to a payment, and is still set as "failed" or "abandoned"...
1634
+		$txn_status = $this->status_ID();
1635
+		if (
1636
+			$txn_status === EEM_Transaction::failed_status_code
1637
+			|| $txn_status === EEM_Transaction::abandoned_status_code
1638
+		) {
1639
+			// if a contact record for the primary registrant has been created
1640
+			if (
1641
+				$this->primary_registration() instanceof EE_Registration
1642
+				&& $this->primary_registration()->attendee() instanceof EE_Attendee
1643
+			) {
1644
+				$this->set_status(EEM_Transaction::incomplete_status_code);
1645
+			} else {
1646
+				// no contact record? yer abandoned!
1647
+				$this->set_status(EEM_Transaction::abandoned_status_code);
1648
+			}
1649
+			return true;
1650
+		}
1651
+		return false;
1652
+	}
1653
+
1654
+
1655
+	/**
1656
+	 * checks if an Abandoned TXN has any related payments, and if so,
1657
+	 * updates the TXN status based on the amount paid
1658
+	 *
1659
+	 * @throws EE_Error
1660
+	 * @throws InvalidArgumentException
1661
+	 * @throws InvalidDataTypeException
1662
+	 * @throws InvalidInterfaceException
1663
+	 * @throws ReflectionException
1664
+	 * @throws RuntimeException
1665
+	 * @throws ReflectionException
1666
+	 */
1667
+	public function verify_abandoned_transaction_status()
1668
+	{
1669
+		if ($this->status_ID() !== EEM_Transaction::abandoned_status_code) {
1670
+			return;
1671
+		}
1672
+		$payments = $this->get_many_related('Payment');
1673
+		if (! empty($payments)) {
1674
+			foreach ($payments as $payment) {
1675
+				if ($payment instanceof EE_Payment) {
1676
+					// kk this TXN should NOT be abandoned
1677
+					$this->update_status_based_on_total_paid();
1678
+					if (! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) {
1679
+						EE_Error::add_attention(
1680
+							sprintf(
1681
+								esc_html__(
1682
+									'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.',
1683
+									'event_espresso'
1684
+								),
1685
+								$this->ID(),
1686
+								$this->pretty_status()
1687
+							)
1688
+						);
1689
+					}
1690
+					// get final reg step status
1691
+					$finalized = $this->final_reg_step_completed();
1692
+					// if the 'finalize_registration' step has been initiated (has a timestamp)
1693
+					// but has not yet been fully completed (TRUE)
1694
+					if (is_int($finalized) && $finalized !== false && $finalized !== true) {
1695
+						$this->set_reg_step_completed('finalize_registration');
1696
+						$this->save();
1697
+					}
1698
+				}
1699
+			}
1700
+		}
1701
+	}
1702
+
1703
+
1704
+	/**
1705
+	 * @throws EE_Error
1706
+	 * @throws InvalidArgumentException
1707
+	 * @throws InvalidDataTypeException
1708
+	 * @throws InvalidInterfaceException
1709
+	 * @throws ReflectionException
1710
+	 * @throws RuntimeException
1711
+	 * @since 4.10.4.p
1712
+	 */
1713
+	public function recalculateLineItems()
1714
+	{
1715
+		$total_line_item = $this->total_line_item(false);
1716
+		if ($total_line_item instanceof EE_Line_Item) {
1717
+			EEH_Line_Item::resetIsTaxableForTickets($total_line_item);
1718
+			return EEH_Line_Item::apply_taxes($total_line_item, true);
1719
+		}
1720
+		return false;
1721
+	}
1722 1722
 }
Please login to merge, or discard this patch.
Spacing   +23 added lines, -23 removed lines patch added patch discarded remove patch
@@ -46,7 +46,7 @@  discard block
 block discarded – undo
46 46
         $txn        = $has_object
47 47
             ? $has_object
48 48
             : new self($props_n_values, false, $timezone, $date_formats);
49
-        if (! $has_object) {
49
+        if ( ! $has_object) {
50 50
             $txn->set_old_txn_status($txn->status_ID());
51 51
         }
52 52
         return $txn;
@@ -86,7 +86,7 @@  discard block
 block discarded – undo
86 86
     public function lock()
87 87
     {
88 88
         // attempt to set lock, but if that fails...
89
-        if (! $this->add_extra_meta('lock', time(), true)) {
89
+        if ( ! $this->add_extra_meta('lock', time(), true)) {
90 90
             // then attempt to remove the lock in case it is expired
91 91
             if ($this->_remove_expired_lock()) {
92 92
                 // if removal was successful, then try setting lock again
@@ -142,7 +142,7 @@  discard block
 block discarded – undo
142 142
     public function is_locked()
143 143
     {
144 144
         // if TXN is not locked, then return false immediately
145
-        if (! $this->_get_lock()) {
145
+        if ( ! $this->_get_lock()) {
146 146
             return false;
147 147
         }
148 148
         // if not, then let's try and remove the lock in case it's expired...
@@ -622,7 +622,7 @@  discard block
 block discarded – undo
622 622
             false,
623 623
             'sentence'
624 624
         );
625
-        $icon   = '';
625
+        $icon = '';
626 626
         switch ($this->status_ID()) {
627 627
             case EEM_Transaction::complete_status_code:
628 628
                 $icon = $show_icons ? '<span class="dashicons dashicons-yes ee-icon-size-24 green-text"></span>' : '';
@@ -641,7 +641,7 @@  discard block
 block discarded – undo
641 641
                 $icon = $show_icons ? '<span class="dashicons dashicons-plus ee-icon-size-16 orange-text"></span>' : '';
642 642
                 break;
643 643
         }
644
-        return $icon . $status[ $this->status_ID() ];
644
+        return $icon.$status[$this->status_ID()];
645 645
     }
646 646
 
647 647
 
@@ -779,7 +779,7 @@  discard block
 block discarded – undo
779 779
     public function invoice_url($type = 'html')
780 780
     {
781 781
         $REG = $this->primary_registration();
782
-        if (! $REG instanceof EE_Registration) {
782
+        if ( ! $REG instanceof EE_Registration) {
783 783
             return '';
784 784
         }
785 785
         return $REG->invoice_url($type);
@@ -831,7 +831,7 @@  discard block
 block discarded – undo
831 831
     public function receipt_url($type = 'html')
832 832
     {
833 833
         $REG = $this->primary_registration();
834
-        if (! $REG instanceof EE_Registration) {
834
+        if ( ! $REG instanceof EE_Registration) {
835 835
             return '';
836 836
         }
837 837
         return $REG->receipt_url($type);
@@ -1021,7 +1021,7 @@  discard block
 block discarded – undo
1021 1021
     public function total_line_item($create_if_not_found = true)
1022 1022
     {
1023 1023
         $item = $this->get_first_related('Line_Item', [['LIN_type' => EEM_Line_Item::type_total]]);
1024
-        if (! $item && $create_if_not_found) {
1024
+        if ( ! $item && $create_if_not_found) {
1025 1025
             $item = EEH_Line_Item::create_total_line_item($this);
1026 1026
         }
1027 1027
         return $item;
@@ -1078,7 +1078,7 @@  discard block
 block discarded – undo
1078 1078
     public function billing_info()
1079 1079
     {
1080 1080
         $payment_method = $this->payment_method();
1081
-        if (! $payment_method) {
1081
+        if ( ! $payment_method) {
1082 1082
             EE_Error::add_error(
1083 1083
                 esc_html__(
1084 1084
                     'Could not find billing info for transaction because no gateway has been used for it yet',
@@ -1091,7 +1091,7 @@  discard block
 block discarded – undo
1091 1091
             return null;
1092 1092
         }
1093 1093
         $primary_reg = $this->primary_registration();
1094
-        if (! $primary_reg) {
1094
+        if ( ! $primary_reg) {
1095 1095
             EE_Error::add_error(
1096 1096
                 esc_html__(
1097 1097
                     'Cannot get billing info for gateway %s on transaction because no primary registration exists',
@@ -1104,7 +1104,7 @@  discard block
 block discarded – undo
1104 1104
             return null;
1105 1105
         }
1106 1106
         $attendee = $primary_reg->attendee();
1107
-        if (! $attendee) {
1107
+        if ( ! $attendee) {
1108 1108
             EE_Error::add_error(
1109 1109
                 esc_html__(
1110 1110
                     'Cannot get billing info for gateway %s on transaction because the primary registration has no attendee exists',
@@ -1261,7 +1261,7 @@  discard block
 block discarded – undo
1261 1261
     public function update_based_on_payments()
1262 1262
     {
1263 1263
         EE_Error::doing_it_wrong(
1264
-            __CLASS__ . '::' . __FUNCTION__,
1264
+            __CLASS__.'::'.__FUNCTION__,
1265 1265
             sprintf(
1266 1266
                 esc_html__('This method is deprecated. Please use "%s" instead', 'event_espresso'),
1267 1267
                 'EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()'
@@ -1329,13 +1329,13 @@  discard block
 block discarded – undo
1329 1329
     private function _reg_steps_completed($reg_step_slug = '', $check_all = true)
1330 1330
     {
1331 1331
         $reg_steps = $this->reg_steps();
1332
-        if (! is_array($reg_steps) || empty($reg_steps)) {
1332
+        if ( ! is_array($reg_steps) || empty($reg_steps)) {
1333 1333
             return false;
1334 1334
         }
1335 1335
         // loop thru reg steps array)
1336 1336
         foreach ($reg_steps as $slug => $reg_step_completed) {
1337 1337
             // if NOT checking ALL steps (only checking one step)
1338
-            if (! $check_all) {
1338
+            if ( ! $check_all) {
1339 1339
                 // and this is the one
1340 1340
                 if ($slug === $reg_step_slug) {
1341 1341
                     return $reg_step_completed;
@@ -1538,30 +1538,30 @@  discard block
 block discarded – undo
1538 1538
         // get reg steps array
1539 1539
         $txn_reg_steps = $this->reg_steps();
1540 1540
         // if reg step does NOT exist
1541
-        if (! isset($txn_reg_steps[ $reg_step_slug ])) {
1541
+        if ( ! isset($txn_reg_steps[$reg_step_slug])) {
1542 1542
             return false;
1543 1543
         }
1544 1544
         // if  we're trying to complete a step that is already completed
1545
-        if ($txn_reg_steps[ $reg_step_slug ] === true) {
1545
+        if ($txn_reg_steps[$reg_step_slug] === true) {
1546 1546
             return true;
1547 1547
         }
1548 1548
         // if  we're trying to complete a step that hasn't even started
1549
-        if ($status === true && $txn_reg_steps[ $reg_step_slug ] === false) {
1549
+        if ($status === true && $txn_reg_steps[$reg_step_slug] === false) {
1550 1550
             return false;
1551 1551
         }
1552 1552
         // if current status value matches the incoming value (no change)
1553 1553
         // type casting as int means values should collapse to either 0, 1, or a timestamp like 1234567890
1554
-        if ((int) $txn_reg_steps[ $reg_step_slug ] === (int) $status) {
1554
+        if ((int) $txn_reg_steps[$reg_step_slug] === (int) $status) {
1555 1555
             // this will happen in cases where multiple AJAX requests occur during the same step
1556 1556
             return true;
1557 1557
         }
1558 1558
         // if we're trying to set a start time, but it has already been set...
1559
-        if (is_numeric($status) && is_numeric($txn_reg_steps[ $reg_step_slug ])) {
1559
+        if (is_numeric($status) && is_numeric($txn_reg_steps[$reg_step_slug])) {
1560 1560
             // skip the update below, but don't return FALSE so that errors won't be displayed
1561 1561
             return true;
1562 1562
         }
1563 1563
         // update completed status
1564
-        $txn_reg_steps[ $reg_step_slug ] = $status;
1564
+        $txn_reg_steps[$reg_step_slug] = $status;
1565 1565
         $this->set_reg_steps($txn_reg_steps);
1566 1566
         $this->save();
1567 1567
         return true;
@@ -1585,7 +1585,7 @@  discard block
 block discarded – undo
1585 1585
     {
1586 1586
         // get reg steps array
1587 1587
         $txn_reg_steps = $this->reg_steps();
1588
-        unset($txn_reg_steps[ $reg_step_slug ]);
1588
+        unset($txn_reg_steps[$reg_step_slug]);
1589 1589
         $this->set_reg_steps($txn_reg_steps);
1590 1590
     }
1591 1591
 
@@ -1670,12 +1670,12 @@  discard block
 block discarded – undo
1670 1670
             return;
1671 1671
         }
1672 1672
         $payments = $this->get_many_related('Payment');
1673
-        if (! empty($payments)) {
1673
+        if ( ! empty($payments)) {
1674 1674
             foreach ($payments as $payment) {
1675 1675
                 if ($payment instanceof EE_Payment) {
1676 1676
                     // kk this TXN should NOT be abandoned
1677 1677
                     $this->update_status_based_on_total_paid();
1678
-                    if (! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) {
1678
+                    if ( ! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) {
1679 1679
                         EE_Error::add_attention(
1680 1680
                             sprintf(
1681 1681
                                 esc_html__(
Please login to merge, or discard this patch.
core/db_classes/EE_Soft_Delete_Base_Class.class.php 1 patch
Indentation   +51 added lines, -51 removed lines patch added patch discarded remove patch
@@ -11,59 +11,59 @@
 block discarded – undo
11 11
  */
12 12
 abstract class EE_Soft_Delete_Base_Class extends EE_Base_Class
13 13
 {
14
-    /**
15
-     * Overrides parent _delete() so that we do soft deletes.
16
-     *
17
-     * @return bool
18
-     * @throws EE_Error
19
-     * @throws ReflectionException
20
-     */
21
-    protected function _delete()
22
-    {
23
-        return $this->delete_or_restore();
24
-    }
14
+	/**
15
+	 * Overrides parent _delete() so that we do soft deletes.
16
+	 *
17
+	 * @return bool
18
+	 * @throws EE_Error
19
+	 * @throws ReflectionException
20
+	 */
21
+	protected function _delete()
22
+	{
23
+		return $this->delete_or_restore();
24
+	}
25 25
 
26 26
 
27
-    /**
28
-     * Deletes or restores this object.
29
-     *
30
-     * @param bool $delete true=>delete, false=>restore
31
-     * @return bool
32
-     * @throws EE_Error
33
-     * @throws ReflectionException
34
-     */
35
-    public function delete_or_restore($delete = true)
36
-    {
37
-        /**
38
-         * Called just before trashing (soft delete) or restoring a trashed item.
39
-         *
40
-         * @param EE_Base_Class $model_object about to be trashed or restored
41
-         * @param bool          $delete       true the item is being trashed, false the item is being restored.
42
-         */
43
-        do_action('AHEE__EE_Soft_Delete_Base_Class__delete_or_restore__before', $this, $delete);
44
-        $model = $this->get_model();
45
-        $result = $model->delete_or_restore_by_ID($delete, $this->ID());
46
-        /**
47
-         * Called just after trashing (soft delete) or restoring a trashed item.
48
-         *
49
-         * @param EE_Base_Class $model_object that was just trashed or restored.
50
-         * @param bool          $delete       true the item is being trashed, false the item is being restored.
51
-         * @param bool|int      $result
52
-         */
53
-        do_action('AHEE__EE_Soft_Delete_Base_Class__delete_or_restore__after', $this, $delete, $result);
54
-        return $result;
55
-    }
27
+	/**
28
+	 * Deletes or restores this object.
29
+	 *
30
+	 * @param bool $delete true=>delete, false=>restore
31
+	 * @return bool
32
+	 * @throws EE_Error
33
+	 * @throws ReflectionException
34
+	 */
35
+	public function delete_or_restore($delete = true)
36
+	{
37
+		/**
38
+		 * Called just before trashing (soft delete) or restoring a trashed item.
39
+		 *
40
+		 * @param EE_Base_Class $model_object about to be trashed or restored
41
+		 * @param bool          $delete       true the item is being trashed, false the item is being restored.
42
+		 */
43
+		do_action('AHEE__EE_Soft_Delete_Base_Class__delete_or_restore__before', $this, $delete);
44
+		$model = $this->get_model();
45
+		$result = $model->delete_or_restore_by_ID($delete, $this->ID());
46
+		/**
47
+		 * Called just after trashing (soft delete) or restoring a trashed item.
48
+		 *
49
+		 * @param EE_Base_Class $model_object that was just trashed or restored.
50
+		 * @param bool          $delete       true the item is being trashed, false the item is being restored.
51
+		 * @param bool|int      $result
52
+		 */
53
+		do_action('AHEE__EE_Soft_Delete_Base_Class__delete_or_restore__after', $this, $delete, $result);
54
+		return $result;
55
+	}
56 56
 
57 57
 
58
-    /**
59
-     * Performs a restoration (un-deletes) this object
60
-     *
61
-     * @return bool
62
-     * @throws EE_Error
63
-     * @throws ReflectionException
64
-     */
65
-    public function restore()
66
-    {
67
-        return $this->delete_or_restore(false);
68
-    }
58
+	/**
59
+	 * Performs a restoration (un-deletes) this object
60
+	 *
61
+	 * @return bool
62
+	 * @throws EE_Error
63
+	 * @throws ReflectionException
64
+	 */
65
+	public function restore()
66
+	{
67
+		return $this->delete_or_restore(false);
68
+	}
69 69
 }
Please login to merge, or discard this patch.
admin_pages/registrations/Registrations_Admin_Page.core.php 1 patch
Indentation   +3680 added lines, -3680 removed lines patch added patch discarded remove patch
@@ -21,2225 +21,2225 @@  discard block
 block discarded – undo
21 21
  */
22 22
 class Registrations_Admin_Page extends EE_Admin_Page_CPT
23 23
 {
24
-    /**
25
-     * @var EE_Registration
26
-     */
27
-    private $_registration;
28
-
29
-    /**
30
-     * @var EE_Event
31
-     */
32
-    private $_reg_event;
33
-
34
-    /**
35
-     * @var EE_Session
36
-     */
37
-    private $_session;
38
-
39
-    /**
40
-     * @var array
41
-     */
42
-    private static $_reg_status;
43
-
44
-    /**
45
-     * Form for displaying the custom questions for this registration.
46
-     * This gets used a few times throughout the request so its best to cache it
47
-     *
48
-     * @var EE_Registration_Custom_Questions_Form
49
-     */
50
-    protected $_reg_custom_questions_form = null;
51
-
52
-    /**
53
-     * @var EEM_Registration $registration_model
54
-     */
55
-    private $registration_model;
56
-
57
-    /**
58
-     * @var EEM_Attendee $attendee_model
59
-     */
60
-    private $attendee_model;
61
-
62
-    /**
63
-     * @var EEM_Event $event_model
64
-     */
65
-    private $event_model;
66
-
67
-    /**
68
-     * @var EEM_Status $status_model
69
-     */
70
-    private $status_model;
71
-
72
-
73
-    /**
74
-     * @param bool $routing
75
-     * @throws EE_Error
76
-     * @throws InvalidArgumentException
77
-     * @throws InvalidDataTypeException
78
-     * @throws InvalidInterfaceException
79
-     * @throws ReflectionException
80
-     */
81
-    public function __construct($routing = true)
82
-    {
83
-        parent::__construct($routing);
84
-        add_action('wp_loaded', [$this, 'wp_loaded']);
85
-    }
86
-
87
-
88
-    /**
89
-     * @return EEM_Registration
90
-     * @throws InvalidArgumentException
91
-     * @throws InvalidDataTypeException
92
-     * @throws InvalidInterfaceException
93
-     * @since 4.10.2.p
94
-     */
95
-    protected function getRegistrationModel()
96
-    {
97
-        if (! $this->registration_model instanceof EEM_Registration) {
98
-            $this->registration_model = $this->getLoader()->getShared('EEM_Registration');
99
-        }
100
-        return $this->registration_model;
101
-    }
102
-
103
-
104
-    /**
105
-     * @return EEM_Attendee
106
-     * @throws InvalidArgumentException
107
-     * @throws InvalidDataTypeException
108
-     * @throws InvalidInterfaceException
109
-     * @since 4.10.2.p
110
-     */
111
-    protected function getAttendeeModel()
112
-    {
113
-        if (! $this->attendee_model instanceof EEM_Attendee) {
114
-            $this->attendee_model = $this->getLoader()->getShared('EEM_Attendee');
115
-        }
116
-        return $this->attendee_model;
117
-    }
118
-
119
-
120
-    /**
121
-     * @return EEM_Event
122
-     * @throws InvalidArgumentException
123
-     * @throws InvalidDataTypeException
124
-     * @throws InvalidInterfaceException
125
-     * @since 4.10.2.p
126
-     */
127
-    protected function getEventModel()
128
-    {
129
-        if (! $this->event_model instanceof EEM_Event) {
130
-            $this->event_model = $this->getLoader()->getShared('EEM_Event');
131
-        }
132
-        return $this->event_model;
133
-    }
134
-
135
-
136
-    /**
137
-     * @return EEM_Status
138
-     * @throws InvalidArgumentException
139
-     * @throws InvalidDataTypeException
140
-     * @throws InvalidInterfaceException
141
-     * @since 4.10.2.p
142
-     */
143
-    protected function getStatusModel()
144
-    {
145
-        if (! $this->status_model instanceof EEM_Status) {
146
-            $this->status_model = $this->getLoader()->getShared('EEM_Status');
147
-        }
148
-        return $this->status_model;
149
-    }
150
-
151
-
152
-    public function wp_loaded()
153
-    {
154
-        // when adding a new registration...
155
-        $action = $this->request->getRequestParam('action');
156
-        if ($action === 'new_registration') {
157
-            EE_System::do_not_cache();
158
-            if ($this->request->getRequestParam('processing_registration', 0, 'int') !== 1) {
159
-                // and it's NOT the attendee information reg step
160
-                // force cookie expiration by setting time to last week
161
-                setcookie('ee_registration_added', 0, time() - WEEK_IN_SECONDS, '/');
162
-                // and update the global
163
-                $_COOKIE['ee_registration_added'] = 0;
164
-            }
165
-        }
166
-    }
167
-
168
-
169
-    protected function _init_page_props()
170
-    {
171
-        $this->page_slug        = REG_PG_SLUG;
172
-        $this->_admin_base_url  = REG_ADMIN_URL;
173
-        $this->_admin_base_path = REG_ADMIN;
174
-        $this->page_label       = esc_html__('Registrations', 'event_espresso');
175
-        $this->_cpt_routes      = [
176
-            'add_new_attendee' => 'espresso_attendees',
177
-            'edit_attendee'    => 'espresso_attendees',
178
-            'insert_attendee'  => 'espresso_attendees',
179
-            'update_attendee'  => 'espresso_attendees',
180
-        ];
181
-        $this->_cpt_model_names = [
182
-            'add_new_attendee' => 'EEM_Attendee',
183
-            'edit_attendee'    => 'EEM_Attendee',
184
-        ];
185
-        $this->_cpt_edit_routes = [
186
-            'espresso_attendees' => 'edit_attendee',
187
-        ];
188
-        $this->_pagenow_map     = [
189
-            'add_new_attendee' => 'post-new.php',
190
-            'edit_attendee'    => 'post.php',
191
-            'trash'            => 'post.php',
192
-        ];
193
-        add_action('edit_form_after_title', [$this, 'after_title_form_fields'], 10);
194
-        // add filters so that the comment urls don't take users to a confusing 404 page
195
-        add_filter('get_comment_link', [$this, 'clear_comment_link'], 10, 2);
196
-    }
197
-
198
-
199
-    /**
200
-     * @param string     $link    The comment permalink with '#comment-$id' appended.
201
-     * @param WP_Comment $comment The current comment object.
202
-     * @return string
203
-     */
204
-    public function clear_comment_link($link, WP_Comment $comment)
205
-    {
206
-        // gotta make sure this only happens on this route
207
-        $post_type = get_post_type($comment->comment_post_ID);
208
-        if ($post_type === 'espresso_attendees') {
209
-            return '#commentsdiv';
210
-        }
211
-        return $link;
212
-    }
213
-
214
-
215
-    protected function _ajax_hooks()
216
-    {
217
-        // todo: all hooks for registrations ajax goes in here
218
-        add_action('wp_ajax_toggle_checkin_status', [$this, 'toggle_checkin_status']);
219
-    }
220
-
221
-
222
-    protected function _define_page_props()
223
-    {
224
-        $this->_admin_page_title = $this->page_label;
225
-        $this->_labels           = [
226
-            'buttons'                      => [
227
-                'add-registrant'      => esc_html__('Add New Registration', 'event_espresso'),
228
-                'add-attendee'        => esc_html__('Add Contact', 'event_espresso'),
229
-                'edit'                => esc_html__('Edit Contact', 'event_espresso'),
230
-                'csv_reg_report'      => esc_html__('Registrations CSV Report', 'event_espresso'),
231
-                'contact_list_report' => esc_html__('Contact List Report', 'event_espresso'),
232
-                'contact_list_export' => esc_html__('Export Data', 'event_espresso'),
233
-            ],
234
-            'publishbox'                   => [
235
-                'add_new_attendee' => esc_html__('Add Contact Record', 'event_espresso'),
236
-                'edit_attendee'    => esc_html__('Update Contact Record', 'event_espresso'),
237
-            ],
238
-            'hide_add_button_on_cpt_route' => [
239
-                'edit_attendee' => true,
240
-            ],
241
-        ];
242
-    }
243
-
244
-
245
-    /**
246
-     * grab url requests and route them
247
-     *
248
-     * @return void
249
-     * @throws EE_Error
250
-     */
251
-    public function _set_page_routes()
252
-    {
253
-        $this->_get_registration_status_array();
254
-        $REG_ID             = $this->request->getRequestParam('_REG_ID', 0, 'int');
255
-        $REG_ID             = $this->request->getRequestParam('reg_status_change_form[REG_ID]', $REG_ID, 'int');
256
-        $ATT_ID             = $this->request->getRequestParam('ATT_ID', 0, 'int');
257
-        $ATT_ID             = $this->request->getRequestParam('post', $ATT_ID, 'int');
258
-        $this->_page_routes = [
259
-            'default'                             => [
260
-                'func'       => [$this, '_registrations_overview_list_table'],
261
-                'capability' => 'ee_read_registrations',
262
-            ],
263
-            'view_registration'                   => [
264
-                'func'       => '_registration_details',
265
-                'capability' => 'ee_read_registration',
266
-                'obj_id'     => $REG_ID,
267
-            ],
268
-            'edit_registration'                   => [
269
-                'func'               => '_update_attendee_registration_form',
270
-                'noheader'           => true,
271
-                'headers_sent_route' => 'view_registration',
272
-                'capability'         => 'ee_edit_registration',
273
-                'obj_id'             => $REG_ID,
274
-                '_REG_ID'            => $REG_ID,
275
-            ],
276
-            'trash_registrations'                 => [
277
-                'func'       => '_trash_or_restore_registrations',
278
-                'args'       => ['trash' => true],
279
-                'noheader'   => true,
280
-                'capability' => 'ee_delete_registrations',
281
-            ],
282
-            'restore_registrations'               => [
283
-                'func'       => '_trash_or_restore_registrations',
284
-                'args'       => ['trash' => false],
285
-                'noheader'   => true,
286
-                'capability' => 'ee_delete_registrations',
287
-            ],
288
-            'delete_registrations'                => [
289
-                'func'       => '_delete_registrations',
290
-                'noheader'   => true,
291
-                'capability' => 'ee_delete_registrations',
292
-            ],
293
-            'new_registration'                    => [
294
-                'func'       => 'new_registration',
295
-                'capability' => 'ee_edit_registrations',
296
-            ],
297
-            'process_reg_step'                    => [
298
-                'func'       => 'process_reg_step',
299
-                'noheader'   => true,
300
-                'capability' => 'ee_edit_registrations',
301
-            ],
302
-            'redirect_to_txn'                     => [
303
-                'func'       => 'redirect_to_txn',
304
-                'noheader'   => true,
305
-                'capability' => 'ee_edit_registrations',
306
-            ],
307
-            'change_reg_status'                   => [
308
-                'func'       => '_change_reg_status',
309
-                'noheader'   => true,
310
-                'capability' => 'ee_edit_registration',
311
-                'obj_id'     => $REG_ID,
312
-            ],
313
-            'approve_registration'                => [
314
-                'func'       => 'approve_registration',
315
-                'noheader'   => true,
316
-                'capability' => 'ee_edit_registration',
317
-                'obj_id'     => $REG_ID,
318
-            ],
319
-            'approve_and_notify_registration'     => [
320
-                'func'       => 'approve_registration',
321
-                'noheader'   => true,
322
-                'args'       => [true],
323
-                'capability' => 'ee_edit_registration',
324
-                'obj_id'     => $REG_ID,
325
-            ],
326
-            'approve_registrations'               => [
327
-                'func'       => 'bulk_action_on_registrations',
328
-                'noheader'   => true,
329
-                'capability' => 'ee_edit_registrations',
330
-                'args'       => ['approve'],
331
-            ],
332
-            'approve_and_notify_registrations'    => [
333
-                'func'       => 'bulk_action_on_registrations',
334
-                'noheader'   => true,
335
-                'capability' => 'ee_edit_registrations',
336
-                'args'       => ['approve', true],
337
-            ],
338
-            'decline_registration'                => [
339
-                'func'       => 'decline_registration',
340
-                'noheader'   => true,
341
-                'capability' => 'ee_edit_registration',
342
-                'obj_id'     => $REG_ID,
343
-            ],
344
-            'decline_and_notify_registration'     => [
345
-                'func'       => 'decline_registration',
346
-                'noheader'   => true,
347
-                'args'       => [true],
348
-                'capability' => 'ee_edit_registration',
349
-                'obj_id'     => $REG_ID,
350
-            ],
351
-            'decline_registrations'               => [
352
-                'func'       => 'bulk_action_on_registrations',
353
-                'noheader'   => true,
354
-                'capability' => 'ee_edit_registrations',
355
-                'args'       => ['decline'],
356
-            ],
357
-            'decline_and_notify_registrations'    => [
358
-                'func'       => 'bulk_action_on_registrations',
359
-                'noheader'   => true,
360
-                'capability' => 'ee_edit_registrations',
361
-                'args'       => ['decline', true],
362
-            ],
363
-            'pending_registration'                => [
364
-                'func'       => 'pending_registration',
365
-                'noheader'   => true,
366
-                'capability' => 'ee_edit_registration',
367
-                'obj_id'     => $REG_ID,
368
-            ],
369
-            'pending_and_notify_registration'     => [
370
-                'func'       => 'pending_registration',
371
-                'noheader'   => true,
372
-                'args'       => [true],
373
-                'capability' => 'ee_edit_registration',
374
-                'obj_id'     => $REG_ID,
375
-            ],
376
-            'pending_registrations'               => [
377
-                'func'       => 'bulk_action_on_registrations',
378
-                'noheader'   => true,
379
-                'capability' => 'ee_edit_registrations',
380
-                'args'       => ['pending'],
381
-            ],
382
-            'pending_and_notify_registrations'    => [
383
-                'func'       => 'bulk_action_on_registrations',
384
-                'noheader'   => true,
385
-                'capability' => 'ee_edit_registrations',
386
-                'args'       => ['pending', true],
387
-            ],
388
-            'no_approve_registration'             => [
389
-                'func'       => 'not_approve_registration',
390
-                'noheader'   => true,
391
-                'capability' => 'ee_edit_registration',
392
-                'obj_id'     => $REG_ID,
393
-            ],
394
-            'no_approve_and_notify_registration'  => [
395
-                'func'       => 'not_approve_registration',
396
-                'noheader'   => true,
397
-                'args'       => [true],
398
-                'capability' => 'ee_edit_registration',
399
-                'obj_id'     => $REG_ID,
400
-            ],
401
-            'no_approve_registrations'            => [
402
-                'func'       => 'bulk_action_on_registrations',
403
-                'noheader'   => true,
404
-                'capability' => 'ee_edit_registrations',
405
-                'args'       => ['not_approve'],
406
-            ],
407
-            'no_approve_and_notify_registrations' => [
408
-                'func'       => 'bulk_action_on_registrations',
409
-                'noheader'   => true,
410
-                'capability' => 'ee_edit_registrations',
411
-                'args'       => ['not_approve', true],
412
-            ],
413
-            'cancel_registration'                 => [
414
-                'func'       => 'cancel_registration',
415
-                'noheader'   => true,
416
-                'capability' => 'ee_edit_registration',
417
-                'obj_id'     => $REG_ID,
418
-            ],
419
-            'cancel_and_notify_registration'      => [
420
-                'func'       => 'cancel_registration',
421
-                'noheader'   => true,
422
-                'args'       => [true],
423
-                'capability' => 'ee_edit_registration',
424
-                'obj_id'     => $REG_ID,
425
-            ],
426
-            'cancel_registrations'                => [
427
-                'func'       => 'bulk_action_on_registrations',
428
-                'noheader'   => true,
429
-                'capability' => 'ee_edit_registrations',
430
-                'args'       => ['cancel'],
431
-            ],
432
-            'cancel_and_notify_registrations'     => [
433
-                'func'       => 'bulk_action_on_registrations',
434
-                'noheader'   => true,
435
-                'capability' => 'ee_edit_registrations',
436
-                'args'       => ['cancel', true],
437
-            ],
438
-            'wait_list_registration'              => [
439
-                'func'       => 'wait_list_registration',
440
-                'noheader'   => true,
441
-                'capability' => 'ee_edit_registration',
442
-                'obj_id'     => $REG_ID,
443
-            ],
444
-            'wait_list_and_notify_registration'   => [
445
-                'func'       => 'wait_list_registration',
446
-                'noheader'   => true,
447
-                'args'       => [true],
448
-                'capability' => 'ee_edit_registration',
449
-                'obj_id'     => $REG_ID,
450
-            ],
451
-            'contact_list'                        => [
452
-                'func'       => '_attendee_contact_list_table',
453
-                'capability' => 'ee_read_contacts',
454
-            ],
455
-            'add_new_attendee'                    => [
456
-                'func' => '_create_new_cpt_item',
457
-                'args' => [
458
-                    'new_attendee' => true,
459
-                    'capability'   => 'ee_edit_contacts',
460
-                ],
461
-            ],
462
-            'edit_attendee'                       => [
463
-                'func'       => '_edit_cpt_item',
464
-                'capability' => 'ee_edit_contacts',
465
-                'obj_id'     => $ATT_ID,
466
-            ],
467
-            'duplicate_attendee'                  => [
468
-                'func'       => '_duplicate_attendee',
469
-                'noheader'   => true,
470
-                'capability' => 'ee_edit_contacts',
471
-                'obj_id'     => $ATT_ID,
472
-            ],
473
-            'insert_attendee'                     => [
474
-                'func'       => '_insert_or_update_attendee',
475
-                'args'       => [
476
-                    'new_attendee' => true,
477
-                ],
478
-                'noheader'   => true,
479
-                'capability' => 'ee_edit_contacts',
480
-            ],
481
-            'update_attendee'                     => [
482
-                'func'       => '_insert_or_update_attendee',
483
-                'args'       => [
484
-                    'new_attendee' => false,
485
-                ],
486
-                'noheader'   => true,
487
-                'capability' => 'ee_edit_contacts',
488
-                'obj_id'     => $ATT_ID,
489
-            ],
490
-            'trash_attendees'                     => [
491
-                'func'       => '_trash_or_restore_attendees',
492
-                'args'       => [
493
-                    'trash' => 'true',
494
-                ],
495
-                'noheader'   => true,
496
-                'capability' => 'ee_delete_contacts',
497
-            ],
498
-            'trash_attendee'                      => [
499
-                'func'       => '_trash_or_restore_attendees',
500
-                'args'       => [
501
-                    'trash' => true,
502
-                ],
503
-                'noheader'   => true,
504
-                'capability' => 'ee_delete_contacts',
505
-                'obj_id'     => $ATT_ID,
506
-            ],
507
-            'restore_attendees'                   => [
508
-                'func'       => '_trash_or_restore_attendees',
509
-                'args'       => [
510
-                    'trash' => false,
511
-                ],
512
-                'noheader'   => true,
513
-                'capability' => 'ee_delete_contacts',
514
-                'obj_id'     => $ATT_ID,
515
-            ],
516
-            'resend_registration'                 => [
517
-                'func'       => '_resend_registration',
518
-                'noheader'   => true,
519
-                'capability' => 'ee_send_message',
520
-            ],
521
-            'registrations_report'                => [
522
-                'func'       => [$this, '_registrations_report'],
523
-                'noheader'   => true,
524
-                'capability' => 'ee_read_registrations',
525
-            ],
526
-            'contact_list_export'                 => [
527
-                'func'       => '_contact_list_export',
528
-                'noheader'   => true,
529
-                'capability' => 'export',
530
-            ],
531
-            'contact_list_report'                 => [
532
-                'func'       => '_contact_list_report',
533
-                'noheader'   => true,
534
-                'capability' => 'ee_read_contacts',
535
-            ],
536
-        ];
537
-    }
538
-
539
-
540
-    protected function _set_page_config()
541
-    {
542
-        $REG_ID             = $this->request->getRequestParam('_REG_ID', 0, 'int');
543
-        $ATT_ID             = $this->request->getRequestParam('ATT_ID', 0, 'int');
544
-        $this->_page_config = [
545
-            'default'           => [
546
-                'nav'           => [
547
-                    'label' => esc_html__('Overview', 'event_espresso'),
548
-                    'order' => 5,
549
-                ],
550
-                'help_tabs'     => [
551
-                    'registrations_overview_help_tab'                       => [
552
-                        'title'    => esc_html__('Registrations Overview', 'event_espresso'),
553
-                        'filename' => 'registrations_overview',
554
-                    ],
555
-                    'registrations_overview_table_column_headings_help_tab' => [
556
-                        'title'    => esc_html__('Registrations Table Column Headings', 'event_espresso'),
557
-                        'filename' => 'registrations_overview_table_column_headings',
558
-                    ],
559
-                    'registrations_overview_filters_help_tab'               => [
560
-                        'title'    => esc_html__('Registration Filters', 'event_espresso'),
561
-                        'filename' => 'registrations_overview_filters',
562
-                    ],
563
-                    'registrations_overview_views_help_tab'                 => [
564
-                        'title'    => esc_html__('Registration Views', 'event_espresso'),
565
-                        'filename' => 'registrations_overview_views',
566
-                    ],
567
-                    'registrations_regoverview_other_help_tab'              => [
568
-                        'title'    => esc_html__('Registrations Other', 'event_espresso'),
569
-                        'filename' => 'registrations_overview_other',
570
-                    ],
571
-                ],
572
-                'qtips'         => ['Registration_List_Table_Tips'],
573
-                'list_table'    => 'EE_Registrations_List_Table',
574
-                'require_nonce' => false,
575
-            ],
576
-            'view_registration' => [
577
-                'nav'           => [
578
-                    'label'      => esc_html__('REG Details', 'event_espresso'),
579
-                    'order'      => 15,
580
-                    'url'        => $REG_ID
581
-                        ? add_query_arg(['_REG_ID' => $REG_ID], $this->_current_page_view_url)
582
-                        : $this->_admin_base_url,
583
-                    'persistent' => false,
584
-                ],
585
-                'help_tabs'     => [
586
-                    'registrations_details_help_tab'                    => [
587
-                        'title'    => esc_html__('Registration Details', 'event_espresso'),
588
-                        'filename' => 'registrations_details',
589
-                    ],
590
-                    'registrations_details_table_help_tab'              => [
591
-                        'title'    => esc_html__('Registration Details Table', 'event_espresso'),
592
-                        'filename' => 'registrations_details_table',
593
-                    ],
594
-                    'registrations_details_form_answers_help_tab'       => [
595
-                        'title'    => esc_html__('Registration Form Answers', 'event_espresso'),
596
-                        'filename' => 'registrations_details_form_answers',
597
-                    ],
598
-                    'registrations_details_registrant_details_help_tab' => [
599
-                        'title'    => esc_html__('Contact Details', 'event_espresso'),
600
-                        'filename' => 'registrations_details_registrant_details',
601
-                    ],
602
-                ],
603
-                'metaboxes'     => array_merge(
604
-                    $this->_default_espresso_metaboxes,
605
-                    ['_registration_details_metaboxes']
606
-                ),
607
-                'require_nonce' => false,
608
-            ],
609
-            'new_registration'  => [
610
-                'nav'           => [
611
-                    'label'      => esc_html__('Add New Registration', 'event_espresso'),
612
-                    'url'        => '#',
613
-                    'order'      => 15,
614
-                    'persistent' => false,
615
-                ],
616
-                'metaboxes'     => $this->_default_espresso_metaboxes,
617
-                'labels'        => [
618
-                    'publishbox' => esc_html__('Save Registration', 'event_espresso'),
619
-                ],
620
-                'require_nonce' => false,
621
-            ],
622
-            'add_new_attendee'  => [
623
-                'nav'           => [
624
-                    'label'      => esc_html__('Add Contact', 'event_espresso'),
625
-                    'order'      => 15,
626
-                    'persistent' => false,
627
-                ],
628
-                'metaboxes'     => array_merge(
629
-                    $this->_default_espresso_metaboxes,
630
-                    ['_publish_post_box', 'attendee_editor_metaboxes']
631
-                ),
632
-                'require_nonce' => false,
633
-            ],
634
-            'edit_attendee'     => [
635
-                'nav'           => [
636
-                    'label'      => esc_html__('Edit Contact', 'event_espresso'),
637
-                    'order'      => 15,
638
-                    'persistent' => false,
639
-                    'url'        => $ATT_ID
640
-                        ? add_query_arg(['ATT_ID' => $ATT_ID], $this->_current_page_view_url)
641
-                        : $this->_admin_base_url,
642
-                ],
643
-                'metaboxes'     => ['attendee_editor_metaboxes'],
644
-                'require_nonce' => false,
645
-            ],
646
-            'contact_list'      => [
647
-                'nav'           => [
648
-                    'label' => esc_html__('Contact List', 'event_espresso'),
649
-                    'order' => 20,
650
-                ],
651
-                'list_table'    => 'EE_Attendee_Contact_List_Table',
652
-                'help_tabs'     => [
653
-                    'registrations_contact_list_help_tab'                       => [
654
-                        'title'    => esc_html__('Registrations Contact List', 'event_espresso'),
655
-                        'filename' => 'registrations_contact_list',
656
-                    ],
657
-                    'registrations_contact-list_table_column_headings_help_tab' => [
658
-                        'title'    => esc_html__('Contact List Table Column Headings', 'event_espresso'),
659
-                        'filename' => 'registrations_contact_list_table_column_headings',
660
-                    ],
661
-                    'registrations_contact_list_views_help_tab'                 => [
662
-                        'title'    => esc_html__('Contact List Views', 'event_espresso'),
663
-                        'filename' => 'registrations_contact_list_views',
664
-                    ],
665
-                    'registrations_contact_list_other_help_tab'                 => [
666
-                        'title'    => esc_html__('Contact List Other', 'event_espresso'),
667
-                        'filename' => 'registrations_contact_list_other',
668
-                    ],
669
-                ],
670
-                'metaboxes'     => [],
671
-                'require_nonce' => false,
672
-            ],
673
-            // override default cpt routes
674
-            'create_new'        => '',
675
-            'edit'              => '',
676
-        ];
677
-    }
678
-
679
-
680
-    /**
681
-     * The below methods aren't used by this class currently
682
-     */
683
-    protected function _add_screen_options()
684
-    {
685
-    }
686
-
687
-
688
-    protected function _add_feature_pointers()
689
-    {
690
-    }
691
-
692
-
693
-    public function admin_init()
694
-    {
695
-        EE_Registry::$i18n_js_strings['update_att_qstns'] = esc_html__(
696
-            'click "Update Registration Questions" to save your changes',
697
-            'event_espresso'
698
-        );
699
-    }
700
-
701
-
702
-    public function admin_notices()
703
-    {
704
-    }
705
-
706
-
707
-    public function admin_footer_scripts()
708
-    {
709
-    }
710
-
711
-
712
-    /**
713
-     * get list of registration statuses
714
-     *
715
-     * @return void
716
-     * @throws EE_Error
717
-     */
718
-    private function _get_registration_status_array()
719
-    {
720
-        self::$_reg_status = EEM_Registration::reg_status_array([], true);
721
-    }
722
-
723
-
724
-    /**
725
-     * @throws InvalidArgumentException
726
-     * @throws InvalidDataTypeException
727
-     * @throws InvalidInterfaceException
728
-     * @since 4.10.2.p
729
-     */
730
-    protected function _add_screen_options_default()
731
-    {
732
-        $this->_per_page_screen_option();
733
-    }
734
-
735
-
736
-    /**
737
-     * @throws InvalidArgumentException
738
-     * @throws InvalidDataTypeException
739
-     * @throws InvalidInterfaceException
740
-     * @since 4.10.2.p
741
-     */
742
-    protected function _add_screen_options_contact_list()
743
-    {
744
-        $page_title              = $this->_admin_page_title;
745
-        $this->_admin_page_title = esc_html__('Contacts', 'event_espresso');
746
-        $this->_per_page_screen_option();
747
-        $this->_admin_page_title = $page_title;
748
-    }
749
-
750
-
751
-    public function load_scripts_styles()
752
-    {
753
-        // style
754
-        wp_register_style(
755
-            'espresso_reg',
756
-            REG_ASSETS_URL . 'espresso_registrations_admin.css',
757
-            ['ee-admin-css'],
758
-            EVENT_ESPRESSO_VERSION
759
-        );
760
-        wp_enqueue_style('espresso_reg');
761
-        // script
762
-        wp_register_script(
763
-            'espresso_reg',
764
-            REG_ASSETS_URL . 'espresso_registrations_admin.js',
765
-            ['jquery-ui-datepicker', 'jquery-ui-draggable', 'ee_admin_js'],
766
-            EVENT_ESPRESSO_VERSION,
767
-            true
768
-        );
769
-        wp_enqueue_script('espresso_reg');
770
-    }
771
-
772
-
773
-    /**
774
-     * @throws EE_Error
775
-     * @throws InvalidArgumentException
776
-     * @throws InvalidDataTypeException
777
-     * @throws InvalidInterfaceException
778
-     * @throws ReflectionException
779
-     * @since 4.10.2.p
780
-     */
781
-    public function load_scripts_styles_edit_attendee()
782
-    {
783
-        // stuff to only show up on our attendee edit details page.
784
-        $attendee_details_translations = [
785
-            'att_publish_text' => sprintf(
786
-            /* translators: The date and time */
787
-                wp_strip_all_tags(__('Created on: %s', 'event_espresso')),
788
-                '<b>' . $this->_cpt_model_obj->get_datetime('ATT_created') . '</b>'
789
-            ),
790
-        ];
791
-        wp_localize_script('espresso_reg', 'ATTENDEE_DETAILS', $attendee_details_translations);
792
-        wp_enqueue_script('jquery-validate');
793
-    }
794
-
795
-
796
-    /**
797
-     * @throws EE_Error
798
-     * @throws InvalidArgumentException
799
-     * @throws InvalidDataTypeException
800
-     * @throws InvalidInterfaceException
801
-     * @throws ReflectionException
802
-     * @since 4.10.2.p
803
-     */
804
-    public function load_scripts_styles_view_registration()
805
-    {
806
-        // styles
807
-        wp_enqueue_style('espresso-ui-theme');
808
-        // scripts
809
-        $this->_get_reg_custom_questions_form($this->_registration->ID());
810
-        $this->_reg_custom_questions_form->wp_enqueue_scripts();
811
-    }
812
-
813
-
814
-    public function load_scripts_styles_contact_list()
815
-    {
816
-        wp_dequeue_style('espresso_reg');
817
-        wp_register_style(
818
-            'espresso_att',
819
-            REG_ASSETS_URL . 'espresso_attendees_admin.css',
820
-            ['ee-admin-css'],
821
-            EVENT_ESPRESSO_VERSION
822
-        );
823
-        wp_enqueue_style('espresso_att');
824
-    }
825
-
826
-
827
-    public function load_scripts_styles_new_registration()
828
-    {
829
-        wp_register_script(
830
-            'ee-spco-for-admin',
831
-            REG_ASSETS_URL . 'spco_for_admin.js',
832
-            ['underscore', 'jquery'],
833
-            EVENT_ESPRESSO_VERSION,
834
-            true
835
-        );
836
-        wp_enqueue_script('ee-spco-for-admin');
837
-        add_filter('FHEE__EED_Ticket_Selector__load_tckt_slctr_assets', '__return_true');
838
-        EE_Form_Section_Proper::wp_enqueue_scripts();
839
-        EED_Ticket_Selector::load_tckt_slctr_assets();
840
-        EE_Datepicker_Input::enqueue_styles_and_scripts();
841
-    }
842
-
843
-
844
-    public function AHEE__EE_Admin_Page__route_admin_request_resend_registration()
845
-    {
846
-        add_filter('FHEE_load_EE_messages', '__return_true');
847
-    }
848
-
849
-
850
-    public function AHEE__EE_Admin_Page__route_admin_request_approve_registration()
851
-    {
852
-        add_filter('FHEE_load_EE_messages', '__return_true');
853
-    }
854
-
855
-
856
-    /**
857
-     * @throws EE_Error
858
-     * @throws InvalidArgumentException
859
-     * @throws InvalidDataTypeException
860
-     * @throws InvalidInterfaceException
861
-     * @throws ReflectionException
862
-     * @since 4.10.2.p
863
-     */
864
-    protected function _set_list_table_views_default()
865
-    {
866
-        // for notification related bulk actions we need to make sure only active messengers have an option.
867
-        EED_Messages::set_autoloaders();
868
-        /** @type EE_Message_Resource_Manager $message_resource_manager */
869
-        $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
870
-        $active_mts               = $message_resource_manager->list_of_active_message_types();
871
-        // key= bulk_action_slug, value= message type.
872
-        $match_array = [
873
-            'approve_registrations'    => 'registration',
874
-            'decline_registrations'    => 'declined_registration',
875
-            'pending_registrations'    => 'pending_approval',
876
-            'no_approve_registrations' => 'not_approved_registration',
877
-            'cancel_registrations'     => 'cancelled_registration',
878
-        ];
879
-        $can_send    = EE_Registry::instance()->CAP->current_user_can(
880
-            'ee_send_message',
881
-            'batch_send_messages'
882
-        );
883
-        /** setup reg status bulk actions **/
884
-        $def_reg_status_actions['approve_registrations'] = esc_html__('Approve Registrations', 'event_espresso');
885
-        if ($can_send && in_array($match_array['approve_registrations'], $active_mts, true)) {
886
-            $def_reg_status_actions['approve_and_notify_registrations'] = esc_html__(
887
-                'Approve and Notify Registrations',
888
-                'event_espresso'
889
-            );
890
-        }
891
-        $def_reg_status_actions['decline_registrations'] = esc_html__('Decline Registrations', 'event_espresso');
892
-        if ($can_send && in_array($match_array['decline_registrations'], $active_mts, true)) {
893
-            $def_reg_status_actions['decline_and_notify_registrations'] = esc_html__(
894
-                'Decline and Notify Registrations',
895
-                'event_espresso'
896
-            );
897
-        }
898
-        $def_reg_status_actions['pending_registrations'] = esc_html__(
899
-            'Set Registrations to Pending Payment',
900
-            'event_espresso'
901
-        );
902
-        if ($can_send && in_array($match_array['pending_registrations'], $active_mts, true)) {
903
-            $def_reg_status_actions['pending_and_notify_registrations'] = esc_html__(
904
-                'Set Registrations to Pending Payment and Notify',
905
-                'event_espresso'
906
-            );
907
-        }
908
-        $def_reg_status_actions['no_approve_registrations'] = esc_html__(
909
-            'Set Registrations to Not Approved',
910
-            'event_espresso'
911
-        );
912
-        if ($can_send && in_array($match_array['no_approve_registrations'], $active_mts, true)) {
913
-            $def_reg_status_actions['no_approve_and_notify_registrations'] = esc_html__(
914
-                'Set Registrations to Not Approved and Notify',
915
-                'event_espresso'
916
-            );
917
-        }
918
-        $def_reg_status_actions['cancel_registrations'] = esc_html__('Cancel Registrations', 'event_espresso');
919
-        if ($can_send && in_array($match_array['cancel_registrations'], $active_mts, true)) {
920
-            $def_reg_status_actions['cancel_and_notify_registrations'] = esc_html__(
921
-                'Cancel Registrations and Notify',
922
-                'event_espresso'
923
-            );
924
-        }
925
-        $def_reg_status_actions = apply_filters(
926
-            'FHEE__Registrations_Admin_Page___set_list_table_views_default__def_reg_status_actions_array',
927
-            $def_reg_status_actions,
928
-            $active_mts,
929
-            $can_send
930
-        );
931
-
932
-        $this->_views = [
933
-            'all'   => [
934
-                'slug'        => 'all',
935
-                'label'       => esc_html__('View All Registrations', 'event_espresso'),
936
-                'count'       => 0,
937
-                'bulk_action' => array_merge(
938
-                    $def_reg_status_actions,
939
-                    [
940
-                        'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
941
-                    ]
942
-                ),
943
-            ],
944
-            'month' => [
945
-                'slug'        => 'month',
946
-                'label'       => esc_html__('This Month', 'event_espresso'),
947
-                'count'       => 0,
948
-                'bulk_action' => array_merge(
949
-                    $def_reg_status_actions,
950
-                    [
951
-                        'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
952
-                    ]
953
-                ),
954
-            ],
955
-            'today' => [
956
-                'slug'        => 'today',
957
-                'label'       => sprintf(
958
-                    esc_html__('Today - %s', 'event_espresso'),
959
-                    date('M d, Y', current_time('timestamp'))
960
-                ),
961
-                'count'       => 0,
962
-                'bulk_action' => array_merge(
963
-                    $def_reg_status_actions,
964
-                    [
965
-                        'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
966
-                    ]
967
-                ),
968
-            ],
969
-        ];
970
-        if (
971
-            EE_Registry::instance()->CAP->current_user_can(
972
-                'ee_delete_registrations',
973
-                'espresso_registrations_delete_registration'
974
-            )
975
-        ) {
976
-            $this->_views['incomplete'] = [
977
-                'slug'        => 'incomplete',
978
-                'label'       => esc_html__('Incomplete', 'event_espresso'),
979
-                'count'       => 0,
980
-                'bulk_action' => [
981
-                    'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
982
-                ],
983
-            ];
984
-            $this->_views['trash']      = [
985
-                'slug'        => 'trash',
986
-                'label'       => esc_html__('Trash', 'event_espresso'),
987
-                'count'       => 0,
988
-                'bulk_action' => [
989
-                    'restore_registrations' => esc_html__('Restore Registrations', 'event_espresso'),
990
-                    'delete_registrations'  => esc_html__('Delete Registrations Permanently', 'event_espresso'),
991
-                ],
992
-            ];
993
-        }
994
-    }
995
-
996
-
997
-    protected function _set_list_table_views_contact_list()
998
-    {
999
-        $this->_views = [
1000
-            'in_use' => [
1001
-                'slug'        => 'in_use',
1002
-                'label'       => esc_html__('In Use', 'event_espresso'),
1003
-                'count'       => 0,
1004
-                'bulk_action' => [
1005
-                    'trash_attendees' => esc_html__('Move to Trash', 'event_espresso'),
1006
-                ],
1007
-            ],
1008
-        ];
1009
-        if (
1010
-            EE_Registry::instance()->CAP->current_user_can(
1011
-                'ee_delete_contacts',
1012
-                'espresso_registrations_trash_attendees'
1013
-            )
1014
-        ) {
1015
-            $this->_views['trash'] = [
1016
-                'slug'        => 'trash',
1017
-                'label'       => esc_html__('Trash', 'event_espresso'),
1018
-                'count'       => 0,
1019
-                'bulk_action' => [
1020
-                    'restore_attendees' => esc_html__('Restore from Trash', 'event_espresso'),
1021
-                ],
1022
-            ];
1023
-        }
1024
-    }
1025
-
1026
-
1027
-    /**
1028
-     * @return array
1029
-     * @throws EE_Error
1030
-     */
1031
-    protected function _registration_legend_items()
1032
-    {
1033
-        $fc_items = [
1034
-            'star-icon'        => [
1035
-                'class' => 'dashicons dashicons-star-filled lt-blue-icon ee-icon-size-8',
1036
-                'desc'  => esc_html__('This is the Primary Registrant', 'event_espresso'),
1037
-            ],
1038
-            'view_details'     => [
1039
-                'class' => 'dashicons dashicons-clipboard',
1040
-                'desc'  => esc_html__('View Registration Details', 'event_espresso'),
1041
-            ],
1042
-            'edit_attendee'    => [
1043
-                'class' => 'ee-icon ee-icon-user-edit ee-icon-size-16',
1044
-                'desc'  => esc_html__('Edit Contact Details', 'event_espresso'),
1045
-            ],
1046
-            'view_transaction' => [
1047
-                'class' => 'dashicons dashicons-cart',
1048
-                'desc'  => esc_html__('View Transaction Details', 'event_espresso'),
1049
-            ],
1050
-            'view_invoice'     => [
1051
-                'class' => 'dashicons dashicons-media-spreadsheet',
1052
-                'desc'  => esc_html__('View Transaction Invoice', 'event_espresso'),
1053
-            ],
1054
-        ];
1055
-        if (
1056
-            EE_Registry::instance()->CAP->current_user_can(
1057
-                'ee_send_message',
1058
-                'espresso_registrations_resend_registration'
1059
-            )
1060
-        ) {
1061
-            $fc_items['resend_registration'] = [
1062
-                'class' => 'dashicons dashicons-email-alt',
1063
-                'desc'  => esc_html__('Resend Registration Details', 'event_espresso'),
1064
-            ];
1065
-        } else {
1066
-            $fc_items['blank'] = ['class' => 'blank', 'desc' => ''];
1067
-        }
1068
-        if (
1069
-            EE_Registry::instance()->CAP->current_user_can(
1070
-                'ee_read_global_messages',
1071
-                'view_filtered_messages'
1072
-            )
1073
-        ) {
1074
-            $related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
1075
-            if (is_array($related_for_icon) && isset($related_for_icon['css_class'], $related_for_icon['label'])) {
1076
-                $fc_items['view_related_messages'] = [
1077
-                    'class' => $related_for_icon['css_class'],
1078
-                    'desc'  => $related_for_icon['label'],
1079
-                ];
1080
-            }
1081
-        }
1082
-        $sc_items = [
1083
-            'approved_status'   => [
1084
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_approved,
1085
-                'desc'  => EEH_Template::pretty_status(
1086
-                    EEM_Registration::status_id_approved,
1087
-                    false,
1088
-                    'sentence'
1089
-                ),
1090
-            ],
1091
-            'pending_status'    => [
1092
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_pending_payment,
1093
-                'desc'  => EEH_Template::pretty_status(
1094
-                    EEM_Registration::status_id_pending_payment,
1095
-                    false,
1096
-                    'sentence'
1097
-                ),
1098
-            ],
1099
-            'wait_list'         => [
1100
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_wait_list,
1101
-                'desc'  => EEH_Template::pretty_status(
1102
-                    EEM_Registration::status_id_wait_list,
1103
-                    false,
1104
-                    'sentence'
1105
-                ),
1106
-            ],
1107
-            'incomplete_status' => [
1108
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_incomplete,
1109
-                'desc'  => EEH_Template::pretty_status(
1110
-                    EEM_Registration::status_id_incomplete,
1111
-                    false,
1112
-                    'sentence'
1113
-                ),
1114
-            ],
1115
-            'not_approved'      => [
1116
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_not_approved,
1117
-                'desc'  => EEH_Template::pretty_status(
1118
-                    EEM_Registration::status_id_not_approved,
1119
-                    false,
1120
-                    'sentence'
1121
-                ),
1122
-            ],
1123
-            'declined_status'   => [
1124
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_declined,
1125
-                'desc'  => EEH_Template::pretty_status(
1126
-                    EEM_Registration::status_id_declined,
1127
-                    false,
1128
-                    'sentence'
1129
-                ),
1130
-            ],
1131
-            'cancelled_status'  => [
1132
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_cancelled,
1133
-                'desc'  => EEH_Template::pretty_status(
1134
-                    EEM_Registration::status_id_cancelled,
1135
-                    false,
1136
-                    'sentence'
1137
-                ),
1138
-            ],
1139
-        ];
1140
-        return array_merge($fc_items, $sc_items);
1141
-    }
1142
-
1143
-
1144
-
1145
-    /***************************************        REGISTRATION OVERVIEW        **************************************/
1146
-
1147
-
1148
-    /**
1149
-     * @throws DomainException
1150
-     * @throws EE_Error
1151
-     * @throws InvalidArgumentException
1152
-     * @throws InvalidDataTypeException
1153
-     * @throws InvalidInterfaceException
1154
-     */
1155
-    protected function _registrations_overview_list_table()
1156
-    {
1157
-        $this->appendAddNewRegistrationButtonToPageTitle();
1158
-        $header_text                  = '';
1159
-        $admin_page_header_decorators = [
1160
-            'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\AttendeeFilterHeader',
1161
-            'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\EventFilterHeader',
1162
-            'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\DateFilterHeader',
1163
-            'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\TicketFilterHeader',
1164
-        ];
1165
-        foreach ($admin_page_header_decorators as $admin_page_header_decorator) {
1166
-            $filter_header_decorator = $this->getLoader()->getNew($admin_page_header_decorator);
1167
-            $header_text             = $filter_header_decorator->getHeaderText($header_text);
1168
-        }
1169
-        $this->_template_args['admin_page_header'] = $header_text;
1170
-        $this->_template_args['after_list_table']  = $this->_display_legend($this->_registration_legend_items());
1171
-        $this->display_admin_list_table_page_with_no_sidebar();
1172
-    }
1173
-
1174
-
1175
-    /**
1176
-     * @throws EE_Error
1177
-     * @throws InvalidArgumentException
1178
-     * @throws InvalidDataTypeException
1179
-     * @throws InvalidInterfaceException
1180
-     */
1181
-    private function appendAddNewRegistrationButtonToPageTitle()
1182
-    {
1183
-        $EVT_ID = $this->request->getRequestParam('event_id', 0, 'int');
1184
-        if (
1185
-            $EVT_ID
1186
-            && EE_Registry::instance()->CAP->current_user_can(
1187
-                'ee_edit_registrations',
1188
-                'espresso_registrations_new_registration',
1189
-                $EVT_ID
1190
-            )
1191
-        ) {
1192
-            $this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
1193
-                'new_registration',
1194
-                'add-registrant',
1195
-                ['event_id' => $EVT_ID],
1196
-                'add-new-h2'
1197
-            );
1198
-        }
1199
-    }
1200
-
1201
-
1202
-    /**
1203
-     * This sets the _registration property for the registration details screen
1204
-     *
1205
-     * @return void
1206
-     * @throws EE_Error
1207
-     * @throws InvalidArgumentException
1208
-     * @throws InvalidDataTypeException
1209
-     * @throws InvalidInterfaceException
1210
-     */
1211
-    private function _set_registration_object()
1212
-    {
1213
-        // get out if we've already set the object
1214
-        if ($this->_registration instanceof EE_Registration) {
1215
-            return;
1216
-        }
1217
-        $REG_ID = $this->request->getRequestParam('_REG_ID', 0, 'int');
1218
-        if ($this->_registration = $this->getRegistrationModel()->get_one_by_ID($REG_ID)) {
1219
-            return;
1220
-        }
1221
-        $error_msg = sprintf(
1222
-            esc_html__(
1223
-                'An error occurred and the details for Registration ID #%s could not be retrieved.',
1224
-                'event_espresso'
1225
-            ),
1226
-            $REG_ID
1227
-        );
1228
-        EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
1229
-        $this->_registration = null;
1230
-    }
1231
-
1232
-
1233
-    /**
1234
-     * Used to retrieve registrations for the list table.
1235
-     *
1236
-     * @param int  $per_page
1237
-     * @param bool $count
1238
-     * @param bool $this_month
1239
-     * @param bool $today
1240
-     * @return EE_Registration[]|int
1241
-     * @throws EE_Error
1242
-     * @throws InvalidArgumentException
1243
-     * @throws InvalidDataTypeException
1244
-     * @throws InvalidInterfaceException
1245
-     */
1246
-    public function get_registrations(
1247
-        $per_page = 10,
1248
-        $count = false,
1249
-        $this_month = false,
1250
-        $today = false
1251
-    ) {
1252
-        if ($this_month) {
1253
-            $this->request->setRequestParam('status', 'month');
1254
-        }
1255
-        if ($today) {
1256
-            $this->request->setRequestParam('status', 'today');
1257
-        }
1258
-        $query_params = $this->_get_registration_query_parameters([], $per_page, $count);
1259
-        /**
1260
-         * Override the default groupby added by EEM_Base so that sorts with multiple order bys work as expected
1261
-         *
1262
-         * @link https://events.codebasehq.com/projects/event-espresso/tickets/10093
1263
-         * @see  https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1264
-         *                      or if you have the development copy of EE you can view this at the path:
1265
-         *                      /docs/G--Model-System/model-query-params.md
1266
-         */
1267
-        $query_params['group_by'] = '';
1268
-
1269
-        return $count
1270
-            ? $this->getRegistrationModel()->count($query_params)
1271
-            /** @type EE_Registration[] */
1272
-            : $this->getRegistrationModel()->get_all($query_params);
1273
-    }
1274
-
1275
-
1276
-    /**
1277
-     * Retrieves the query parameters to be used by the Registration model for getting registrations.
1278
-     * Note: this listens to values on the request for some of the query parameters.
1279
-     *
1280
-     * @param array $request
1281
-     * @param int   $per_page
1282
-     * @param bool  $count
1283
-     * @return array
1284
-     * @throws EE_Error
1285
-     * @throws InvalidArgumentException
1286
-     * @throws InvalidDataTypeException
1287
-     * @throws InvalidInterfaceException
1288
-     */
1289
-    protected function _get_registration_query_parameters(
1290
-        $request = [],
1291
-        $per_page = 10,
1292
-        $count = false
1293
-    ) {
1294
-        /** @var EventEspresso\core\domain\services\admin\registrations\list_table\QueryBuilder $list_table_query_builder */
1295
-        $list_table_query_builder = $this->getLoader()->getNew(
1296
-            'EventEspresso\core\domain\services\admin\registrations\list_table\QueryBuilder',
1297
-            [null, null, $request]
1298
-        );
1299
-        return $list_table_query_builder->getQueryParams($per_page, $count);
1300
-    }
1301
-
1302
-
1303
-    public function get_registration_status_array()
1304
-    {
1305
-        return self::$_reg_status;
1306
-    }
1307
-
1308
-
1309
-
1310
-
1311
-    /***************************************        REGISTRATION DETAILS        ***************************************/
1312
-    /**
1313
-     * generates HTML for the View Registration Details Admin page
1314
-     *
1315
-     * @return void
1316
-     * @throws DomainException
1317
-     * @throws EE_Error
1318
-     * @throws InvalidArgumentException
1319
-     * @throws InvalidDataTypeException
1320
-     * @throws InvalidInterfaceException
1321
-     * @throws EntityNotFoundException
1322
-     * @throws ReflectionException
1323
-     */
1324
-    protected function _registration_details()
1325
-    {
1326
-        $this->_template_args = [];
1327
-        $this->_set_registration_object();
1328
-        if (is_object($this->_registration)) {
1329
-            $transaction                                   = $this->_registration->transaction()
1330
-                ? $this->_registration->transaction()
1331
-                : EE_Transaction::new_instance();
1332
-            $this->_session                                = $transaction->session_data();
1333
-            $event_id                                      = $this->_registration->event_ID();
1334
-            $this->_template_args['reg_nmbr']['value']     = $this->_registration->ID();
1335
-            $this->_template_args['reg_nmbr']['label']     = esc_html__('Registration Number', 'event_espresso');
1336
-            $this->_template_args['reg_datetime']['value'] = $this->_registration->get_i18n_datetime('REG_date');
1337
-            $this->_template_args['reg_datetime']['label'] = esc_html__('Date', 'event_espresso');
1338
-            $this->_template_args['grand_total']           = $transaction->total();
1339
-            $this->_template_args['currency_sign']         = EE_Registry::instance()->CFG->currency->sign;
1340
-            // link back to overview
1341
-            $this->_template_args['reg_overview_url']            = REG_ADMIN_URL;
1342
-            $this->_template_args['registration']                = $this->_registration;
1343
-            $this->_template_args['filtered_registrations_link'] = EE_Admin_Page::add_query_args_and_nonce(
1344
-                [
1345
-                    'action'   => 'default',
1346
-                    'event_id' => $event_id,
1347
-                ],
1348
-                REG_ADMIN_URL
1349
-            );
1350
-            $this->_template_args['filtered_transactions_link']  = EE_Admin_Page::add_query_args_and_nonce(
1351
-                [
1352
-                    'action' => 'default',
1353
-                    'EVT_ID' => $event_id,
1354
-                    'page'   => 'espresso_transactions',
1355
-                ],
1356
-                admin_url('admin.php')
1357
-            );
1358
-            $this->_template_args['event_link']                  = EE_Admin_Page::add_query_args_and_nonce(
1359
-                [
1360
-                    'page'   => 'espresso_events',
1361
-                    'action' => 'edit',
1362
-                    'post'   => $event_id,
1363
-                ],
1364
-                admin_url('admin.php')
1365
-            );
1366
-            // next and previous links
1367
-            $next_reg                                      = $this->_registration->next(
1368
-                null,
1369
-                [],
1370
-                'REG_ID'
1371
-            );
1372
-            $this->_template_args['next_registration']     = $next_reg
1373
-                ? $this->_next_link(
1374
-                    EE_Admin_Page::add_query_args_and_nonce(
1375
-                        [
1376
-                            'action'  => 'view_registration',
1377
-                            '_REG_ID' => $next_reg['REG_ID'],
1378
-                        ],
1379
-                        REG_ADMIN_URL
1380
-                    ),
1381
-                    'dashicons dashicons-arrow-right ee-icon-size-22'
1382
-                )
1383
-                : '';
1384
-            $previous_reg                                  = $this->_registration->previous(
1385
-                null,
1386
-                [],
1387
-                'REG_ID'
1388
-            );
1389
-            $this->_template_args['previous_registration'] = $previous_reg
1390
-                ? $this->_previous_link(
1391
-                    EE_Admin_Page::add_query_args_and_nonce(
1392
-                        [
1393
-                            'action'  => 'view_registration',
1394
-                            '_REG_ID' => $previous_reg['REG_ID'],
1395
-                        ],
1396
-                        REG_ADMIN_URL
1397
-                    ),
1398
-                    'dashicons dashicons-arrow-left ee-icon-size-22'
1399
-                )
1400
-                : '';
1401
-            // grab header
1402
-            $template_path                             = REG_TEMPLATE_PATH . 'reg_admin_details_header.template.php';
1403
-            $this->_template_args['REG_ID']            = $this->_registration->ID();
1404
-            $this->_template_args['admin_page_header'] = EEH_Template::display_template(
1405
-                $template_path,
1406
-                $this->_template_args,
1407
-                true
1408
-            );
1409
-        } else {
1410
-            $this->_template_args['admin_page_header'] = '';
1411
-            $this->_display_espresso_notices();
1412
-        }
1413
-        // the details template wrapper
1414
-        $this->display_admin_page_with_sidebar();
1415
-    }
1416
-
1417
-
1418
-    /**
1419
-     * @throws EE_Error
1420
-     * @throws InvalidArgumentException
1421
-     * @throws InvalidDataTypeException
1422
-     * @throws InvalidInterfaceException
1423
-     * @throws ReflectionException
1424
-     * @since 4.10.2.p
1425
-     */
1426
-    protected function _registration_details_metaboxes()
1427
-    {
1428
-        do_action('AHEE__Registrations_Admin_Page___registration_details_metabox__start', $this);
1429
-        $this->_set_registration_object();
1430
-        $attendee = $this->_registration instanceof EE_Registration ? $this->_registration->attendee() : null;
1431
-        add_meta_box(
1432
-            'edit-reg-status-mbox',
1433
-            esc_html__('Registration Status', 'event_espresso'),
1434
-            [$this, 'set_reg_status_buttons_metabox'],
1435
-            $this->_wp_page_slug,
1436
-            'normal',
1437
-            'high'
1438
-        );
1439
-        add_meta_box(
1440
-            'edit-reg-details-mbox',
1441
-            esc_html__('Registration Details', 'event_espresso'),
1442
-            [$this, '_reg_details_meta_box'],
1443
-            $this->_wp_page_slug,
1444
-            'normal',
1445
-            'high'
1446
-        );
1447
-        if (
1448
-            $attendee instanceof EE_Attendee
1449
-            && EE_Registry::instance()->CAP->current_user_can(
1450
-                'ee_read_registration',
1451
-                'edit-reg-questions-mbox',
1452
-                $this->_registration->ID()
1453
-            )
1454
-        ) {
1455
-            add_meta_box(
1456
-                'edit-reg-questions-mbox',
1457
-                esc_html__('Registration Form Answers', 'event_espresso'),
1458
-                [$this, '_reg_questions_meta_box'],
1459
-                $this->_wp_page_slug,
1460
-                'normal',
1461
-                'high'
1462
-            );
1463
-        }
1464
-        add_meta_box(
1465
-            'edit-reg-registrant-mbox',
1466
-            esc_html__('Contact Details', 'event_espresso'),
1467
-            [$this, '_reg_registrant_side_meta_box'],
1468
-            $this->_wp_page_slug,
1469
-            'side',
1470
-            'high'
1471
-        );
1472
-        if ($this->_registration->group_size() > 1) {
1473
-            add_meta_box(
1474
-                'edit-reg-attendees-mbox',
1475
-                esc_html__('Other Registrations in this Transaction', 'event_espresso'),
1476
-                [$this, '_reg_attendees_meta_box'],
1477
-                $this->_wp_page_slug,
1478
-                'normal',
1479
-                'high'
1480
-            );
1481
-        }
1482
-    }
1483
-
1484
-
1485
-    /**
1486
-     * set_reg_status_buttons_metabox
1487
-     *
1488
-     * @return void
1489
-     * @throws EE_Error
1490
-     * @throws EntityNotFoundException
1491
-     * @throws InvalidArgumentException
1492
-     * @throws InvalidDataTypeException
1493
-     * @throws InvalidInterfaceException
1494
-     * @throws ReflectionException
1495
-     */
1496
-    public function set_reg_status_buttons_metabox()
1497
-    {
1498
-        $this->_set_registration_object();
1499
-        $change_reg_status_form = $this->_generate_reg_status_change_form();
1500
-        $output                 = $change_reg_status_form->form_open(
1501
-            self::add_query_args_and_nonce(
1502
-                [
1503
-                    'action' => 'change_reg_status',
1504
-                ],
1505
-                REG_ADMIN_URL
1506
-            )
1507
-        );
1508
-        $output                 .= $change_reg_status_form->get_html();
1509
-        $output                 .= $change_reg_status_form->form_close();
1510
-        echo wp_kses($output, AllowedTags::getWithFormTags());
1511
-    }
1512
-
1513
-
1514
-    /**
1515
-     * @return EE_Form_Section_Proper
1516
-     * @throws EE_Error
1517
-     * @throws InvalidArgumentException
1518
-     * @throws InvalidDataTypeException
1519
-     * @throws InvalidInterfaceException
1520
-     * @throws EntityNotFoundException
1521
-     * @throws ReflectionException
1522
-     */
1523
-    protected function _generate_reg_status_change_form()
1524
-    {
1525
-        $reg_status_change_form_array = [
1526
-            'name'            => 'reg_status_change_form',
1527
-            'html_id'         => 'reg-status-change-form',
1528
-            'layout_strategy' => new EE_Admin_Two_Column_Layout(),
1529
-            'subsections'     => [
1530
-                'return'         => new EE_Hidden_Input(
1531
-                    [
1532
-                        'name'    => 'return',
1533
-                        'default' => 'view_registration',
1534
-                    ]
1535
-                ),
1536
-                'REG_ID'         => new EE_Hidden_Input(
1537
-                    [
1538
-                        'name'    => 'REG_ID',
1539
-                        'default' => $this->_registration->ID(),
1540
-                    ]
1541
-                ),
1542
-                'current_status' => new EE_Form_Section_HTML(
1543
-                    EEH_HTML::table(
1544
-                        EEH_HTML::tr(
1545
-                            EEH_HTML::th(
1546
-                                EEH_HTML::label(
1547
-                                    EEH_HTML::strong(
1548
-                                        esc_html__('Current Registration Status', 'event_espresso')
1549
-                                    )
1550
-                                )
1551
-                            )
1552
-                            . EEH_HTML::td(
1553
-                                EEH_HTML::strong(
1554
-                                    $this->_registration->pretty_status(),
1555
-                                    '',
1556
-                                    'status-' . $this->_registration->status_ID(),
1557
-                                    'line-height: 1em; font-size: 1.5em; font-weight: bold;'
1558
-                                )
1559
-                            )
1560
-                        )
1561
-                    )
1562
-                ),
1563
-            ],
1564
-        ];
1565
-        if (
1566
-            EE_Registry::instance()->CAP->current_user_can(
1567
-                'ee_edit_registration',
1568
-                'toggle_registration_status',
1569
-                $this->_registration->ID()
1570
-            )
1571
-        ) {
1572
-            $reg_status_change_form_array['subsections']['reg_status']         = new EE_Select_Input(
1573
-                $this->_get_reg_statuses(),
1574
-                [
1575
-                    'html_label_text' => esc_html__('Change Registration Status to', 'event_espresso'),
1576
-                    'default'         => $this->_registration->status_ID(),
1577
-                ]
1578
-            );
1579
-            $reg_status_change_form_array['subsections']['send_notifications'] = new EE_Yes_No_Input(
1580
-                [
1581
-                    'html_label_text' => esc_html__('Send Related Messages', 'event_espresso'),
1582
-                    'default'         => false,
1583
-                    'html_help_text'  => esc_html__(
1584
-                        'If set to "Yes", then the related messages will be sent to the registrant.',
1585
-                        'event_espresso'
1586
-                    ),
1587
-                ]
1588
-            );
1589
-            $reg_status_change_form_array['subsections']['submit']             = new EE_Submit_Input(
1590
-                [
1591
-                    'html_class'      => 'button-primary',
1592
-                    'html_label_text' => '&nbsp;',
1593
-                    'default'         => esc_html__('Update Registration Status', 'event_espresso'),
1594
-                ]
1595
-            );
1596
-        }
1597
-        return new EE_Form_Section_Proper($reg_status_change_form_array);
1598
-    }
1599
-
1600
-
1601
-    /**
1602
-     * Returns an array of all the buttons for the various statuses and switch status actions
1603
-     *
1604
-     * @return array
1605
-     * @throws EE_Error
1606
-     * @throws InvalidArgumentException
1607
-     * @throws InvalidDataTypeException
1608
-     * @throws InvalidInterfaceException
1609
-     * @throws EntityNotFoundException
1610
-     */
1611
-    protected function _get_reg_statuses()
1612
-    {
1613
-        $reg_status_array = $this->getRegistrationModel()->reg_status_array();
1614
-        unset($reg_status_array[ EEM_Registration::status_id_incomplete ]);
1615
-        // get current reg status
1616
-        $current_status = $this->_registration->status_ID();
1617
-        // is registration for free event? This will determine whether to display the pending payment option
1618
-        if (
1619
-            $current_status !== EEM_Registration::status_id_pending_payment
1620
-            && EEH_Money::compare_floats($this->_registration->ticket()->price(), 0.00)
1621
-        ) {
1622
-            unset($reg_status_array[ EEM_Registration::status_id_pending_payment ]);
1623
-        }
1624
-        return $this->getStatusModel()->localized_status($reg_status_array, false, 'sentence');
1625
-    }
1626
-
1627
-
1628
-    /**
1629
-     * This method is used when using _REG_ID from request which may or may not be an array of reg_ids.
1630
-     *
1631
-     * @param bool $status REG status given for changing registrations to.
1632
-     * @param bool $notify Whether to send messages notifications or not.
1633
-     * @return array (array with reg_id(s) updated and whether update was successful.
1634
-     * @throws DomainException
1635
-     * @throws EE_Error
1636
-     * @throws EntityNotFoundException
1637
-     * @throws InvalidArgumentException
1638
-     * @throws InvalidDataTypeException
1639
-     * @throws InvalidInterfaceException
1640
-     * @throws ReflectionException
1641
-     * @throws RuntimeException
1642
-     */
1643
-    protected function _set_registration_status_from_request($status = false, $notify = false)
1644
-    {
1645
-        $REG_IDs = $this->request->requestParamIsSet('reg_status_change_form')
1646
-            ? $this->request->getRequestParam('reg_status_change_form[REG_ID]', [], 'int', true)
1647
-            : $this->request->getRequestParam('_REG_ID', [], 'int', true);
1648
-
1649
-        // sanitize $REG_IDs
1650
-        $REG_IDs = array_map('absint', $REG_IDs);
1651
-        // and remove empty entries
1652
-        $REG_IDs = array_filter($REG_IDs);
1653
-
1654
-        $result = $this->_set_registration_status($REG_IDs, $status, $notify);
1655
-
1656
-        /**
1657
-         * Set and filter $_req_data['_REG_ID'] for any potential future messages notifications.
1658
-         * Currently this value is used downstream by the _process_resend_registration method.
1659
-         *
1660
-         * @param int|array                $registration_ids The registration ids that have had their status changed successfully.
1661
-         * @param bool                     $status           The status registrations were changed to.
1662
-         * @param bool                     $success          If the status was changed successfully for all registrations.
1663
-         * @param Registrations_Admin_Page $admin_page_object
1664
-         */
1665
-        $REG_ID = apply_filters(
1666
-            'FHEE__Registrations_Admin_Page___set_registration_status_from_request__REG_IDs',
1667
-            $result['REG_ID'],
1668
-            $status,
1669
-            $result['success'],
1670
-            $this
1671
-        );
1672
-        $this->request->setRequestParam('_REG_ID', $REG_ID);
1673
-
1674
-        // notify?
1675
-        if (
1676
-            $notify
1677
-            && $result['success']
1678
-            && ! empty($REG_ID)
1679
-            && EE_Registry::instance()->CAP->current_user_can(
1680
-                'ee_send_message',
1681
-                'espresso_registrations_resend_registration'
1682
-            )
1683
-        ) {
1684
-            $this->_process_resend_registration();
1685
-        }
1686
-        return $result;
1687
-    }
1688
-
1689
-
1690
-    /**
1691
-     * Set the registration status for the given reg_id (which may or may not be an array, it gets typecast to an
1692
-     * array). Note, this method does NOT take care of possible notifications.  That is required by calling code.
1693
-     *
1694
-     * @param array  $REG_IDs
1695
-     * @param string $status
1696
-     * @param bool   $notify Used to indicate whether notification was requested or not.  This determines the context
1697
-     *                       slug sent with setting the registration status.
1698
-     * @return array (an array with 'success' key representing whether status change was successful, and 'REG_ID' as
1699
-     * @throws EE_Error
1700
-     * @throws InvalidArgumentException
1701
-     * @throws InvalidDataTypeException
1702
-     * @throws InvalidInterfaceException
1703
-     * @throws ReflectionException
1704
-     * @throws RuntimeException
1705
-     * @throws EntityNotFoundException
1706
-     * @throws DomainException
1707
-     */
1708
-    protected function _set_registration_status($REG_IDs = [], $status = '', $notify = false)
1709
-    {
1710
-        $success = false;
1711
-        // typecast $REG_IDs
1712
-        $REG_IDs = (array) $REG_IDs;
1713
-        if (! empty($REG_IDs)) {
1714
-            $success = true;
1715
-            // set default status if none is passed
1716
-            $status         = $status ?: EEM_Registration::status_id_pending_payment;
1717
-            $status_context = $notify
1718
-                ? Domain::CONTEXT_REGISTRATION_STATUS_CHANGE_REGISTRATION_ADMIN_NOTIFY
1719
-                : Domain::CONTEXT_REGISTRATION_STATUS_CHANGE_REGISTRATION_ADMIN;
1720
-            // loop through REG_ID's and change status
1721
-            foreach ($REG_IDs as $REG_ID) {
1722
-                $registration = $this->getRegistrationModel()->get_one_by_ID($REG_ID);
1723
-                if ($registration instanceof EE_Registration) {
1724
-                    $registration->set_status(
1725
-                        $status,
1726
-                        false,
1727
-                        new Context(
1728
-                            $status_context,
1729
-                            esc_html__(
1730
-                                'Manually triggered status change on a Registration Admin Page route.',
1731
-                                'event_espresso'
1732
-                            )
1733
-                        )
1734
-                    );
1735
-                    $result = $registration->save();
1736
-                    // verifying explicit fails because update *may* just return 0 for 0 rows affected
1737
-                    $success = $result !== false ? $success : false;
1738
-                }
1739
-            }
1740
-        }
1741
-
1742
-        // return $success and processed registrations
1743
-        return ['REG_ID' => $REG_IDs, 'success' => $success];
1744
-    }
1745
-
1746
-
1747
-    /**
1748
-     * Common logic for setting up success message and redirecting to appropriate route
1749
-     *
1750
-     * @param string $STS_ID status id for the registration changed to
1751
-     * @param bool   $notify indicates whether the _set_registration_status_from_request does notifications or not.
1752
-     * @return void
1753
-     * @throws DomainException
1754
-     * @throws EE_Error
1755
-     * @throws EntityNotFoundException
1756
-     * @throws InvalidArgumentException
1757
-     * @throws InvalidDataTypeException
1758
-     * @throws InvalidInterfaceException
1759
-     * @throws ReflectionException
1760
-     * @throws RuntimeException
1761
-     */
1762
-    protected function _reg_status_change_return($STS_ID, $notify = false)
1763
-    {
1764
-        $result  = ! empty($STS_ID) ? $this->_set_registration_status_from_request($STS_ID, $notify)
1765
-            : ['success' => false];
1766
-        $success = isset($result['success']) && $result['success'];
1767
-        // setup success message
1768
-        if ($success) {
1769
-            if (is_array($result['REG_ID']) && count($result['REG_ID']) === 1) {
1770
-                $msg = sprintf(
1771
-                    esc_html__('Registration status has been set to %s', 'event_espresso'),
1772
-                    EEH_Template::pretty_status($STS_ID, false, 'lower')
1773
-                );
1774
-            } else {
1775
-                $msg = sprintf(
1776
-                    esc_html__('Registrations have been set to %s.', 'event_espresso'),
1777
-                    EEH_Template::pretty_status($STS_ID, false, 'lower')
1778
-                );
1779
-            }
1780
-            EE_Error::add_success($msg);
1781
-        } else {
1782
-            EE_Error::add_error(
1783
-                esc_html__(
1784
-                    'Something went wrong, and the status was not changed',
1785
-                    'event_espresso'
1786
-                ),
1787
-                __FILE__,
1788
-                __LINE__,
1789
-                __FUNCTION__
1790
-            );
1791
-        }
1792
-        $return = $this->request->getRequestParam('return');
1793
-        $route  = $return === 'view_registration'
1794
-            ? ['action' => 'view_registration', '_REG_ID' => reset($result['REG_ID'])]
1795
-            : ['action' => 'default'];
1796
-        $route  = $this->mergeExistingRequestParamsWithRedirectArgs($route);
1797
-        $this->_redirect_after_action($success, '', '', $route, true);
1798
-    }
1799
-
1800
-
1801
-    /**
1802
-     * incoming reg status change from reg details page.
1803
-     *
1804
-     * @return void
1805
-     * @throws EE_Error
1806
-     * @throws EntityNotFoundException
1807
-     * @throws InvalidArgumentException
1808
-     * @throws InvalidDataTypeException
1809
-     * @throws InvalidInterfaceException
1810
-     * @throws ReflectionException
1811
-     * @throws RuntimeException
1812
-     * @throws DomainException
1813
-     */
1814
-    protected function _change_reg_status()
1815
-    {
1816
-        $this->request->setRequestParam('return', 'view_registration');
1817
-        // set notify based on whether the send notifications toggle is set or not
1818
-        $notify     = $this->request->getRequestParam('reg_status_change_form[send_notifications]', false, 'bool');
1819
-        $reg_status = $this->request->getRequestParam('reg_status_change_form[reg_status]', '');
1820
-        $this->request->setRequestParam('reg_status_change_form[reg_status]', $reg_status);
1821
-        switch ($reg_status) {
1822
-            case EEM_Registration::status_id_approved:
1823
-            case EEH_Template::pretty_status(EEM_Registration::status_id_approved, false, 'sentence'):
1824
-                $this->approve_registration($notify);
1825
-                break;
1826
-            case EEM_Registration::status_id_pending_payment:
1827
-            case EEH_Template::pretty_status(EEM_Registration::status_id_pending_payment, false, 'sentence'):
1828
-                $this->pending_registration($notify);
1829
-                break;
1830
-            case EEM_Registration::status_id_not_approved:
1831
-            case EEH_Template::pretty_status(EEM_Registration::status_id_not_approved, false, 'sentence'):
1832
-                $this->not_approve_registration($notify);
1833
-                break;
1834
-            case EEM_Registration::status_id_declined:
1835
-            case EEH_Template::pretty_status(EEM_Registration::status_id_declined, false, 'sentence'):
1836
-                $this->decline_registration($notify);
1837
-                break;
1838
-            case EEM_Registration::status_id_cancelled:
1839
-            case EEH_Template::pretty_status(EEM_Registration::status_id_cancelled, false, 'sentence'):
1840
-                $this->cancel_registration($notify);
1841
-                break;
1842
-            case EEM_Registration::status_id_wait_list:
1843
-            case EEH_Template::pretty_status(EEM_Registration::status_id_wait_list, false, 'sentence'):
1844
-                $this->wait_list_registration($notify);
1845
-                break;
1846
-            case EEM_Registration::status_id_incomplete:
1847
-            default:
1848
-                $this->request->unSetRequestParam('return');
1849
-                $this->_reg_status_change_return('');
1850
-                break;
1851
-        }
1852
-    }
1853
-
1854
-
1855
-    /**
1856
-     * Callback for bulk action routes.
1857
-     * Note: although we could just register the singular route callbacks for each bulk action route as well, this
1858
-     * method was chosen so there is one central place all the registration status bulk actions are going through.
1859
-     * Potentially, this provides an easier place to locate logic that is specific to these bulk actions (as opposed to
1860
-     * when an action is happening on just a single registration).
1861
-     *
1862
-     * @param      $action
1863
-     * @param bool $notify
1864
-     */
1865
-    protected function bulk_action_on_registrations($action, $notify = false)
1866
-    {
1867
-        do_action(
1868
-            'AHEE__Registrations_Admin_Page__bulk_action_on_registrations__before_execution',
1869
-            $this,
1870
-            $action,
1871
-            $notify
1872
-        );
1873
-        $method = $action . '_registration';
1874
-        if (method_exists($this, $method)) {
1875
-            $this->$method($notify);
1876
-        }
1877
-    }
1878
-
1879
-
1880
-    /**
1881
-     * approve_registration
1882
-     *
1883
-     * @param bool $notify whether or not to notify the registrant about their approval.
1884
-     * @return void
1885
-     * @throws EE_Error
1886
-     * @throws EntityNotFoundException
1887
-     * @throws InvalidArgumentException
1888
-     * @throws InvalidDataTypeException
1889
-     * @throws InvalidInterfaceException
1890
-     * @throws ReflectionException
1891
-     * @throws RuntimeException
1892
-     * @throws DomainException
1893
-     */
1894
-    protected function approve_registration($notify = false)
1895
-    {
1896
-        $this->_reg_status_change_return(EEM_Registration::status_id_approved, $notify);
1897
-    }
1898
-
1899
-
1900
-    /**
1901
-     * decline_registration
1902
-     *
1903
-     * @param bool $notify whether or not to notify the registrant about their status change.
1904
-     * @return void
1905
-     * @throws EE_Error
1906
-     * @throws EntityNotFoundException
1907
-     * @throws InvalidArgumentException
1908
-     * @throws InvalidDataTypeException
1909
-     * @throws InvalidInterfaceException
1910
-     * @throws ReflectionException
1911
-     * @throws RuntimeException
1912
-     * @throws DomainException
1913
-     */
1914
-    protected function decline_registration($notify = false)
1915
-    {
1916
-        $this->_reg_status_change_return(EEM_Registration::status_id_declined, $notify);
1917
-    }
1918
-
1919
-
1920
-    /**
1921
-     * cancel_registration
1922
-     *
1923
-     * @param bool $notify whether or not to notify the registrant about their status change.
1924
-     * @return void
1925
-     * @throws EE_Error
1926
-     * @throws EntityNotFoundException
1927
-     * @throws InvalidArgumentException
1928
-     * @throws InvalidDataTypeException
1929
-     * @throws InvalidInterfaceException
1930
-     * @throws ReflectionException
1931
-     * @throws RuntimeException
1932
-     * @throws DomainException
1933
-     */
1934
-    protected function cancel_registration($notify = false)
1935
-    {
1936
-        $this->_reg_status_change_return(EEM_Registration::status_id_cancelled, $notify);
1937
-    }
1938
-
1939
-
1940
-    /**
1941
-     * not_approve_registration
1942
-     *
1943
-     * @param bool $notify whether or not to notify the registrant about their status change.
1944
-     * @return void
1945
-     * @throws EE_Error
1946
-     * @throws EntityNotFoundException
1947
-     * @throws InvalidArgumentException
1948
-     * @throws InvalidDataTypeException
1949
-     * @throws InvalidInterfaceException
1950
-     * @throws ReflectionException
1951
-     * @throws RuntimeException
1952
-     * @throws DomainException
1953
-     */
1954
-    protected function not_approve_registration($notify = false)
1955
-    {
1956
-        $this->_reg_status_change_return(EEM_Registration::status_id_not_approved, $notify);
1957
-    }
1958
-
1959
-
1960
-    /**
1961
-     * decline_registration
1962
-     *
1963
-     * @param bool $notify whether or not to notify the registrant about their status change.
1964
-     * @return void
1965
-     * @throws EE_Error
1966
-     * @throws EntityNotFoundException
1967
-     * @throws InvalidArgumentException
1968
-     * @throws InvalidDataTypeException
1969
-     * @throws InvalidInterfaceException
1970
-     * @throws ReflectionException
1971
-     * @throws RuntimeException
1972
-     * @throws DomainException
1973
-     */
1974
-    protected function pending_registration($notify = false)
1975
-    {
1976
-        $this->_reg_status_change_return(EEM_Registration::status_id_pending_payment, $notify);
1977
-    }
1978
-
1979
-
1980
-    /**
1981
-     * waitlist_registration
1982
-     *
1983
-     * @param bool $notify whether or not to notify the registrant about their status change.
1984
-     * @return void
1985
-     * @throws EE_Error
1986
-     * @throws EntityNotFoundException
1987
-     * @throws InvalidArgumentException
1988
-     * @throws InvalidDataTypeException
1989
-     * @throws InvalidInterfaceException
1990
-     * @throws ReflectionException
1991
-     * @throws RuntimeException
1992
-     * @throws DomainException
1993
-     */
1994
-    protected function wait_list_registration($notify = false)
1995
-    {
1996
-        $this->_reg_status_change_return(EEM_Registration::status_id_wait_list, $notify);
1997
-    }
1998
-
1999
-
2000
-    /**
2001
-     * generates HTML for the Registration main meta box
2002
-     *
2003
-     * @return void
2004
-     * @throws DomainException
2005
-     * @throws EE_Error
2006
-     * @throws InvalidArgumentException
2007
-     * @throws InvalidDataTypeException
2008
-     * @throws InvalidInterfaceException
2009
-     * @throws ReflectionException
2010
-     * @throws EntityNotFoundException
2011
-     */
2012
-    public function _reg_details_meta_box()
2013
-    {
2014
-        EEH_Autoloader::register_line_item_display_autoloaders();
2015
-        EEH_Autoloader::register_line_item_filter_autoloaders();
2016
-        EE_Registry::instance()->load_helper('Line_Item');
2017
-        $transaction    = $this->_registration->transaction() ? $this->_registration->transaction()
2018
-            : EE_Transaction::new_instance();
2019
-        $this->_session = $transaction->session_data();
2020
-        $filters        = new EE_Line_Item_Filter_Collection();
2021
-        $filters->add(new EE_Single_Registration_Line_Item_Filter($this->_registration));
2022
-        $filters->add(new EE_Non_Zero_Line_Item_Filter());
2023
-        $line_item_filter_processor              = new EE_Line_Item_Filter_Processor(
2024
-            $filters,
2025
-            $transaction->total_line_item()
2026
-        );
2027
-        $filtered_line_item_tree                 = $line_item_filter_processor->process();
2028
-        $line_item_display                       = new EE_Line_Item_Display(
2029
-            'reg_admin_table',
2030
-            'EE_Admin_Table_Registration_Line_Item_Display_Strategy'
2031
-        );
2032
-        $this->_template_args['line_item_table'] = $line_item_display->display_line_item(
2033
-            $filtered_line_item_tree,
2034
-            ['EE_Registration' => $this->_registration]
2035
-        );
2036
-        $attendee                                = $this->_registration->attendee();
2037
-        if (
2038
-            EE_Registry::instance()->CAP->current_user_can(
2039
-                'ee_read_transaction',
2040
-                'espresso_transactions_view_transaction'
2041
-            )
2042
-        ) {
2043
-            $this->_template_args['view_transaction_button'] = EEH_Template::get_button_or_link(
2044
-                EE_Admin_Page::add_query_args_and_nonce(
2045
-                    [
2046
-                        'action' => 'view_transaction',
2047
-                        'TXN_ID' => $transaction->ID(),
2048
-                    ],
2049
-                    TXN_ADMIN_URL
2050
-                ),
2051
-                esc_html__(' View Transaction', 'event_espresso'),
2052
-                'button secondary-button right',
2053
-                'dashicons dashicons-cart'
2054
-            );
2055
-        } else {
2056
-            $this->_template_args['view_transaction_button'] = '';
2057
-        }
2058
-        if (
2059
-            $attendee instanceof EE_Attendee
2060
-            && EE_Registry::instance()->CAP->current_user_can(
2061
-                'ee_send_message',
2062
-                'espresso_registrations_resend_registration'
2063
-            )
2064
-        ) {
2065
-            $this->_template_args['resend_registration_button'] = EEH_Template::get_button_or_link(
2066
-                EE_Admin_Page::add_query_args_and_nonce(
2067
-                    [
2068
-                        'action'      => 'resend_registration',
2069
-                        '_REG_ID'     => $this->_registration->ID(),
2070
-                        'redirect_to' => 'view_registration',
2071
-                    ],
2072
-                    REG_ADMIN_URL
2073
-                ),
2074
-                esc_html__(' Resend Registration', 'event_espresso'),
2075
-                'button secondary-button right',
2076
-                'dashicons dashicons-email-alt'
2077
-            );
2078
-        } else {
2079
-            $this->_template_args['resend_registration_button'] = '';
2080
-        }
2081
-        $this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
2082
-        $payment                               = $transaction->get_first_related('Payment');
2083
-        $payment                               = ! $payment instanceof EE_Payment
2084
-            ? EE_Payment::new_instance()
2085
-            : $payment;
2086
-        $payment_method                        = $payment->get_first_related('Payment_Method');
2087
-        $payment_method                        = ! $payment_method instanceof EE_Payment_Method
2088
-            ? EE_Payment_Method::new_instance()
2089
-            : $payment_method;
2090
-        $reg_details                           = [
2091
-            'payment_method'       => $payment_method->name(),
2092
-            'response_msg'         => $payment->gateway_response(),
2093
-            'registration_id'      => $this->_registration->get('REG_code'),
2094
-            'registration_session' => $this->_registration->session_ID(),
2095
-            'ip_address'           => isset($this->_session['ip_address']) ? $this->_session['ip_address'] : '',
2096
-            'user_agent'           => isset($this->_session['user_agent']) ? $this->_session['user_agent'] : '',
2097
-        ];
2098
-        if (isset($reg_details['registration_id'])) {
2099
-            $this->_template_args['reg_details']['registration_id']['value'] = $reg_details['registration_id'];
2100
-            $this->_template_args['reg_details']['registration_id']['label'] = esc_html__(
2101
-                'Registration ID',
2102
-                'event_espresso'
2103
-            );
2104
-            $this->_template_args['reg_details']['registration_id']['class'] = 'regular-text';
2105
-        }
2106
-        if (isset($reg_details['payment_method'])) {
2107
-            $this->_template_args['reg_details']['payment_method']['value'] = $reg_details['payment_method'];
2108
-            $this->_template_args['reg_details']['payment_method']['label'] = esc_html__(
2109
-                'Most Recent Payment Method',
2110
-                'event_espresso'
2111
-            );
2112
-            $this->_template_args['reg_details']['payment_method']['class'] = 'regular-text';
2113
-            $this->_template_args['reg_details']['response_msg']['value']   = $reg_details['response_msg'];
2114
-            $this->_template_args['reg_details']['response_msg']['label']   = esc_html__(
2115
-                'Payment method response',
2116
-                'event_espresso'
2117
-            );
2118
-            $this->_template_args['reg_details']['response_msg']['class']   = 'regular-text';
2119
-        }
2120
-        $this->_template_args['reg_details']['registration_session']['value'] = $reg_details['registration_session'];
2121
-        $this->_template_args['reg_details']['registration_session']['label'] = esc_html__(
2122
-            'Registration Session',
2123
-            'event_espresso'
2124
-        );
2125
-        $this->_template_args['reg_details']['registration_session']['class'] = 'regular-text';
2126
-        $this->_template_args['reg_details']['ip_address']['value']           = $reg_details['ip_address'];
2127
-        $this->_template_args['reg_details']['ip_address']['label']           = esc_html__(
2128
-            'Registration placed from IP',
2129
-            'event_espresso'
2130
-        );
2131
-        $this->_template_args['reg_details']['ip_address']['class']           = 'regular-text';
2132
-        $this->_template_args['reg_details']['user_agent']['value']           = $reg_details['user_agent'];
2133
-        $this->_template_args['reg_details']['user_agent']['label']           = esc_html__(
2134
-            'Registrant User Agent',
2135
-            'event_espresso'
2136
-        );
2137
-        $this->_template_args['reg_details']['user_agent']['class']           = 'large-text';
2138
-        $this->_template_args['event_link']                                   = EE_Admin_Page::add_query_args_and_nonce(
2139
-            [
2140
-                'action'   => 'default',
2141
-                'event_id' => $this->_registration->event_ID(),
2142
-            ],
2143
-            REG_ADMIN_URL
2144
-        );
2145
-        $this->_template_args['REG_ID']                                       = $this->_registration->ID();
2146
-        $this->_template_args['event_id']                                     = $this->_registration->event_ID();
2147
-        $template_path                                                        =
2148
-            REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_details.template.php';
2149
-        EEH_Template::display_template($template_path, $this->_template_args); // already escaped
2150
-    }
2151
-
2152
-
2153
-    /**
2154
-     * generates HTML for the Registration Questions meta box.
2155
-     * If pre-4.8.32.rc.000 hooks are used, uses old methods (with its filters),
2156
-     * otherwise uses new forms system
2157
-     *
2158
-     * @return void
2159
-     * @throws DomainException
2160
-     * @throws EE_Error
2161
-     * @throws InvalidArgumentException
2162
-     * @throws InvalidDataTypeException
2163
-     * @throws InvalidInterfaceException
2164
-     * @throws ReflectionException
2165
-     */
2166
-    public function _reg_questions_meta_box()
2167
-    {
2168
-        // allow someone to override this method entirely
2169
-        if (
2170
-            apply_filters(
2171
-                'FHEE__Registrations_Admin_Page___reg_questions_meta_box__do_default',
2172
-                true,
2173
-                $this,
2174
-                $this->_registration
2175
-            )
2176
-        ) {
2177
-            $form                                              = $this->_get_reg_custom_questions_form(
2178
-                $this->_registration->ID()
2179
-            );
2180
-            $this->_template_args['att_questions']             = count($form->subforms()) > 0
2181
-                ? $form->get_html_and_js()
2182
-                : '';
2183
-            $this->_template_args['reg_questions_form_action'] = 'edit_registration';
2184
-            $this->_template_args['REG_ID']                    = $this->_registration->ID();
2185
-            $template_path                                     =
2186
-                REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_questions.template.php';
2187
-            EEH_Template::display_template($template_path, $this->_template_args);
2188
-        }
2189
-    }
2190
-
2191
-
2192
-    /**
2193
-     * form_before_question_group
2194
-     *
2195
-     * @param string $output
2196
-     * @return        string
2197
-     * @deprecated    as of 4.8.32.rc.000
2198
-     */
2199
-    public function form_before_question_group($output)
2200
-    {
2201
-        EE_Error::doing_it_wrong(
2202
-            __CLASS__ . '::' . __FUNCTION__,
2203
-            esc_html__(
2204
-                '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.',
2205
-                'event_espresso'
2206
-            ),
2207
-            '4.8.32.rc.000'
2208
-        );
2209
-        return '
24
+	/**
25
+	 * @var EE_Registration
26
+	 */
27
+	private $_registration;
28
+
29
+	/**
30
+	 * @var EE_Event
31
+	 */
32
+	private $_reg_event;
33
+
34
+	/**
35
+	 * @var EE_Session
36
+	 */
37
+	private $_session;
38
+
39
+	/**
40
+	 * @var array
41
+	 */
42
+	private static $_reg_status;
43
+
44
+	/**
45
+	 * Form for displaying the custom questions for this registration.
46
+	 * This gets used a few times throughout the request so its best to cache it
47
+	 *
48
+	 * @var EE_Registration_Custom_Questions_Form
49
+	 */
50
+	protected $_reg_custom_questions_form = null;
51
+
52
+	/**
53
+	 * @var EEM_Registration $registration_model
54
+	 */
55
+	private $registration_model;
56
+
57
+	/**
58
+	 * @var EEM_Attendee $attendee_model
59
+	 */
60
+	private $attendee_model;
61
+
62
+	/**
63
+	 * @var EEM_Event $event_model
64
+	 */
65
+	private $event_model;
66
+
67
+	/**
68
+	 * @var EEM_Status $status_model
69
+	 */
70
+	private $status_model;
71
+
72
+
73
+	/**
74
+	 * @param bool $routing
75
+	 * @throws EE_Error
76
+	 * @throws InvalidArgumentException
77
+	 * @throws InvalidDataTypeException
78
+	 * @throws InvalidInterfaceException
79
+	 * @throws ReflectionException
80
+	 */
81
+	public function __construct($routing = true)
82
+	{
83
+		parent::__construct($routing);
84
+		add_action('wp_loaded', [$this, 'wp_loaded']);
85
+	}
86
+
87
+
88
+	/**
89
+	 * @return EEM_Registration
90
+	 * @throws InvalidArgumentException
91
+	 * @throws InvalidDataTypeException
92
+	 * @throws InvalidInterfaceException
93
+	 * @since 4.10.2.p
94
+	 */
95
+	protected function getRegistrationModel()
96
+	{
97
+		if (! $this->registration_model instanceof EEM_Registration) {
98
+			$this->registration_model = $this->getLoader()->getShared('EEM_Registration');
99
+		}
100
+		return $this->registration_model;
101
+	}
102
+
103
+
104
+	/**
105
+	 * @return EEM_Attendee
106
+	 * @throws InvalidArgumentException
107
+	 * @throws InvalidDataTypeException
108
+	 * @throws InvalidInterfaceException
109
+	 * @since 4.10.2.p
110
+	 */
111
+	protected function getAttendeeModel()
112
+	{
113
+		if (! $this->attendee_model instanceof EEM_Attendee) {
114
+			$this->attendee_model = $this->getLoader()->getShared('EEM_Attendee');
115
+		}
116
+		return $this->attendee_model;
117
+	}
118
+
119
+
120
+	/**
121
+	 * @return EEM_Event
122
+	 * @throws InvalidArgumentException
123
+	 * @throws InvalidDataTypeException
124
+	 * @throws InvalidInterfaceException
125
+	 * @since 4.10.2.p
126
+	 */
127
+	protected function getEventModel()
128
+	{
129
+		if (! $this->event_model instanceof EEM_Event) {
130
+			$this->event_model = $this->getLoader()->getShared('EEM_Event');
131
+		}
132
+		return $this->event_model;
133
+	}
134
+
135
+
136
+	/**
137
+	 * @return EEM_Status
138
+	 * @throws InvalidArgumentException
139
+	 * @throws InvalidDataTypeException
140
+	 * @throws InvalidInterfaceException
141
+	 * @since 4.10.2.p
142
+	 */
143
+	protected function getStatusModel()
144
+	{
145
+		if (! $this->status_model instanceof EEM_Status) {
146
+			$this->status_model = $this->getLoader()->getShared('EEM_Status');
147
+		}
148
+		return $this->status_model;
149
+	}
150
+
151
+
152
+	public function wp_loaded()
153
+	{
154
+		// when adding a new registration...
155
+		$action = $this->request->getRequestParam('action');
156
+		if ($action === 'new_registration') {
157
+			EE_System::do_not_cache();
158
+			if ($this->request->getRequestParam('processing_registration', 0, 'int') !== 1) {
159
+				// and it's NOT the attendee information reg step
160
+				// force cookie expiration by setting time to last week
161
+				setcookie('ee_registration_added', 0, time() - WEEK_IN_SECONDS, '/');
162
+				// and update the global
163
+				$_COOKIE['ee_registration_added'] = 0;
164
+			}
165
+		}
166
+	}
167
+
168
+
169
+	protected function _init_page_props()
170
+	{
171
+		$this->page_slug        = REG_PG_SLUG;
172
+		$this->_admin_base_url  = REG_ADMIN_URL;
173
+		$this->_admin_base_path = REG_ADMIN;
174
+		$this->page_label       = esc_html__('Registrations', 'event_espresso');
175
+		$this->_cpt_routes      = [
176
+			'add_new_attendee' => 'espresso_attendees',
177
+			'edit_attendee'    => 'espresso_attendees',
178
+			'insert_attendee'  => 'espresso_attendees',
179
+			'update_attendee'  => 'espresso_attendees',
180
+		];
181
+		$this->_cpt_model_names = [
182
+			'add_new_attendee' => 'EEM_Attendee',
183
+			'edit_attendee'    => 'EEM_Attendee',
184
+		];
185
+		$this->_cpt_edit_routes = [
186
+			'espresso_attendees' => 'edit_attendee',
187
+		];
188
+		$this->_pagenow_map     = [
189
+			'add_new_attendee' => 'post-new.php',
190
+			'edit_attendee'    => 'post.php',
191
+			'trash'            => 'post.php',
192
+		];
193
+		add_action('edit_form_after_title', [$this, 'after_title_form_fields'], 10);
194
+		// add filters so that the comment urls don't take users to a confusing 404 page
195
+		add_filter('get_comment_link', [$this, 'clear_comment_link'], 10, 2);
196
+	}
197
+
198
+
199
+	/**
200
+	 * @param string     $link    The comment permalink with '#comment-$id' appended.
201
+	 * @param WP_Comment $comment The current comment object.
202
+	 * @return string
203
+	 */
204
+	public function clear_comment_link($link, WP_Comment $comment)
205
+	{
206
+		// gotta make sure this only happens on this route
207
+		$post_type = get_post_type($comment->comment_post_ID);
208
+		if ($post_type === 'espresso_attendees') {
209
+			return '#commentsdiv';
210
+		}
211
+		return $link;
212
+	}
213
+
214
+
215
+	protected function _ajax_hooks()
216
+	{
217
+		// todo: all hooks for registrations ajax goes in here
218
+		add_action('wp_ajax_toggle_checkin_status', [$this, 'toggle_checkin_status']);
219
+	}
220
+
221
+
222
+	protected function _define_page_props()
223
+	{
224
+		$this->_admin_page_title = $this->page_label;
225
+		$this->_labels           = [
226
+			'buttons'                      => [
227
+				'add-registrant'      => esc_html__('Add New Registration', 'event_espresso'),
228
+				'add-attendee'        => esc_html__('Add Contact', 'event_espresso'),
229
+				'edit'                => esc_html__('Edit Contact', 'event_espresso'),
230
+				'csv_reg_report'      => esc_html__('Registrations CSV Report', 'event_espresso'),
231
+				'contact_list_report' => esc_html__('Contact List Report', 'event_espresso'),
232
+				'contact_list_export' => esc_html__('Export Data', 'event_espresso'),
233
+			],
234
+			'publishbox'                   => [
235
+				'add_new_attendee' => esc_html__('Add Contact Record', 'event_espresso'),
236
+				'edit_attendee'    => esc_html__('Update Contact Record', 'event_espresso'),
237
+			],
238
+			'hide_add_button_on_cpt_route' => [
239
+				'edit_attendee' => true,
240
+			],
241
+		];
242
+	}
243
+
244
+
245
+	/**
246
+	 * grab url requests and route them
247
+	 *
248
+	 * @return void
249
+	 * @throws EE_Error
250
+	 */
251
+	public function _set_page_routes()
252
+	{
253
+		$this->_get_registration_status_array();
254
+		$REG_ID             = $this->request->getRequestParam('_REG_ID', 0, 'int');
255
+		$REG_ID             = $this->request->getRequestParam('reg_status_change_form[REG_ID]', $REG_ID, 'int');
256
+		$ATT_ID             = $this->request->getRequestParam('ATT_ID', 0, 'int');
257
+		$ATT_ID             = $this->request->getRequestParam('post', $ATT_ID, 'int');
258
+		$this->_page_routes = [
259
+			'default'                             => [
260
+				'func'       => [$this, '_registrations_overview_list_table'],
261
+				'capability' => 'ee_read_registrations',
262
+			],
263
+			'view_registration'                   => [
264
+				'func'       => '_registration_details',
265
+				'capability' => 'ee_read_registration',
266
+				'obj_id'     => $REG_ID,
267
+			],
268
+			'edit_registration'                   => [
269
+				'func'               => '_update_attendee_registration_form',
270
+				'noheader'           => true,
271
+				'headers_sent_route' => 'view_registration',
272
+				'capability'         => 'ee_edit_registration',
273
+				'obj_id'             => $REG_ID,
274
+				'_REG_ID'            => $REG_ID,
275
+			],
276
+			'trash_registrations'                 => [
277
+				'func'       => '_trash_or_restore_registrations',
278
+				'args'       => ['trash' => true],
279
+				'noheader'   => true,
280
+				'capability' => 'ee_delete_registrations',
281
+			],
282
+			'restore_registrations'               => [
283
+				'func'       => '_trash_or_restore_registrations',
284
+				'args'       => ['trash' => false],
285
+				'noheader'   => true,
286
+				'capability' => 'ee_delete_registrations',
287
+			],
288
+			'delete_registrations'                => [
289
+				'func'       => '_delete_registrations',
290
+				'noheader'   => true,
291
+				'capability' => 'ee_delete_registrations',
292
+			],
293
+			'new_registration'                    => [
294
+				'func'       => 'new_registration',
295
+				'capability' => 'ee_edit_registrations',
296
+			],
297
+			'process_reg_step'                    => [
298
+				'func'       => 'process_reg_step',
299
+				'noheader'   => true,
300
+				'capability' => 'ee_edit_registrations',
301
+			],
302
+			'redirect_to_txn'                     => [
303
+				'func'       => 'redirect_to_txn',
304
+				'noheader'   => true,
305
+				'capability' => 'ee_edit_registrations',
306
+			],
307
+			'change_reg_status'                   => [
308
+				'func'       => '_change_reg_status',
309
+				'noheader'   => true,
310
+				'capability' => 'ee_edit_registration',
311
+				'obj_id'     => $REG_ID,
312
+			],
313
+			'approve_registration'                => [
314
+				'func'       => 'approve_registration',
315
+				'noheader'   => true,
316
+				'capability' => 'ee_edit_registration',
317
+				'obj_id'     => $REG_ID,
318
+			],
319
+			'approve_and_notify_registration'     => [
320
+				'func'       => 'approve_registration',
321
+				'noheader'   => true,
322
+				'args'       => [true],
323
+				'capability' => 'ee_edit_registration',
324
+				'obj_id'     => $REG_ID,
325
+			],
326
+			'approve_registrations'               => [
327
+				'func'       => 'bulk_action_on_registrations',
328
+				'noheader'   => true,
329
+				'capability' => 'ee_edit_registrations',
330
+				'args'       => ['approve'],
331
+			],
332
+			'approve_and_notify_registrations'    => [
333
+				'func'       => 'bulk_action_on_registrations',
334
+				'noheader'   => true,
335
+				'capability' => 'ee_edit_registrations',
336
+				'args'       => ['approve', true],
337
+			],
338
+			'decline_registration'                => [
339
+				'func'       => 'decline_registration',
340
+				'noheader'   => true,
341
+				'capability' => 'ee_edit_registration',
342
+				'obj_id'     => $REG_ID,
343
+			],
344
+			'decline_and_notify_registration'     => [
345
+				'func'       => 'decline_registration',
346
+				'noheader'   => true,
347
+				'args'       => [true],
348
+				'capability' => 'ee_edit_registration',
349
+				'obj_id'     => $REG_ID,
350
+			],
351
+			'decline_registrations'               => [
352
+				'func'       => 'bulk_action_on_registrations',
353
+				'noheader'   => true,
354
+				'capability' => 'ee_edit_registrations',
355
+				'args'       => ['decline'],
356
+			],
357
+			'decline_and_notify_registrations'    => [
358
+				'func'       => 'bulk_action_on_registrations',
359
+				'noheader'   => true,
360
+				'capability' => 'ee_edit_registrations',
361
+				'args'       => ['decline', true],
362
+			],
363
+			'pending_registration'                => [
364
+				'func'       => 'pending_registration',
365
+				'noheader'   => true,
366
+				'capability' => 'ee_edit_registration',
367
+				'obj_id'     => $REG_ID,
368
+			],
369
+			'pending_and_notify_registration'     => [
370
+				'func'       => 'pending_registration',
371
+				'noheader'   => true,
372
+				'args'       => [true],
373
+				'capability' => 'ee_edit_registration',
374
+				'obj_id'     => $REG_ID,
375
+			],
376
+			'pending_registrations'               => [
377
+				'func'       => 'bulk_action_on_registrations',
378
+				'noheader'   => true,
379
+				'capability' => 'ee_edit_registrations',
380
+				'args'       => ['pending'],
381
+			],
382
+			'pending_and_notify_registrations'    => [
383
+				'func'       => 'bulk_action_on_registrations',
384
+				'noheader'   => true,
385
+				'capability' => 'ee_edit_registrations',
386
+				'args'       => ['pending', true],
387
+			],
388
+			'no_approve_registration'             => [
389
+				'func'       => 'not_approve_registration',
390
+				'noheader'   => true,
391
+				'capability' => 'ee_edit_registration',
392
+				'obj_id'     => $REG_ID,
393
+			],
394
+			'no_approve_and_notify_registration'  => [
395
+				'func'       => 'not_approve_registration',
396
+				'noheader'   => true,
397
+				'args'       => [true],
398
+				'capability' => 'ee_edit_registration',
399
+				'obj_id'     => $REG_ID,
400
+			],
401
+			'no_approve_registrations'            => [
402
+				'func'       => 'bulk_action_on_registrations',
403
+				'noheader'   => true,
404
+				'capability' => 'ee_edit_registrations',
405
+				'args'       => ['not_approve'],
406
+			],
407
+			'no_approve_and_notify_registrations' => [
408
+				'func'       => 'bulk_action_on_registrations',
409
+				'noheader'   => true,
410
+				'capability' => 'ee_edit_registrations',
411
+				'args'       => ['not_approve', true],
412
+			],
413
+			'cancel_registration'                 => [
414
+				'func'       => 'cancel_registration',
415
+				'noheader'   => true,
416
+				'capability' => 'ee_edit_registration',
417
+				'obj_id'     => $REG_ID,
418
+			],
419
+			'cancel_and_notify_registration'      => [
420
+				'func'       => 'cancel_registration',
421
+				'noheader'   => true,
422
+				'args'       => [true],
423
+				'capability' => 'ee_edit_registration',
424
+				'obj_id'     => $REG_ID,
425
+			],
426
+			'cancel_registrations'                => [
427
+				'func'       => 'bulk_action_on_registrations',
428
+				'noheader'   => true,
429
+				'capability' => 'ee_edit_registrations',
430
+				'args'       => ['cancel'],
431
+			],
432
+			'cancel_and_notify_registrations'     => [
433
+				'func'       => 'bulk_action_on_registrations',
434
+				'noheader'   => true,
435
+				'capability' => 'ee_edit_registrations',
436
+				'args'       => ['cancel', true],
437
+			],
438
+			'wait_list_registration'              => [
439
+				'func'       => 'wait_list_registration',
440
+				'noheader'   => true,
441
+				'capability' => 'ee_edit_registration',
442
+				'obj_id'     => $REG_ID,
443
+			],
444
+			'wait_list_and_notify_registration'   => [
445
+				'func'       => 'wait_list_registration',
446
+				'noheader'   => true,
447
+				'args'       => [true],
448
+				'capability' => 'ee_edit_registration',
449
+				'obj_id'     => $REG_ID,
450
+			],
451
+			'contact_list'                        => [
452
+				'func'       => '_attendee_contact_list_table',
453
+				'capability' => 'ee_read_contacts',
454
+			],
455
+			'add_new_attendee'                    => [
456
+				'func' => '_create_new_cpt_item',
457
+				'args' => [
458
+					'new_attendee' => true,
459
+					'capability'   => 'ee_edit_contacts',
460
+				],
461
+			],
462
+			'edit_attendee'                       => [
463
+				'func'       => '_edit_cpt_item',
464
+				'capability' => 'ee_edit_contacts',
465
+				'obj_id'     => $ATT_ID,
466
+			],
467
+			'duplicate_attendee'                  => [
468
+				'func'       => '_duplicate_attendee',
469
+				'noheader'   => true,
470
+				'capability' => 'ee_edit_contacts',
471
+				'obj_id'     => $ATT_ID,
472
+			],
473
+			'insert_attendee'                     => [
474
+				'func'       => '_insert_or_update_attendee',
475
+				'args'       => [
476
+					'new_attendee' => true,
477
+				],
478
+				'noheader'   => true,
479
+				'capability' => 'ee_edit_contacts',
480
+			],
481
+			'update_attendee'                     => [
482
+				'func'       => '_insert_or_update_attendee',
483
+				'args'       => [
484
+					'new_attendee' => false,
485
+				],
486
+				'noheader'   => true,
487
+				'capability' => 'ee_edit_contacts',
488
+				'obj_id'     => $ATT_ID,
489
+			],
490
+			'trash_attendees'                     => [
491
+				'func'       => '_trash_or_restore_attendees',
492
+				'args'       => [
493
+					'trash' => 'true',
494
+				],
495
+				'noheader'   => true,
496
+				'capability' => 'ee_delete_contacts',
497
+			],
498
+			'trash_attendee'                      => [
499
+				'func'       => '_trash_or_restore_attendees',
500
+				'args'       => [
501
+					'trash' => true,
502
+				],
503
+				'noheader'   => true,
504
+				'capability' => 'ee_delete_contacts',
505
+				'obj_id'     => $ATT_ID,
506
+			],
507
+			'restore_attendees'                   => [
508
+				'func'       => '_trash_or_restore_attendees',
509
+				'args'       => [
510
+					'trash' => false,
511
+				],
512
+				'noheader'   => true,
513
+				'capability' => 'ee_delete_contacts',
514
+				'obj_id'     => $ATT_ID,
515
+			],
516
+			'resend_registration'                 => [
517
+				'func'       => '_resend_registration',
518
+				'noheader'   => true,
519
+				'capability' => 'ee_send_message',
520
+			],
521
+			'registrations_report'                => [
522
+				'func'       => [$this, '_registrations_report'],
523
+				'noheader'   => true,
524
+				'capability' => 'ee_read_registrations',
525
+			],
526
+			'contact_list_export'                 => [
527
+				'func'       => '_contact_list_export',
528
+				'noheader'   => true,
529
+				'capability' => 'export',
530
+			],
531
+			'contact_list_report'                 => [
532
+				'func'       => '_contact_list_report',
533
+				'noheader'   => true,
534
+				'capability' => 'ee_read_contacts',
535
+			],
536
+		];
537
+	}
538
+
539
+
540
+	protected function _set_page_config()
541
+	{
542
+		$REG_ID             = $this->request->getRequestParam('_REG_ID', 0, 'int');
543
+		$ATT_ID             = $this->request->getRequestParam('ATT_ID', 0, 'int');
544
+		$this->_page_config = [
545
+			'default'           => [
546
+				'nav'           => [
547
+					'label' => esc_html__('Overview', 'event_espresso'),
548
+					'order' => 5,
549
+				],
550
+				'help_tabs'     => [
551
+					'registrations_overview_help_tab'                       => [
552
+						'title'    => esc_html__('Registrations Overview', 'event_espresso'),
553
+						'filename' => 'registrations_overview',
554
+					],
555
+					'registrations_overview_table_column_headings_help_tab' => [
556
+						'title'    => esc_html__('Registrations Table Column Headings', 'event_espresso'),
557
+						'filename' => 'registrations_overview_table_column_headings',
558
+					],
559
+					'registrations_overview_filters_help_tab'               => [
560
+						'title'    => esc_html__('Registration Filters', 'event_espresso'),
561
+						'filename' => 'registrations_overview_filters',
562
+					],
563
+					'registrations_overview_views_help_tab'                 => [
564
+						'title'    => esc_html__('Registration Views', 'event_espresso'),
565
+						'filename' => 'registrations_overview_views',
566
+					],
567
+					'registrations_regoverview_other_help_tab'              => [
568
+						'title'    => esc_html__('Registrations Other', 'event_espresso'),
569
+						'filename' => 'registrations_overview_other',
570
+					],
571
+				],
572
+				'qtips'         => ['Registration_List_Table_Tips'],
573
+				'list_table'    => 'EE_Registrations_List_Table',
574
+				'require_nonce' => false,
575
+			],
576
+			'view_registration' => [
577
+				'nav'           => [
578
+					'label'      => esc_html__('REG Details', 'event_espresso'),
579
+					'order'      => 15,
580
+					'url'        => $REG_ID
581
+						? add_query_arg(['_REG_ID' => $REG_ID], $this->_current_page_view_url)
582
+						: $this->_admin_base_url,
583
+					'persistent' => false,
584
+				],
585
+				'help_tabs'     => [
586
+					'registrations_details_help_tab'                    => [
587
+						'title'    => esc_html__('Registration Details', 'event_espresso'),
588
+						'filename' => 'registrations_details',
589
+					],
590
+					'registrations_details_table_help_tab'              => [
591
+						'title'    => esc_html__('Registration Details Table', 'event_espresso'),
592
+						'filename' => 'registrations_details_table',
593
+					],
594
+					'registrations_details_form_answers_help_tab'       => [
595
+						'title'    => esc_html__('Registration Form Answers', 'event_espresso'),
596
+						'filename' => 'registrations_details_form_answers',
597
+					],
598
+					'registrations_details_registrant_details_help_tab' => [
599
+						'title'    => esc_html__('Contact Details', 'event_espresso'),
600
+						'filename' => 'registrations_details_registrant_details',
601
+					],
602
+				],
603
+				'metaboxes'     => array_merge(
604
+					$this->_default_espresso_metaboxes,
605
+					['_registration_details_metaboxes']
606
+				),
607
+				'require_nonce' => false,
608
+			],
609
+			'new_registration'  => [
610
+				'nav'           => [
611
+					'label'      => esc_html__('Add New Registration', 'event_espresso'),
612
+					'url'        => '#',
613
+					'order'      => 15,
614
+					'persistent' => false,
615
+				],
616
+				'metaboxes'     => $this->_default_espresso_metaboxes,
617
+				'labels'        => [
618
+					'publishbox' => esc_html__('Save Registration', 'event_espresso'),
619
+				],
620
+				'require_nonce' => false,
621
+			],
622
+			'add_new_attendee'  => [
623
+				'nav'           => [
624
+					'label'      => esc_html__('Add Contact', 'event_espresso'),
625
+					'order'      => 15,
626
+					'persistent' => false,
627
+				],
628
+				'metaboxes'     => array_merge(
629
+					$this->_default_espresso_metaboxes,
630
+					['_publish_post_box', 'attendee_editor_metaboxes']
631
+				),
632
+				'require_nonce' => false,
633
+			],
634
+			'edit_attendee'     => [
635
+				'nav'           => [
636
+					'label'      => esc_html__('Edit Contact', 'event_espresso'),
637
+					'order'      => 15,
638
+					'persistent' => false,
639
+					'url'        => $ATT_ID
640
+						? add_query_arg(['ATT_ID' => $ATT_ID], $this->_current_page_view_url)
641
+						: $this->_admin_base_url,
642
+				],
643
+				'metaboxes'     => ['attendee_editor_metaboxes'],
644
+				'require_nonce' => false,
645
+			],
646
+			'contact_list'      => [
647
+				'nav'           => [
648
+					'label' => esc_html__('Contact List', 'event_espresso'),
649
+					'order' => 20,
650
+				],
651
+				'list_table'    => 'EE_Attendee_Contact_List_Table',
652
+				'help_tabs'     => [
653
+					'registrations_contact_list_help_tab'                       => [
654
+						'title'    => esc_html__('Registrations Contact List', 'event_espresso'),
655
+						'filename' => 'registrations_contact_list',
656
+					],
657
+					'registrations_contact-list_table_column_headings_help_tab' => [
658
+						'title'    => esc_html__('Contact List Table Column Headings', 'event_espresso'),
659
+						'filename' => 'registrations_contact_list_table_column_headings',
660
+					],
661
+					'registrations_contact_list_views_help_tab'                 => [
662
+						'title'    => esc_html__('Contact List Views', 'event_espresso'),
663
+						'filename' => 'registrations_contact_list_views',
664
+					],
665
+					'registrations_contact_list_other_help_tab'                 => [
666
+						'title'    => esc_html__('Contact List Other', 'event_espresso'),
667
+						'filename' => 'registrations_contact_list_other',
668
+					],
669
+				],
670
+				'metaboxes'     => [],
671
+				'require_nonce' => false,
672
+			],
673
+			// override default cpt routes
674
+			'create_new'        => '',
675
+			'edit'              => '',
676
+		];
677
+	}
678
+
679
+
680
+	/**
681
+	 * The below methods aren't used by this class currently
682
+	 */
683
+	protected function _add_screen_options()
684
+	{
685
+	}
686
+
687
+
688
+	protected function _add_feature_pointers()
689
+	{
690
+	}
691
+
692
+
693
+	public function admin_init()
694
+	{
695
+		EE_Registry::$i18n_js_strings['update_att_qstns'] = esc_html__(
696
+			'click "Update Registration Questions" to save your changes',
697
+			'event_espresso'
698
+		);
699
+	}
700
+
701
+
702
+	public function admin_notices()
703
+	{
704
+	}
705
+
706
+
707
+	public function admin_footer_scripts()
708
+	{
709
+	}
710
+
711
+
712
+	/**
713
+	 * get list of registration statuses
714
+	 *
715
+	 * @return void
716
+	 * @throws EE_Error
717
+	 */
718
+	private function _get_registration_status_array()
719
+	{
720
+		self::$_reg_status = EEM_Registration::reg_status_array([], true);
721
+	}
722
+
723
+
724
+	/**
725
+	 * @throws InvalidArgumentException
726
+	 * @throws InvalidDataTypeException
727
+	 * @throws InvalidInterfaceException
728
+	 * @since 4.10.2.p
729
+	 */
730
+	protected function _add_screen_options_default()
731
+	{
732
+		$this->_per_page_screen_option();
733
+	}
734
+
735
+
736
+	/**
737
+	 * @throws InvalidArgumentException
738
+	 * @throws InvalidDataTypeException
739
+	 * @throws InvalidInterfaceException
740
+	 * @since 4.10.2.p
741
+	 */
742
+	protected function _add_screen_options_contact_list()
743
+	{
744
+		$page_title              = $this->_admin_page_title;
745
+		$this->_admin_page_title = esc_html__('Contacts', 'event_espresso');
746
+		$this->_per_page_screen_option();
747
+		$this->_admin_page_title = $page_title;
748
+	}
749
+
750
+
751
+	public function load_scripts_styles()
752
+	{
753
+		// style
754
+		wp_register_style(
755
+			'espresso_reg',
756
+			REG_ASSETS_URL . 'espresso_registrations_admin.css',
757
+			['ee-admin-css'],
758
+			EVENT_ESPRESSO_VERSION
759
+		);
760
+		wp_enqueue_style('espresso_reg');
761
+		// script
762
+		wp_register_script(
763
+			'espresso_reg',
764
+			REG_ASSETS_URL . 'espresso_registrations_admin.js',
765
+			['jquery-ui-datepicker', 'jquery-ui-draggable', 'ee_admin_js'],
766
+			EVENT_ESPRESSO_VERSION,
767
+			true
768
+		);
769
+		wp_enqueue_script('espresso_reg');
770
+	}
771
+
772
+
773
+	/**
774
+	 * @throws EE_Error
775
+	 * @throws InvalidArgumentException
776
+	 * @throws InvalidDataTypeException
777
+	 * @throws InvalidInterfaceException
778
+	 * @throws ReflectionException
779
+	 * @since 4.10.2.p
780
+	 */
781
+	public function load_scripts_styles_edit_attendee()
782
+	{
783
+		// stuff to only show up on our attendee edit details page.
784
+		$attendee_details_translations = [
785
+			'att_publish_text' => sprintf(
786
+			/* translators: The date and time */
787
+				wp_strip_all_tags(__('Created on: %s', 'event_espresso')),
788
+				'<b>' . $this->_cpt_model_obj->get_datetime('ATT_created') . '</b>'
789
+			),
790
+		];
791
+		wp_localize_script('espresso_reg', 'ATTENDEE_DETAILS', $attendee_details_translations);
792
+		wp_enqueue_script('jquery-validate');
793
+	}
794
+
795
+
796
+	/**
797
+	 * @throws EE_Error
798
+	 * @throws InvalidArgumentException
799
+	 * @throws InvalidDataTypeException
800
+	 * @throws InvalidInterfaceException
801
+	 * @throws ReflectionException
802
+	 * @since 4.10.2.p
803
+	 */
804
+	public function load_scripts_styles_view_registration()
805
+	{
806
+		// styles
807
+		wp_enqueue_style('espresso-ui-theme');
808
+		// scripts
809
+		$this->_get_reg_custom_questions_form($this->_registration->ID());
810
+		$this->_reg_custom_questions_form->wp_enqueue_scripts();
811
+	}
812
+
813
+
814
+	public function load_scripts_styles_contact_list()
815
+	{
816
+		wp_dequeue_style('espresso_reg');
817
+		wp_register_style(
818
+			'espresso_att',
819
+			REG_ASSETS_URL . 'espresso_attendees_admin.css',
820
+			['ee-admin-css'],
821
+			EVENT_ESPRESSO_VERSION
822
+		);
823
+		wp_enqueue_style('espresso_att');
824
+	}
825
+
826
+
827
+	public function load_scripts_styles_new_registration()
828
+	{
829
+		wp_register_script(
830
+			'ee-spco-for-admin',
831
+			REG_ASSETS_URL . 'spco_for_admin.js',
832
+			['underscore', 'jquery'],
833
+			EVENT_ESPRESSO_VERSION,
834
+			true
835
+		);
836
+		wp_enqueue_script('ee-spco-for-admin');
837
+		add_filter('FHEE__EED_Ticket_Selector__load_tckt_slctr_assets', '__return_true');
838
+		EE_Form_Section_Proper::wp_enqueue_scripts();
839
+		EED_Ticket_Selector::load_tckt_slctr_assets();
840
+		EE_Datepicker_Input::enqueue_styles_and_scripts();
841
+	}
842
+
843
+
844
+	public function AHEE__EE_Admin_Page__route_admin_request_resend_registration()
845
+	{
846
+		add_filter('FHEE_load_EE_messages', '__return_true');
847
+	}
848
+
849
+
850
+	public function AHEE__EE_Admin_Page__route_admin_request_approve_registration()
851
+	{
852
+		add_filter('FHEE_load_EE_messages', '__return_true');
853
+	}
854
+
855
+
856
+	/**
857
+	 * @throws EE_Error
858
+	 * @throws InvalidArgumentException
859
+	 * @throws InvalidDataTypeException
860
+	 * @throws InvalidInterfaceException
861
+	 * @throws ReflectionException
862
+	 * @since 4.10.2.p
863
+	 */
864
+	protected function _set_list_table_views_default()
865
+	{
866
+		// for notification related bulk actions we need to make sure only active messengers have an option.
867
+		EED_Messages::set_autoloaders();
868
+		/** @type EE_Message_Resource_Manager $message_resource_manager */
869
+		$message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
870
+		$active_mts               = $message_resource_manager->list_of_active_message_types();
871
+		// key= bulk_action_slug, value= message type.
872
+		$match_array = [
873
+			'approve_registrations'    => 'registration',
874
+			'decline_registrations'    => 'declined_registration',
875
+			'pending_registrations'    => 'pending_approval',
876
+			'no_approve_registrations' => 'not_approved_registration',
877
+			'cancel_registrations'     => 'cancelled_registration',
878
+		];
879
+		$can_send    = EE_Registry::instance()->CAP->current_user_can(
880
+			'ee_send_message',
881
+			'batch_send_messages'
882
+		);
883
+		/** setup reg status bulk actions **/
884
+		$def_reg_status_actions['approve_registrations'] = esc_html__('Approve Registrations', 'event_espresso');
885
+		if ($can_send && in_array($match_array['approve_registrations'], $active_mts, true)) {
886
+			$def_reg_status_actions['approve_and_notify_registrations'] = esc_html__(
887
+				'Approve and Notify Registrations',
888
+				'event_espresso'
889
+			);
890
+		}
891
+		$def_reg_status_actions['decline_registrations'] = esc_html__('Decline Registrations', 'event_espresso');
892
+		if ($can_send && in_array($match_array['decline_registrations'], $active_mts, true)) {
893
+			$def_reg_status_actions['decline_and_notify_registrations'] = esc_html__(
894
+				'Decline and Notify Registrations',
895
+				'event_espresso'
896
+			);
897
+		}
898
+		$def_reg_status_actions['pending_registrations'] = esc_html__(
899
+			'Set Registrations to Pending Payment',
900
+			'event_espresso'
901
+		);
902
+		if ($can_send && in_array($match_array['pending_registrations'], $active_mts, true)) {
903
+			$def_reg_status_actions['pending_and_notify_registrations'] = esc_html__(
904
+				'Set Registrations to Pending Payment and Notify',
905
+				'event_espresso'
906
+			);
907
+		}
908
+		$def_reg_status_actions['no_approve_registrations'] = esc_html__(
909
+			'Set Registrations to Not Approved',
910
+			'event_espresso'
911
+		);
912
+		if ($can_send && in_array($match_array['no_approve_registrations'], $active_mts, true)) {
913
+			$def_reg_status_actions['no_approve_and_notify_registrations'] = esc_html__(
914
+				'Set Registrations to Not Approved and Notify',
915
+				'event_espresso'
916
+			);
917
+		}
918
+		$def_reg_status_actions['cancel_registrations'] = esc_html__('Cancel Registrations', 'event_espresso');
919
+		if ($can_send && in_array($match_array['cancel_registrations'], $active_mts, true)) {
920
+			$def_reg_status_actions['cancel_and_notify_registrations'] = esc_html__(
921
+				'Cancel Registrations and Notify',
922
+				'event_espresso'
923
+			);
924
+		}
925
+		$def_reg_status_actions = apply_filters(
926
+			'FHEE__Registrations_Admin_Page___set_list_table_views_default__def_reg_status_actions_array',
927
+			$def_reg_status_actions,
928
+			$active_mts,
929
+			$can_send
930
+		);
931
+
932
+		$this->_views = [
933
+			'all'   => [
934
+				'slug'        => 'all',
935
+				'label'       => esc_html__('View All Registrations', 'event_espresso'),
936
+				'count'       => 0,
937
+				'bulk_action' => array_merge(
938
+					$def_reg_status_actions,
939
+					[
940
+						'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
941
+					]
942
+				),
943
+			],
944
+			'month' => [
945
+				'slug'        => 'month',
946
+				'label'       => esc_html__('This Month', 'event_espresso'),
947
+				'count'       => 0,
948
+				'bulk_action' => array_merge(
949
+					$def_reg_status_actions,
950
+					[
951
+						'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
952
+					]
953
+				),
954
+			],
955
+			'today' => [
956
+				'slug'        => 'today',
957
+				'label'       => sprintf(
958
+					esc_html__('Today - %s', 'event_espresso'),
959
+					date('M d, Y', current_time('timestamp'))
960
+				),
961
+				'count'       => 0,
962
+				'bulk_action' => array_merge(
963
+					$def_reg_status_actions,
964
+					[
965
+						'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
966
+					]
967
+				),
968
+			],
969
+		];
970
+		if (
971
+			EE_Registry::instance()->CAP->current_user_can(
972
+				'ee_delete_registrations',
973
+				'espresso_registrations_delete_registration'
974
+			)
975
+		) {
976
+			$this->_views['incomplete'] = [
977
+				'slug'        => 'incomplete',
978
+				'label'       => esc_html__('Incomplete', 'event_espresso'),
979
+				'count'       => 0,
980
+				'bulk_action' => [
981
+					'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
982
+				],
983
+			];
984
+			$this->_views['trash']      = [
985
+				'slug'        => 'trash',
986
+				'label'       => esc_html__('Trash', 'event_espresso'),
987
+				'count'       => 0,
988
+				'bulk_action' => [
989
+					'restore_registrations' => esc_html__('Restore Registrations', 'event_espresso'),
990
+					'delete_registrations'  => esc_html__('Delete Registrations Permanently', 'event_espresso'),
991
+				],
992
+			];
993
+		}
994
+	}
995
+
996
+
997
+	protected function _set_list_table_views_contact_list()
998
+	{
999
+		$this->_views = [
1000
+			'in_use' => [
1001
+				'slug'        => 'in_use',
1002
+				'label'       => esc_html__('In Use', 'event_espresso'),
1003
+				'count'       => 0,
1004
+				'bulk_action' => [
1005
+					'trash_attendees' => esc_html__('Move to Trash', 'event_espresso'),
1006
+				],
1007
+			],
1008
+		];
1009
+		if (
1010
+			EE_Registry::instance()->CAP->current_user_can(
1011
+				'ee_delete_contacts',
1012
+				'espresso_registrations_trash_attendees'
1013
+			)
1014
+		) {
1015
+			$this->_views['trash'] = [
1016
+				'slug'        => 'trash',
1017
+				'label'       => esc_html__('Trash', 'event_espresso'),
1018
+				'count'       => 0,
1019
+				'bulk_action' => [
1020
+					'restore_attendees' => esc_html__('Restore from Trash', 'event_espresso'),
1021
+				],
1022
+			];
1023
+		}
1024
+	}
1025
+
1026
+
1027
+	/**
1028
+	 * @return array
1029
+	 * @throws EE_Error
1030
+	 */
1031
+	protected function _registration_legend_items()
1032
+	{
1033
+		$fc_items = [
1034
+			'star-icon'        => [
1035
+				'class' => 'dashicons dashicons-star-filled lt-blue-icon ee-icon-size-8',
1036
+				'desc'  => esc_html__('This is the Primary Registrant', 'event_espresso'),
1037
+			],
1038
+			'view_details'     => [
1039
+				'class' => 'dashicons dashicons-clipboard',
1040
+				'desc'  => esc_html__('View Registration Details', 'event_espresso'),
1041
+			],
1042
+			'edit_attendee'    => [
1043
+				'class' => 'ee-icon ee-icon-user-edit ee-icon-size-16',
1044
+				'desc'  => esc_html__('Edit Contact Details', 'event_espresso'),
1045
+			],
1046
+			'view_transaction' => [
1047
+				'class' => 'dashicons dashicons-cart',
1048
+				'desc'  => esc_html__('View Transaction Details', 'event_espresso'),
1049
+			],
1050
+			'view_invoice'     => [
1051
+				'class' => 'dashicons dashicons-media-spreadsheet',
1052
+				'desc'  => esc_html__('View Transaction Invoice', 'event_espresso'),
1053
+			],
1054
+		];
1055
+		if (
1056
+			EE_Registry::instance()->CAP->current_user_can(
1057
+				'ee_send_message',
1058
+				'espresso_registrations_resend_registration'
1059
+			)
1060
+		) {
1061
+			$fc_items['resend_registration'] = [
1062
+				'class' => 'dashicons dashicons-email-alt',
1063
+				'desc'  => esc_html__('Resend Registration Details', 'event_espresso'),
1064
+			];
1065
+		} else {
1066
+			$fc_items['blank'] = ['class' => 'blank', 'desc' => ''];
1067
+		}
1068
+		if (
1069
+			EE_Registry::instance()->CAP->current_user_can(
1070
+				'ee_read_global_messages',
1071
+				'view_filtered_messages'
1072
+			)
1073
+		) {
1074
+			$related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
1075
+			if (is_array($related_for_icon) && isset($related_for_icon['css_class'], $related_for_icon['label'])) {
1076
+				$fc_items['view_related_messages'] = [
1077
+					'class' => $related_for_icon['css_class'],
1078
+					'desc'  => $related_for_icon['label'],
1079
+				];
1080
+			}
1081
+		}
1082
+		$sc_items = [
1083
+			'approved_status'   => [
1084
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_approved,
1085
+				'desc'  => EEH_Template::pretty_status(
1086
+					EEM_Registration::status_id_approved,
1087
+					false,
1088
+					'sentence'
1089
+				),
1090
+			],
1091
+			'pending_status'    => [
1092
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_pending_payment,
1093
+				'desc'  => EEH_Template::pretty_status(
1094
+					EEM_Registration::status_id_pending_payment,
1095
+					false,
1096
+					'sentence'
1097
+				),
1098
+			],
1099
+			'wait_list'         => [
1100
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_wait_list,
1101
+				'desc'  => EEH_Template::pretty_status(
1102
+					EEM_Registration::status_id_wait_list,
1103
+					false,
1104
+					'sentence'
1105
+				),
1106
+			],
1107
+			'incomplete_status' => [
1108
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_incomplete,
1109
+				'desc'  => EEH_Template::pretty_status(
1110
+					EEM_Registration::status_id_incomplete,
1111
+					false,
1112
+					'sentence'
1113
+				),
1114
+			],
1115
+			'not_approved'      => [
1116
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_not_approved,
1117
+				'desc'  => EEH_Template::pretty_status(
1118
+					EEM_Registration::status_id_not_approved,
1119
+					false,
1120
+					'sentence'
1121
+				),
1122
+			],
1123
+			'declined_status'   => [
1124
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_declined,
1125
+				'desc'  => EEH_Template::pretty_status(
1126
+					EEM_Registration::status_id_declined,
1127
+					false,
1128
+					'sentence'
1129
+				),
1130
+			],
1131
+			'cancelled_status'  => [
1132
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_cancelled,
1133
+				'desc'  => EEH_Template::pretty_status(
1134
+					EEM_Registration::status_id_cancelled,
1135
+					false,
1136
+					'sentence'
1137
+				),
1138
+			],
1139
+		];
1140
+		return array_merge($fc_items, $sc_items);
1141
+	}
1142
+
1143
+
1144
+
1145
+	/***************************************        REGISTRATION OVERVIEW        **************************************/
1146
+
1147
+
1148
+	/**
1149
+	 * @throws DomainException
1150
+	 * @throws EE_Error
1151
+	 * @throws InvalidArgumentException
1152
+	 * @throws InvalidDataTypeException
1153
+	 * @throws InvalidInterfaceException
1154
+	 */
1155
+	protected function _registrations_overview_list_table()
1156
+	{
1157
+		$this->appendAddNewRegistrationButtonToPageTitle();
1158
+		$header_text                  = '';
1159
+		$admin_page_header_decorators = [
1160
+			'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\AttendeeFilterHeader',
1161
+			'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\EventFilterHeader',
1162
+			'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\DateFilterHeader',
1163
+			'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\TicketFilterHeader',
1164
+		];
1165
+		foreach ($admin_page_header_decorators as $admin_page_header_decorator) {
1166
+			$filter_header_decorator = $this->getLoader()->getNew($admin_page_header_decorator);
1167
+			$header_text             = $filter_header_decorator->getHeaderText($header_text);
1168
+		}
1169
+		$this->_template_args['admin_page_header'] = $header_text;
1170
+		$this->_template_args['after_list_table']  = $this->_display_legend($this->_registration_legend_items());
1171
+		$this->display_admin_list_table_page_with_no_sidebar();
1172
+	}
1173
+
1174
+
1175
+	/**
1176
+	 * @throws EE_Error
1177
+	 * @throws InvalidArgumentException
1178
+	 * @throws InvalidDataTypeException
1179
+	 * @throws InvalidInterfaceException
1180
+	 */
1181
+	private function appendAddNewRegistrationButtonToPageTitle()
1182
+	{
1183
+		$EVT_ID = $this->request->getRequestParam('event_id', 0, 'int');
1184
+		if (
1185
+			$EVT_ID
1186
+			&& EE_Registry::instance()->CAP->current_user_can(
1187
+				'ee_edit_registrations',
1188
+				'espresso_registrations_new_registration',
1189
+				$EVT_ID
1190
+			)
1191
+		) {
1192
+			$this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
1193
+				'new_registration',
1194
+				'add-registrant',
1195
+				['event_id' => $EVT_ID],
1196
+				'add-new-h2'
1197
+			);
1198
+		}
1199
+	}
1200
+
1201
+
1202
+	/**
1203
+	 * This sets the _registration property for the registration details screen
1204
+	 *
1205
+	 * @return void
1206
+	 * @throws EE_Error
1207
+	 * @throws InvalidArgumentException
1208
+	 * @throws InvalidDataTypeException
1209
+	 * @throws InvalidInterfaceException
1210
+	 */
1211
+	private function _set_registration_object()
1212
+	{
1213
+		// get out if we've already set the object
1214
+		if ($this->_registration instanceof EE_Registration) {
1215
+			return;
1216
+		}
1217
+		$REG_ID = $this->request->getRequestParam('_REG_ID', 0, 'int');
1218
+		if ($this->_registration = $this->getRegistrationModel()->get_one_by_ID($REG_ID)) {
1219
+			return;
1220
+		}
1221
+		$error_msg = sprintf(
1222
+			esc_html__(
1223
+				'An error occurred and the details for Registration ID #%s could not be retrieved.',
1224
+				'event_espresso'
1225
+			),
1226
+			$REG_ID
1227
+		);
1228
+		EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
1229
+		$this->_registration = null;
1230
+	}
1231
+
1232
+
1233
+	/**
1234
+	 * Used to retrieve registrations for the list table.
1235
+	 *
1236
+	 * @param int  $per_page
1237
+	 * @param bool $count
1238
+	 * @param bool $this_month
1239
+	 * @param bool $today
1240
+	 * @return EE_Registration[]|int
1241
+	 * @throws EE_Error
1242
+	 * @throws InvalidArgumentException
1243
+	 * @throws InvalidDataTypeException
1244
+	 * @throws InvalidInterfaceException
1245
+	 */
1246
+	public function get_registrations(
1247
+		$per_page = 10,
1248
+		$count = false,
1249
+		$this_month = false,
1250
+		$today = false
1251
+	) {
1252
+		if ($this_month) {
1253
+			$this->request->setRequestParam('status', 'month');
1254
+		}
1255
+		if ($today) {
1256
+			$this->request->setRequestParam('status', 'today');
1257
+		}
1258
+		$query_params = $this->_get_registration_query_parameters([], $per_page, $count);
1259
+		/**
1260
+		 * Override the default groupby added by EEM_Base so that sorts with multiple order bys work as expected
1261
+		 *
1262
+		 * @link https://events.codebasehq.com/projects/event-espresso/tickets/10093
1263
+		 * @see  https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1264
+		 *                      or if you have the development copy of EE you can view this at the path:
1265
+		 *                      /docs/G--Model-System/model-query-params.md
1266
+		 */
1267
+		$query_params['group_by'] = '';
1268
+
1269
+		return $count
1270
+			? $this->getRegistrationModel()->count($query_params)
1271
+			/** @type EE_Registration[] */
1272
+			: $this->getRegistrationModel()->get_all($query_params);
1273
+	}
1274
+
1275
+
1276
+	/**
1277
+	 * Retrieves the query parameters to be used by the Registration model for getting registrations.
1278
+	 * Note: this listens to values on the request for some of the query parameters.
1279
+	 *
1280
+	 * @param array $request
1281
+	 * @param int   $per_page
1282
+	 * @param bool  $count
1283
+	 * @return array
1284
+	 * @throws EE_Error
1285
+	 * @throws InvalidArgumentException
1286
+	 * @throws InvalidDataTypeException
1287
+	 * @throws InvalidInterfaceException
1288
+	 */
1289
+	protected function _get_registration_query_parameters(
1290
+		$request = [],
1291
+		$per_page = 10,
1292
+		$count = false
1293
+	) {
1294
+		/** @var EventEspresso\core\domain\services\admin\registrations\list_table\QueryBuilder $list_table_query_builder */
1295
+		$list_table_query_builder = $this->getLoader()->getNew(
1296
+			'EventEspresso\core\domain\services\admin\registrations\list_table\QueryBuilder',
1297
+			[null, null, $request]
1298
+		);
1299
+		return $list_table_query_builder->getQueryParams($per_page, $count);
1300
+	}
1301
+
1302
+
1303
+	public function get_registration_status_array()
1304
+	{
1305
+		return self::$_reg_status;
1306
+	}
1307
+
1308
+
1309
+
1310
+
1311
+	/***************************************        REGISTRATION DETAILS        ***************************************/
1312
+	/**
1313
+	 * generates HTML for the View Registration Details Admin page
1314
+	 *
1315
+	 * @return void
1316
+	 * @throws DomainException
1317
+	 * @throws EE_Error
1318
+	 * @throws InvalidArgumentException
1319
+	 * @throws InvalidDataTypeException
1320
+	 * @throws InvalidInterfaceException
1321
+	 * @throws EntityNotFoundException
1322
+	 * @throws ReflectionException
1323
+	 */
1324
+	protected function _registration_details()
1325
+	{
1326
+		$this->_template_args = [];
1327
+		$this->_set_registration_object();
1328
+		if (is_object($this->_registration)) {
1329
+			$transaction                                   = $this->_registration->transaction()
1330
+				? $this->_registration->transaction()
1331
+				: EE_Transaction::new_instance();
1332
+			$this->_session                                = $transaction->session_data();
1333
+			$event_id                                      = $this->_registration->event_ID();
1334
+			$this->_template_args['reg_nmbr']['value']     = $this->_registration->ID();
1335
+			$this->_template_args['reg_nmbr']['label']     = esc_html__('Registration Number', 'event_espresso');
1336
+			$this->_template_args['reg_datetime']['value'] = $this->_registration->get_i18n_datetime('REG_date');
1337
+			$this->_template_args['reg_datetime']['label'] = esc_html__('Date', 'event_espresso');
1338
+			$this->_template_args['grand_total']           = $transaction->total();
1339
+			$this->_template_args['currency_sign']         = EE_Registry::instance()->CFG->currency->sign;
1340
+			// link back to overview
1341
+			$this->_template_args['reg_overview_url']            = REG_ADMIN_URL;
1342
+			$this->_template_args['registration']                = $this->_registration;
1343
+			$this->_template_args['filtered_registrations_link'] = EE_Admin_Page::add_query_args_and_nonce(
1344
+				[
1345
+					'action'   => 'default',
1346
+					'event_id' => $event_id,
1347
+				],
1348
+				REG_ADMIN_URL
1349
+			);
1350
+			$this->_template_args['filtered_transactions_link']  = EE_Admin_Page::add_query_args_and_nonce(
1351
+				[
1352
+					'action' => 'default',
1353
+					'EVT_ID' => $event_id,
1354
+					'page'   => 'espresso_transactions',
1355
+				],
1356
+				admin_url('admin.php')
1357
+			);
1358
+			$this->_template_args['event_link']                  = EE_Admin_Page::add_query_args_and_nonce(
1359
+				[
1360
+					'page'   => 'espresso_events',
1361
+					'action' => 'edit',
1362
+					'post'   => $event_id,
1363
+				],
1364
+				admin_url('admin.php')
1365
+			);
1366
+			// next and previous links
1367
+			$next_reg                                      = $this->_registration->next(
1368
+				null,
1369
+				[],
1370
+				'REG_ID'
1371
+			);
1372
+			$this->_template_args['next_registration']     = $next_reg
1373
+				? $this->_next_link(
1374
+					EE_Admin_Page::add_query_args_and_nonce(
1375
+						[
1376
+							'action'  => 'view_registration',
1377
+							'_REG_ID' => $next_reg['REG_ID'],
1378
+						],
1379
+						REG_ADMIN_URL
1380
+					),
1381
+					'dashicons dashicons-arrow-right ee-icon-size-22'
1382
+				)
1383
+				: '';
1384
+			$previous_reg                                  = $this->_registration->previous(
1385
+				null,
1386
+				[],
1387
+				'REG_ID'
1388
+			);
1389
+			$this->_template_args['previous_registration'] = $previous_reg
1390
+				? $this->_previous_link(
1391
+					EE_Admin_Page::add_query_args_and_nonce(
1392
+						[
1393
+							'action'  => 'view_registration',
1394
+							'_REG_ID' => $previous_reg['REG_ID'],
1395
+						],
1396
+						REG_ADMIN_URL
1397
+					),
1398
+					'dashicons dashicons-arrow-left ee-icon-size-22'
1399
+				)
1400
+				: '';
1401
+			// grab header
1402
+			$template_path                             = REG_TEMPLATE_PATH . 'reg_admin_details_header.template.php';
1403
+			$this->_template_args['REG_ID']            = $this->_registration->ID();
1404
+			$this->_template_args['admin_page_header'] = EEH_Template::display_template(
1405
+				$template_path,
1406
+				$this->_template_args,
1407
+				true
1408
+			);
1409
+		} else {
1410
+			$this->_template_args['admin_page_header'] = '';
1411
+			$this->_display_espresso_notices();
1412
+		}
1413
+		// the details template wrapper
1414
+		$this->display_admin_page_with_sidebar();
1415
+	}
1416
+
1417
+
1418
+	/**
1419
+	 * @throws EE_Error
1420
+	 * @throws InvalidArgumentException
1421
+	 * @throws InvalidDataTypeException
1422
+	 * @throws InvalidInterfaceException
1423
+	 * @throws ReflectionException
1424
+	 * @since 4.10.2.p
1425
+	 */
1426
+	protected function _registration_details_metaboxes()
1427
+	{
1428
+		do_action('AHEE__Registrations_Admin_Page___registration_details_metabox__start', $this);
1429
+		$this->_set_registration_object();
1430
+		$attendee = $this->_registration instanceof EE_Registration ? $this->_registration->attendee() : null;
1431
+		add_meta_box(
1432
+			'edit-reg-status-mbox',
1433
+			esc_html__('Registration Status', 'event_espresso'),
1434
+			[$this, 'set_reg_status_buttons_metabox'],
1435
+			$this->_wp_page_slug,
1436
+			'normal',
1437
+			'high'
1438
+		);
1439
+		add_meta_box(
1440
+			'edit-reg-details-mbox',
1441
+			esc_html__('Registration Details', 'event_espresso'),
1442
+			[$this, '_reg_details_meta_box'],
1443
+			$this->_wp_page_slug,
1444
+			'normal',
1445
+			'high'
1446
+		);
1447
+		if (
1448
+			$attendee instanceof EE_Attendee
1449
+			&& EE_Registry::instance()->CAP->current_user_can(
1450
+				'ee_read_registration',
1451
+				'edit-reg-questions-mbox',
1452
+				$this->_registration->ID()
1453
+			)
1454
+		) {
1455
+			add_meta_box(
1456
+				'edit-reg-questions-mbox',
1457
+				esc_html__('Registration Form Answers', 'event_espresso'),
1458
+				[$this, '_reg_questions_meta_box'],
1459
+				$this->_wp_page_slug,
1460
+				'normal',
1461
+				'high'
1462
+			);
1463
+		}
1464
+		add_meta_box(
1465
+			'edit-reg-registrant-mbox',
1466
+			esc_html__('Contact Details', 'event_espresso'),
1467
+			[$this, '_reg_registrant_side_meta_box'],
1468
+			$this->_wp_page_slug,
1469
+			'side',
1470
+			'high'
1471
+		);
1472
+		if ($this->_registration->group_size() > 1) {
1473
+			add_meta_box(
1474
+				'edit-reg-attendees-mbox',
1475
+				esc_html__('Other Registrations in this Transaction', 'event_espresso'),
1476
+				[$this, '_reg_attendees_meta_box'],
1477
+				$this->_wp_page_slug,
1478
+				'normal',
1479
+				'high'
1480
+			);
1481
+		}
1482
+	}
1483
+
1484
+
1485
+	/**
1486
+	 * set_reg_status_buttons_metabox
1487
+	 *
1488
+	 * @return void
1489
+	 * @throws EE_Error
1490
+	 * @throws EntityNotFoundException
1491
+	 * @throws InvalidArgumentException
1492
+	 * @throws InvalidDataTypeException
1493
+	 * @throws InvalidInterfaceException
1494
+	 * @throws ReflectionException
1495
+	 */
1496
+	public function set_reg_status_buttons_metabox()
1497
+	{
1498
+		$this->_set_registration_object();
1499
+		$change_reg_status_form = $this->_generate_reg_status_change_form();
1500
+		$output                 = $change_reg_status_form->form_open(
1501
+			self::add_query_args_and_nonce(
1502
+				[
1503
+					'action' => 'change_reg_status',
1504
+				],
1505
+				REG_ADMIN_URL
1506
+			)
1507
+		);
1508
+		$output                 .= $change_reg_status_form->get_html();
1509
+		$output                 .= $change_reg_status_form->form_close();
1510
+		echo wp_kses($output, AllowedTags::getWithFormTags());
1511
+	}
1512
+
1513
+
1514
+	/**
1515
+	 * @return EE_Form_Section_Proper
1516
+	 * @throws EE_Error
1517
+	 * @throws InvalidArgumentException
1518
+	 * @throws InvalidDataTypeException
1519
+	 * @throws InvalidInterfaceException
1520
+	 * @throws EntityNotFoundException
1521
+	 * @throws ReflectionException
1522
+	 */
1523
+	protected function _generate_reg_status_change_form()
1524
+	{
1525
+		$reg_status_change_form_array = [
1526
+			'name'            => 'reg_status_change_form',
1527
+			'html_id'         => 'reg-status-change-form',
1528
+			'layout_strategy' => new EE_Admin_Two_Column_Layout(),
1529
+			'subsections'     => [
1530
+				'return'         => new EE_Hidden_Input(
1531
+					[
1532
+						'name'    => 'return',
1533
+						'default' => 'view_registration',
1534
+					]
1535
+				),
1536
+				'REG_ID'         => new EE_Hidden_Input(
1537
+					[
1538
+						'name'    => 'REG_ID',
1539
+						'default' => $this->_registration->ID(),
1540
+					]
1541
+				),
1542
+				'current_status' => new EE_Form_Section_HTML(
1543
+					EEH_HTML::table(
1544
+						EEH_HTML::tr(
1545
+							EEH_HTML::th(
1546
+								EEH_HTML::label(
1547
+									EEH_HTML::strong(
1548
+										esc_html__('Current Registration Status', 'event_espresso')
1549
+									)
1550
+								)
1551
+							)
1552
+							. EEH_HTML::td(
1553
+								EEH_HTML::strong(
1554
+									$this->_registration->pretty_status(),
1555
+									'',
1556
+									'status-' . $this->_registration->status_ID(),
1557
+									'line-height: 1em; font-size: 1.5em; font-weight: bold;'
1558
+								)
1559
+							)
1560
+						)
1561
+					)
1562
+				),
1563
+			],
1564
+		];
1565
+		if (
1566
+			EE_Registry::instance()->CAP->current_user_can(
1567
+				'ee_edit_registration',
1568
+				'toggle_registration_status',
1569
+				$this->_registration->ID()
1570
+			)
1571
+		) {
1572
+			$reg_status_change_form_array['subsections']['reg_status']         = new EE_Select_Input(
1573
+				$this->_get_reg_statuses(),
1574
+				[
1575
+					'html_label_text' => esc_html__('Change Registration Status to', 'event_espresso'),
1576
+					'default'         => $this->_registration->status_ID(),
1577
+				]
1578
+			);
1579
+			$reg_status_change_form_array['subsections']['send_notifications'] = new EE_Yes_No_Input(
1580
+				[
1581
+					'html_label_text' => esc_html__('Send Related Messages', 'event_espresso'),
1582
+					'default'         => false,
1583
+					'html_help_text'  => esc_html__(
1584
+						'If set to "Yes", then the related messages will be sent to the registrant.',
1585
+						'event_espresso'
1586
+					),
1587
+				]
1588
+			);
1589
+			$reg_status_change_form_array['subsections']['submit']             = new EE_Submit_Input(
1590
+				[
1591
+					'html_class'      => 'button-primary',
1592
+					'html_label_text' => '&nbsp;',
1593
+					'default'         => esc_html__('Update Registration Status', 'event_espresso'),
1594
+				]
1595
+			);
1596
+		}
1597
+		return new EE_Form_Section_Proper($reg_status_change_form_array);
1598
+	}
1599
+
1600
+
1601
+	/**
1602
+	 * Returns an array of all the buttons for the various statuses and switch status actions
1603
+	 *
1604
+	 * @return array
1605
+	 * @throws EE_Error
1606
+	 * @throws InvalidArgumentException
1607
+	 * @throws InvalidDataTypeException
1608
+	 * @throws InvalidInterfaceException
1609
+	 * @throws EntityNotFoundException
1610
+	 */
1611
+	protected function _get_reg_statuses()
1612
+	{
1613
+		$reg_status_array = $this->getRegistrationModel()->reg_status_array();
1614
+		unset($reg_status_array[ EEM_Registration::status_id_incomplete ]);
1615
+		// get current reg status
1616
+		$current_status = $this->_registration->status_ID();
1617
+		// is registration for free event? This will determine whether to display the pending payment option
1618
+		if (
1619
+			$current_status !== EEM_Registration::status_id_pending_payment
1620
+			&& EEH_Money::compare_floats($this->_registration->ticket()->price(), 0.00)
1621
+		) {
1622
+			unset($reg_status_array[ EEM_Registration::status_id_pending_payment ]);
1623
+		}
1624
+		return $this->getStatusModel()->localized_status($reg_status_array, false, 'sentence');
1625
+	}
1626
+
1627
+
1628
+	/**
1629
+	 * This method is used when using _REG_ID from request which may or may not be an array of reg_ids.
1630
+	 *
1631
+	 * @param bool $status REG status given for changing registrations to.
1632
+	 * @param bool $notify Whether to send messages notifications or not.
1633
+	 * @return array (array with reg_id(s) updated and whether update was successful.
1634
+	 * @throws DomainException
1635
+	 * @throws EE_Error
1636
+	 * @throws EntityNotFoundException
1637
+	 * @throws InvalidArgumentException
1638
+	 * @throws InvalidDataTypeException
1639
+	 * @throws InvalidInterfaceException
1640
+	 * @throws ReflectionException
1641
+	 * @throws RuntimeException
1642
+	 */
1643
+	protected function _set_registration_status_from_request($status = false, $notify = false)
1644
+	{
1645
+		$REG_IDs = $this->request->requestParamIsSet('reg_status_change_form')
1646
+			? $this->request->getRequestParam('reg_status_change_form[REG_ID]', [], 'int', true)
1647
+			: $this->request->getRequestParam('_REG_ID', [], 'int', true);
1648
+
1649
+		// sanitize $REG_IDs
1650
+		$REG_IDs = array_map('absint', $REG_IDs);
1651
+		// and remove empty entries
1652
+		$REG_IDs = array_filter($REG_IDs);
1653
+
1654
+		$result = $this->_set_registration_status($REG_IDs, $status, $notify);
1655
+
1656
+		/**
1657
+		 * Set and filter $_req_data['_REG_ID'] for any potential future messages notifications.
1658
+		 * Currently this value is used downstream by the _process_resend_registration method.
1659
+		 *
1660
+		 * @param int|array                $registration_ids The registration ids that have had their status changed successfully.
1661
+		 * @param bool                     $status           The status registrations were changed to.
1662
+		 * @param bool                     $success          If the status was changed successfully for all registrations.
1663
+		 * @param Registrations_Admin_Page $admin_page_object
1664
+		 */
1665
+		$REG_ID = apply_filters(
1666
+			'FHEE__Registrations_Admin_Page___set_registration_status_from_request__REG_IDs',
1667
+			$result['REG_ID'],
1668
+			$status,
1669
+			$result['success'],
1670
+			$this
1671
+		);
1672
+		$this->request->setRequestParam('_REG_ID', $REG_ID);
1673
+
1674
+		// notify?
1675
+		if (
1676
+			$notify
1677
+			&& $result['success']
1678
+			&& ! empty($REG_ID)
1679
+			&& EE_Registry::instance()->CAP->current_user_can(
1680
+				'ee_send_message',
1681
+				'espresso_registrations_resend_registration'
1682
+			)
1683
+		) {
1684
+			$this->_process_resend_registration();
1685
+		}
1686
+		return $result;
1687
+	}
1688
+
1689
+
1690
+	/**
1691
+	 * Set the registration status for the given reg_id (which may or may not be an array, it gets typecast to an
1692
+	 * array). Note, this method does NOT take care of possible notifications.  That is required by calling code.
1693
+	 *
1694
+	 * @param array  $REG_IDs
1695
+	 * @param string $status
1696
+	 * @param bool   $notify Used to indicate whether notification was requested or not.  This determines the context
1697
+	 *                       slug sent with setting the registration status.
1698
+	 * @return array (an array with 'success' key representing whether status change was successful, and 'REG_ID' as
1699
+	 * @throws EE_Error
1700
+	 * @throws InvalidArgumentException
1701
+	 * @throws InvalidDataTypeException
1702
+	 * @throws InvalidInterfaceException
1703
+	 * @throws ReflectionException
1704
+	 * @throws RuntimeException
1705
+	 * @throws EntityNotFoundException
1706
+	 * @throws DomainException
1707
+	 */
1708
+	protected function _set_registration_status($REG_IDs = [], $status = '', $notify = false)
1709
+	{
1710
+		$success = false;
1711
+		// typecast $REG_IDs
1712
+		$REG_IDs = (array) $REG_IDs;
1713
+		if (! empty($REG_IDs)) {
1714
+			$success = true;
1715
+			// set default status if none is passed
1716
+			$status         = $status ?: EEM_Registration::status_id_pending_payment;
1717
+			$status_context = $notify
1718
+				? Domain::CONTEXT_REGISTRATION_STATUS_CHANGE_REGISTRATION_ADMIN_NOTIFY
1719
+				: Domain::CONTEXT_REGISTRATION_STATUS_CHANGE_REGISTRATION_ADMIN;
1720
+			// loop through REG_ID's and change status
1721
+			foreach ($REG_IDs as $REG_ID) {
1722
+				$registration = $this->getRegistrationModel()->get_one_by_ID($REG_ID);
1723
+				if ($registration instanceof EE_Registration) {
1724
+					$registration->set_status(
1725
+						$status,
1726
+						false,
1727
+						new Context(
1728
+							$status_context,
1729
+							esc_html__(
1730
+								'Manually triggered status change on a Registration Admin Page route.',
1731
+								'event_espresso'
1732
+							)
1733
+						)
1734
+					);
1735
+					$result = $registration->save();
1736
+					// verifying explicit fails because update *may* just return 0 for 0 rows affected
1737
+					$success = $result !== false ? $success : false;
1738
+				}
1739
+			}
1740
+		}
1741
+
1742
+		// return $success and processed registrations
1743
+		return ['REG_ID' => $REG_IDs, 'success' => $success];
1744
+	}
1745
+
1746
+
1747
+	/**
1748
+	 * Common logic for setting up success message and redirecting to appropriate route
1749
+	 *
1750
+	 * @param string $STS_ID status id for the registration changed to
1751
+	 * @param bool   $notify indicates whether the _set_registration_status_from_request does notifications or not.
1752
+	 * @return void
1753
+	 * @throws DomainException
1754
+	 * @throws EE_Error
1755
+	 * @throws EntityNotFoundException
1756
+	 * @throws InvalidArgumentException
1757
+	 * @throws InvalidDataTypeException
1758
+	 * @throws InvalidInterfaceException
1759
+	 * @throws ReflectionException
1760
+	 * @throws RuntimeException
1761
+	 */
1762
+	protected function _reg_status_change_return($STS_ID, $notify = false)
1763
+	{
1764
+		$result  = ! empty($STS_ID) ? $this->_set_registration_status_from_request($STS_ID, $notify)
1765
+			: ['success' => false];
1766
+		$success = isset($result['success']) && $result['success'];
1767
+		// setup success message
1768
+		if ($success) {
1769
+			if (is_array($result['REG_ID']) && count($result['REG_ID']) === 1) {
1770
+				$msg = sprintf(
1771
+					esc_html__('Registration status has been set to %s', 'event_espresso'),
1772
+					EEH_Template::pretty_status($STS_ID, false, 'lower')
1773
+				);
1774
+			} else {
1775
+				$msg = sprintf(
1776
+					esc_html__('Registrations have been set to %s.', 'event_espresso'),
1777
+					EEH_Template::pretty_status($STS_ID, false, 'lower')
1778
+				);
1779
+			}
1780
+			EE_Error::add_success($msg);
1781
+		} else {
1782
+			EE_Error::add_error(
1783
+				esc_html__(
1784
+					'Something went wrong, and the status was not changed',
1785
+					'event_espresso'
1786
+				),
1787
+				__FILE__,
1788
+				__LINE__,
1789
+				__FUNCTION__
1790
+			);
1791
+		}
1792
+		$return = $this->request->getRequestParam('return');
1793
+		$route  = $return === 'view_registration'
1794
+			? ['action' => 'view_registration', '_REG_ID' => reset($result['REG_ID'])]
1795
+			: ['action' => 'default'];
1796
+		$route  = $this->mergeExistingRequestParamsWithRedirectArgs($route);
1797
+		$this->_redirect_after_action($success, '', '', $route, true);
1798
+	}
1799
+
1800
+
1801
+	/**
1802
+	 * incoming reg status change from reg details page.
1803
+	 *
1804
+	 * @return void
1805
+	 * @throws EE_Error
1806
+	 * @throws EntityNotFoundException
1807
+	 * @throws InvalidArgumentException
1808
+	 * @throws InvalidDataTypeException
1809
+	 * @throws InvalidInterfaceException
1810
+	 * @throws ReflectionException
1811
+	 * @throws RuntimeException
1812
+	 * @throws DomainException
1813
+	 */
1814
+	protected function _change_reg_status()
1815
+	{
1816
+		$this->request->setRequestParam('return', 'view_registration');
1817
+		// set notify based on whether the send notifications toggle is set or not
1818
+		$notify     = $this->request->getRequestParam('reg_status_change_form[send_notifications]', false, 'bool');
1819
+		$reg_status = $this->request->getRequestParam('reg_status_change_form[reg_status]', '');
1820
+		$this->request->setRequestParam('reg_status_change_form[reg_status]', $reg_status);
1821
+		switch ($reg_status) {
1822
+			case EEM_Registration::status_id_approved:
1823
+			case EEH_Template::pretty_status(EEM_Registration::status_id_approved, false, 'sentence'):
1824
+				$this->approve_registration($notify);
1825
+				break;
1826
+			case EEM_Registration::status_id_pending_payment:
1827
+			case EEH_Template::pretty_status(EEM_Registration::status_id_pending_payment, false, 'sentence'):
1828
+				$this->pending_registration($notify);
1829
+				break;
1830
+			case EEM_Registration::status_id_not_approved:
1831
+			case EEH_Template::pretty_status(EEM_Registration::status_id_not_approved, false, 'sentence'):
1832
+				$this->not_approve_registration($notify);
1833
+				break;
1834
+			case EEM_Registration::status_id_declined:
1835
+			case EEH_Template::pretty_status(EEM_Registration::status_id_declined, false, 'sentence'):
1836
+				$this->decline_registration($notify);
1837
+				break;
1838
+			case EEM_Registration::status_id_cancelled:
1839
+			case EEH_Template::pretty_status(EEM_Registration::status_id_cancelled, false, 'sentence'):
1840
+				$this->cancel_registration($notify);
1841
+				break;
1842
+			case EEM_Registration::status_id_wait_list:
1843
+			case EEH_Template::pretty_status(EEM_Registration::status_id_wait_list, false, 'sentence'):
1844
+				$this->wait_list_registration($notify);
1845
+				break;
1846
+			case EEM_Registration::status_id_incomplete:
1847
+			default:
1848
+				$this->request->unSetRequestParam('return');
1849
+				$this->_reg_status_change_return('');
1850
+				break;
1851
+		}
1852
+	}
1853
+
1854
+
1855
+	/**
1856
+	 * Callback for bulk action routes.
1857
+	 * Note: although we could just register the singular route callbacks for each bulk action route as well, this
1858
+	 * method was chosen so there is one central place all the registration status bulk actions are going through.
1859
+	 * Potentially, this provides an easier place to locate logic that is specific to these bulk actions (as opposed to
1860
+	 * when an action is happening on just a single registration).
1861
+	 *
1862
+	 * @param      $action
1863
+	 * @param bool $notify
1864
+	 */
1865
+	protected function bulk_action_on_registrations($action, $notify = false)
1866
+	{
1867
+		do_action(
1868
+			'AHEE__Registrations_Admin_Page__bulk_action_on_registrations__before_execution',
1869
+			$this,
1870
+			$action,
1871
+			$notify
1872
+		);
1873
+		$method = $action . '_registration';
1874
+		if (method_exists($this, $method)) {
1875
+			$this->$method($notify);
1876
+		}
1877
+	}
1878
+
1879
+
1880
+	/**
1881
+	 * approve_registration
1882
+	 *
1883
+	 * @param bool $notify whether or not to notify the registrant about their approval.
1884
+	 * @return void
1885
+	 * @throws EE_Error
1886
+	 * @throws EntityNotFoundException
1887
+	 * @throws InvalidArgumentException
1888
+	 * @throws InvalidDataTypeException
1889
+	 * @throws InvalidInterfaceException
1890
+	 * @throws ReflectionException
1891
+	 * @throws RuntimeException
1892
+	 * @throws DomainException
1893
+	 */
1894
+	protected function approve_registration($notify = false)
1895
+	{
1896
+		$this->_reg_status_change_return(EEM_Registration::status_id_approved, $notify);
1897
+	}
1898
+
1899
+
1900
+	/**
1901
+	 * decline_registration
1902
+	 *
1903
+	 * @param bool $notify whether or not to notify the registrant about their status change.
1904
+	 * @return void
1905
+	 * @throws EE_Error
1906
+	 * @throws EntityNotFoundException
1907
+	 * @throws InvalidArgumentException
1908
+	 * @throws InvalidDataTypeException
1909
+	 * @throws InvalidInterfaceException
1910
+	 * @throws ReflectionException
1911
+	 * @throws RuntimeException
1912
+	 * @throws DomainException
1913
+	 */
1914
+	protected function decline_registration($notify = false)
1915
+	{
1916
+		$this->_reg_status_change_return(EEM_Registration::status_id_declined, $notify);
1917
+	}
1918
+
1919
+
1920
+	/**
1921
+	 * cancel_registration
1922
+	 *
1923
+	 * @param bool $notify whether or not to notify the registrant about their status change.
1924
+	 * @return void
1925
+	 * @throws EE_Error
1926
+	 * @throws EntityNotFoundException
1927
+	 * @throws InvalidArgumentException
1928
+	 * @throws InvalidDataTypeException
1929
+	 * @throws InvalidInterfaceException
1930
+	 * @throws ReflectionException
1931
+	 * @throws RuntimeException
1932
+	 * @throws DomainException
1933
+	 */
1934
+	protected function cancel_registration($notify = false)
1935
+	{
1936
+		$this->_reg_status_change_return(EEM_Registration::status_id_cancelled, $notify);
1937
+	}
1938
+
1939
+
1940
+	/**
1941
+	 * not_approve_registration
1942
+	 *
1943
+	 * @param bool $notify whether or not to notify the registrant about their status change.
1944
+	 * @return void
1945
+	 * @throws EE_Error
1946
+	 * @throws EntityNotFoundException
1947
+	 * @throws InvalidArgumentException
1948
+	 * @throws InvalidDataTypeException
1949
+	 * @throws InvalidInterfaceException
1950
+	 * @throws ReflectionException
1951
+	 * @throws RuntimeException
1952
+	 * @throws DomainException
1953
+	 */
1954
+	protected function not_approve_registration($notify = false)
1955
+	{
1956
+		$this->_reg_status_change_return(EEM_Registration::status_id_not_approved, $notify);
1957
+	}
1958
+
1959
+
1960
+	/**
1961
+	 * decline_registration
1962
+	 *
1963
+	 * @param bool $notify whether or not to notify the registrant about their status change.
1964
+	 * @return void
1965
+	 * @throws EE_Error
1966
+	 * @throws EntityNotFoundException
1967
+	 * @throws InvalidArgumentException
1968
+	 * @throws InvalidDataTypeException
1969
+	 * @throws InvalidInterfaceException
1970
+	 * @throws ReflectionException
1971
+	 * @throws RuntimeException
1972
+	 * @throws DomainException
1973
+	 */
1974
+	protected function pending_registration($notify = false)
1975
+	{
1976
+		$this->_reg_status_change_return(EEM_Registration::status_id_pending_payment, $notify);
1977
+	}
1978
+
1979
+
1980
+	/**
1981
+	 * waitlist_registration
1982
+	 *
1983
+	 * @param bool $notify whether or not to notify the registrant about their status change.
1984
+	 * @return void
1985
+	 * @throws EE_Error
1986
+	 * @throws EntityNotFoundException
1987
+	 * @throws InvalidArgumentException
1988
+	 * @throws InvalidDataTypeException
1989
+	 * @throws InvalidInterfaceException
1990
+	 * @throws ReflectionException
1991
+	 * @throws RuntimeException
1992
+	 * @throws DomainException
1993
+	 */
1994
+	protected function wait_list_registration($notify = false)
1995
+	{
1996
+		$this->_reg_status_change_return(EEM_Registration::status_id_wait_list, $notify);
1997
+	}
1998
+
1999
+
2000
+	/**
2001
+	 * generates HTML for the Registration main meta box
2002
+	 *
2003
+	 * @return void
2004
+	 * @throws DomainException
2005
+	 * @throws EE_Error
2006
+	 * @throws InvalidArgumentException
2007
+	 * @throws InvalidDataTypeException
2008
+	 * @throws InvalidInterfaceException
2009
+	 * @throws ReflectionException
2010
+	 * @throws EntityNotFoundException
2011
+	 */
2012
+	public function _reg_details_meta_box()
2013
+	{
2014
+		EEH_Autoloader::register_line_item_display_autoloaders();
2015
+		EEH_Autoloader::register_line_item_filter_autoloaders();
2016
+		EE_Registry::instance()->load_helper('Line_Item');
2017
+		$transaction    = $this->_registration->transaction() ? $this->_registration->transaction()
2018
+			: EE_Transaction::new_instance();
2019
+		$this->_session = $transaction->session_data();
2020
+		$filters        = new EE_Line_Item_Filter_Collection();
2021
+		$filters->add(new EE_Single_Registration_Line_Item_Filter($this->_registration));
2022
+		$filters->add(new EE_Non_Zero_Line_Item_Filter());
2023
+		$line_item_filter_processor              = new EE_Line_Item_Filter_Processor(
2024
+			$filters,
2025
+			$transaction->total_line_item()
2026
+		);
2027
+		$filtered_line_item_tree                 = $line_item_filter_processor->process();
2028
+		$line_item_display                       = new EE_Line_Item_Display(
2029
+			'reg_admin_table',
2030
+			'EE_Admin_Table_Registration_Line_Item_Display_Strategy'
2031
+		);
2032
+		$this->_template_args['line_item_table'] = $line_item_display->display_line_item(
2033
+			$filtered_line_item_tree,
2034
+			['EE_Registration' => $this->_registration]
2035
+		);
2036
+		$attendee                                = $this->_registration->attendee();
2037
+		if (
2038
+			EE_Registry::instance()->CAP->current_user_can(
2039
+				'ee_read_transaction',
2040
+				'espresso_transactions_view_transaction'
2041
+			)
2042
+		) {
2043
+			$this->_template_args['view_transaction_button'] = EEH_Template::get_button_or_link(
2044
+				EE_Admin_Page::add_query_args_and_nonce(
2045
+					[
2046
+						'action' => 'view_transaction',
2047
+						'TXN_ID' => $transaction->ID(),
2048
+					],
2049
+					TXN_ADMIN_URL
2050
+				),
2051
+				esc_html__(' View Transaction', 'event_espresso'),
2052
+				'button secondary-button right',
2053
+				'dashicons dashicons-cart'
2054
+			);
2055
+		} else {
2056
+			$this->_template_args['view_transaction_button'] = '';
2057
+		}
2058
+		if (
2059
+			$attendee instanceof EE_Attendee
2060
+			&& EE_Registry::instance()->CAP->current_user_can(
2061
+				'ee_send_message',
2062
+				'espresso_registrations_resend_registration'
2063
+			)
2064
+		) {
2065
+			$this->_template_args['resend_registration_button'] = EEH_Template::get_button_or_link(
2066
+				EE_Admin_Page::add_query_args_and_nonce(
2067
+					[
2068
+						'action'      => 'resend_registration',
2069
+						'_REG_ID'     => $this->_registration->ID(),
2070
+						'redirect_to' => 'view_registration',
2071
+					],
2072
+					REG_ADMIN_URL
2073
+				),
2074
+				esc_html__(' Resend Registration', 'event_espresso'),
2075
+				'button secondary-button right',
2076
+				'dashicons dashicons-email-alt'
2077
+			);
2078
+		} else {
2079
+			$this->_template_args['resend_registration_button'] = '';
2080
+		}
2081
+		$this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
2082
+		$payment                               = $transaction->get_first_related('Payment');
2083
+		$payment                               = ! $payment instanceof EE_Payment
2084
+			? EE_Payment::new_instance()
2085
+			: $payment;
2086
+		$payment_method                        = $payment->get_first_related('Payment_Method');
2087
+		$payment_method                        = ! $payment_method instanceof EE_Payment_Method
2088
+			? EE_Payment_Method::new_instance()
2089
+			: $payment_method;
2090
+		$reg_details                           = [
2091
+			'payment_method'       => $payment_method->name(),
2092
+			'response_msg'         => $payment->gateway_response(),
2093
+			'registration_id'      => $this->_registration->get('REG_code'),
2094
+			'registration_session' => $this->_registration->session_ID(),
2095
+			'ip_address'           => isset($this->_session['ip_address']) ? $this->_session['ip_address'] : '',
2096
+			'user_agent'           => isset($this->_session['user_agent']) ? $this->_session['user_agent'] : '',
2097
+		];
2098
+		if (isset($reg_details['registration_id'])) {
2099
+			$this->_template_args['reg_details']['registration_id']['value'] = $reg_details['registration_id'];
2100
+			$this->_template_args['reg_details']['registration_id']['label'] = esc_html__(
2101
+				'Registration ID',
2102
+				'event_espresso'
2103
+			);
2104
+			$this->_template_args['reg_details']['registration_id']['class'] = 'regular-text';
2105
+		}
2106
+		if (isset($reg_details['payment_method'])) {
2107
+			$this->_template_args['reg_details']['payment_method']['value'] = $reg_details['payment_method'];
2108
+			$this->_template_args['reg_details']['payment_method']['label'] = esc_html__(
2109
+				'Most Recent Payment Method',
2110
+				'event_espresso'
2111
+			);
2112
+			$this->_template_args['reg_details']['payment_method']['class'] = 'regular-text';
2113
+			$this->_template_args['reg_details']['response_msg']['value']   = $reg_details['response_msg'];
2114
+			$this->_template_args['reg_details']['response_msg']['label']   = esc_html__(
2115
+				'Payment method response',
2116
+				'event_espresso'
2117
+			);
2118
+			$this->_template_args['reg_details']['response_msg']['class']   = 'regular-text';
2119
+		}
2120
+		$this->_template_args['reg_details']['registration_session']['value'] = $reg_details['registration_session'];
2121
+		$this->_template_args['reg_details']['registration_session']['label'] = esc_html__(
2122
+			'Registration Session',
2123
+			'event_espresso'
2124
+		);
2125
+		$this->_template_args['reg_details']['registration_session']['class'] = 'regular-text';
2126
+		$this->_template_args['reg_details']['ip_address']['value']           = $reg_details['ip_address'];
2127
+		$this->_template_args['reg_details']['ip_address']['label']           = esc_html__(
2128
+			'Registration placed from IP',
2129
+			'event_espresso'
2130
+		);
2131
+		$this->_template_args['reg_details']['ip_address']['class']           = 'regular-text';
2132
+		$this->_template_args['reg_details']['user_agent']['value']           = $reg_details['user_agent'];
2133
+		$this->_template_args['reg_details']['user_agent']['label']           = esc_html__(
2134
+			'Registrant User Agent',
2135
+			'event_espresso'
2136
+		);
2137
+		$this->_template_args['reg_details']['user_agent']['class']           = 'large-text';
2138
+		$this->_template_args['event_link']                                   = EE_Admin_Page::add_query_args_and_nonce(
2139
+			[
2140
+				'action'   => 'default',
2141
+				'event_id' => $this->_registration->event_ID(),
2142
+			],
2143
+			REG_ADMIN_URL
2144
+		);
2145
+		$this->_template_args['REG_ID']                                       = $this->_registration->ID();
2146
+		$this->_template_args['event_id']                                     = $this->_registration->event_ID();
2147
+		$template_path                                                        =
2148
+			REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_details.template.php';
2149
+		EEH_Template::display_template($template_path, $this->_template_args); // already escaped
2150
+	}
2151
+
2152
+
2153
+	/**
2154
+	 * generates HTML for the Registration Questions meta box.
2155
+	 * If pre-4.8.32.rc.000 hooks are used, uses old methods (with its filters),
2156
+	 * otherwise uses new forms system
2157
+	 *
2158
+	 * @return void
2159
+	 * @throws DomainException
2160
+	 * @throws EE_Error
2161
+	 * @throws InvalidArgumentException
2162
+	 * @throws InvalidDataTypeException
2163
+	 * @throws InvalidInterfaceException
2164
+	 * @throws ReflectionException
2165
+	 */
2166
+	public function _reg_questions_meta_box()
2167
+	{
2168
+		// allow someone to override this method entirely
2169
+		if (
2170
+			apply_filters(
2171
+				'FHEE__Registrations_Admin_Page___reg_questions_meta_box__do_default',
2172
+				true,
2173
+				$this,
2174
+				$this->_registration
2175
+			)
2176
+		) {
2177
+			$form                                              = $this->_get_reg_custom_questions_form(
2178
+				$this->_registration->ID()
2179
+			);
2180
+			$this->_template_args['att_questions']             = count($form->subforms()) > 0
2181
+				? $form->get_html_and_js()
2182
+				: '';
2183
+			$this->_template_args['reg_questions_form_action'] = 'edit_registration';
2184
+			$this->_template_args['REG_ID']                    = $this->_registration->ID();
2185
+			$template_path                                     =
2186
+				REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_questions.template.php';
2187
+			EEH_Template::display_template($template_path, $this->_template_args);
2188
+		}
2189
+	}
2190
+
2191
+
2192
+	/**
2193
+	 * form_before_question_group
2194
+	 *
2195
+	 * @param string $output
2196
+	 * @return        string
2197
+	 * @deprecated    as of 4.8.32.rc.000
2198
+	 */
2199
+	public function form_before_question_group($output)
2200
+	{
2201
+		EE_Error::doing_it_wrong(
2202
+			__CLASS__ . '::' . __FUNCTION__,
2203
+			esc_html__(
2204
+				'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.',
2205
+				'event_espresso'
2206
+			),
2207
+			'4.8.32.rc.000'
2208
+		);
2209
+		return '
2210 2210
 	<table class="form-table ee-width-100">
2211 2211
 		<tbody>
2212 2212
 			';
2213
-    }
2214
-
2215
-
2216
-    /**
2217
-     * form_after_question_group
2218
-     *
2219
-     * @param string $output
2220
-     * @return        string
2221
-     * @deprecated    as of 4.8.32.rc.000
2222
-     */
2223
-    public function form_after_question_group($output)
2224
-    {
2225
-        EE_Error::doing_it_wrong(
2226
-            __CLASS__ . '::' . __FUNCTION__,
2227
-            esc_html__(
2228
-                '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.',
2229
-                'event_espresso'
2230
-            ),
2231
-            '4.8.32.rc.000'
2232
-        );
2233
-        return '
2213
+	}
2214
+
2215
+
2216
+	/**
2217
+	 * form_after_question_group
2218
+	 *
2219
+	 * @param string $output
2220
+	 * @return        string
2221
+	 * @deprecated    as of 4.8.32.rc.000
2222
+	 */
2223
+	public function form_after_question_group($output)
2224
+	{
2225
+		EE_Error::doing_it_wrong(
2226
+			__CLASS__ . '::' . __FUNCTION__,
2227
+			esc_html__(
2228
+				'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.',
2229
+				'event_espresso'
2230
+			),
2231
+			'4.8.32.rc.000'
2232
+		);
2233
+		return '
2234 2234
 			<tr class="hide-if-no-js">
2235 2235
 				<th> </th>
2236 2236
 				<td class="reg-admin-edit-attendee-question-td">
2237 2237
 					<a class="reg-admin-edit-attendee-question-lnk" href="#" title="'
2238
-               . esc_attr__('click to edit question', 'event_espresso')
2239
-               . '">
2238
+			   . esc_attr__('click to edit question', 'event_espresso')
2239
+			   . '">
2240 2240
 						<span class="reg-admin-edit-question-group-spn lt-grey-txt">'
2241
-               . esc_html__('edit the above question group', 'event_espresso')
2242
-               . '</span>
2241
+			   . esc_html__('edit the above question group', 'event_espresso')
2242
+			   . '</span>
2243 2243
 						<div class="dashicons dashicons-edit"></div>
2244 2244
 					</a>
2245 2245
 				</td>
@@ -2247,641 +2247,641 @@  discard block
 block discarded – undo
2247 2247
 		</tbody>
2248 2248
 	</table>
2249 2249
 ';
2250
-    }
2251
-
2252
-
2253
-    /**
2254
-     * form_form_field_label_wrap
2255
-     *
2256
-     * @param string $label
2257
-     * @return        string
2258
-     * @deprecated    as of 4.8.32.rc.000
2259
-     */
2260
-    public function form_form_field_label_wrap($label)
2261
-    {
2262
-        EE_Error::doing_it_wrong(
2263
-            __CLASS__ . '::' . __FUNCTION__,
2264
-            esc_html__(
2265
-                '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.',
2266
-                'event_espresso'
2267
-            ),
2268
-            '4.8.32.rc.000'
2269
-        );
2270
-        return '
2250
+	}
2251
+
2252
+
2253
+	/**
2254
+	 * form_form_field_label_wrap
2255
+	 *
2256
+	 * @param string $label
2257
+	 * @return        string
2258
+	 * @deprecated    as of 4.8.32.rc.000
2259
+	 */
2260
+	public function form_form_field_label_wrap($label)
2261
+	{
2262
+		EE_Error::doing_it_wrong(
2263
+			__CLASS__ . '::' . __FUNCTION__,
2264
+			esc_html__(
2265
+				'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.',
2266
+				'event_espresso'
2267
+			),
2268
+			'4.8.32.rc.000'
2269
+		);
2270
+		return '
2271 2271
 			<tr>
2272 2272
 				<th>
2273 2273
 					' . $label . '
2274 2274
 				</th>';
2275
-    }
2276
-
2277
-
2278
-    /**
2279
-     * form_form_field_input__wrap
2280
-     *
2281
-     * @param string $input
2282
-     * @return        string
2283
-     * @deprecated    as of 4.8.32.rc.000
2284
-     */
2285
-    public function form_form_field_input__wrap($input)
2286
-    {
2287
-        EE_Error::doing_it_wrong(
2288
-            __CLASS__ . '::' . __FUNCTION__,
2289
-            esc_html__(
2290
-                '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.',
2291
-                'event_espresso'
2292
-            ),
2293
-            '4.8.32.rc.000'
2294
-        );
2295
-        return '
2275
+	}
2276
+
2277
+
2278
+	/**
2279
+	 * form_form_field_input__wrap
2280
+	 *
2281
+	 * @param string $input
2282
+	 * @return        string
2283
+	 * @deprecated    as of 4.8.32.rc.000
2284
+	 */
2285
+	public function form_form_field_input__wrap($input)
2286
+	{
2287
+		EE_Error::doing_it_wrong(
2288
+			__CLASS__ . '::' . __FUNCTION__,
2289
+			esc_html__(
2290
+				'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.',
2291
+				'event_espresso'
2292
+			),
2293
+			'4.8.32.rc.000'
2294
+		);
2295
+		return '
2296 2296
 				<td class="reg-admin-attendee-questions-input-td disabled-input">
2297 2297
 					' . $input . '
2298 2298
 				</td>
2299 2299
 			</tr>';
2300
-    }
2301
-
2302
-
2303
-    /**
2304
-     * Updates the registration's custom questions according to the form info, if the form is submitted.
2305
-     * If it's not a post, the "view_registrations" route will be called next on the SAME request
2306
-     * to display the page
2307
-     *
2308
-     * @return void
2309
-     * @throws EE_Error
2310
-     * @throws InvalidArgumentException
2311
-     * @throws InvalidDataTypeException
2312
-     * @throws InvalidInterfaceException
2313
-     * @throws ReflectionException
2314
-     */
2315
-    protected function _update_attendee_registration_form()
2316
-    {
2317
-        do_action('AHEE__Registrations_Admin_Page___update_attendee_registration_form__start', $this);
2318
-        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
2319
-            $REG_ID  = $this->request->getRequestParam('_REG_ID', 0, 'int');
2320
-            $success = $this->_save_reg_custom_questions_form($REG_ID);
2321
-            if ($success) {
2322
-                $what  = esc_html__('Registration Form', 'event_espresso');
2323
-                $route = $REG_ID
2324
-                    ? ['action' => 'view_registration', '_REG_ID' => $REG_ID]
2325
-                    : ['action' => 'default'];
2326
-                $this->_redirect_after_action(true, $what, esc_html__('updated', 'event_espresso'), $route);
2327
-            }
2328
-        }
2329
-    }
2330
-
2331
-
2332
-    /**
2333
-     * Gets the form for saving registrations custom questions (if done
2334
-     * previously retrieves the cached form object, which may have validation errors in it)
2335
-     *
2336
-     * @param int $REG_ID
2337
-     * @return EE_Registration_Custom_Questions_Form
2338
-     * @throws EE_Error
2339
-     * @throws InvalidArgumentException
2340
-     * @throws InvalidDataTypeException
2341
-     * @throws InvalidInterfaceException
2342
-     * @throws ReflectionException
2343
-     */
2344
-    protected function _get_reg_custom_questions_form($REG_ID)
2345
-    {
2346
-        if (! $this->_reg_custom_questions_form) {
2347
-            require_once(REG_ADMIN . 'form_sections/EE_Registration_Custom_Questions_Form.form.php');
2348
-            $this->_reg_custom_questions_form = new EE_Registration_Custom_Questions_Form(
2349
-                $this->getRegistrationModel()->get_one_by_ID($REG_ID)
2350
-            );
2351
-            $this->_reg_custom_questions_form->_construct_finalize(null, null);
2352
-        }
2353
-        return $this->_reg_custom_questions_form;
2354
-    }
2355
-
2356
-
2357
-    /**
2358
-     * Saves
2359
-     *
2360
-     * @param bool $REG_ID
2361
-     * @return bool
2362
-     * @throws EE_Error
2363
-     * @throws InvalidArgumentException
2364
-     * @throws InvalidDataTypeException
2365
-     * @throws InvalidInterfaceException
2366
-     * @throws ReflectionException
2367
-     */
2368
-    private function _save_reg_custom_questions_form($REG_ID = 0)
2369
-    {
2370
-        if (! $REG_ID) {
2371
-            EE_Error::add_error(
2372
-                esc_html__(
2373
-                    'An error occurred. No registration ID was received.',
2374
-                    'event_espresso'
2375
-                ),
2376
-                __FILE__,
2377
-                __FUNCTION__,
2378
-                __LINE__
2379
-            );
2380
-        }
2381
-        $form = $this->_get_reg_custom_questions_form($REG_ID);
2382
-        $form->receive_form_submission($this->request->requestParams());
2383
-        $success = false;
2384
-        if ($form->is_valid()) {
2385
-            foreach ($form->subforms() as $question_group_form) {
2386
-                foreach ($question_group_form->inputs() as $question_id => $input) {
2387
-                    $where_conditions    = [
2388
-                        'QST_ID' => $question_id,
2389
-                        'REG_ID' => $REG_ID,
2390
-                    ];
2391
-                    $possibly_new_values = [
2392
-                        'ANS_value' => $input->normalized_value(),
2393
-                    ];
2394
-                    $answer              = EEM_Answer::instance()->get_one([$where_conditions]);
2395
-                    if ($answer instanceof EE_Answer) {
2396
-                        $success = $answer->save($possibly_new_values);
2397
-                    } else {
2398
-                        // insert it then
2399
-                        $cols_n_vals = array_merge($where_conditions, $possibly_new_values);
2400
-                        $answer      = EE_Answer::new_instance($cols_n_vals);
2401
-                        $success     = $answer->save();
2402
-                    }
2403
-                }
2404
-            }
2405
-        } else {
2406
-            EE_Error::add_error($form->get_validation_error_string(), __FILE__, __FUNCTION__, __LINE__);
2407
-        }
2408
-        return $success;
2409
-    }
2410
-
2411
-
2412
-    /**
2413
-     * generates HTML for the Registration main meta box
2414
-     *
2415
-     * @return void
2416
-     * @throws DomainException
2417
-     * @throws EE_Error
2418
-     * @throws InvalidArgumentException
2419
-     * @throws InvalidDataTypeException
2420
-     * @throws InvalidInterfaceException
2421
-     * @throws ReflectionException
2422
-     */
2423
-    public function _reg_attendees_meta_box()
2424
-    {
2425
-        $REG = $this->getRegistrationModel();
2426
-        // get all other registrations on this transaction, and cache
2427
-        // the attendees for them so we don't have to run another query using force_join
2428
-        $registrations                           = $REG->get_all(
2429
-            [
2430
-                [
2431
-                    'TXN_ID' => $this->_registration->transaction_ID(),
2432
-                    'REG_ID' => ['!=', $this->_registration->ID()],
2433
-                ],
2434
-                'force_join'               => ['Attendee'],
2435
-                'default_where_conditions' => 'other_models_only',
2436
-            ]
2437
-        );
2438
-        $this->_template_args['attendees']       = [];
2439
-        $this->_template_args['attendee_notice'] = '';
2440
-        if (
2441
-            empty($registrations)
2442
-            || (is_array($registrations)
2443
-                && ! EEH_Array::get_one_item_from_array($registrations))
2444
-        ) {
2445
-            EE_Error::add_error(
2446
-                esc_html__(
2447
-                    'There are no records attached to this registration. Something may have gone wrong with the registration',
2448
-                    'event_espresso'
2449
-                ),
2450
-                __FILE__,
2451
-                __FUNCTION__,
2452
-                __LINE__
2453
-            );
2454
-            $this->_template_args['attendee_notice'] = EE_Error::get_notices();
2455
-        } else {
2456
-            $att_nmbr = 1;
2457
-            foreach ($registrations as $registration) {
2458
-                /* @var $registration EE_Registration */
2459
-                $attendee                                                      = $registration->attendee()
2460
-                    ? $registration->attendee()
2461
-                    : $this->getAttendeeModel()->create_default_object();
2462
-                $this->_template_args['attendees'][ $att_nmbr ]['STS_ID']      = $registration->status_ID();
2463
-                $this->_template_args['attendees'][ $att_nmbr ]['fname']       = $attendee->fname();
2464
-                $this->_template_args['attendees'][ $att_nmbr ]['lname']       = $attendee->lname();
2465
-                $this->_template_args['attendees'][ $att_nmbr ]['email']       = $attendee->email();
2466
-                $this->_template_args['attendees'][ $att_nmbr ]['final_price'] = $registration->final_price();
2467
-                $this->_template_args['attendees'][ $att_nmbr ]['address']     = implode(
2468
-                    ', ',
2469
-                    $attendee->full_address_as_array()
2470
-                );
2471
-                $this->_template_args['attendees'][ $att_nmbr ]['att_link']    = self::add_query_args_and_nonce(
2472
-                    [
2473
-                        'action' => 'edit_attendee',
2474
-                        'post'   => $attendee->ID(),
2475
-                    ],
2476
-                    REG_ADMIN_URL
2477
-                );
2478
-                $this->_template_args['attendees'][ $att_nmbr ]['event_name']  =
2479
-                    $registration->event_obj() instanceof EE_Event
2480
-                        ? $registration->event_obj()->name()
2481
-                        : '';
2482
-                $att_nmbr++;
2483
-            }
2484
-            $this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
2485
-        }
2486
-        $template_path = REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_attendees.template.php';
2487
-        EEH_Template::display_template($template_path, $this->_template_args);
2488
-    }
2489
-
2490
-
2491
-    /**
2492
-     * generates HTML for the Edit Registration side meta box
2493
-     *
2494
-     * @return void
2495
-     * @throws DomainException
2496
-     * @throws EE_Error
2497
-     * @throws InvalidArgumentException
2498
-     * @throws InvalidDataTypeException
2499
-     * @throws InvalidInterfaceException
2500
-     * @throws ReflectionException
2501
-     */
2502
-    public function _reg_registrant_side_meta_box()
2503
-    {
2504
-        /*@var $attendee EE_Attendee */
2505
-        $att_check = $this->_registration->attendee();
2506
-        $attendee  = $att_check instanceof EE_Attendee
2507
-            ? $att_check
2508
-            : $this->getAttendeeModel()->create_default_object();
2509
-        // now let's determine if this is not the primary registration.  If it isn't then we set the
2510
-        // primary_registration object for reference BUT ONLY if the Attendee object loaded is not the same as the
2511
-        // primary registration object (that way we know if we need to show create button or not)
2512
-        if (! $this->_registration->is_primary_registrant()) {
2513
-            $primary_registration = $this->_registration->get_primary_registration();
2514
-            $primary_attendee     = $primary_registration instanceof EE_Registration ? $primary_registration->attendee()
2515
-                : null;
2516
-            if (! $primary_attendee instanceof EE_Attendee || $attendee->ID() !== $primary_attendee->ID()) {
2517
-                // in here?  This means the displayed registration is not the primary registrant but ALREADY HAS its own
2518
-                // custom attendee object so let's not worry about the primary reg.
2519
-                $primary_registration = null;
2520
-            }
2521
-        } else {
2522
-            $primary_registration = null;
2523
-        }
2524
-        $this->_template_args['ATT_ID']            = $attendee->ID();
2525
-        $this->_template_args['fname']             = $attendee->fname();
2526
-        $this->_template_args['lname']             = $attendee->lname();
2527
-        $this->_template_args['email']             = $attendee->email();
2528
-        $this->_template_args['phone']             = $attendee->phone();
2529
-        $this->_template_args['formatted_address'] = EEH_Address::format($attendee);
2530
-        // edit link
2531
-        $this->_template_args['att_edit_link']  = EE_Admin_Page::add_query_args_and_nonce(
2532
-            [
2533
-                'action' => 'edit_attendee',
2534
-                'post'   => $attendee->ID(),
2535
-            ],
2536
-            REG_ADMIN_URL
2537
-        );
2538
-        $this->_template_args['att_edit_label'] = esc_html__('View/Edit Contact', 'event_espresso');
2539
-        // create link
2540
-        $this->_template_args['create_link']  = $primary_registration instanceof EE_Registration
2541
-            ? EE_Admin_Page::add_query_args_and_nonce(
2542
-                [
2543
-                    'action'  => 'duplicate_attendee',
2544
-                    '_REG_ID' => $this->_registration->ID(),
2545
-                ],
2546
-                REG_ADMIN_URL
2547
-            ) : '';
2548
-        $this->_template_args['create_label'] = esc_html__('Create Contact', 'event_espresso');
2549
-        $this->_template_args['att_check']    = $att_check;
2550
-        $template_path                        =
2551
-            REG_TEMPLATE_PATH . 'reg_admin_details_side_meta_box_registrant.template.php';
2552
-        EEH_Template::display_template($template_path, $this->_template_args);
2553
-    }
2554
-
2555
-
2556
-    /**
2557
-     * trash or restore registrations
2558
-     *
2559
-     * @param boolean $trash whether to archive or restore
2560
-     * @return void
2561
-     * @throws DomainException
2562
-     * @throws EE_Error
2563
-     * @throws EntityNotFoundException
2564
-     * @throws InvalidArgumentException
2565
-     * @throws InvalidDataTypeException
2566
-     * @throws InvalidInterfaceException
2567
-     * @throws ReflectionException
2568
-     * @throws RuntimeException
2569
-     * @throws UnexpectedEntityException
2570
-     */
2571
-    protected function _trash_or_restore_registrations($trash = true)
2572
-    {
2573
-        // if empty _REG_ID then get out because there's nothing to do
2574
-        $REG_IDs = $this->request->getRequestParam('_REG_ID', [], 'int', true);
2575
-        if (empty($REG_IDs)) {
2576
-            EE_Error::add_error(
2577
-                sprintf(
2578
-                    esc_html__(
2579
-                        'In order to %1$s registrations you must select which ones you wish to %1$s by clicking the checkboxes.',
2580
-                        'event_espresso'
2581
-                    ),
2582
-                    $trash ? 'trash' : 'restore'
2583
-                ),
2584
-                __FILE__,
2585
-                __LINE__,
2586
-                __FUNCTION__
2587
-            );
2588
-            $this->_redirect_after_action(false, '', '', [], true);
2589
-        }
2590
-        $success        = 0;
2591
-        $overwrite_msgs = false;
2592
-        // Checkboxes
2593
-        $reg_count = count($REG_IDs);
2594
-        // cycle thru checkboxes
2595
-        foreach ($REG_IDs as $REG_ID) {
2596
-            /** @var EE_Registration $REG */
2597
-            $REG      = $this->getRegistrationModel()->get_one_by_ID($REG_ID);
2598
-            $payments = $REG->registration_payments();
2599
-            if (! empty($payments)) {
2600
-                $name           = $REG->attendee() instanceof EE_Attendee
2601
-                    ? $REG->attendee()->full_name()
2602
-                    : esc_html__('Unknown Attendee', 'event_espresso');
2603
-                $overwrite_msgs = true;
2604
-                EE_Error::add_error(
2605
-                    sprintf(
2606
-                        esc_html__(
2607
-                            '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.',
2608
-                            'event_espresso'
2609
-                        ),
2610
-                        $name
2611
-                    ),
2612
-                    __FILE__,
2613
-                    __FUNCTION__,
2614
-                    __LINE__
2615
-                );
2616
-                // can't trash this registration because it has payments.
2617
-                continue;
2618
-            }
2619
-            $updated = $trash ? $REG->delete() : $REG->restore();
2620
-            if ($updated) {
2621
-                $success++;
2622
-            }
2623
-        }
2624
-        $this->_redirect_after_action(
2625
-            $success === $reg_count, // were ALL registrations affected?
2626
-            $success > 1
2627
-                ? esc_html__('Registrations', 'event_espresso')
2628
-                : esc_html__('Registration', 'event_espresso'),
2629
-            $trash
2630
-                ? esc_html__('moved to the trash', 'event_espresso')
2631
-                : esc_html__('restored', 'event_espresso'),
2632
-            $this->mergeExistingRequestParamsWithRedirectArgs(['action' => 'default']),
2633
-            $overwrite_msgs
2634
-        );
2635
-    }
2636
-
2637
-
2638
-    /**
2639
-     * This is used to permanently delete registrations.  Note, this will handle not only deleting permanently the
2640
-     * registration but also.
2641
-     * 1. Removing relations to EE_Attendee
2642
-     * 2. Deleting permanently the related transaction, but ONLY if all related registrations to the transaction are
2643
-     * ALSO trashed.
2644
-     * 3. Deleting permanently any related Line items but only if the above conditions are met.
2645
-     * 4. Removing relationships between all tickets and the related registrations
2646
-     * 5. Deleting permanently any related Answers (and the answers for other related registrations that were deleted.)
2647
-     * 6. Deleting permanently any related Checkins.
2648
-     *
2649
-     * @return void
2650
-     * @throws EE_Error
2651
-     * @throws InvalidArgumentException
2652
-     * @throws InvalidDataTypeException
2653
-     * @throws InvalidInterfaceException
2654
-     * @throws ReflectionException
2655
-     */
2656
-    protected function _delete_registrations()
2657
-    {
2658
-        $REG_MDL = $this->getRegistrationModel();
2659
-        $success = 0;
2660
-        // Checkboxes
2661
-        $REG_IDs = $this->request->getRequestParam('_REG_ID', [], 'int', true);
2662
-
2663
-        if (! empty($REG_IDs)) {
2664
-            // if array has more than one element than success message should be plural
2665
-            $success = count($REG_IDs) > 1 ? 2 : 1;
2666
-            // cycle thru checkboxes
2667
-            foreach ($REG_IDs as $REG_ID) {
2668
-                $REG = $REG_MDL->get_one_by_ID($REG_ID);
2669
-                if (! $REG instanceof EE_Registration) {
2670
-                    continue;
2671
-                }
2672
-                $deleted = $this->_delete_registration($REG);
2673
-                if (! $deleted) {
2674
-                    $success = 0;
2675
-                }
2676
-            }
2677
-        }
2678
-
2679
-        $what        = $success > 1
2680
-            ? esc_html__('Registrations', 'event_espresso')
2681
-            : esc_html__('Registration', 'event_espresso');
2682
-        $action_desc = esc_html__('permanently deleted.', 'event_espresso');
2683
-        $this->_redirect_after_action(
2684
-            $success,
2685
-            $what,
2686
-            $action_desc,
2687
-            $this->mergeExistingRequestParamsWithRedirectArgs(['action' => 'default']),
2688
-            true
2689
-        );
2690
-    }
2691
-
2692
-
2693
-    /**
2694
-     * handles the permanent deletion of a registration.  See comments with _delete_registrations() for details on what
2695
-     * models get affected.
2696
-     *
2697
-     * @param EE_Registration $REG registration to be deleted permanently
2698
-     * @return bool true = successful deletion, false = fail.
2699
-     * @throws EE_Error
2700
-     * @throws InvalidArgumentException
2701
-     * @throws InvalidDataTypeException
2702
-     * @throws InvalidInterfaceException
2703
-     * @throws ReflectionException
2704
-     */
2705
-    protected function _delete_registration(EE_Registration $REG)
2706
-    {
2707
-        // first we start with the transaction... ultimately, we WILL not delete permanently if there are any related
2708
-        // registrations on the transaction that are NOT trashed.
2709
-        $TXN = $REG->get_first_related('Transaction');
2710
-        if (! $TXN instanceof EE_Transaction) {
2711
-            EE_Error::add_error(
2712
-                sprintf(
2713
-                    esc_html__(
2714
-                        'Unable to permanently delete registration %d because its related transaction has already been deleted. If you can restore the related transaction to the database then this registration can be deleted.',
2715
-                        'event_espresso'
2716
-                    ),
2717
-                    $REG->id()
2718
-                ),
2719
-                __FILE__,
2720
-                __FUNCTION__,
2721
-                __LINE__
2722
-            );
2723
-            return false;
2724
-        }
2725
-        $REGS        = $TXN->get_many_related('Registration');
2726
-        $all_trashed = true;
2727
-        foreach ($REGS as $registration) {
2728
-            if (! $registration->get('REG_deleted')) {
2729
-                $all_trashed = false;
2730
-            }
2731
-        }
2732
-        if (! $all_trashed) {
2733
-            EE_Error::add_error(
2734
-                esc_html__(
2735
-                    '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.',
2736
-                    'event_espresso'
2737
-                ),
2738
-                __FILE__,
2739
-                __FUNCTION__,
2740
-                __LINE__
2741
-            );
2742
-            return false;
2743
-        }
2744
-        // k made it here so that means we can delete all the related transactions and their answers (but let's do them
2745
-        // separately from THIS one).
2746
-        foreach ($REGS as $registration) {
2747
-            // delete related answers
2748
-            $registration->delete_related_permanently('Answer');
2749
-            // remove relationship to EE_Attendee (but we ALWAYS leave the contact record intact)
2750
-            $attendee = $registration->get_first_related('Attendee');
2751
-            if ($attendee instanceof EE_Attendee) {
2752
-                $registration->_remove_relation_to($attendee, 'Attendee');
2753
-            }
2754
-            // now remove relationships to tickets on this registration.
2755
-            $registration->_remove_relations('Ticket');
2756
-            // now delete permanently the checkins related to this registration.
2757
-            $registration->delete_related_permanently('Checkin');
2758
-            if ($registration->ID() === $REG->ID()) {
2759
-                continue;
2760
-            } //we don't want to delete permanently the existing registration just yet.
2761
-            // remove relation to transaction for these registrations if NOT the existing registrations
2762
-            $registration->_remove_relations('Transaction');
2763
-            // delete permanently any related messages.
2764
-            $registration->delete_related_permanently('Message');
2765
-            // now delete this registration permanently
2766
-            $registration->delete_permanently();
2767
-        }
2768
-        // now all related registrations on the transaction are handled.  So let's just handle this registration itself
2769
-        // (the transaction and line items should be all that's left).
2770
-        // delete the line items related to the transaction for this registration.
2771
-        $TXN->delete_related_permanently('Line_Item');
2772
-        // we need to remove all the relationships on the transaction
2773
-        $TXN->delete_related_permanently('Payment');
2774
-        $TXN->delete_related_permanently('Extra_Meta');
2775
-        $TXN->delete_related_permanently('Message');
2776
-        // now we can delete this REG permanently (and the transaction of course)
2777
-        $REG->delete_related_permanently('Transaction');
2778
-        return $REG->delete_permanently();
2779
-    }
2780
-
2781
-
2782
-    /**
2783
-     *    generates HTML for the Register New Attendee Admin page
2784
-     *
2785
-     * @throws DomainException
2786
-     * @throws EE_Error
2787
-     * @throws InvalidArgumentException
2788
-     * @throws InvalidDataTypeException
2789
-     * @throws InvalidInterfaceException
2790
-     * @throws ReflectionException
2791
-     */
2792
-    public function new_registration()
2793
-    {
2794
-        if (! $this->_set_reg_event()) {
2795
-            throw new EE_Error(
2796
-                esc_html__(
2797
-                    'Unable to continue with registering because there is no Event ID in the request',
2798
-                    'event_espresso'
2799
-                )
2800
-            );
2801
-        }
2802
-        /** @var CurrentPage $current_page */
2803
-        $current_page = $this->loader->getShared(CurrentPage::class);
2804
-        $current_page->setEspressoPage(true);
2805
-        // gotta start with a clean slate if we're not coming here via ajax
2806
-        if (
2807
-            ! $this->request->isAjax()
2808
-            && (
2809
-                ! $this->request->requestParamIsSet('processing_registration')
2810
-                || $this->request->requestParamIsSet('step_error')
2811
-            )
2812
-        ) {
2813
-            EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
2814
-        }
2815
-        $this->_template_args['event_name'] = '';
2816
-        // event name
2817
-        if ($this->_reg_event) {
2818
-            $this->_template_args['event_name'] = $this->_reg_event->name();
2819
-            $edit_event_url                     = self::add_query_args_and_nonce(
2820
-                [
2821
-                    'action' => 'edit',
2822
-                    'post'   => $this->_reg_event->ID(),
2823
-                ],
2824
-                EVENTS_ADMIN_URL
2825
-            );
2826
-            $edit_event_lnk                     = '<a href="'
2827
-                                                  . $edit_event_url
2828
-                                                  . '" title="'
2829
-                                                  . esc_attr__('Edit ', 'event_espresso')
2830
-                                                  . $this->_reg_event->name()
2831
-                                                  . '">'
2832
-                                                  . esc_html__('Edit Event', 'event_espresso')
2833
-                                                  . '</a>';
2834
-            $this->_template_args['event_name'] .= ' <span class="admin-page-header-edit-lnk not-bold">'
2835
-                                                   . $edit_event_lnk
2836
-                                                   . '</span>';
2837
-        }
2838
-        $this->_template_args['step_content'] = $this->_get_registration_step_content();
2839
-        if ($this->request->isAjax()) {
2840
-            $this->_return_json();
2841
-        }
2842
-        // grab header
2843
-        $template_path                              =
2844
-            REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee.template.php';
2845
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
2846
-            $template_path,
2847
-            $this->_template_args,
2848
-            true
2849
-        );
2850
-        // $this->_set_publish_post_box_vars( NULL, FALSE, FALSE, NULL, FALSE );
2851
-        // the details template wrapper
2852
-        $this->display_admin_page_with_sidebar();
2853
-    }
2854
-
2855
-
2856
-    /**
2857
-     * This returns the content for a registration step
2858
-     *
2859
-     * @return string html
2860
-     * @throws DomainException
2861
-     * @throws EE_Error
2862
-     * @throws InvalidArgumentException
2863
-     * @throws InvalidDataTypeException
2864
-     * @throws InvalidInterfaceException
2865
-     * @throws ReflectionException
2866
-     */
2867
-    protected function _get_registration_step_content()
2868
-    {
2869
-        if (isset($_COOKIE['ee_registration_added']) && $_COOKIE['ee_registration_added']) {
2870
-            $warning_msg = sprintf(
2871
-                esc_html__(
2872
-                    '%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',
2873
-                    'event_espresso'
2874
-                ),
2875
-                '<br />',
2876
-                '<h3 class="important-notice">',
2877
-                '</h3>',
2878
-                '<div class="float-right">',
2879
-                '<span id="redirect_timer" class="important-notice">30</span>',
2880
-                '</div>',
2881
-                '<b>',
2882
-                '</b>'
2883
-            );
2884
-            return '
2300
+	}
2301
+
2302
+
2303
+	/**
2304
+	 * Updates the registration's custom questions according to the form info, if the form is submitted.
2305
+	 * If it's not a post, the "view_registrations" route will be called next on the SAME request
2306
+	 * to display the page
2307
+	 *
2308
+	 * @return void
2309
+	 * @throws EE_Error
2310
+	 * @throws InvalidArgumentException
2311
+	 * @throws InvalidDataTypeException
2312
+	 * @throws InvalidInterfaceException
2313
+	 * @throws ReflectionException
2314
+	 */
2315
+	protected function _update_attendee_registration_form()
2316
+	{
2317
+		do_action('AHEE__Registrations_Admin_Page___update_attendee_registration_form__start', $this);
2318
+		if ($_SERVER['REQUEST_METHOD'] === 'POST') {
2319
+			$REG_ID  = $this->request->getRequestParam('_REG_ID', 0, 'int');
2320
+			$success = $this->_save_reg_custom_questions_form($REG_ID);
2321
+			if ($success) {
2322
+				$what  = esc_html__('Registration Form', 'event_espresso');
2323
+				$route = $REG_ID
2324
+					? ['action' => 'view_registration', '_REG_ID' => $REG_ID]
2325
+					: ['action' => 'default'];
2326
+				$this->_redirect_after_action(true, $what, esc_html__('updated', 'event_espresso'), $route);
2327
+			}
2328
+		}
2329
+	}
2330
+
2331
+
2332
+	/**
2333
+	 * Gets the form for saving registrations custom questions (if done
2334
+	 * previously retrieves the cached form object, which may have validation errors in it)
2335
+	 *
2336
+	 * @param int $REG_ID
2337
+	 * @return EE_Registration_Custom_Questions_Form
2338
+	 * @throws EE_Error
2339
+	 * @throws InvalidArgumentException
2340
+	 * @throws InvalidDataTypeException
2341
+	 * @throws InvalidInterfaceException
2342
+	 * @throws ReflectionException
2343
+	 */
2344
+	protected function _get_reg_custom_questions_form($REG_ID)
2345
+	{
2346
+		if (! $this->_reg_custom_questions_form) {
2347
+			require_once(REG_ADMIN . 'form_sections/EE_Registration_Custom_Questions_Form.form.php');
2348
+			$this->_reg_custom_questions_form = new EE_Registration_Custom_Questions_Form(
2349
+				$this->getRegistrationModel()->get_one_by_ID($REG_ID)
2350
+			);
2351
+			$this->_reg_custom_questions_form->_construct_finalize(null, null);
2352
+		}
2353
+		return $this->_reg_custom_questions_form;
2354
+	}
2355
+
2356
+
2357
+	/**
2358
+	 * Saves
2359
+	 *
2360
+	 * @param bool $REG_ID
2361
+	 * @return bool
2362
+	 * @throws EE_Error
2363
+	 * @throws InvalidArgumentException
2364
+	 * @throws InvalidDataTypeException
2365
+	 * @throws InvalidInterfaceException
2366
+	 * @throws ReflectionException
2367
+	 */
2368
+	private function _save_reg_custom_questions_form($REG_ID = 0)
2369
+	{
2370
+		if (! $REG_ID) {
2371
+			EE_Error::add_error(
2372
+				esc_html__(
2373
+					'An error occurred. No registration ID was received.',
2374
+					'event_espresso'
2375
+				),
2376
+				__FILE__,
2377
+				__FUNCTION__,
2378
+				__LINE__
2379
+			);
2380
+		}
2381
+		$form = $this->_get_reg_custom_questions_form($REG_ID);
2382
+		$form->receive_form_submission($this->request->requestParams());
2383
+		$success = false;
2384
+		if ($form->is_valid()) {
2385
+			foreach ($form->subforms() as $question_group_form) {
2386
+				foreach ($question_group_form->inputs() as $question_id => $input) {
2387
+					$where_conditions    = [
2388
+						'QST_ID' => $question_id,
2389
+						'REG_ID' => $REG_ID,
2390
+					];
2391
+					$possibly_new_values = [
2392
+						'ANS_value' => $input->normalized_value(),
2393
+					];
2394
+					$answer              = EEM_Answer::instance()->get_one([$where_conditions]);
2395
+					if ($answer instanceof EE_Answer) {
2396
+						$success = $answer->save($possibly_new_values);
2397
+					} else {
2398
+						// insert it then
2399
+						$cols_n_vals = array_merge($where_conditions, $possibly_new_values);
2400
+						$answer      = EE_Answer::new_instance($cols_n_vals);
2401
+						$success     = $answer->save();
2402
+					}
2403
+				}
2404
+			}
2405
+		} else {
2406
+			EE_Error::add_error($form->get_validation_error_string(), __FILE__, __FUNCTION__, __LINE__);
2407
+		}
2408
+		return $success;
2409
+	}
2410
+
2411
+
2412
+	/**
2413
+	 * generates HTML for the Registration main meta box
2414
+	 *
2415
+	 * @return void
2416
+	 * @throws DomainException
2417
+	 * @throws EE_Error
2418
+	 * @throws InvalidArgumentException
2419
+	 * @throws InvalidDataTypeException
2420
+	 * @throws InvalidInterfaceException
2421
+	 * @throws ReflectionException
2422
+	 */
2423
+	public function _reg_attendees_meta_box()
2424
+	{
2425
+		$REG = $this->getRegistrationModel();
2426
+		// get all other registrations on this transaction, and cache
2427
+		// the attendees for them so we don't have to run another query using force_join
2428
+		$registrations                           = $REG->get_all(
2429
+			[
2430
+				[
2431
+					'TXN_ID' => $this->_registration->transaction_ID(),
2432
+					'REG_ID' => ['!=', $this->_registration->ID()],
2433
+				],
2434
+				'force_join'               => ['Attendee'],
2435
+				'default_where_conditions' => 'other_models_only',
2436
+			]
2437
+		);
2438
+		$this->_template_args['attendees']       = [];
2439
+		$this->_template_args['attendee_notice'] = '';
2440
+		if (
2441
+			empty($registrations)
2442
+			|| (is_array($registrations)
2443
+				&& ! EEH_Array::get_one_item_from_array($registrations))
2444
+		) {
2445
+			EE_Error::add_error(
2446
+				esc_html__(
2447
+					'There are no records attached to this registration. Something may have gone wrong with the registration',
2448
+					'event_espresso'
2449
+				),
2450
+				__FILE__,
2451
+				__FUNCTION__,
2452
+				__LINE__
2453
+			);
2454
+			$this->_template_args['attendee_notice'] = EE_Error::get_notices();
2455
+		} else {
2456
+			$att_nmbr = 1;
2457
+			foreach ($registrations as $registration) {
2458
+				/* @var $registration EE_Registration */
2459
+				$attendee                                                      = $registration->attendee()
2460
+					? $registration->attendee()
2461
+					: $this->getAttendeeModel()->create_default_object();
2462
+				$this->_template_args['attendees'][ $att_nmbr ]['STS_ID']      = $registration->status_ID();
2463
+				$this->_template_args['attendees'][ $att_nmbr ]['fname']       = $attendee->fname();
2464
+				$this->_template_args['attendees'][ $att_nmbr ]['lname']       = $attendee->lname();
2465
+				$this->_template_args['attendees'][ $att_nmbr ]['email']       = $attendee->email();
2466
+				$this->_template_args['attendees'][ $att_nmbr ]['final_price'] = $registration->final_price();
2467
+				$this->_template_args['attendees'][ $att_nmbr ]['address']     = implode(
2468
+					', ',
2469
+					$attendee->full_address_as_array()
2470
+				);
2471
+				$this->_template_args['attendees'][ $att_nmbr ]['att_link']    = self::add_query_args_and_nonce(
2472
+					[
2473
+						'action' => 'edit_attendee',
2474
+						'post'   => $attendee->ID(),
2475
+					],
2476
+					REG_ADMIN_URL
2477
+				);
2478
+				$this->_template_args['attendees'][ $att_nmbr ]['event_name']  =
2479
+					$registration->event_obj() instanceof EE_Event
2480
+						? $registration->event_obj()->name()
2481
+						: '';
2482
+				$att_nmbr++;
2483
+			}
2484
+			$this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
2485
+		}
2486
+		$template_path = REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_attendees.template.php';
2487
+		EEH_Template::display_template($template_path, $this->_template_args);
2488
+	}
2489
+
2490
+
2491
+	/**
2492
+	 * generates HTML for the Edit Registration side meta box
2493
+	 *
2494
+	 * @return void
2495
+	 * @throws DomainException
2496
+	 * @throws EE_Error
2497
+	 * @throws InvalidArgumentException
2498
+	 * @throws InvalidDataTypeException
2499
+	 * @throws InvalidInterfaceException
2500
+	 * @throws ReflectionException
2501
+	 */
2502
+	public function _reg_registrant_side_meta_box()
2503
+	{
2504
+		/*@var $attendee EE_Attendee */
2505
+		$att_check = $this->_registration->attendee();
2506
+		$attendee  = $att_check instanceof EE_Attendee
2507
+			? $att_check
2508
+			: $this->getAttendeeModel()->create_default_object();
2509
+		// now let's determine if this is not the primary registration.  If it isn't then we set the
2510
+		// primary_registration object for reference BUT ONLY if the Attendee object loaded is not the same as the
2511
+		// primary registration object (that way we know if we need to show create button or not)
2512
+		if (! $this->_registration->is_primary_registrant()) {
2513
+			$primary_registration = $this->_registration->get_primary_registration();
2514
+			$primary_attendee     = $primary_registration instanceof EE_Registration ? $primary_registration->attendee()
2515
+				: null;
2516
+			if (! $primary_attendee instanceof EE_Attendee || $attendee->ID() !== $primary_attendee->ID()) {
2517
+				// in here?  This means the displayed registration is not the primary registrant but ALREADY HAS its own
2518
+				// custom attendee object so let's not worry about the primary reg.
2519
+				$primary_registration = null;
2520
+			}
2521
+		} else {
2522
+			$primary_registration = null;
2523
+		}
2524
+		$this->_template_args['ATT_ID']            = $attendee->ID();
2525
+		$this->_template_args['fname']             = $attendee->fname();
2526
+		$this->_template_args['lname']             = $attendee->lname();
2527
+		$this->_template_args['email']             = $attendee->email();
2528
+		$this->_template_args['phone']             = $attendee->phone();
2529
+		$this->_template_args['formatted_address'] = EEH_Address::format($attendee);
2530
+		// edit link
2531
+		$this->_template_args['att_edit_link']  = EE_Admin_Page::add_query_args_and_nonce(
2532
+			[
2533
+				'action' => 'edit_attendee',
2534
+				'post'   => $attendee->ID(),
2535
+			],
2536
+			REG_ADMIN_URL
2537
+		);
2538
+		$this->_template_args['att_edit_label'] = esc_html__('View/Edit Contact', 'event_espresso');
2539
+		// create link
2540
+		$this->_template_args['create_link']  = $primary_registration instanceof EE_Registration
2541
+			? EE_Admin_Page::add_query_args_and_nonce(
2542
+				[
2543
+					'action'  => 'duplicate_attendee',
2544
+					'_REG_ID' => $this->_registration->ID(),
2545
+				],
2546
+				REG_ADMIN_URL
2547
+			) : '';
2548
+		$this->_template_args['create_label'] = esc_html__('Create Contact', 'event_espresso');
2549
+		$this->_template_args['att_check']    = $att_check;
2550
+		$template_path                        =
2551
+			REG_TEMPLATE_PATH . 'reg_admin_details_side_meta_box_registrant.template.php';
2552
+		EEH_Template::display_template($template_path, $this->_template_args);
2553
+	}
2554
+
2555
+
2556
+	/**
2557
+	 * trash or restore registrations
2558
+	 *
2559
+	 * @param boolean $trash whether to archive or restore
2560
+	 * @return void
2561
+	 * @throws DomainException
2562
+	 * @throws EE_Error
2563
+	 * @throws EntityNotFoundException
2564
+	 * @throws InvalidArgumentException
2565
+	 * @throws InvalidDataTypeException
2566
+	 * @throws InvalidInterfaceException
2567
+	 * @throws ReflectionException
2568
+	 * @throws RuntimeException
2569
+	 * @throws UnexpectedEntityException
2570
+	 */
2571
+	protected function _trash_or_restore_registrations($trash = true)
2572
+	{
2573
+		// if empty _REG_ID then get out because there's nothing to do
2574
+		$REG_IDs = $this->request->getRequestParam('_REG_ID', [], 'int', true);
2575
+		if (empty($REG_IDs)) {
2576
+			EE_Error::add_error(
2577
+				sprintf(
2578
+					esc_html__(
2579
+						'In order to %1$s registrations you must select which ones you wish to %1$s by clicking the checkboxes.',
2580
+						'event_espresso'
2581
+					),
2582
+					$trash ? 'trash' : 'restore'
2583
+				),
2584
+				__FILE__,
2585
+				__LINE__,
2586
+				__FUNCTION__
2587
+			);
2588
+			$this->_redirect_after_action(false, '', '', [], true);
2589
+		}
2590
+		$success        = 0;
2591
+		$overwrite_msgs = false;
2592
+		// Checkboxes
2593
+		$reg_count = count($REG_IDs);
2594
+		// cycle thru checkboxes
2595
+		foreach ($REG_IDs as $REG_ID) {
2596
+			/** @var EE_Registration $REG */
2597
+			$REG      = $this->getRegistrationModel()->get_one_by_ID($REG_ID);
2598
+			$payments = $REG->registration_payments();
2599
+			if (! empty($payments)) {
2600
+				$name           = $REG->attendee() instanceof EE_Attendee
2601
+					? $REG->attendee()->full_name()
2602
+					: esc_html__('Unknown Attendee', 'event_espresso');
2603
+				$overwrite_msgs = true;
2604
+				EE_Error::add_error(
2605
+					sprintf(
2606
+						esc_html__(
2607
+							'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.',
2608
+							'event_espresso'
2609
+						),
2610
+						$name
2611
+					),
2612
+					__FILE__,
2613
+					__FUNCTION__,
2614
+					__LINE__
2615
+				);
2616
+				// can't trash this registration because it has payments.
2617
+				continue;
2618
+			}
2619
+			$updated = $trash ? $REG->delete() : $REG->restore();
2620
+			if ($updated) {
2621
+				$success++;
2622
+			}
2623
+		}
2624
+		$this->_redirect_after_action(
2625
+			$success === $reg_count, // were ALL registrations affected?
2626
+			$success > 1
2627
+				? esc_html__('Registrations', 'event_espresso')
2628
+				: esc_html__('Registration', 'event_espresso'),
2629
+			$trash
2630
+				? esc_html__('moved to the trash', 'event_espresso')
2631
+				: esc_html__('restored', 'event_espresso'),
2632
+			$this->mergeExistingRequestParamsWithRedirectArgs(['action' => 'default']),
2633
+			$overwrite_msgs
2634
+		);
2635
+	}
2636
+
2637
+
2638
+	/**
2639
+	 * This is used to permanently delete registrations.  Note, this will handle not only deleting permanently the
2640
+	 * registration but also.
2641
+	 * 1. Removing relations to EE_Attendee
2642
+	 * 2. Deleting permanently the related transaction, but ONLY if all related registrations to the transaction are
2643
+	 * ALSO trashed.
2644
+	 * 3. Deleting permanently any related Line items but only if the above conditions are met.
2645
+	 * 4. Removing relationships between all tickets and the related registrations
2646
+	 * 5. Deleting permanently any related Answers (and the answers for other related registrations that were deleted.)
2647
+	 * 6. Deleting permanently any related Checkins.
2648
+	 *
2649
+	 * @return void
2650
+	 * @throws EE_Error
2651
+	 * @throws InvalidArgumentException
2652
+	 * @throws InvalidDataTypeException
2653
+	 * @throws InvalidInterfaceException
2654
+	 * @throws ReflectionException
2655
+	 */
2656
+	protected function _delete_registrations()
2657
+	{
2658
+		$REG_MDL = $this->getRegistrationModel();
2659
+		$success = 0;
2660
+		// Checkboxes
2661
+		$REG_IDs = $this->request->getRequestParam('_REG_ID', [], 'int', true);
2662
+
2663
+		if (! empty($REG_IDs)) {
2664
+			// if array has more than one element than success message should be plural
2665
+			$success = count($REG_IDs) > 1 ? 2 : 1;
2666
+			// cycle thru checkboxes
2667
+			foreach ($REG_IDs as $REG_ID) {
2668
+				$REG = $REG_MDL->get_one_by_ID($REG_ID);
2669
+				if (! $REG instanceof EE_Registration) {
2670
+					continue;
2671
+				}
2672
+				$deleted = $this->_delete_registration($REG);
2673
+				if (! $deleted) {
2674
+					$success = 0;
2675
+				}
2676
+			}
2677
+		}
2678
+
2679
+		$what        = $success > 1
2680
+			? esc_html__('Registrations', 'event_espresso')
2681
+			: esc_html__('Registration', 'event_espresso');
2682
+		$action_desc = esc_html__('permanently deleted.', 'event_espresso');
2683
+		$this->_redirect_after_action(
2684
+			$success,
2685
+			$what,
2686
+			$action_desc,
2687
+			$this->mergeExistingRequestParamsWithRedirectArgs(['action' => 'default']),
2688
+			true
2689
+		);
2690
+	}
2691
+
2692
+
2693
+	/**
2694
+	 * handles the permanent deletion of a registration.  See comments with _delete_registrations() for details on what
2695
+	 * models get affected.
2696
+	 *
2697
+	 * @param EE_Registration $REG registration to be deleted permanently
2698
+	 * @return bool true = successful deletion, false = fail.
2699
+	 * @throws EE_Error
2700
+	 * @throws InvalidArgumentException
2701
+	 * @throws InvalidDataTypeException
2702
+	 * @throws InvalidInterfaceException
2703
+	 * @throws ReflectionException
2704
+	 */
2705
+	protected function _delete_registration(EE_Registration $REG)
2706
+	{
2707
+		// first we start with the transaction... ultimately, we WILL not delete permanently if there are any related
2708
+		// registrations on the transaction that are NOT trashed.
2709
+		$TXN = $REG->get_first_related('Transaction');
2710
+		if (! $TXN instanceof EE_Transaction) {
2711
+			EE_Error::add_error(
2712
+				sprintf(
2713
+					esc_html__(
2714
+						'Unable to permanently delete registration %d because its related transaction has already been deleted. If you can restore the related transaction to the database then this registration can be deleted.',
2715
+						'event_espresso'
2716
+					),
2717
+					$REG->id()
2718
+				),
2719
+				__FILE__,
2720
+				__FUNCTION__,
2721
+				__LINE__
2722
+			);
2723
+			return false;
2724
+		}
2725
+		$REGS        = $TXN->get_many_related('Registration');
2726
+		$all_trashed = true;
2727
+		foreach ($REGS as $registration) {
2728
+			if (! $registration->get('REG_deleted')) {
2729
+				$all_trashed = false;
2730
+			}
2731
+		}
2732
+		if (! $all_trashed) {
2733
+			EE_Error::add_error(
2734
+				esc_html__(
2735
+					'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.',
2736
+					'event_espresso'
2737
+				),
2738
+				__FILE__,
2739
+				__FUNCTION__,
2740
+				__LINE__
2741
+			);
2742
+			return false;
2743
+		}
2744
+		// k made it here so that means we can delete all the related transactions and their answers (but let's do them
2745
+		// separately from THIS one).
2746
+		foreach ($REGS as $registration) {
2747
+			// delete related answers
2748
+			$registration->delete_related_permanently('Answer');
2749
+			// remove relationship to EE_Attendee (but we ALWAYS leave the contact record intact)
2750
+			$attendee = $registration->get_first_related('Attendee');
2751
+			if ($attendee instanceof EE_Attendee) {
2752
+				$registration->_remove_relation_to($attendee, 'Attendee');
2753
+			}
2754
+			// now remove relationships to tickets on this registration.
2755
+			$registration->_remove_relations('Ticket');
2756
+			// now delete permanently the checkins related to this registration.
2757
+			$registration->delete_related_permanently('Checkin');
2758
+			if ($registration->ID() === $REG->ID()) {
2759
+				continue;
2760
+			} //we don't want to delete permanently the existing registration just yet.
2761
+			// remove relation to transaction for these registrations if NOT the existing registrations
2762
+			$registration->_remove_relations('Transaction');
2763
+			// delete permanently any related messages.
2764
+			$registration->delete_related_permanently('Message');
2765
+			// now delete this registration permanently
2766
+			$registration->delete_permanently();
2767
+		}
2768
+		// now all related registrations on the transaction are handled.  So let's just handle this registration itself
2769
+		// (the transaction and line items should be all that's left).
2770
+		// delete the line items related to the transaction for this registration.
2771
+		$TXN->delete_related_permanently('Line_Item');
2772
+		// we need to remove all the relationships on the transaction
2773
+		$TXN->delete_related_permanently('Payment');
2774
+		$TXN->delete_related_permanently('Extra_Meta');
2775
+		$TXN->delete_related_permanently('Message');
2776
+		// now we can delete this REG permanently (and the transaction of course)
2777
+		$REG->delete_related_permanently('Transaction');
2778
+		return $REG->delete_permanently();
2779
+	}
2780
+
2781
+
2782
+	/**
2783
+	 *    generates HTML for the Register New Attendee Admin page
2784
+	 *
2785
+	 * @throws DomainException
2786
+	 * @throws EE_Error
2787
+	 * @throws InvalidArgumentException
2788
+	 * @throws InvalidDataTypeException
2789
+	 * @throws InvalidInterfaceException
2790
+	 * @throws ReflectionException
2791
+	 */
2792
+	public function new_registration()
2793
+	{
2794
+		if (! $this->_set_reg_event()) {
2795
+			throw new EE_Error(
2796
+				esc_html__(
2797
+					'Unable to continue with registering because there is no Event ID in the request',
2798
+					'event_espresso'
2799
+				)
2800
+			);
2801
+		}
2802
+		/** @var CurrentPage $current_page */
2803
+		$current_page = $this->loader->getShared(CurrentPage::class);
2804
+		$current_page->setEspressoPage(true);
2805
+		// gotta start with a clean slate if we're not coming here via ajax
2806
+		if (
2807
+			! $this->request->isAjax()
2808
+			&& (
2809
+				! $this->request->requestParamIsSet('processing_registration')
2810
+				|| $this->request->requestParamIsSet('step_error')
2811
+			)
2812
+		) {
2813
+			EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
2814
+		}
2815
+		$this->_template_args['event_name'] = '';
2816
+		// event name
2817
+		if ($this->_reg_event) {
2818
+			$this->_template_args['event_name'] = $this->_reg_event->name();
2819
+			$edit_event_url                     = self::add_query_args_and_nonce(
2820
+				[
2821
+					'action' => 'edit',
2822
+					'post'   => $this->_reg_event->ID(),
2823
+				],
2824
+				EVENTS_ADMIN_URL
2825
+			);
2826
+			$edit_event_lnk                     = '<a href="'
2827
+												  . $edit_event_url
2828
+												  . '" title="'
2829
+												  . esc_attr__('Edit ', 'event_espresso')
2830
+												  . $this->_reg_event->name()
2831
+												  . '">'
2832
+												  . esc_html__('Edit Event', 'event_espresso')
2833
+												  . '</a>';
2834
+			$this->_template_args['event_name'] .= ' <span class="admin-page-header-edit-lnk not-bold">'
2835
+												   . $edit_event_lnk
2836
+												   . '</span>';
2837
+		}
2838
+		$this->_template_args['step_content'] = $this->_get_registration_step_content();
2839
+		if ($this->request->isAjax()) {
2840
+			$this->_return_json();
2841
+		}
2842
+		// grab header
2843
+		$template_path                              =
2844
+			REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee.template.php';
2845
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
2846
+			$template_path,
2847
+			$this->_template_args,
2848
+			true
2849
+		);
2850
+		// $this->_set_publish_post_box_vars( NULL, FALSE, FALSE, NULL, FALSE );
2851
+		// the details template wrapper
2852
+		$this->display_admin_page_with_sidebar();
2853
+	}
2854
+
2855
+
2856
+	/**
2857
+	 * This returns the content for a registration step
2858
+	 *
2859
+	 * @return string html
2860
+	 * @throws DomainException
2861
+	 * @throws EE_Error
2862
+	 * @throws InvalidArgumentException
2863
+	 * @throws InvalidDataTypeException
2864
+	 * @throws InvalidInterfaceException
2865
+	 * @throws ReflectionException
2866
+	 */
2867
+	protected function _get_registration_step_content()
2868
+	{
2869
+		if (isset($_COOKIE['ee_registration_added']) && $_COOKIE['ee_registration_added']) {
2870
+			$warning_msg = sprintf(
2871
+				esc_html__(
2872
+					'%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',
2873
+					'event_espresso'
2874
+				),
2875
+				'<br />',
2876
+				'<h3 class="important-notice">',
2877
+				'</h3>',
2878
+				'<div class="float-right">',
2879
+				'<span id="redirect_timer" class="important-notice">30</span>',
2880
+				'</div>',
2881
+				'<b>',
2882
+				'</b>'
2883
+			);
2884
+			return '
2885 2885
 	<div id="ee-add-reg-back-button-dv"><p>' . $warning_msg . '</p></div>
2886 2886
 	<script >
2887 2887
 		// WHOAH !!! it appears that someone is using the back button from the Transaction admin page
@@ -2894,846 +2894,846 @@  discard block
 block discarded – undo
2894 2894
 	        }
2895 2895
 	    }, 800 );
2896 2896
 	</script >';
2897
-        }
2898
-        $template_args = [
2899
-            'title'                    => '',
2900
-            'content'                  => '',
2901
-            'step_button_text'         => '',
2902
-            'show_notification_toggle' => false,
2903
-        ];
2904
-        // to indicate we're processing a new registration
2905
-        $hidden_fields = [
2906
-            'processing_registration' => [
2907
-                'type'  => 'hidden',
2908
-                'value' => 0,
2909
-            ],
2910
-            'event_id'                => [
2911
-                'type'  => 'hidden',
2912
-                'value' => $this->_reg_event->ID(),
2913
-            ],
2914
-        ];
2915
-        // if the cart is empty then we know we're at step one, so we'll display the ticket selector
2916
-        $cart = EE_Registry::instance()->SSN->cart();
2917
-        $step = ! $cart instanceof EE_Cart ? 'ticket' : 'questions';
2918
-        switch ($step) {
2919
-            case 'ticket':
2920
-                $hidden_fields['processing_registration']['value'] = 1;
2921
-                $template_args['title']                            = esc_html__(
2922
-                    'Step One: Select the Ticket for this registration',
2923
-                    'event_espresso'
2924
-                );
2925
-                $template_args['content']                          =
2926
-                    EED_Ticket_Selector::instance()->display_ticket_selector($this->_reg_event);
2927
-                $template_args['content']                          .= '</div>';
2928
-                $template_args['step_button_text']                 = esc_html__(
2929
-                    'Add Tickets and Continue to Registrant Details',
2930
-                    'event_espresso'
2931
-                );
2932
-                $template_args['show_notification_toggle']         = false;
2933
-                break;
2934
-            case 'questions':
2935
-                $hidden_fields['processing_registration']['value'] = 2;
2936
-                $template_args['title']                            = esc_html__(
2937
-                    'Step Two: Add Registrant Details for this Registration',
2938
-                    'event_espresso'
2939
-                );
2940
-                // in theory, we should be able to run EED_SPCO at this point
2941
-                // because the cart should have been set up properly by the first process_reg_step run.
2942
-                $template_args['content']                  =
2943
-                    EED_Single_Page_Checkout::registration_checkout_for_admin();
2944
-                $template_args['step_button_text']         = esc_html__(
2945
-                    'Save Registration and Continue to Details',
2946
-                    'event_espresso'
2947
-                );
2948
-                $template_args['show_notification_toggle'] = true;
2949
-                break;
2950
-        }
2951
-        // we come back to the process_registration_step route.
2952
-        $this->_set_add_edit_form_tags('process_reg_step', $hidden_fields);
2953
-        return EEH_Template::display_template(
2954
-            REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee_step_content.template.php',
2955
-            $template_args,
2956
-            true
2957
-        );
2958
-    }
2959
-
2960
-
2961
-    /**
2962
-     * set_reg_event
2963
-     *
2964
-     * @return bool
2965
-     * @throws EE_Error
2966
-     * @throws InvalidArgumentException
2967
-     * @throws InvalidDataTypeException
2968
-     * @throws InvalidInterfaceException
2969
-     */
2970
-    private function _set_reg_event()
2971
-    {
2972
-        if (is_object($this->_reg_event)) {
2973
-            return true;
2974
-        }
2975
-
2976
-        $EVT_ID = $this->request->getRequestParam('event_id', 0, 'int');
2977
-        if (! $EVT_ID) {
2978
-            return false;
2979
-        }
2980
-        $this->_reg_event = $this->getEventModel()->get_one_by_ID($EVT_ID);
2981
-        return true;
2982
-    }
2983
-
2984
-
2985
-    /**
2986
-     * process_reg_step
2987
-     *
2988
-     * @return void
2989
-     * @throws DomainException
2990
-     * @throws EE_Error
2991
-     * @throws InvalidArgumentException
2992
-     * @throws InvalidDataTypeException
2993
-     * @throws InvalidInterfaceException
2994
-     * @throws ReflectionException
2995
-     * @throws RuntimeException
2996
-     */
2997
-    public function process_reg_step()
2998
-    {
2999
-        EE_System::do_not_cache();
3000
-        $this->_set_reg_event();
3001
-        /** @var CurrentPage $current_page */
3002
-        $current_page = $this->loader->getShared(CurrentPage::class);
3003
-        $current_page->setEspressoPage(true);
3004
-        $this->request->setRequestParam('uts', time());
3005
-        // what step are we on?
3006
-        $cart = EE_Registry::instance()->SSN->cart();
3007
-        $step = ! $cart instanceof EE_Cart ? 'ticket' : 'questions';
3008
-        // if doing ajax then we need to verify the nonce
3009
-        if ($this->request->isAjax()) {
3010
-            $nonce = $this->request->getRequestParam($this->_req_nonce, '');
3011
-            $this->_verify_nonce($nonce, $this->_req_nonce);
3012
-        }
3013
-        switch ($step) {
3014
-            case 'ticket':
3015
-                // process ticket selection
3016
-                $success = EED_Ticket_Selector::instance()->process_ticket_selections();
3017
-                if ($success) {
3018
-                    EE_Error::add_success(
3019
-                        esc_html__(
3020
-                            'Tickets Selected. Now complete the registration.',
3021
-                            'event_espresso'
3022
-                        )
3023
-                    );
3024
-                } else {
3025
-                    $this->request->setRequestParam('step_error', true);
3026
-                    $query_args['step_error'] = $this->request->getRequestParam('step_error', true, 'bool');
3027
-                }
3028
-                if ($this->request->isAjax()) {
3029
-                    $this->new_registration(); // display next step
3030
-                } else {
3031
-                    $query_args = [
3032
-                        'action'                  => 'new_registration',
3033
-                        'processing_registration' => 1,
3034
-                        'event_id'                => $this->_reg_event->ID(),
3035
-                        'uts'                     => time(),
3036
-                    ];
3037
-                    $this->_redirect_after_action(
3038
-                        false,
3039
-                        '',
3040
-                        '',
3041
-                        $query_args,
3042
-                        true
3043
-                    );
3044
-                }
3045
-                break;
3046
-            case 'questions':
3047
-                if (! $this->request->requestParamIsSet('txn_reg_status_change[send_notifications]')) {
3048
-                    add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_false', 15);
3049
-                }
3050
-                // process registration
3051
-                $transaction = EED_Single_Page_Checkout::instance()->process_registration_from_admin();
3052
-                if ($cart instanceof EE_Cart) {
3053
-                    $grand_total = $cart->get_grand_total();
3054
-                    if ($grand_total instanceof EE_Line_Item) {
3055
-                        $grand_total->save_this_and_descendants_to_txn();
3056
-                    }
3057
-                }
3058
-                if (! $transaction instanceof EE_Transaction) {
3059
-                    $query_args = [
3060
-                        'action'                  => 'new_registration',
3061
-                        'processing_registration' => 2,
3062
-                        'event_id'                => $this->_reg_event->ID(),
3063
-                        'uts'                     => time(),
3064
-                    ];
3065
-                    if ($this->request->isAjax()) {
3066
-                        // display registration form again because there are errors (maybe validation?)
3067
-                        $this->new_registration();
3068
-                        return;
3069
-                    }
3070
-                    $this->_redirect_after_action(
3071
-                        false,
3072
-                        '',
3073
-                        '',
3074
-                        $query_args,
3075
-                        true
3076
-                    );
3077
-                    return;
3078
-                }
3079
-                // maybe update status, and make sure to save transaction if not done already
3080
-                if (! $transaction->update_status_based_on_total_paid()) {
3081
-                    $transaction->save();
3082
-                }
3083
-                EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
3084
-                $query_args = [
3085
-                    'action'        => 'redirect_to_txn',
3086
-                    'TXN_ID'        => $transaction->ID(),
3087
-                    'EVT_ID'        => $this->_reg_event->ID(),
3088
-                    'event_name'    => urlencode($this->_reg_event->name()),
3089
-                    'redirect_from' => 'new_registration',
3090
-                ];
3091
-                $this->_redirect_after_action(false, '', '', $query_args, true);
3092
-                break;
3093
-        }
3094
-        // what are you looking here for?  Should be nothing to do at this point.
3095
-    }
3096
-
3097
-
3098
-    /**
3099
-     * redirect_to_txn
3100
-     *
3101
-     * @return void
3102
-     * @throws EE_Error
3103
-     * @throws InvalidArgumentException
3104
-     * @throws InvalidDataTypeException
3105
-     * @throws InvalidInterfaceException
3106
-     * @throws ReflectionException
3107
-     */
3108
-    public function redirect_to_txn()
3109
-    {
3110
-        EE_System::do_not_cache();
3111
-        EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
3112
-        $query_args = [
3113
-            'action' => 'view_transaction',
3114
-            'TXN_ID' => $this->request->getRequestParam('TXN_ID', 0, 'int'),
3115
-            'page'   => 'espresso_transactions',
3116
-        ];
3117
-        if ($this->request->requestParamIsSet('EVT_ID') && $this->request->requestParamIsSet('redirect_from')) {
3118
-            $query_args['EVT_ID']        = $this->request->getRequestParam('EVT_ID', 0, 'int');
3119
-            $query_args['event_name']    = urlencode($this->request->getRequestParam('event_name'));
3120
-            $query_args['redirect_from'] = $this->request->getRequestParam('redirect_from');
3121
-        }
3122
-        EE_Error::add_success(
3123
-            esc_html__(
3124
-                'Registration Created.  Please review the transaction and add any payments as necessary',
3125
-                'event_espresso'
3126
-            )
3127
-        );
3128
-        $this->_redirect_after_action(false, '', '', $query_args, true);
3129
-    }
3130
-
3131
-
3132
-    /**
3133
-     * generates HTML for the Attendee Contact List
3134
-     *
3135
-     * @return void
3136
-     * @throws DomainException
3137
-     * @throws EE_Error
3138
-     */
3139
-    protected function _attendee_contact_list_table()
3140
-    {
3141
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3142
-        $this->_search_btn_label = esc_html__('Contacts', 'event_espresso');
3143
-        $this->display_admin_list_table_page_with_no_sidebar();
3144
-    }
3145
-
3146
-
3147
-    /**
3148
-     * get_attendees
3149
-     *
3150
-     * @param      $per_page
3151
-     * @param bool $count whether to return count or data.
3152
-     * @param bool $trash
3153
-     * @return array|int
3154
-     * @throws EE_Error
3155
-     * @throws InvalidArgumentException
3156
-     * @throws InvalidDataTypeException
3157
-     * @throws InvalidInterfaceException
3158
-     */
3159
-    public function get_attendees($per_page, $count = false, $trash = false)
3160
-    {
3161
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3162
-        require_once(REG_ADMIN . 'EE_Attendee_Contact_List_Table.class.php');
3163
-        $orderby = $this->request->getRequestParam('orderby');
3164
-        switch ($orderby) {
3165
-            case 'ATT_ID':
3166
-            case 'ATT_fname':
3167
-            case 'ATT_email':
3168
-            case 'ATT_city':
3169
-            case 'STA_ID':
3170
-            case 'CNT_ID':
3171
-                break;
3172
-            case 'Registration_Count':
3173
-                $orderby = 'Registration_Count';
3174
-                break;
3175
-            default:
3176
-                $orderby = 'ATT_lname';
3177
-        }
3178
-        $sort         = $this->request->getRequestParam('order', 'ASC');
3179
-        $current_page = $this->request->getRequestParam('paged', 1, 'int');
3180
-        $per_page     = absint($per_page) ? $per_page : 10;
3181
-        $per_page     = $this->request->getRequestParam('perpage', $per_page, 'int');
3182
-        $_where       = [];
3183
-        $search_term  = $this->request->getRequestParam('s');
3184
-        if ($search_term) {
3185
-            $search_term  = '%' . $search_term . '%';
3186
-            $_where['OR'] = [
3187
-                'Registration.Event.EVT_name'       => ['LIKE', $search_term],
3188
-                'Registration.Event.EVT_desc'       => ['LIKE', $search_term],
3189
-                'Registration.Event.EVT_short_desc' => ['LIKE', $search_term],
3190
-                'ATT_fname'                         => ['LIKE', $search_term],
3191
-                'ATT_lname'                         => ['LIKE', $search_term],
3192
-                'ATT_short_bio'                     => ['LIKE', $search_term],
3193
-                'ATT_email'                         => ['LIKE', $search_term],
3194
-                'ATT_address'                       => ['LIKE', $search_term],
3195
-                'ATT_address2'                      => ['LIKE', $search_term],
3196
-                'ATT_city'                          => ['LIKE', $search_term],
3197
-                'Country.CNT_name'                  => ['LIKE', $search_term],
3198
-                'State.STA_name'                    => ['LIKE', $search_term],
3199
-                'ATT_phone'                         => ['LIKE', $search_term],
3200
-                'Registration.REG_final_price'      => ['LIKE', $search_term],
3201
-                'Registration.REG_code'             => ['LIKE', $search_term],
3202
-                'Registration.REG_group_size'       => ['LIKE', $search_term],
3203
-            ];
3204
-        }
3205
-        $offset     = ($current_page - 1) * $per_page;
3206
-        $limit      = $count ? null : [$offset, $per_page];
3207
-        $query_args = [
3208
-            $_where,
3209
-            'extra_selects' => ['Registration_Count' => ['Registration.REG_ID', 'count', '%d']],
3210
-            'limit'         => $limit,
3211
-        ];
3212
-        if (! $count) {
3213
-            $query_args['order_by'] = [$orderby => $sort];
3214
-        }
3215
-        $query_args[0]['status'] = $trash ? ['!=', 'publish'] : ['IN', ['publish']];
3216
-        return $count
3217
-            ? $this->getAttendeeModel()->count($query_args, 'ATT_ID', true)
3218
-            : $this->getAttendeeModel()->get_all($query_args);
3219
-    }
3220
-
3221
-
3222
-    /**
3223
-     * This is just taking care of resending the registration confirmation
3224
-     *
3225
-     * @return void
3226
-     * @throws EE_Error
3227
-     * @throws InvalidArgumentException
3228
-     * @throws InvalidDataTypeException
3229
-     * @throws InvalidInterfaceException
3230
-     * @throws ReflectionException
3231
-     */
3232
-    protected function _resend_registration()
3233
-    {
3234
-        $this->_process_resend_registration();
3235
-        $REG_ID      = $this->request->getRequestParam('_REG_ID', 0, 'int');
3236
-        $redirect_to = $this->request->getRequestParam('redirect_to');
3237
-        $query_args  = $redirect_to
3238
-            ? ['action' => $redirect_to, '_REG_ID' => $REG_ID]
3239
-            : ['action' => 'default'];
3240
-        $this->_redirect_after_action(false, '', '', $query_args, true);
3241
-    }
3242
-
3243
-
3244
-    /**
3245
-     * Creates a registration report, but accepts the name of a method to use for preparing the query parameters
3246
-     * to use when selecting registrations
3247
-     *
3248
-     * @param string $method_name_for_getting_query_params the name of the method (on this class) to use for preparing
3249
-     *                                                     the query parameters from the request
3250
-     * @return void ends the request with a redirect or download
3251
-     */
3252
-    public function _registrations_report_base($method_name_for_getting_query_params)
3253
-    {
3254
-        $EVT_ID = $this->request->requestParamIsSet('EVT_ID')
3255
-            ? $this->request->getRequestParam('EVT_ID', 0, 'int')
3256
-            : null;
3257
-        if (! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3258
-            $filters = $this->request->getRequestParam('filters', [], DataType::STRING, true);
3259
-            $report_params  = $this->$method_name_for_getting_query_params($filters);
3260
-            wp_redirect(
3261
-                EE_Admin_Page::add_query_args_and_nonce(
3262
-                    [
3263
-                        'page'        => 'espresso_batch',
3264
-                        'batch'       => 'file',
3265
-                        'EVT_ID'      => $EVT_ID,
3266
-                        'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\RegistrationsReport'),
3267
-                        'return_url'  => urlencode($this->request->getRequestParam('return_url', '', DataType::URL)),
3268
-                        'filters'     => urlencode(serialize($report_params)),
3269
-                        'use_filters' => $this->request->getRequestParam('use_filters', false, DataType::BOOL)
3270
-                    ]
3271
-                )
3272
-            );
3273
-        } else {
3274
-            // Pull the current request params
3275
-            $request_args = $this->request->requestParams();
3276
-            // Set the required request_args to be passed to the export
3277
-            $required_request_args = [
3278
-                'export' => 'report',
3279
-                'action' => 'registrations_report_for_event',
3280
-                'EVT_ID' => $EVT_ID,
3281
-            ];
3282
-            // Merge required request args, overriding any currently set
3283
-            $request_args = array_merge($request_args, $required_request_args);
3284
-            if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3285
-                require_once(EE_CLASSES . 'EE_Export.class.php');
3286
-                $EE_Export = EE_Export::instance($request_args);
3287
-                $EE_Export->export();
3288
-            }
3289
-        }
3290
-    }
3291
-
3292
-
3293
-    /**
3294
-     * Creates a registration report using only query parameters in the request
3295
-     *
3296
-     * @return void
3297
-     */
3298
-    public function _registrations_report()
3299
-    {
3300
-        $this->_registrations_report_base('_get_registration_query_parameters');
3301
-    }
3302
-
3303
-
3304
-    public function _contact_list_export()
3305
-    {
3306
-        if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3307
-            require_once(EE_CLASSES . 'EE_Export.class.php');
3308
-            $EE_Export = EE_Export::instance($this->request->requestParams());
3309
-            $EE_Export->export_attendees();
3310
-        }
3311
-    }
3312
-
3313
-
3314
-    public function _contact_list_report()
3315
-    {
3316
-        if (! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3317
-            wp_redirect(
3318
-                EE_Admin_Page::add_query_args_and_nonce(
3319
-                    [
3320
-                        'page'        => 'espresso_batch',
3321
-                        'batch'       => 'file',
3322
-                        'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\AttendeesReport'),
3323
-                        'return_url'  => urlencode($this->request->getRequestParam('return_url', '', 'url')),
3324
-                    ]
3325
-                )
3326
-            );
3327
-        } else {
3328
-            if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3329
-                require_once(EE_CLASSES . 'EE_Export.class.php');
3330
-                $EE_Export = EE_Export::instance($this->request->requestParams());
3331
-                $EE_Export->report_attendees();
3332
-            }
3333
-        }
3334
-    }
3335
-
3336
-
3337
-
3338
-
3339
-
3340
-    /***************************************        ATTENDEE DETAILS        ***************************************/
3341
-    /**
3342
-     * This duplicates the attendee object for the given incoming registration id and attendee_id.
3343
-     *
3344
-     * @return void
3345
-     * @throws EE_Error
3346
-     * @throws InvalidArgumentException
3347
-     * @throws InvalidDataTypeException
3348
-     * @throws InvalidInterfaceException
3349
-     * @throws ReflectionException
3350
-     */
3351
-    protected function _duplicate_attendee()
3352
-    {
3353
-        $REG_ID = $this->request->getRequestParam('_REG_ID', 0, 'int');
3354
-        $action = $this->request->getRequestParam('return', 'default');
3355
-        // verify we have necessary info
3356
-        if (! $REG_ID) {
3357
-            EE_Error::add_error(
3358
-                esc_html__(
3359
-                    'Unable to create the contact for the registration because the required parameters are not present (_REG_ID )',
3360
-                    'event_espresso'
3361
-                ),
3362
-                __FILE__,
3363
-                __LINE__,
3364
-                __FUNCTION__
3365
-            );
3366
-            $query_args = ['action' => $action];
3367
-            $this->_redirect_after_action('', '', '', $query_args, true);
3368
-        }
3369
-        // okay necessary deets present... let's dupe the incoming attendee and attach to incoming registration.
3370
-        $registration = $this->getRegistrationModel()->get_one_by_ID($REG_ID);
3371
-        if (! $registration instanceof EE_Registration) {
3372
-            throw new RuntimeException(
3373
-                sprintf(
3374
-                    esc_html__(
3375
-                        'Unable to create the contact because a valid registration could not be retrieved for REG ID: %1$d',
3376
-                        'event_espresso'
3377
-                    ),
3378
-                    $REG_ID
3379
-                )
3380
-            );
3381
-        }
3382
-        $attendee = $registration->attendee();
3383
-        // remove relation of existing attendee on registration
3384
-        $registration->_remove_relation_to($attendee, 'Attendee');
3385
-        // new attendee
3386
-        $new_attendee = clone $attendee;
3387
-        $new_attendee->set('ATT_ID', 0);
3388
-        $new_attendee->save();
3389
-        // add new attendee to reg
3390
-        $registration->_add_relation_to($new_attendee, 'Attendee');
3391
-        EE_Error::add_success(
3392
-            esc_html__(
3393
-                'New Contact record created.  Now make any edits you wish to make for this contact.',
3394
-                'event_espresso'
3395
-            )
3396
-        );
3397
-        // redirect to edit page for attendee
3398
-        $query_args = ['post' => $new_attendee->ID(), 'action' => 'edit_attendee'];
3399
-        $this->_redirect_after_action('', '', '', $query_args, true);
3400
-    }
3401
-
3402
-
3403
-    /**
3404
-     * Callback invoked by parent EE_Admin_CPT class hooked in on `save_post` wp hook.
3405
-     *
3406
-     * @param int     $post_id
3407
-     * @param WP_Post $post
3408
-     * @throws DomainException
3409
-     * @throws EE_Error
3410
-     * @throws InvalidArgumentException
3411
-     * @throws InvalidDataTypeException
3412
-     * @throws InvalidInterfaceException
3413
-     * @throws LogicException
3414
-     * @throws InvalidFormSubmissionException
3415
-     * @throws ReflectionException
3416
-     */
3417
-    protected function _insert_update_cpt_item($post_id, $post)
3418
-    {
3419
-        $success  = true;
3420
-        $attendee = $post instanceof WP_Post && $post->post_type === 'espresso_attendees'
3421
-            ? $this->getAttendeeModel()->get_one_by_ID($post_id)
3422
-            : null;
3423
-        // for attendee updates
3424
-        if ($attendee instanceof EE_Attendee) {
3425
-            // note we should only be UPDATING attendees at this point.
3426
-            $fname          = $this->request->getRequestParam('ATT_fname', '');
3427
-            $lname          = $this->request->getRequestParam('ATT_lname', '');
3428
-            $updated_fields = [
3429
-                'ATT_fname'     => $fname,
3430
-                'ATT_lname'     => $lname,
3431
-                'ATT_full_name' => "{$fname} {$lname}",
3432
-                'ATT_address'   => $this->request->getRequestParam('ATT_address', ''),
3433
-                'ATT_address2'  => $this->request->getRequestParam('ATT_address2', ''),
3434
-                'ATT_city'      => $this->request->getRequestParam('ATT_city', ''),
3435
-                'STA_ID'        => $this->request->getRequestParam('STA_ID', ''),
3436
-                'CNT_ISO'       => $this->request->getRequestParam('CNT_ISO', ''),
3437
-                'ATT_zip'       => $this->request->getRequestParam('ATT_zip', ''),
3438
-            ];
3439
-            foreach ($updated_fields as $field => $value) {
3440
-                $attendee->set($field, $value);
3441
-            }
3442
-
3443
-            // process contact details metabox form handler (which will also save the attendee)
3444
-            $contact_details_form = $this->getAttendeeContactDetailsMetaboxFormHandler($attendee);
3445
-            $success              = $contact_details_form->process($this->request->requestParams());
3446
-
3447
-            $attendee_update_callbacks = apply_filters(
3448
-                'FHEE__Registrations_Admin_Page__insert_update_cpt_item__attendee_update',
3449
-                []
3450
-            );
3451
-            foreach ($attendee_update_callbacks as $a_callback) {
3452
-                if (false === call_user_func_array($a_callback, [$attendee, $this->request->requestParams()])) {
3453
-                    throw new EE_Error(
3454
-                        sprintf(
3455
-                            esc_html__(
3456
-                                '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.',
3457
-                                'event_espresso'
3458
-                            ),
3459
-                            $a_callback
3460
-                        )
3461
-                    );
3462
-                }
3463
-            }
3464
-        }
3465
-
3466
-        if ($success === false) {
3467
-            EE_Error::add_error(
3468
-                esc_html__(
3469
-                    'Something went wrong with updating the meta table data for the registration.',
3470
-                    'event_espresso'
3471
-                ),
3472
-                __FILE__,
3473
-                __FUNCTION__,
3474
-                __LINE__
3475
-            );
3476
-        }
3477
-    }
3478
-
3479
-
3480
-    public function trash_cpt_item($post_id)
3481
-    {
3482
-    }
3483
-
3484
-
3485
-    public function delete_cpt_item($post_id)
3486
-    {
3487
-    }
3488
-
3489
-
3490
-    public function restore_cpt_item($post_id)
3491
-    {
3492
-    }
3493
-
3494
-
3495
-    protected function _restore_cpt_item($post_id, $revision_id)
3496
-    {
3497
-    }
3498
-
3499
-
3500
-    /**
3501
-     * @throws EE_Error
3502
-     * @throws ReflectionException
3503
-     * @since 4.10.2.p
3504
-     */
3505
-    public function attendee_editor_metaboxes()
3506
-    {
3507
-        $this->verify_cpt_object();
3508
-        remove_meta_box(
3509
-            'postexcerpt',
3510
-            $this->_cpt_routes[ $this->_req_action ],
3511
-            'normal'
3512
-        );
3513
-        remove_meta_box('commentstatusdiv', $this->_cpt_routes[ $this->_req_action ], 'normal');
3514
-        if (post_type_supports('espresso_attendees', 'excerpt')) {
3515
-            add_meta_box(
3516
-                'postexcerpt',
3517
-                esc_html__('Short Biography', 'event_espresso'),
3518
-                'post_excerpt_meta_box',
3519
-                $this->_cpt_routes[ $this->_req_action ],
3520
-                'normal'
3521
-            );
3522
-        }
3523
-        if (post_type_supports('espresso_attendees', 'comments')) {
3524
-            add_meta_box(
3525
-                'commentsdiv',
3526
-                esc_html__('Notes on the Contact', 'event_espresso'),
3527
-                'post_comment_meta_box',
3528
-                $this->_cpt_routes[ $this->_req_action ],
3529
-                'normal',
3530
-                'core'
3531
-            );
3532
-        }
3533
-        add_meta_box(
3534
-            'attendee_contact_info',
3535
-            esc_html__('Contact Info', 'event_espresso'),
3536
-            [$this, 'attendee_contact_info'],
3537
-            $this->_cpt_routes[ $this->_req_action ],
3538
-            'side',
3539
-            'core'
3540
-        );
3541
-        add_meta_box(
3542
-            'attendee_details_address',
3543
-            esc_html__('Address Details', 'event_espresso'),
3544
-            [$this, 'attendee_address_details'],
3545
-            $this->_cpt_routes[ $this->_req_action ],
3546
-            'normal',
3547
-            'core'
3548
-        );
3549
-        add_meta_box(
3550
-            'attendee_registrations',
3551
-            esc_html__('Registrations for this Contact', 'event_espresso'),
3552
-            [$this, 'attendee_registrations_meta_box'],
3553
-            $this->_cpt_routes[ $this->_req_action ],
3554
-            'normal',
3555
-            'high'
3556
-        );
3557
-    }
3558
-
3559
-
3560
-    /**
3561
-     * Metabox for attendee contact info
3562
-     *
3563
-     * @param WP_Post $post wp post object
3564
-     * @return void attendee contact info ( and form )
3565
-     * @throws EE_Error
3566
-     * @throws InvalidArgumentException
3567
-     * @throws InvalidDataTypeException
3568
-     * @throws InvalidInterfaceException
3569
-     * @throws LogicException
3570
-     * @throws DomainException
3571
-     */
3572
-    public function attendee_contact_info($post)
3573
-    {
3574
-        // get attendee object ( should already have it )
3575
-        $form = $this->getAttendeeContactDetailsMetaboxFormHandler($this->_cpt_model_obj);
3576
-        $form->enqueueStylesAndScripts();
3577
-        echo wp_kses($form->display(), AllowedTags::getWithFormTags());
3578
-    }
3579
-
3580
-
3581
-    /**
3582
-     * Return form handler for the contact details metabox
3583
-     *
3584
-     * @param EE_Attendee $attendee
3585
-     * @return AttendeeContactDetailsMetaboxFormHandler
3586
-     * @throws DomainException
3587
-     * @throws InvalidArgumentException
3588
-     * @throws InvalidDataTypeException
3589
-     * @throws InvalidInterfaceException
3590
-     */
3591
-    protected function getAttendeeContactDetailsMetaboxFormHandler(EE_Attendee $attendee)
3592
-    {
3593
-        return new AttendeeContactDetailsMetaboxFormHandler($attendee, EE_Registry::instance());
3594
-    }
3595
-
3596
-
3597
-    /**
3598
-     * Metabox for attendee details
3599
-     *
3600
-     * @param WP_Post $post wp post object
3601
-     * @throws EE_Error
3602
-     * @throws ReflectionException
3603
-     */
3604
-    public function attendee_address_details($post)
3605
-    {
3606
-        // get attendee object (should already have it)
3607
-        $this->_template_args['attendee']     = $this->_cpt_model_obj;
3608
-        $this->_template_args['state_html']   = EEH_Form_Fields::generate_form_input(
3609
-            new EE_Question_Form_Input(
3610
-                EE_Question::new_instance(
3611
-                    [
3612
-                        'QST_ID'           => 0,
3613
-                        'QST_display_text' => esc_html__('State/Province', 'event_espresso'),
3614
-                        'QST_system'       => 'admin-state',
3615
-                    ]
3616
-                ),
3617
-                EE_Answer::new_instance(
3618
-                    [
3619
-                        'ANS_ID'    => 0,
3620
-                        'ANS_value' => $this->_cpt_model_obj->state_ID(),
3621
-                    ]
3622
-                ),
3623
-                [
3624
-                    'input_id'       => 'STA_ID',
3625
-                    'input_name'     => 'STA_ID',
3626
-                    'input_prefix'   => '',
3627
-                    'append_qstn_id' => false,
3628
-                ]
3629
-            )
3630
-        );
3631
-        $this->_template_args['country_html'] = EEH_Form_Fields::generate_form_input(
3632
-            new EE_Question_Form_Input(
3633
-                EE_Question::new_instance(
3634
-                    [
3635
-                        'QST_ID'           => 0,
3636
-                        'QST_display_text' => esc_html__('Country', 'event_espresso'),
3637
-                        'QST_system'       => 'admin-country',
3638
-                    ]
3639
-                ),
3640
-                EE_Answer::new_instance(
3641
-                    [
3642
-                        'ANS_ID'    => 0,
3643
-                        'ANS_value' => $this->_cpt_model_obj->country_ID(),
3644
-                    ]
3645
-                ),
3646
-                [
3647
-                    'input_id'       => 'CNT_ISO',
3648
-                    'input_name'     => 'CNT_ISO',
3649
-                    'input_prefix'   => '',
3650
-                    'append_qstn_id' => false,
3651
-                ]
3652
-            )
3653
-        );
3654
-        $template                             =
3655
-            REG_TEMPLATE_PATH . 'attendee_address_details_metabox_content.template.php';
3656
-        EEH_Template::display_template($template, $this->_template_args);
3657
-    }
3658
-
3659
-
3660
-    /**
3661
-     * _attendee_details
3662
-     *
3663
-     * @param $post
3664
-     * @return void
3665
-     * @throws DomainException
3666
-     * @throws EE_Error
3667
-     * @throws InvalidArgumentException
3668
-     * @throws InvalidDataTypeException
3669
-     * @throws InvalidInterfaceException
3670
-     * @throws ReflectionException
3671
-     */
3672
-    public function attendee_registrations_meta_box($post)
3673
-    {
3674
-        $this->_template_args['attendee']      = $this->_cpt_model_obj;
3675
-        $this->_template_args['registrations'] = $this->_cpt_model_obj->get_many_related('Registration');
3676
-        $template                              =
3677
-            REG_TEMPLATE_PATH . 'attendee_registrations_main_meta_box.template.php';
3678
-        EEH_Template::display_template($template, $this->_template_args);
3679
-    }
3680
-
3681
-
3682
-    /**
3683
-     * add in the form fields for the attendee edit
3684
-     *
3685
-     * @param WP_Post $post wp post object
3686
-     * @return void echos html for new form.
3687
-     * @throws DomainException
3688
-     */
3689
-    public function after_title_form_fields($post)
3690
-    {
3691
-        if ($post->post_type === 'espresso_attendees') {
3692
-            $template                  = REG_TEMPLATE_PATH . 'attendee_details_after_title_form_fields.template.php';
3693
-            $template_args['attendee'] = $this->_cpt_model_obj;
3694
-            EEH_Template::display_template($template, $template_args);
3695
-        }
3696
-    }
3697
-
3698
-
3699
-    /**
3700
-     * _trash_or_restore_attendee
3701
-     *
3702
-     * @param boolean $trash - whether to move item to trash (TRUE) or restore it (FALSE)
3703
-     * @return void
3704
-     * @throws EE_Error
3705
-     * @throws InvalidArgumentException
3706
-     * @throws InvalidDataTypeException
3707
-     * @throws InvalidInterfaceException
3708
-     */
3709
-    protected function _trash_or_restore_attendees($trash = true)
3710
-    {
3711
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3712
-        $status = $trash ? 'trash' : 'publish';
3713
-        // Checkboxes
3714
-        if ($this->request->requestParamIsSet('checkbox')) {
3715
-            $ATT_IDs = $this->request->getRequestParam('checkbox', [], 'int', true);
3716
-            // if array has more than one element than success message should be plural
3717
-            $success = count($ATT_IDs) > 1 ? 2 : 1;
3718
-            // cycle thru checkboxes
3719
-            foreach ($ATT_IDs as $ATT_ID) {
3720
-                $updated = $this->getAttendeeModel()->update_by_ID(['status' => $status], $ATT_ID);
3721
-                if (! $updated) {
3722
-                    $success = 0;
3723
-                }
3724
-            }
3725
-        } else {
3726
-            // grab single id and delete
3727
-            $ATT_ID = $this->request->getRequestParam('ATT_ID', 0, 'int');
3728
-            // update attendee
3729
-            $success = $this->getAttendeeModel()->update_by_ID(['status' => $status], $ATT_ID) ? 1 : 0;
3730
-        }
3731
-        $what        = $success > 1
3732
-            ? esc_html__('Contacts', 'event_espresso')
3733
-            : esc_html__('Contact', 'event_espresso');
3734
-        $action_desc = $trash
3735
-            ? esc_html__('moved to the trash', 'event_espresso')
3736
-            : esc_html__('restored', 'event_espresso');
3737
-        $this->_redirect_after_action($success, $what, $action_desc, ['action' => 'contact_list']);
3738
-    }
2897
+		}
2898
+		$template_args = [
2899
+			'title'                    => '',
2900
+			'content'                  => '',
2901
+			'step_button_text'         => '',
2902
+			'show_notification_toggle' => false,
2903
+		];
2904
+		// to indicate we're processing a new registration
2905
+		$hidden_fields = [
2906
+			'processing_registration' => [
2907
+				'type'  => 'hidden',
2908
+				'value' => 0,
2909
+			],
2910
+			'event_id'                => [
2911
+				'type'  => 'hidden',
2912
+				'value' => $this->_reg_event->ID(),
2913
+			],
2914
+		];
2915
+		// if the cart is empty then we know we're at step one, so we'll display the ticket selector
2916
+		$cart = EE_Registry::instance()->SSN->cart();
2917
+		$step = ! $cart instanceof EE_Cart ? 'ticket' : 'questions';
2918
+		switch ($step) {
2919
+			case 'ticket':
2920
+				$hidden_fields['processing_registration']['value'] = 1;
2921
+				$template_args['title']                            = esc_html__(
2922
+					'Step One: Select the Ticket for this registration',
2923
+					'event_espresso'
2924
+				);
2925
+				$template_args['content']                          =
2926
+					EED_Ticket_Selector::instance()->display_ticket_selector($this->_reg_event);
2927
+				$template_args['content']                          .= '</div>';
2928
+				$template_args['step_button_text']                 = esc_html__(
2929
+					'Add Tickets and Continue to Registrant Details',
2930
+					'event_espresso'
2931
+				);
2932
+				$template_args['show_notification_toggle']         = false;
2933
+				break;
2934
+			case 'questions':
2935
+				$hidden_fields['processing_registration']['value'] = 2;
2936
+				$template_args['title']                            = esc_html__(
2937
+					'Step Two: Add Registrant Details for this Registration',
2938
+					'event_espresso'
2939
+				);
2940
+				// in theory, we should be able to run EED_SPCO at this point
2941
+				// because the cart should have been set up properly by the first process_reg_step run.
2942
+				$template_args['content']                  =
2943
+					EED_Single_Page_Checkout::registration_checkout_for_admin();
2944
+				$template_args['step_button_text']         = esc_html__(
2945
+					'Save Registration and Continue to Details',
2946
+					'event_espresso'
2947
+				);
2948
+				$template_args['show_notification_toggle'] = true;
2949
+				break;
2950
+		}
2951
+		// we come back to the process_registration_step route.
2952
+		$this->_set_add_edit_form_tags('process_reg_step', $hidden_fields);
2953
+		return EEH_Template::display_template(
2954
+			REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee_step_content.template.php',
2955
+			$template_args,
2956
+			true
2957
+		);
2958
+	}
2959
+
2960
+
2961
+	/**
2962
+	 * set_reg_event
2963
+	 *
2964
+	 * @return bool
2965
+	 * @throws EE_Error
2966
+	 * @throws InvalidArgumentException
2967
+	 * @throws InvalidDataTypeException
2968
+	 * @throws InvalidInterfaceException
2969
+	 */
2970
+	private function _set_reg_event()
2971
+	{
2972
+		if (is_object($this->_reg_event)) {
2973
+			return true;
2974
+		}
2975
+
2976
+		$EVT_ID = $this->request->getRequestParam('event_id', 0, 'int');
2977
+		if (! $EVT_ID) {
2978
+			return false;
2979
+		}
2980
+		$this->_reg_event = $this->getEventModel()->get_one_by_ID($EVT_ID);
2981
+		return true;
2982
+	}
2983
+
2984
+
2985
+	/**
2986
+	 * process_reg_step
2987
+	 *
2988
+	 * @return void
2989
+	 * @throws DomainException
2990
+	 * @throws EE_Error
2991
+	 * @throws InvalidArgumentException
2992
+	 * @throws InvalidDataTypeException
2993
+	 * @throws InvalidInterfaceException
2994
+	 * @throws ReflectionException
2995
+	 * @throws RuntimeException
2996
+	 */
2997
+	public function process_reg_step()
2998
+	{
2999
+		EE_System::do_not_cache();
3000
+		$this->_set_reg_event();
3001
+		/** @var CurrentPage $current_page */
3002
+		$current_page = $this->loader->getShared(CurrentPage::class);
3003
+		$current_page->setEspressoPage(true);
3004
+		$this->request->setRequestParam('uts', time());
3005
+		// what step are we on?
3006
+		$cart = EE_Registry::instance()->SSN->cart();
3007
+		$step = ! $cart instanceof EE_Cart ? 'ticket' : 'questions';
3008
+		// if doing ajax then we need to verify the nonce
3009
+		if ($this->request->isAjax()) {
3010
+			$nonce = $this->request->getRequestParam($this->_req_nonce, '');
3011
+			$this->_verify_nonce($nonce, $this->_req_nonce);
3012
+		}
3013
+		switch ($step) {
3014
+			case 'ticket':
3015
+				// process ticket selection
3016
+				$success = EED_Ticket_Selector::instance()->process_ticket_selections();
3017
+				if ($success) {
3018
+					EE_Error::add_success(
3019
+						esc_html__(
3020
+							'Tickets Selected. Now complete the registration.',
3021
+							'event_espresso'
3022
+						)
3023
+					);
3024
+				} else {
3025
+					$this->request->setRequestParam('step_error', true);
3026
+					$query_args['step_error'] = $this->request->getRequestParam('step_error', true, 'bool');
3027
+				}
3028
+				if ($this->request->isAjax()) {
3029
+					$this->new_registration(); // display next step
3030
+				} else {
3031
+					$query_args = [
3032
+						'action'                  => 'new_registration',
3033
+						'processing_registration' => 1,
3034
+						'event_id'                => $this->_reg_event->ID(),
3035
+						'uts'                     => time(),
3036
+					];
3037
+					$this->_redirect_after_action(
3038
+						false,
3039
+						'',
3040
+						'',
3041
+						$query_args,
3042
+						true
3043
+					);
3044
+				}
3045
+				break;
3046
+			case 'questions':
3047
+				if (! $this->request->requestParamIsSet('txn_reg_status_change[send_notifications]')) {
3048
+					add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_false', 15);
3049
+				}
3050
+				// process registration
3051
+				$transaction = EED_Single_Page_Checkout::instance()->process_registration_from_admin();
3052
+				if ($cart instanceof EE_Cart) {
3053
+					$grand_total = $cart->get_grand_total();
3054
+					if ($grand_total instanceof EE_Line_Item) {
3055
+						$grand_total->save_this_and_descendants_to_txn();
3056
+					}
3057
+				}
3058
+				if (! $transaction instanceof EE_Transaction) {
3059
+					$query_args = [
3060
+						'action'                  => 'new_registration',
3061
+						'processing_registration' => 2,
3062
+						'event_id'                => $this->_reg_event->ID(),
3063
+						'uts'                     => time(),
3064
+					];
3065
+					if ($this->request->isAjax()) {
3066
+						// display registration form again because there are errors (maybe validation?)
3067
+						$this->new_registration();
3068
+						return;
3069
+					}
3070
+					$this->_redirect_after_action(
3071
+						false,
3072
+						'',
3073
+						'',
3074
+						$query_args,
3075
+						true
3076
+					);
3077
+					return;
3078
+				}
3079
+				// maybe update status, and make sure to save transaction if not done already
3080
+				if (! $transaction->update_status_based_on_total_paid()) {
3081
+					$transaction->save();
3082
+				}
3083
+				EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
3084
+				$query_args = [
3085
+					'action'        => 'redirect_to_txn',
3086
+					'TXN_ID'        => $transaction->ID(),
3087
+					'EVT_ID'        => $this->_reg_event->ID(),
3088
+					'event_name'    => urlencode($this->_reg_event->name()),
3089
+					'redirect_from' => 'new_registration',
3090
+				];
3091
+				$this->_redirect_after_action(false, '', '', $query_args, true);
3092
+				break;
3093
+		}
3094
+		// what are you looking here for?  Should be nothing to do at this point.
3095
+	}
3096
+
3097
+
3098
+	/**
3099
+	 * redirect_to_txn
3100
+	 *
3101
+	 * @return void
3102
+	 * @throws EE_Error
3103
+	 * @throws InvalidArgumentException
3104
+	 * @throws InvalidDataTypeException
3105
+	 * @throws InvalidInterfaceException
3106
+	 * @throws ReflectionException
3107
+	 */
3108
+	public function redirect_to_txn()
3109
+	{
3110
+		EE_System::do_not_cache();
3111
+		EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
3112
+		$query_args = [
3113
+			'action' => 'view_transaction',
3114
+			'TXN_ID' => $this->request->getRequestParam('TXN_ID', 0, 'int'),
3115
+			'page'   => 'espresso_transactions',
3116
+		];
3117
+		if ($this->request->requestParamIsSet('EVT_ID') && $this->request->requestParamIsSet('redirect_from')) {
3118
+			$query_args['EVT_ID']        = $this->request->getRequestParam('EVT_ID', 0, 'int');
3119
+			$query_args['event_name']    = urlencode($this->request->getRequestParam('event_name'));
3120
+			$query_args['redirect_from'] = $this->request->getRequestParam('redirect_from');
3121
+		}
3122
+		EE_Error::add_success(
3123
+			esc_html__(
3124
+				'Registration Created.  Please review the transaction and add any payments as necessary',
3125
+				'event_espresso'
3126
+			)
3127
+		);
3128
+		$this->_redirect_after_action(false, '', '', $query_args, true);
3129
+	}
3130
+
3131
+
3132
+	/**
3133
+	 * generates HTML for the Attendee Contact List
3134
+	 *
3135
+	 * @return void
3136
+	 * @throws DomainException
3137
+	 * @throws EE_Error
3138
+	 */
3139
+	protected function _attendee_contact_list_table()
3140
+	{
3141
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3142
+		$this->_search_btn_label = esc_html__('Contacts', 'event_espresso');
3143
+		$this->display_admin_list_table_page_with_no_sidebar();
3144
+	}
3145
+
3146
+
3147
+	/**
3148
+	 * get_attendees
3149
+	 *
3150
+	 * @param      $per_page
3151
+	 * @param bool $count whether to return count or data.
3152
+	 * @param bool $trash
3153
+	 * @return array|int
3154
+	 * @throws EE_Error
3155
+	 * @throws InvalidArgumentException
3156
+	 * @throws InvalidDataTypeException
3157
+	 * @throws InvalidInterfaceException
3158
+	 */
3159
+	public function get_attendees($per_page, $count = false, $trash = false)
3160
+	{
3161
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3162
+		require_once(REG_ADMIN . 'EE_Attendee_Contact_List_Table.class.php');
3163
+		$orderby = $this->request->getRequestParam('orderby');
3164
+		switch ($orderby) {
3165
+			case 'ATT_ID':
3166
+			case 'ATT_fname':
3167
+			case 'ATT_email':
3168
+			case 'ATT_city':
3169
+			case 'STA_ID':
3170
+			case 'CNT_ID':
3171
+				break;
3172
+			case 'Registration_Count':
3173
+				$orderby = 'Registration_Count';
3174
+				break;
3175
+			default:
3176
+				$orderby = 'ATT_lname';
3177
+		}
3178
+		$sort         = $this->request->getRequestParam('order', 'ASC');
3179
+		$current_page = $this->request->getRequestParam('paged', 1, 'int');
3180
+		$per_page     = absint($per_page) ? $per_page : 10;
3181
+		$per_page     = $this->request->getRequestParam('perpage', $per_page, 'int');
3182
+		$_where       = [];
3183
+		$search_term  = $this->request->getRequestParam('s');
3184
+		if ($search_term) {
3185
+			$search_term  = '%' . $search_term . '%';
3186
+			$_where['OR'] = [
3187
+				'Registration.Event.EVT_name'       => ['LIKE', $search_term],
3188
+				'Registration.Event.EVT_desc'       => ['LIKE', $search_term],
3189
+				'Registration.Event.EVT_short_desc' => ['LIKE', $search_term],
3190
+				'ATT_fname'                         => ['LIKE', $search_term],
3191
+				'ATT_lname'                         => ['LIKE', $search_term],
3192
+				'ATT_short_bio'                     => ['LIKE', $search_term],
3193
+				'ATT_email'                         => ['LIKE', $search_term],
3194
+				'ATT_address'                       => ['LIKE', $search_term],
3195
+				'ATT_address2'                      => ['LIKE', $search_term],
3196
+				'ATT_city'                          => ['LIKE', $search_term],
3197
+				'Country.CNT_name'                  => ['LIKE', $search_term],
3198
+				'State.STA_name'                    => ['LIKE', $search_term],
3199
+				'ATT_phone'                         => ['LIKE', $search_term],
3200
+				'Registration.REG_final_price'      => ['LIKE', $search_term],
3201
+				'Registration.REG_code'             => ['LIKE', $search_term],
3202
+				'Registration.REG_group_size'       => ['LIKE', $search_term],
3203
+			];
3204
+		}
3205
+		$offset     = ($current_page - 1) * $per_page;
3206
+		$limit      = $count ? null : [$offset, $per_page];
3207
+		$query_args = [
3208
+			$_where,
3209
+			'extra_selects' => ['Registration_Count' => ['Registration.REG_ID', 'count', '%d']],
3210
+			'limit'         => $limit,
3211
+		];
3212
+		if (! $count) {
3213
+			$query_args['order_by'] = [$orderby => $sort];
3214
+		}
3215
+		$query_args[0]['status'] = $trash ? ['!=', 'publish'] : ['IN', ['publish']];
3216
+		return $count
3217
+			? $this->getAttendeeModel()->count($query_args, 'ATT_ID', true)
3218
+			: $this->getAttendeeModel()->get_all($query_args);
3219
+	}
3220
+
3221
+
3222
+	/**
3223
+	 * This is just taking care of resending the registration confirmation
3224
+	 *
3225
+	 * @return void
3226
+	 * @throws EE_Error
3227
+	 * @throws InvalidArgumentException
3228
+	 * @throws InvalidDataTypeException
3229
+	 * @throws InvalidInterfaceException
3230
+	 * @throws ReflectionException
3231
+	 */
3232
+	protected function _resend_registration()
3233
+	{
3234
+		$this->_process_resend_registration();
3235
+		$REG_ID      = $this->request->getRequestParam('_REG_ID', 0, 'int');
3236
+		$redirect_to = $this->request->getRequestParam('redirect_to');
3237
+		$query_args  = $redirect_to
3238
+			? ['action' => $redirect_to, '_REG_ID' => $REG_ID]
3239
+			: ['action' => 'default'];
3240
+		$this->_redirect_after_action(false, '', '', $query_args, true);
3241
+	}
3242
+
3243
+
3244
+	/**
3245
+	 * Creates a registration report, but accepts the name of a method to use for preparing the query parameters
3246
+	 * to use when selecting registrations
3247
+	 *
3248
+	 * @param string $method_name_for_getting_query_params the name of the method (on this class) to use for preparing
3249
+	 *                                                     the query parameters from the request
3250
+	 * @return void ends the request with a redirect or download
3251
+	 */
3252
+	public function _registrations_report_base($method_name_for_getting_query_params)
3253
+	{
3254
+		$EVT_ID = $this->request->requestParamIsSet('EVT_ID')
3255
+			? $this->request->getRequestParam('EVT_ID', 0, 'int')
3256
+			: null;
3257
+		if (! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3258
+			$filters = $this->request->getRequestParam('filters', [], DataType::STRING, true);
3259
+			$report_params  = $this->$method_name_for_getting_query_params($filters);
3260
+			wp_redirect(
3261
+				EE_Admin_Page::add_query_args_and_nonce(
3262
+					[
3263
+						'page'        => 'espresso_batch',
3264
+						'batch'       => 'file',
3265
+						'EVT_ID'      => $EVT_ID,
3266
+						'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\RegistrationsReport'),
3267
+						'return_url'  => urlencode($this->request->getRequestParam('return_url', '', DataType::URL)),
3268
+						'filters'     => urlencode(serialize($report_params)),
3269
+						'use_filters' => $this->request->getRequestParam('use_filters', false, DataType::BOOL)
3270
+					]
3271
+				)
3272
+			);
3273
+		} else {
3274
+			// Pull the current request params
3275
+			$request_args = $this->request->requestParams();
3276
+			// Set the required request_args to be passed to the export
3277
+			$required_request_args = [
3278
+				'export' => 'report',
3279
+				'action' => 'registrations_report_for_event',
3280
+				'EVT_ID' => $EVT_ID,
3281
+			];
3282
+			// Merge required request args, overriding any currently set
3283
+			$request_args = array_merge($request_args, $required_request_args);
3284
+			if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3285
+				require_once(EE_CLASSES . 'EE_Export.class.php');
3286
+				$EE_Export = EE_Export::instance($request_args);
3287
+				$EE_Export->export();
3288
+			}
3289
+		}
3290
+	}
3291
+
3292
+
3293
+	/**
3294
+	 * Creates a registration report using only query parameters in the request
3295
+	 *
3296
+	 * @return void
3297
+	 */
3298
+	public function _registrations_report()
3299
+	{
3300
+		$this->_registrations_report_base('_get_registration_query_parameters');
3301
+	}
3302
+
3303
+
3304
+	public function _contact_list_export()
3305
+	{
3306
+		if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3307
+			require_once(EE_CLASSES . 'EE_Export.class.php');
3308
+			$EE_Export = EE_Export::instance($this->request->requestParams());
3309
+			$EE_Export->export_attendees();
3310
+		}
3311
+	}
3312
+
3313
+
3314
+	public function _contact_list_report()
3315
+	{
3316
+		if (! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3317
+			wp_redirect(
3318
+				EE_Admin_Page::add_query_args_and_nonce(
3319
+					[
3320
+						'page'        => 'espresso_batch',
3321
+						'batch'       => 'file',
3322
+						'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\AttendeesReport'),
3323
+						'return_url'  => urlencode($this->request->getRequestParam('return_url', '', 'url')),
3324
+					]
3325
+				)
3326
+			);
3327
+		} else {
3328
+			if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3329
+				require_once(EE_CLASSES . 'EE_Export.class.php');
3330
+				$EE_Export = EE_Export::instance($this->request->requestParams());
3331
+				$EE_Export->report_attendees();
3332
+			}
3333
+		}
3334
+	}
3335
+
3336
+
3337
+
3338
+
3339
+
3340
+	/***************************************        ATTENDEE DETAILS        ***************************************/
3341
+	/**
3342
+	 * This duplicates the attendee object for the given incoming registration id and attendee_id.
3343
+	 *
3344
+	 * @return void
3345
+	 * @throws EE_Error
3346
+	 * @throws InvalidArgumentException
3347
+	 * @throws InvalidDataTypeException
3348
+	 * @throws InvalidInterfaceException
3349
+	 * @throws ReflectionException
3350
+	 */
3351
+	protected function _duplicate_attendee()
3352
+	{
3353
+		$REG_ID = $this->request->getRequestParam('_REG_ID', 0, 'int');
3354
+		$action = $this->request->getRequestParam('return', 'default');
3355
+		// verify we have necessary info
3356
+		if (! $REG_ID) {
3357
+			EE_Error::add_error(
3358
+				esc_html__(
3359
+					'Unable to create the contact for the registration because the required parameters are not present (_REG_ID )',
3360
+					'event_espresso'
3361
+				),
3362
+				__FILE__,
3363
+				__LINE__,
3364
+				__FUNCTION__
3365
+			);
3366
+			$query_args = ['action' => $action];
3367
+			$this->_redirect_after_action('', '', '', $query_args, true);
3368
+		}
3369
+		// okay necessary deets present... let's dupe the incoming attendee and attach to incoming registration.
3370
+		$registration = $this->getRegistrationModel()->get_one_by_ID($REG_ID);
3371
+		if (! $registration instanceof EE_Registration) {
3372
+			throw new RuntimeException(
3373
+				sprintf(
3374
+					esc_html__(
3375
+						'Unable to create the contact because a valid registration could not be retrieved for REG ID: %1$d',
3376
+						'event_espresso'
3377
+					),
3378
+					$REG_ID
3379
+				)
3380
+			);
3381
+		}
3382
+		$attendee = $registration->attendee();
3383
+		// remove relation of existing attendee on registration
3384
+		$registration->_remove_relation_to($attendee, 'Attendee');
3385
+		// new attendee
3386
+		$new_attendee = clone $attendee;
3387
+		$new_attendee->set('ATT_ID', 0);
3388
+		$new_attendee->save();
3389
+		// add new attendee to reg
3390
+		$registration->_add_relation_to($new_attendee, 'Attendee');
3391
+		EE_Error::add_success(
3392
+			esc_html__(
3393
+				'New Contact record created.  Now make any edits you wish to make for this contact.',
3394
+				'event_espresso'
3395
+			)
3396
+		);
3397
+		// redirect to edit page for attendee
3398
+		$query_args = ['post' => $new_attendee->ID(), 'action' => 'edit_attendee'];
3399
+		$this->_redirect_after_action('', '', '', $query_args, true);
3400
+	}
3401
+
3402
+
3403
+	/**
3404
+	 * Callback invoked by parent EE_Admin_CPT class hooked in on `save_post` wp hook.
3405
+	 *
3406
+	 * @param int     $post_id
3407
+	 * @param WP_Post $post
3408
+	 * @throws DomainException
3409
+	 * @throws EE_Error
3410
+	 * @throws InvalidArgumentException
3411
+	 * @throws InvalidDataTypeException
3412
+	 * @throws InvalidInterfaceException
3413
+	 * @throws LogicException
3414
+	 * @throws InvalidFormSubmissionException
3415
+	 * @throws ReflectionException
3416
+	 */
3417
+	protected function _insert_update_cpt_item($post_id, $post)
3418
+	{
3419
+		$success  = true;
3420
+		$attendee = $post instanceof WP_Post && $post->post_type === 'espresso_attendees'
3421
+			? $this->getAttendeeModel()->get_one_by_ID($post_id)
3422
+			: null;
3423
+		// for attendee updates
3424
+		if ($attendee instanceof EE_Attendee) {
3425
+			// note we should only be UPDATING attendees at this point.
3426
+			$fname          = $this->request->getRequestParam('ATT_fname', '');
3427
+			$lname          = $this->request->getRequestParam('ATT_lname', '');
3428
+			$updated_fields = [
3429
+				'ATT_fname'     => $fname,
3430
+				'ATT_lname'     => $lname,
3431
+				'ATT_full_name' => "{$fname} {$lname}",
3432
+				'ATT_address'   => $this->request->getRequestParam('ATT_address', ''),
3433
+				'ATT_address2'  => $this->request->getRequestParam('ATT_address2', ''),
3434
+				'ATT_city'      => $this->request->getRequestParam('ATT_city', ''),
3435
+				'STA_ID'        => $this->request->getRequestParam('STA_ID', ''),
3436
+				'CNT_ISO'       => $this->request->getRequestParam('CNT_ISO', ''),
3437
+				'ATT_zip'       => $this->request->getRequestParam('ATT_zip', ''),
3438
+			];
3439
+			foreach ($updated_fields as $field => $value) {
3440
+				$attendee->set($field, $value);
3441
+			}
3442
+
3443
+			// process contact details metabox form handler (which will also save the attendee)
3444
+			$contact_details_form = $this->getAttendeeContactDetailsMetaboxFormHandler($attendee);
3445
+			$success              = $contact_details_form->process($this->request->requestParams());
3446
+
3447
+			$attendee_update_callbacks = apply_filters(
3448
+				'FHEE__Registrations_Admin_Page__insert_update_cpt_item__attendee_update',
3449
+				[]
3450
+			);
3451
+			foreach ($attendee_update_callbacks as $a_callback) {
3452
+				if (false === call_user_func_array($a_callback, [$attendee, $this->request->requestParams()])) {
3453
+					throw new EE_Error(
3454
+						sprintf(
3455
+							esc_html__(
3456
+								'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.',
3457
+								'event_espresso'
3458
+							),
3459
+							$a_callback
3460
+						)
3461
+					);
3462
+				}
3463
+			}
3464
+		}
3465
+
3466
+		if ($success === false) {
3467
+			EE_Error::add_error(
3468
+				esc_html__(
3469
+					'Something went wrong with updating the meta table data for the registration.',
3470
+					'event_espresso'
3471
+				),
3472
+				__FILE__,
3473
+				__FUNCTION__,
3474
+				__LINE__
3475
+			);
3476
+		}
3477
+	}
3478
+
3479
+
3480
+	public function trash_cpt_item($post_id)
3481
+	{
3482
+	}
3483
+
3484
+
3485
+	public function delete_cpt_item($post_id)
3486
+	{
3487
+	}
3488
+
3489
+
3490
+	public function restore_cpt_item($post_id)
3491
+	{
3492
+	}
3493
+
3494
+
3495
+	protected function _restore_cpt_item($post_id, $revision_id)
3496
+	{
3497
+	}
3498
+
3499
+
3500
+	/**
3501
+	 * @throws EE_Error
3502
+	 * @throws ReflectionException
3503
+	 * @since 4.10.2.p
3504
+	 */
3505
+	public function attendee_editor_metaboxes()
3506
+	{
3507
+		$this->verify_cpt_object();
3508
+		remove_meta_box(
3509
+			'postexcerpt',
3510
+			$this->_cpt_routes[ $this->_req_action ],
3511
+			'normal'
3512
+		);
3513
+		remove_meta_box('commentstatusdiv', $this->_cpt_routes[ $this->_req_action ], 'normal');
3514
+		if (post_type_supports('espresso_attendees', 'excerpt')) {
3515
+			add_meta_box(
3516
+				'postexcerpt',
3517
+				esc_html__('Short Biography', 'event_espresso'),
3518
+				'post_excerpt_meta_box',
3519
+				$this->_cpt_routes[ $this->_req_action ],
3520
+				'normal'
3521
+			);
3522
+		}
3523
+		if (post_type_supports('espresso_attendees', 'comments')) {
3524
+			add_meta_box(
3525
+				'commentsdiv',
3526
+				esc_html__('Notes on the Contact', 'event_espresso'),
3527
+				'post_comment_meta_box',
3528
+				$this->_cpt_routes[ $this->_req_action ],
3529
+				'normal',
3530
+				'core'
3531
+			);
3532
+		}
3533
+		add_meta_box(
3534
+			'attendee_contact_info',
3535
+			esc_html__('Contact Info', 'event_espresso'),
3536
+			[$this, 'attendee_contact_info'],
3537
+			$this->_cpt_routes[ $this->_req_action ],
3538
+			'side',
3539
+			'core'
3540
+		);
3541
+		add_meta_box(
3542
+			'attendee_details_address',
3543
+			esc_html__('Address Details', 'event_espresso'),
3544
+			[$this, 'attendee_address_details'],
3545
+			$this->_cpt_routes[ $this->_req_action ],
3546
+			'normal',
3547
+			'core'
3548
+		);
3549
+		add_meta_box(
3550
+			'attendee_registrations',
3551
+			esc_html__('Registrations for this Contact', 'event_espresso'),
3552
+			[$this, 'attendee_registrations_meta_box'],
3553
+			$this->_cpt_routes[ $this->_req_action ],
3554
+			'normal',
3555
+			'high'
3556
+		);
3557
+	}
3558
+
3559
+
3560
+	/**
3561
+	 * Metabox for attendee contact info
3562
+	 *
3563
+	 * @param WP_Post $post wp post object
3564
+	 * @return void attendee contact info ( and form )
3565
+	 * @throws EE_Error
3566
+	 * @throws InvalidArgumentException
3567
+	 * @throws InvalidDataTypeException
3568
+	 * @throws InvalidInterfaceException
3569
+	 * @throws LogicException
3570
+	 * @throws DomainException
3571
+	 */
3572
+	public function attendee_contact_info($post)
3573
+	{
3574
+		// get attendee object ( should already have it )
3575
+		$form = $this->getAttendeeContactDetailsMetaboxFormHandler($this->_cpt_model_obj);
3576
+		$form->enqueueStylesAndScripts();
3577
+		echo wp_kses($form->display(), AllowedTags::getWithFormTags());
3578
+	}
3579
+
3580
+
3581
+	/**
3582
+	 * Return form handler for the contact details metabox
3583
+	 *
3584
+	 * @param EE_Attendee $attendee
3585
+	 * @return AttendeeContactDetailsMetaboxFormHandler
3586
+	 * @throws DomainException
3587
+	 * @throws InvalidArgumentException
3588
+	 * @throws InvalidDataTypeException
3589
+	 * @throws InvalidInterfaceException
3590
+	 */
3591
+	protected function getAttendeeContactDetailsMetaboxFormHandler(EE_Attendee $attendee)
3592
+	{
3593
+		return new AttendeeContactDetailsMetaboxFormHandler($attendee, EE_Registry::instance());
3594
+	}
3595
+
3596
+
3597
+	/**
3598
+	 * Metabox for attendee details
3599
+	 *
3600
+	 * @param WP_Post $post wp post object
3601
+	 * @throws EE_Error
3602
+	 * @throws ReflectionException
3603
+	 */
3604
+	public function attendee_address_details($post)
3605
+	{
3606
+		// get attendee object (should already have it)
3607
+		$this->_template_args['attendee']     = $this->_cpt_model_obj;
3608
+		$this->_template_args['state_html']   = EEH_Form_Fields::generate_form_input(
3609
+			new EE_Question_Form_Input(
3610
+				EE_Question::new_instance(
3611
+					[
3612
+						'QST_ID'           => 0,
3613
+						'QST_display_text' => esc_html__('State/Province', 'event_espresso'),
3614
+						'QST_system'       => 'admin-state',
3615
+					]
3616
+				),
3617
+				EE_Answer::new_instance(
3618
+					[
3619
+						'ANS_ID'    => 0,
3620
+						'ANS_value' => $this->_cpt_model_obj->state_ID(),
3621
+					]
3622
+				),
3623
+				[
3624
+					'input_id'       => 'STA_ID',
3625
+					'input_name'     => 'STA_ID',
3626
+					'input_prefix'   => '',
3627
+					'append_qstn_id' => false,
3628
+				]
3629
+			)
3630
+		);
3631
+		$this->_template_args['country_html'] = EEH_Form_Fields::generate_form_input(
3632
+			new EE_Question_Form_Input(
3633
+				EE_Question::new_instance(
3634
+					[
3635
+						'QST_ID'           => 0,
3636
+						'QST_display_text' => esc_html__('Country', 'event_espresso'),
3637
+						'QST_system'       => 'admin-country',
3638
+					]
3639
+				),
3640
+				EE_Answer::new_instance(
3641
+					[
3642
+						'ANS_ID'    => 0,
3643
+						'ANS_value' => $this->_cpt_model_obj->country_ID(),
3644
+					]
3645
+				),
3646
+				[
3647
+					'input_id'       => 'CNT_ISO',
3648
+					'input_name'     => 'CNT_ISO',
3649
+					'input_prefix'   => '',
3650
+					'append_qstn_id' => false,
3651
+				]
3652
+			)
3653
+		);
3654
+		$template                             =
3655
+			REG_TEMPLATE_PATH . 'attendee_address_details_metabox_content.template.php';
3656
+		EEH_Template::display_template($template, $this->_template_args);
3657
+	}
3658
+
3659
+
3660
+	/**
3661
+	 * _attendee_details
3662
+	 *
3663
+	 * @param $post
3664
+	 * @return void
3665
+	 * @throws DomainException
3666
+	 * @throws EE_Error
3667
+	 * @throws InvalidArgumentException
3668
+	 * @throws InvalidDataTypeException
3669
+	 * @throws InvalidInterfaceException
3670
+	 * @throws ReflectionException
3671
+	 */
3672
+	public function attendee_registrations_meta_box($post)
3673
+	{
3674
+		$this->_template_args['attendee']      = $this->_cpt_model_obj;
3675
+		$this->_template_args['registrations'] = $this->_cpt_model_obj->get_many_related('Registration');
3676
+		$template                              =
3677
+			REG_TEMPLATE_PATH . 'attendee_registrations_main_meta_box.template.php';
3678
+		EEH_Template::display_template($template, $this->_template_args);
3679
+	}
3680
+
3681
+
3682
+	/**
3683
+	 * add in the form fields for the attendee edit
3684
+	 *
3685
+	 * @param WP_Post $post wp post object
3686
+	 * @return void echos html for new form.
3687
+	 * @throws DomainException
3688
+	 */
3689
+	public function after_title_form_fields($post)
3690
+	{
3691
+		if ($post->post_type === 'espresso_attendees') {
3692
+			$template                  = REG_TEMPLATE_PATH . 'attendee_details_after_title_form_fields.template.php';
3693
+			$template_args['attendee'] = $this->_cpt_model_obj;
3694
+			EEH_Template::display_template($template, $template_args);
3695
+		}
3696
+	}
3697
+
3698
+
3699
+	/**
3700
+	 * _trash_or_restore_attendee
3701
+	 *
3702
+	 * @param boolean $trash - whether to move item to trash (TRUE) or restore it (FALSE)
3703
+	 * @return void
3704
+	 * @throws EE_Error
3705
+	 * @throws InvalidArgumentException
3706
+	 * @throws InvalidDataTypeException
3707
+	 * @throws InvalidInterfaceException
3708
+	 */
3709
+	protected function _trash_or_restore_attendees($trash = true)
3710
+	{
3711
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3712
+		$status = $trash ? 'trash' : 'publish';
3713
+		// Checkboxes
3714
+		if ($this->request->requestParamIsSet('checkbox')) {
3715
+			$ATT_IDs = $this->request->getRequestParam('checkbox', [], 'int', true);
3716
+			// if array has more than one element than success message should be plural
3717
+			$success = count($ATT_IDs) > 1 ? 2 : 1;
3718
+			// cycle thru checkboxes
3719
+			foreach ($ATT_IDs as $ATT_ID) {
3720
+				$updated = $this->getAttendeeModel()->update_by_ID(['status' => $status], $ATT_ID);
3721
+				if (! $updated) {
3722
+					$success = 0;
3723
+				}
3724
+			}
3725
+		} else {
3726
+			// grab single id and delete
3727
+			$ATT_ID = $this->request->getRequestParam('ATT_ID', 0, 'int');
3728
+			// update attendee
3729
+			$success = $this->getAttendeeModel()->update_by_ID(['status' => $status], $ATT_ID) ? 1 : 0;
3730
+		}
3731
+		$what        = $success > 1
3732
+			? esc_html__('Contacts', 'event_espresso')
3733
+			: esc_html__('Contact', 'event_espresso');
3734
+		$action_desc = $trash
3735
+			? esc_html__('moved to the trash', 'event_espresso')
3736
+			: esc_html__('restored', 'event_espresso');
3737
+		$this->_redirect_after_action($success, $what, $action_desc, ['action' => 'contact_list']);
3738
+	}
3739 3739
 }
Please login to merge, or discard this patch.