Completed
Branch apply-extra-txn-fees-to-regs (69a605)
by
unknown
03:37 queued 13s
created
core/db_classes/EE_Registration.class.php 1 patch
Indentation   +2509 added lines, -2509 removed lines patch added patch discarded remove patch
@@ -16,2513 +16,2513 @@
 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
-     * calculate the amount remaining for this registration and return;
1348
-     *
1349
-     * @return float amount remaining
1350
-     * @throws EE_Error
1351
-     */
1352
-    public function remaining()
1353
-    {
1354
-        return $this->final_price() - $this->paid();
1355
-    }
1356
-
1357
-
1358
-    /**
1359
-     * owes_monies_and_can_pay
1360
-     * whether or not this registration has monies owing and it's' status allows payment
1361
-     * will also return true if this is the primary registrant and there are monies owing on the TXN
1362
-     *
1363
-     * @param array $requires_payment
1364
-     * @return bool
1365
-     * @throws EE_Error
1366
-     * @throws ReflectionException
1367
-     */
1368
-    public function owes_monies_and_can_pay($requires_payment = array())
1369
-    {
1370
-        // these reg statuses require payment (if event is not free)
1371
-        $requires_payment = ! empty($requires_payment)
1372
-            ? $requires_payment
1373
-            : EEM_Registration::reg_statuses_that_allow_payment();
1374
-        // if this registration has a status that requires payment AND...
1375
-        return in_array($this->status_ID(), $requires_payment)
1376
-               && (
1377
-                   // ticket was not free and has not been fully paid for
1378
-                   ($this->final_price() > 0 && $this->remaining() > 0)
1379
-                   // OR this is the primary registrant and there are still monies owing on the TXN
1380
-                   || ($this->is_primary_registrant() && $this->transaction()->remaining() > 0)
1381
-               );
1382
-    }
1383
-
1384
-
1385
-    /**
1386
-     * Prints out the return value of $this->pretty_status()
1387
-     *
1388
-     * @param bool $show_icons
1389
-     * @return void
1390
-     * @throws EE_Error
1391
-     * @throws InvalidArgumentException
1392
-     * @throws InvalidDataTypeException
1393
-     * @throws InvalidInterfaceException
1394
-     * @throws ReflectionException
1395
-     */
1396
-    public function e_pretty_status($show_icons = false)
1397
-    {
1398
-        echo wp_kses($this->pretty_status($show_icons), AllowedTags::getAllowedTags());
1399
-    }
1400
-
1401
-
1402
-    /**
1403
-     * Returns a nice version of the status for displaying to customers
1404
-     *
1405
-     * @param bool $show_icons
1406
-     * @return string
1407
-     * @throws EE_Error
1408
-     * @throws InvalidArgumentException
1409
-     * @throws InvalidDataTypeException
1410
-     * @throws InvalidInterfaceException
1411
-     * @throws ReflectionException
1412
-     */
1413
-    public function pretty_status($show_icons = false)
1414
-    {
1415
-        $status = EEM_Status::instance()->localized_status(
1416
-            array($this->status_ID() => esc_html__('unknown', 'event_espresso')),
1417
-            false,
1418
-            'sentence'
1419
-        );
1420
-        $icon = '';
1421
-        switch ($this->status_ID()) {
1422
-            case EEM_Registration::status_id_approved:
1423
-                $icon = $show_icons
1424
-                    ? '<span class="dashicons dashicons-star-filled ee-icon-size-16 green-text"></span>'
1425
-                    : '';
1426
-                break;
1427
-            case EEM_Registration::status_id_pending_payment:
1428
-                $icon = $show_icons
1429
-                    ? '<span class="dashicons dashicons-star-half ee-icon-size-16 orange-text"></span>'
1430
-                    : '';
1431
-                break;
1432
-            case EEM_Registration::status_id_not_approved:
1433
-                $icon = $show_icons
1434
-                    ? '<span class="dashicons dashicons-marker ee-icon-size-16 orange-text"></span>'
1435
-                    : '';
1436
-                break;
1437
-            case EEM_Registration::status_id_cancelled:
1438
-                $icon = $show_icons
1439
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 lt-grey-text"></span>'
1440
-                    : '';
1441
-                break;
1442
-            case EEM_Registration::status_id_incomplete:
1443
-                $icon = $show_icons
1444
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 lt-orange-text"></span>'
1445
-                    : '';
1446
-                break;
1447
-            case EEM_Registration::status_id_declined:
1448
-                $icon = $show_icons
1449
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>'
1450
-                    : '';
1451
-                break;
1452
-            case EEM_Registration::status_id_wait_list:
1453
-                $icon = $show_icons
1454
-                    ? '<span class="dashicons dashicons-clipboard ee-icon-size-16 purple-text"></span>'
1455
-                    : '';
1456
-                break;
1457
-        }
1458
-        return $icon . $status[ $this->status_ID() ];
1459
-    }
1460
-
1461
-
1462
-    /**
1463
-     *        get Attendee Is Going
1464
-     */
1465
-    public function att_is_going()
1466
-    {
1467
-        return $this->get('REG_att_is_going');
1468
-    }
1469
-
1470
-
1471
-    /**
1472
-     * Gets related answers
1473
-     *
1474
-     * @param array $query_params @see
1475
-     *                            https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1476
-     * @return EE_Answer[]|EE_Base_Class[]
1477
-     * @throws EE_Error
1478
-     * @throws InvalidArgumentException
1479
-     * @throws InvalidDataTypeException
1480
-     * @throws InvalidInterfaceException
1481
-     * @throws ReflectionException
1482
-     */
1483
-    public function answers($query_params = null)
1484
-    {
1485
-        return $this->get_many_related('Answer', $query_params);
1486
-    }
1487
-
1488
-
1489
-    /**
1490
-     * Gets the registration's answer value to the specified question
1491
-     * (either the question's ID or a question object)
1492
-     *
1493
-     * @param EE_Question|int $question
1494
-     * @param bool            $pretty_value
1495
-     * @return array|string if pretty_value= true, the result will always be a string
1496
-     * (because the answer might be an array of answer values, so passing pretty_value=true
1497
-     * will convert it into some kind of string)
1498
-     * @throws EE_Error
1499
-     * @throws InvalidArgumentException
1500
-     * @throws InvalidDataTypeException
1501
-     * @throws InvalidInterfaceException
1502
-     */
1503
-    public function answer_value_to_question($question, $pretty_value = true)
1504
-    {
1505
-        $question_id = EEM_Question::instance()->ensure_is_ID($question);
1506
-        return EEM_Answer::instance()->get_answer_value_to_question($this, $question_id, $pretty_value);
1507
-    }
1508
-
1509
-
1510
-    /**
1511
-     * question_groups
1512
-     * returns an array of EE_Question_Group objects for this registration
1513
-     *
1514
-     * @return EE_Question_Group[]
1515
-     * @throws EE_Error
1516
-     * @throws InvalidArgumentException
1517
-     * @throws InvalidDataTypeException
1518
-     * @throws InvalidInterfaceException
1519
-     * @throws ReflectionException
1520
-     */
1521
-    public function question_groups()
1522
-    {
1523
-        return EEM_Event::instance()->get_question_groups_for_event($this->event_ID(), $this);
1524
-    }
1525
-
1526
-
1527
-    /**
1528
-     * count_question_groups
1529
-     * returns a count of the number of EE_Question_Group objects for this registration
1530
-     *
1531
-     * @return int
1532
-     * @throws EE_Error
1533
-     * @throws EntityNotFoundException
1534
-     * @throws InvalidArgumentException
1535
-     * @throws InvalidDataTypeException
1536
-     * @throws InvalidInterfaceException
1537
-     * @throws ReflectionException
1538
-     */
1539
-    public function count_question_groups()
1540
-    {
1541
-        return EEM_Event::instance()->count_related(
1542
-            $this->event_ID(),
1543
-            'Question_Group',
1544
-            [
1545
-                [
1546
-                    'Event_Question_Group.'
1547
-                    . EEM_Event_Question_Group::instance()->fieldNameForContext($this->is_primary_registrant()) => true,
1548
-                ]
1549
-            ]
1550
-        );
1551
-    }
1552
-
1553
-
1554
-    /**
1555
-     * Returns the registration date in the 'standard' string format
1556
-     * (function may be improved in the future to allow for different formats and timezones)
1557
-     *
1558
-     * @return string
1559
-     * @throws EE_Error
1560
-     * @throws InvalidArgumentException
1561
-     * @throws InvalidDataTypeException
1562
-     * @throws InvalidInterfaceException
1563
-     * @throws ReflectionException
1564
-     */
1565
-    public function reg_date()
1566
-    {
1567
-        return $this->get_datetime('REG_date');
1568
-    }
1569
-
1570
-
1571
-    /**
1572
-     * Gets the datetime-ticket for this registration (ie, it can be used to isolate
1573
-     * the ticket this registration purchased, or the datetime they have registered
1574
-     * to attend)
1575
-     *
1576
-     * @return EE_Base_Class|EE_Datetime_Ticket
1577
-     * @throws EE_Error
1578
-     * @throws InvalidArgumentException
1579
-     * @throws InvalidDataTypeException
1580
-     * @throws InvalidInterfaceException
1581
-     * @throws ReflectionException
1582
-     */
1583
-    public function datetime_ticket()
1584
-    {
1585
-        return $this->get_first_related('Datetime_Ticket');
1586
-    }
1587
-
1588
-
1589
-    /**
1590
-     * Sets the registration's datetime_ticket.
1591
-     *
1592
-     * @param EE_Datetime_Ticket $datetime_ticket
1593
-     * @return EE_Base_Class|EE_Datetime_Ticket
1594
-     * @throws EE_Error
1595
-     * @throws InvalidArgumentException
1596
-     * @throws InvalidDataTypeException
1597
-     * @throws InvalidInterfaceException
1598
-     * @throws ReflectionException
1599
-     */
1600
-    public function set_datetime_ticket($datetime_ticket)
1601
-    {
1602
-        return $this->_add_relation_to($datetime_ticket, 'Datetime_Ticket');
1603
-    }
1604
-
1605
-
1606
-    /**
1607
-     * Gets deleted
1608
-     *
1609
-     * @return bool
1610
-     * @throws EE_Error
1611
-     * @throws InvalidArgumentException
1612
-     * @throws InvalidDataTypeException
1613
-     * @throws InvalidInterfaceException
1614
-     * @throws ReflectionException
1615
-     */
1616
-    public function deleted()
1617
-    {
1618
-        return $this->get('REG_deleted');
1619
-    }
1620
-
1621
-
1622
-    /**
1623
-     * Sets deleted
1624
-     *
1625
-     * @param boolean $deleted
1626
-     * @return void
1627
-     * @throws DomainException
1628
-     * @throws EE_Error
1629
-     * @throws EntityNotFoundException
1630
-     * @throws InvalidArgumentException
1631
-     * @throws InvalidDataTypeException
1632
-     * @throws InvalidInterfaceException
1633
-     * @throws ReflectionException
1634
-     * @throws RuntimeException
1635
-     * @throws UnexpectedEntityException
1636
-     */
1637
-    public function set_deleted($deleted)
1638
-    {
1639
-        if ($deleted) {
1640
-            $this->delete();
1641
-        } else {
1642
-            $this->restore();
1643
-        }
1644
-    }
1645
-
1646
-
1647
-    /**
1648
-     * Get the status object of this object
1649
-     *
1650
-     * @return EE_Base_Class|EE_Status
1651
-     * @throws EE_Error
1652
-     * @throws InvalidArgumentException
1653
-     * @throws InvalidDataTypeException
1654
-     * @throws InvalidInterfaceException
1655
-     * @throws ReflectionException
1656
-     */
1657
-    public function status_obj()
1658
-    {
1659
-        return $this->get_first_related('Status');
1660
-    }
1661
-
1662
-
1663
-    /**
1664
-     * Returns the number of times this registration has checked into any of the datetimes
1665
-     * its available for
1666
-     *
1667
-     * @return int
1668
-     * @throws EE_Error
1669
-     * @throws InvalidArgumentException
1670
-     * @throws InvalidDataTypeException
1671
-     * @throws InvalidInterfaceException
1672
-     * @throws ReflectionException
1673
-     */
1674
-    public function count_checkins()
1675
-    {
1676
-        return $this->get_model()->count_related($this, 'Checkin');
1677
-    }
1678
-
1679
-
1680
-    /**
1681
-     * Returns the number of current Check-ins this registration is checked into for any of the datetimes the
1682
-     * registration is for.  Note, this is ONLY checked in (does not include checkedout)
1683
-     *
1684
-     * @return int
1685
-     * @throws EE_Error
1686
-     * @throws InvalidArgumentException
1687
-     * @throws InvalidDataTypeException
1688
-     * @throws InvalidInterfaceException
1689
-     * @throws ReflectionException
1690
-     */
1691
-    public function count_checkins_not_checkedout()
1692
-    {
1693
-        return $this->get_model()->count_related($this, 'Checkin', array(array('CHK_in' => 1)));
1694
-    }
1695
-
1696
-
1697
-    /**
1698
-     * The purpose of this method is simply to check whether this registration can checkin to the given datetime.
1699
-     *
1700
-     * @param int | EE_Datetime $DTT_OR_ID      The datetime the registration is being checked against
1701
-     * @param bool              $check_approved This is used to indicate whether the caller wants can_checkin to also
1702
-     *                                          consider registration status as well as datetime access.
1703
-     * @return bool
1704
-     * @throws EE_Error
1705
-     * @throws InvalidArgumentException
1706
-     * @throws InvalidDataTypeException
1707
-     * @throws InvalidInterfaceException
1708
-     * @throws ReflectionException
1709
-     */
1710
-    public function can_checkin($DTT_OR_ID, $check_approved = true)
1711
-    {
1712
-        $DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1713
-        // first check registration status
1714
-        if (! $DTT_ID || ($check_approved && ! $this->is_approved())) {
1715
-            return false;
1716
-        }
1717
-        // is there a datetime ticket that matches this dtt_ID?
1718
-        if (
1719
-            ! (EEM_Datetime_Ticket::instance()->exists(
1720
-                array(
1721
-                    array(
1722
-                        'TKT_ID' => $this->get('TKT_ID'),
1723
-                        'DTT_ID' => $DTT_ID,
1724
-                    ),
1725
-                )
1726
-            ))
1727
-        ) {
1728
-            return false;
1729
-        }
1730
-
1731
-        // final check is against TKT_uses
1732
-        return $this->verify_can_checkin_against_TKT_uses($DTT_ID);
1733
-    }
1734
-
1735
-
1736
-    /**
1737
-     * This method verifies whether the user can checkin for the given datetime considering the max uses value set on
1738
-     * the ticket. To do this,  a query is done to get the count of the datetime records already checked into.  If the
1739
-     * datetime given does not have a check-in record and checking in for that datetime will exceed the allowed uses,
1740
-     * then return false.  Otherwise return true.
1741
-     *
1742
-     * @param int | EE_Datetime $DTT_OR_ID The datetime the registration is being checked against
1743
-     * @return bool true means can checkin.  false means cannot checkin.
1744
-     * @throws EE_Error
1745
-     * @throws InvalidArgumentException
1746
-     * @throws InvalidDataTypeException
1747
-     * @throws InvalidInterfaceException
1748
-     * @throws ReflectionException
1749
-     */
1750
-    public function verify_can_checkin_against_TKT_uses($DTT_OR_ID)
1751
-    {
1752
-        $DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1753
-
1754
-        if (! $DTT_ID) {
1755
-            return false;
1756
-        }
1757
-
1758
-        $max_uses = $this->ticket() instanceof EE_Ticket ? $this->ticket()->uses() : EE_INF;
1759
-
1760
-        // if max uses is not set or equals infinity then return true cause its not a factor for whether user can
1761
-        // check-in or not.
1762
-        if (! $max_uses || $max_uses === EE_INF) {
1763
-            return true;
1764
-        }
1765
-
1766
-        // does this datetime have a checkin record?  If so, then the dtt count has already been verified so we can just
1767
-        // go ahead and toggle.
1768
-        if (EEM_Checkin::instance()->exists(array(array('REG_ID' => $this->ID(), 'DTT_ID' => $DTT_ID)))) {
1769
-            return true;
1770
-        }
1771
-
1772
-        // made it here so the last check is whether the number of checkins per unique datetime on this registration
1773
-        // disallows further check-ins.
1774
-        $count_unique_dtt_checkins = EEM_Checkin::instance()->count(
1775
-            array(
1776
-                array(
1777
-                    'REG_ID' => $this->ID(),
1778
-                    'CHK_in' => true,
1779
-                ),
1780
-            ),
1781
-            'DTT_ID',
1782
-            true
1783
-        );
1784
-        // checkins have already reached their max number of uses
1785
-        // so registrant can NOT checkin
1786
-        if ($count_unique_dtt_checkins >= $max_uses) {
1787
-            EE_Error::add_error(
1788
-                esc_html__(
1789
-                    'Check-in denied because number of datetime uses for the ticket has been reached or exceeded.',
1790
-                    'event_espresso'
1791
-                ),
1792
-                __FILE__,
1793
-                __FUNCTION__,
1794
-                __LINE__
1795
-            );
1796
-            return false;
1797
-        }
1798
-        return true;
1799
-    }
1800
-
1801
-
1802
-    /**
1803
-     * toggle Check-in status for this registration
1804
-     * Check-ins are toggled in the following order:
1805
-     * never checked in -> checked in
1806
-     * checked in -> checked out
1807
-     * checked out -> checked in
1808
-     *
1809
-     * @param  int $DTT_ID  include specific datetime to toggle Check-in for.
1810
-     *                      If not included or null, then it is assumed latest datetime is being toggled.
1811
-     * @param bool $verify  If true then can_checkin() is used to verify whether the person
1812
-     *                      can be checked in or not.  Otherwise this forces change in checkin status.
1813
-     * @return bool|int     the chk_in status toggled to OR false if nothing got changed.
1814
-     * @throws EE_Error
1815
-     * @throws InvalidArgumentException
1816
-     * @throws InvalidDataTypeException
1817
-     * @throws InvalidInterfaceException
1818
-     * @throws ReflectionException
1819
-     */
1820
-    public function toggle_checkin_status($DTT_ID = null, $verify = false)
1821
-    {
1822
-        if (empty($DTT_ID)) {
1823
-            $datetime = $this->get_latest_related_datetime();
1824
-            $DTT_ID = $datetime instanceof EE_Datetime ? $datetime->ID() : 0;
1825
-            // verify the registration can checkin for the given DTT_ID
1826
-        } elseif (! $this->can_checkin($DTT_ID, $verify)) {
1827
-            EE_Error::add_error(
1828
-                sprintf(
1829
-                    esc_html__(
1830
-                        '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',
1831
-                        'event_espresso'
1832
-                    ),
1833
-                    $this->ID(),
1834
-                    $DTT_ID
1835
-                ),
1836
-                __FILE__,
1837
-                __FUNCTION__,
1838
-                __LINE__
1839
-            );
1840
-            return false;
1841
-        }
1842
-        $status_paths = array(
1843
-            EE_Checkin::status_checked_never => EE_Checkin::status_checked_in,
1844
-            EE_Checkin::status_checked_in    => EE_Checkin::status_checked_out,
1845
-            EE_Checkin::status_checked_out   => EE_Checkin::status_checked_in,
1846
-        );
1847
-        // start by getting the current status so we know what status we'll be changing to.
1848
-        $cur_status = $this->check_in_status_for_datetime($DTT_ID);
1849
-        $status_to = $status_paths[ $cur_status ];
1850
-        // database only records true for checked IN or false for checked OUT
1851
-        // no record ( null ) means checked in NEVER, but we obviously don't save that
1852
-        $new_status = $status_to === EE_Checkin::status_checked_in;
1853
-        // add relation - note Check-ins are always creating new rows
1854
-        // because we are keeping track of Check-ins over time.
1855
-        // Eventually we'll probably want to show a list table
1856
-        // for the individual Check-ins so that they can be managed.
1857
-        $checkin = EE_Checkin::new_instance(
1858
-            array(
1859
-                'REG_ID' => $this->ID(),
1860
-                'DTT_ID' => $DTT_ID,
1861
-                'CHK_in' => $new_status,
1862
-            )
1863
-        );
1864
-        // if the record could not be saved then return false
1865
-        if ($checkin->save() === 0) {
1866
-            if (WP_DEBUG) {
1867
-                global $wpdb;
1868
-                $error = sprintf(
1869
-                    esc_html__(
1870
-                        'Registration check in update failed because of the following database error: %1$s%2$s',
1871
-                        'event_espresso'
1872
-                    ),
1873
-                    '<br />',
1874
-                    $wpdb->last_error
1875
-                );
1876
-            } else {
1877
-                $error = esc_html__(
1878
-                    'Registration check in update failed because of an unknown database error',
1879
-                    'event_espresso'
1880
-                );
1881
-            }
1882
-            EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
1883
-            return false;
1884
-        }
1885
-        // Fire a checked_in and checkout_out action.
1886
-        $checked_status = $status_to === EE_Checkin::status_checked_in ? 'checked_in' : 'checked_out';
1887
-        do_action("AHEE__EE_Registration__toggle_checkin_status__{$checked_status}", $this, $DTT_ID);
1888
-        return $status_to;
1889
-    }
1890
-
1891
-
1892
-    /**
1893
-     * Returns the latest datetime related to this registration (via the ticket attached to the registration).
1894
-     * "Latest" is defined by the `DTT_EVT_start` column.
1895
-     *
1896
-     * @return EE_Datetime|null
1897
-     * @throws EE_Error
1898
-     * @throws InvalidArgumentException
1899
-     * @throws InvalidDataTypeException
1900
-     * @throws InvalidInterfaceException
1901
-     * @throws ReflectionException
1902
-     */
1903
-    public function get_latest_related_datetime()
1904
-    {
1905
-        return EEM_Datetime::instance()->get_one(
1906
-            array(
1907
-                array(
1908
-                    'Ticket.Registration.REG_ID' => $this->ID(),
1909
-                ),
1910
-                'order_by' => array('DTT_EVT_start' => 'DESC'),
1911
-            )
1912
-        );
1913
-    }
1914
-
1915
-
1916
-    /**
1917
-     * Returns the earliest datetime related to this registration (via the ticket attached to the registration).
1918
-     * "Earliest" is defined by the `DTT_EVT_start` column.
1919
-     *
1920
-     * @return EE_Base_Class|EE_Soft_Delete_Base_Class|NULL
1921
-     * @throws EE_Error
1922
-     * @throws InvalidArgumentException
1923
-     * @throws InvalidDataTypeException
1924
-     * @throws InvalidInterfaceException
1925
-     * @throws ReflectionException
1926
-     */
1927
-    public function get_earliest_related_datetime()
1928
-    {
1929
-        return EEM_Datetime::instance()->get_one(
1930
-            array(
1931
-                array(
1932
-                    'Ticket.Registration.REG_ID' => $this->ID(),
1933
-                ),
1934
-                'order_by' => array('DTT_EVT_start' => 'ASC'),
1935
-            )
1936
-        );
1937
-    }
1938
-
1939
-
1940
-    /**
1941
-     * This method simply returns the check-in status for this registration and the given datetime.
1942
-     * If neither the datetime nor the checkin values are provided as arguments,
1943
-     * then this will return the LATEST check-in status for the registration across all datetimes it belongs to.
1944
-     *
1945
-     * @param  int       $DTT_ID  The ID of the datetime we're checking against
1946
-     *                            (if empty we'll get the primary datetime for
1947
-     *                            this registration (via event) and use it's ID);
1948
-     * @param EE_Checkin $checkin If present, we use the given checkin object rather than the dtt_id.
1949
-     * @return int                Integer representing Check-in status.
1950
-     * @throws EE_Error
1951
-     * @throws InvalidArgumentException
1952
-     * @throws InvalidDataTypeException
1953
-     * @throws InvalidInterfaceException
1954
-     * @throws ReflectionException
1955
-     */
1956
-    public function check_in_status_for_datetime($DTT_ID = 0, $checkin = null)
1957
-    {
1958
-        $checkin_query_params = array(
1959
-            'order_by' => array('CHK_timestamp' => 'DESC'),
1960
-        );
1961
-
1962
-        if ($DTT_ID > 0) {
1963
-            $checkin_query_params[0] = array('DTT_ID' => $DTT_ID);
1964
-        }
1965
-
1966
-        // get checkin object (if exists)
1967
-        $checkin = $checkin instanceof EE_Checkin
1968
-            ? $checkin
1969
-            : $this->get_first_related('Checkin', $checkin_query_params);
1970
-        if ($checkin instanceof EE_Checkin) {
1971
-            if ($checkin->get('CHK_in')) {
1972
-                return EE_Checkin::status_checked_in; // checked in
1973
-            }
1974
-            return EE_Checkin::status_checked_out; // had checked in but is now checked out.
1975
-        }
1976
-        return EE_Checkin::status_checked_never; // never been checked in
1977
-    }
1978
-
1979
-
1980
-    /**
1981
-     * This method returns a localized message for the toggled Check-in message.
1982
-     *
1983
-     * @param  int $DTT_ID include specific datetime to get the correct Check-in message.  If not included or null,
1984
-     *                     then it is assumed Check-in for primary datetime was toggled.
1985
-     * @param bool $error  This just flags that you want an error message returned. This is put in so that the error
1986
-     *                     message can be customized with the attendee name.
1987
-     * @return string internationalized message
1988
-     * @throws EE_Error
1989
-     * @throws InvalidArgumentException
1990
-     * @throws InvalidDataTypeException
1991
-     * @throws InvalidInterfaceException
1992
-     * @throws ReflectionException
1993
-     */
1994
-    public function get_checkin_msg($DTT_ID, $error = false)
1995
-    {
1996
-        // let's get the attendee first so we can include the name of the attendee
1997
-        $attendee = $this->get_first_related('Attendee');
1998
-        if ($attendee instanceof EE_Attendee) {
1999
-            if ($error) {
2000
-                return sprintf(
2001
-                    esc_html__("%s's check-in status was not changed.", "event_espresso"),
2002
-                    $attendee->full_name()
2003
-                );
2004
-            }
2005
-            $cur_status = $this->check_in_status_for_datetime($DTT_ID);
2006
-            // what is the status message going to be?
2007
-            switch ($cur_status) {
2008
-                case EE_Checkin::status_checked_never:
2009
-                    return sprintf(
2010
-                        esc_html__('%s has been removed from Check-in records', 'event_espresso'),
2011
-                        $attendee->full_name()
2012
-                    );
2013
-                    break;
2014
-                case EE_Checkin::status_checked_in:
2015
-                    return sprintf(esc_html__('%s has been checked in', 'event_espresso'), $attendee->full_name());
2016
-                    break;
2017
-                case EE_Checkin::status_checked_out:
2018
-                    return sprintf(esc_html__('%s has been checked out', 'event_espresso'), $attendee->full_name());
2019
-                    break;
2020
-            }
2021
-        }
2022
-        return esc_html__('The check-in status could not be determined.', 'event_espresso');
2023
-    }
2024
-
2025
-
2026
-    /**
2027
-     * Returns the related EE_Transaction to this registration
2028
-     *
2029
-     * @return EE_Transaction
2030
-     * @throws EE_Error
2031
-     * @throws EntityNotFoundException
2032
-     * @throws InvalidArgumentException
2033
-     * @throws InvalidDataTypeException
2034
-     * @throws InvalidInterfaceException
2035
-     * @throws ReflectionException
2036
-     */
2037
-    public function transaction()
2038
-    {
2039
-        $transaction = $this->get_first_related('Transaction');
2040
-        if (! $transaction instanceof \EE_Transaction) {
2041
-            throw new EntityNotFoundException('Transaction ID', $this->transaction_ID());
2042
-        }
2043
-        return $transaction;
2044
-    }
2045
-
2046
-
2047
-    /**
2048
-     * get Registration Code
2049
-     *
2050
-     * @return mixed
2051
-     * @throws EE_Error
2052
-     * @throws InvalidArgumentException
2053
-     * @throws InvalidDataTypeException
2054
-     * @throws InvalidInterfaceException
2055
-     * @throws ReflectionException
2056
-     */
2057
-    public function reg_code()
2058
-    {
2059
-        return $this->get('REG_code');
2060
-    }
2061
-
2062
-
2063
-    /**
2064
-     * @return mixed
2065
-     * @throws EE_Error
2066
-     * @throws InvalidArgumentException
2067
-     * @throws InvalidDataTypeException
2068
-     * @throws InvalidInterfaceException
2069
-     * @throws ReflectionException
2070
-     */
2071
-    public function transaction_ID()
2072
-    {
2073
-        return $this->get('TXN_ID');
2074
-    }
2075
-
2076
-
2077
-    /**
2078
-     * @return int
2079
-     * @throws EE_Error
2080
-     * @throws InvalidArgumentException
2081
-     * @throws InvalidDataTypeException
2082
-     * @throws InvalidInterfaceException
2083
-     * @throws ReflectionException
2084
-     */
2085
-    public function ticket_ID()
2086
-    {
2087
-        return $this->get('TKT_ID');
2088
-    }
2089
-
2090
-
2091
-    /**
2092
-     * Set Registration Code
2093
-     *
2094
-     * @param    string  $REG_code Registration Code
2095
-     * @param    boolean $use_default
2096
-     * @throws EE_Error
2097
-     * @throws InvalidArgumentException
2098
-     * @throws InvalidDataTypeException
2099
-     * @throws InvalidInterfaceException
2100
-     * @throws ReflectionException
2101
-     */
2102
-    public function set_reg_code($REG_code, $use_default = false)
2103
-    {
2104
-        if (empty($REG_code)) {
2105
-            EE_Error::add_error(
2106
-                esc_html__('REG_code can not be empty.', 'event_espresso'),
2107
-                __FILE__,
2108
-                __FUNCTION__,
2109
-                __LINE__
2110
-            );
2111
-            return;
2112
-        }
2113
-        if (! $this->reg_code()) {
2114
-            parent::set('REG_code', $REG_code, $use_default);
2115
-        } else {
2116
-            EE_Error::doing_it_wrong(
2117
-                __CLASS__ . '::' . __FUNCTION__,
2118
-                esc_html__('Can not change a registration REG_code once it has been set.', 'event_espresso'),
2119
-                '4.6.0'
2120
-            );
2121
-        }
2122
-    }
2123
-
2124
-
2125
-    /**
2126
-     * Returns all other registrations in the same group as this registrant who have the same ticket option.
2127
-     * Note, if you want to just get all registrations in the same transaction (group), use:
2128
-     *    $registration->transaction()->registrations();
2129
-     *
2130
-     * @since 4.5.0
2131
-     * @return EE_Registration[] or empty array if this isn't a group registration.
2132
-     * @throws EE_Error
2133
-     * @throws InvalidArgumentException
2134
-     * @throws InvalidDataTypeException
2135
-     * @throws InvalidInterfaceException
2136
-     * @throws ReflectionException
2137
-     */
2138
-    public function get_all_other_registrations_in_group()
2139
-    {
2140
-        if ($this->group_size() < 2) {
2141
-            return array();
2142
-        }
2143
-
2144
-        $query[0] = array(
2145
-            'TXN_ID' => $this->transaction_ID(),
2146
-            'REG_ID' => array('!=', $this->ID()),
2147
-            'TKT_ID' => $this->ticket_ID(),
2148
-        );
2149
-        /** @var EE_Registration[] $registrations */
2150
-        $registrations = $this->get_model()->get_all($query);
2151
-        return $registrations;
2152
-    }
2153
-
2154
-
2155
-    /**
2156
-     * Return the link to the admin details for the object.
2157
-     *
2158
-     * @return string
2159
-     * @throws EE_Error
2160
-     * @throws InvalidArgumentException
2161
-     * @throws InvalidDataTypeException
2162
-     * @throws InvalidInterfaceException
2163
-     * @throws ReflectionException
2164
-     */
2165
-    public function get_admin_details_link()
2166
-    {
2167
-        EE_Registry::instance()->load_helper('URL');
2168
-        return EEH_URL::add_query_args_and_nonce(
2169
-            array(
2170
-                'page'    => 'espresso_registrations',
2171
-                'action'  => 'view_registration',
2172
-                '_REG_ID' => $this->ID(),
2173
-            ),
2174
-            admin_url('admin.php')
2175
-        );
2176
-    }
2177
-
2178
-
2179
-    /**
2180
-     * Returns the link to the editor for the object.  Sometimes this is the same as the details.
2181
-     *
2182
-     * @return string
2183
-     * @throws EE_Error
2184
-     * @throws InvalidArgumentException
2185
-     * @throws InvalidDataTypeException
2186
-     * @throws InvalidInterfaceException
2187
-     * @throws ReflectionException
2188
-     */
2189
-    public function get_admin_edit_link()
2190
-    {
2191
-        return $this->get_admin_details_link();
2192
-    }
2193
-
2194
-
2195
-    /**
2196
-     * Returns the link to a settings page for the object.
2197
-     *
2198
-     * @return string
2199
-     * @throws EE_Error
2200
-     * @throws InvalidArgumentException
2201
-     * @throws InvalidDataTypeException
2202
-     * @throws InvalidInterfaceException
2203
-     * @throws ReflectionException
2204
-     */
2205
-    public function get_admin_settings_link()
2206
-    {
2207
-        return $this->get_admin_details_link();
2208
-    }
2209
-
2210
-
2211
-    /**
2212
-     * Returns the link to the "overview" for the object (typically the "list table" view).
2213
-     *
2214
-     * @return string
2215
-     * @throws EE_Error
2216
-     * @throws InvalidArgumentException
2217
-     * @throws InvalidDataTypeException
2218
-     * @throws InvalidInterfaceException
2219
-     * @throws ReflectionException
2220
-     */
2221
-    public function get_admin_overview_link()
2222
-    {
2223
-        EE_Registry::instance()->load_helper('URL');
2224
-        return EEH_URL::add_query_args_and_nonce(
2225
-            array(
2226
-                'page' => 'espresso_registrations',
2227
-            ),
2228
-            admin_url('admin.php')
2229
-        );
2230
-    }
2231
-
2232
-
2233
-    /**
2234
-     * @param array $query_params
2235
-     * @return EE_Base_Class[]|EE_Registration[]
2236
-     * @throws EE_Error
2237
-     * @throws InvalidArgumentException
2238
-     * @throws InvalidDataTypeException
2239
-     * @throws InvalidInterfaceException
2240
-     * @throws ReflectionException
2241
-     */
2242
-    public function payments($query_params = array())
2243
-    {
2244
-        return $this->get_many_related('Payment', $query_params);
2245
-    }
2246
-
2247
-
2248
-    /**
2249
-     * @param array $query_params
2250
-     * @return EE_Base_Class[]|EE_Registration_Payment[]
2251
-     * @throws EE_Error
2252
-     * @throws InvalidArgumentException
2253
-     * @throws InvalidDataTypeException
2254
-     * @throws InvalidInterfaceException
2255
-     * @throws ReflectionException
2256
-     */
2257
-    public function registration_payments($query_params = array())
2258
-    {
2259
-        return $this->get_many_related('Registration_Payment', $query_params);
2260
-    }
2261
-
2262
-
2263
-    /**
2264
-     * This grabs the payment method corresponding to the last payment made for the amount owing on the registration.
2265
-     * Note: if there are no payments on the registration there will be no payment method returned.
2266
-     *
2267
-     * @return EE_Payment|EE_Payment_Method|null
2268
-     * @throws EE_Error
2269
-     * @throws InvalidArgumentException
2270
-     * @throws InvalidDataTypeException
2271
-     * @throws InvalidInterfaceException
2272
-     */
2273
-    public function payment_method()
2274
-    {
2275
-        return EEM_Payment_Method::instance()->get_last_used_for_registration($this);
2276
-    }
2277
-
2278
-
2279
-    /**
2280
-     * @return \EE_Line_Item
2281
-     * @throws EE_Error
2282
-     * @throws EntityNotFoundException
2283
-     * @throws InvalidArgumentException
2284
-     * @throws InvalidDataTypeException
2285
-     * @throws InvalidInterfaceException
2286
-     * @throws ReflectionException
2287
-     */
2288
-    public function ticket_line_item()
2289
-    {
2290
-        $ticket = $this->ticket();
2291
-        $transaction = $this->transaction();
2292
-        $line_item = null;
2293
-        $ticket_line_items = \EEH_Line_Item::get_line_items_by_object_type_and_IDs(
2294
-            $transaction->total_line_item(),
2295
-            'Ticket',
2296
-            array($ticket->ID())
2297
-        );
2298
-        foreach ($ticket_line_items as $ticket_line_item) {
2299
-            if (
2300
-                $ticket_line_item instanceof \EE_Line_Item
2301
-                && $ticket_line_item->OBJ_type() === 'Ticket'
2302
-                && $ticket_line_item->OBJ_ID() === $ticket->ID()
2303
-            ) {
2304
-                $line_item = $ticket_line_item;
2305
-                break;
2306
-            }
2307
-        }
2308
-        if (! ($line_item instanceof \EE_Line_Item && $line_item->OBJ_type() === 'Ticket')) {
2309
-            throw new EntityNotFoundException('Line Item Ticket ID', $ticket->ID());
2310
-        }
2311
-        return $line_item;
2312
-    }
2313
-
2314
-
2315
-    /**
2316
-     * Soft Deletes this model object.
2317
-     *
2318
-     * @param string $source function name that called this method
2319
-     * @return boolean | int
2320
-     * @throws DomainException
2321
-     * @throws EE_Error
2322
-     * @throws EntityNotFoundException
2323
-     * @throws InvalidArgumentException
2324
-     * @throws InvalidDataTypeException
2325
-     * @throws InvalidInterfaceException
2326
-     * @throws ReflectionException
2327
-     * @throws RuntimeException
2328
-     * @throws UnexpectedEntityException
2329
-     */
2330
-    public function delete()
2331
-    {
2332
-        if ($this->update_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY, $this->status_ID()) === true) {
2333
-            $this->set_status(EEM_Registration::status_id_cancelled);
2334
-        }
2335
-        return parent::delete();
2336
-    }
2337
-
2338
-
2339
-    /**
2340
-     * Restores whatever the previous status was on a registration before it was trashed (if possible)
2341
-     *
2342
-     * @param string $source function name that called this method
2343
-     * @return bool|int
2344
-     * @throws DomainException
2345
-     * @throws EE_Error
2346
-     * @throws EntityNotFoundException
2347
-     * @throws InvalidArgumentException
2348
-     * @throws InvalidDataTypeException
2349
-     * @throws InvalidInterfaceException
2350
-     * @throws ReflectionException
2351
-     * @throws RuntimeException
2352
-     * @throws UnexpectedEntityException
2353
-     */
2354
-    public function restore()
2355
-    {
2356
-        $previous_status = $this->get_extra_meta(
2357
-            EE_Registration::PRE_TRASH_REG_STATUS_KEY,
2358
-            true,
2359
-            EEM_Registration::status_id_cancelled
2360
-        );
2361
-        if ($previous_status) {
2362
-            $this->delete_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY);
2363
-            $this->set_status($previous_status);
2364
-        }
2365
-        return parent::restore();
2366
-    }
2367
-
2368
-
2369
-    /**
2370
-     * possibly toggle Registration status based on comparison of REG_paid vs REG_final_price
2371
-     *
2372
-     * @param  boolean $trigger_set_status_logic EE_Registration::set_status() can trigger additional logic
2373
-     *                                           depending on whether the reg status changes to or from "Approved"
2374
-     * @return boolean whether the Registration status was updated
2375
-     * @throws DomainException
2376
-     * @throws EE_Error
2377
-     * @throws EntityNotFoundException
2378
-     * @throws InvalidArgumentException
2379
-     * @throws InvalidDataTypeException
2380
-     * @throws InvalidInterfaceException
2381
-     * @throws ReflectionException
2382
-     * @throws RuntimeException
2383
-     * @throws UnexpectedEntityException
2384
-     */
2385
-    public function updateStatusBasedOnTotalPaid($trigger_set_status_logic = true)
2386
-    {
2387
-        $paid = $this->paid();
2388
-        $price = $this->final_price();
2389
-        switch (true) {
2390
-            // overpaid or paid
2391
-            case EEH_Money::compare_floats($paid, $price, '>'):
2392
-            case EEH_Money::compare_floats($paid, $price):
2393
-                $new_status = EEM_Registration::status_id_approved;
2394
-                break;
2395
-            //  underpaid
2396
-            case EEH_Money::compare_floats($paid, $price, '<'):
2397
-                $new_status = EEM_Registration::status_id_pending_payment;
2398
-                break;
2399
-            // uhhh Houston...
2400
-            default:
2401
-                throw new RuntimeException(
2402
-                    esc_html__('The total paid calculation for this registration is inaccurate.', 'event_espresso')
2403
-                );
2404
-        }
2405
-        if ($new_status !== $this->status_ID()) {
2406
-            if ($trigger_set_status_logic) {
2407
-                return $this->set_status($new_status);
2408
-            }
2409
-            parent::set('STS_ID', $new_status);
2410
-            return true;
2411
-        }
2412
-        return false;
2413
-    }
2414
-
2415
-
2416
-    /*************************** DEPRECATED ***************************/
2417
-
2418
-
2419
-    /**
2420
-     * @deprecated
2421
-     * @since     4.7.0
2422
-     */
2423
-    public function price_paid()
2424
-    {
2425
-        EE_Error::doing_it_wrong(
2426
-            'EE_Registration::price_paid()',
2427
-            esc_html__(
2428
-                'This method is deprecated, please use EE_Registration::final_price() instead.',
2429
-                'event_espresso'
2430
-            ),
2431
-            '4.7.0'
2432
-        );
2433
-        return $this->final_price();
2434
-    }
2435
-
2436
-
2437
-    /**
2438
-     * @deprecated
2439
-     * @since     4.7.0
2440
-     * @param    float $REG_final_price
2441
-     * @throws EE_Error
2442
-     * @throws EntityNotFoundException
2443
-     * @throws InvalidArgumentException
2444
-     * @throws InvalidDataTypeException
2445
-     * @throws InvalidInterfaceException
2446
-     * @throws ReflectionException
2447
-     * @throws RuntimeException
2448
-     * @throws DomainException
2449
-     */
2450
-    public function set_price_paid($REG_final_price = 0.00)
2451
-    {
2452
-        EE_Error::doing_it_wrong(
2453
-            'EE_Registration::set_price_paid()',
2454
-            esc_html__(
2455
-                'This method is deprecated, please use EE_Registration::set_final_price() instead.',
2456
-                'event_espresso'
2457
-            ),
2458
-            '4.7.0'
2459
-        );
2460
-        $this->set_final_price($REG_final_price);
2461
-    }
2462
-
2463
-
2464
-    /**
2465
-     * @deprecated
2466
-     * @since 4.7.0
2467
-     * @return string
2468
-     * @throws EE_Error
2469
-     * @throws InvalidArgumentException
2470
-     * @throws InvalidDataTypeException
2471
-     * @throws InvalidInterfaceException
2472
-     * @throws ReflectionException
2473
-     */
2474
-    public function pretty_price_paid()
2475
-    {
2476
-        EE_Error::doing_it_wrong(
2477
-            'EE_Registration::pretty_price_paid()',
2478
-            esc_html__(
2479
-                'This method is deprecated, please use EE_Registration::pretty_final_price() instead.',
2480
-                'event_espresso'
2481
-            ),
2482
-            '4.7.0'
2483
-        );
2484
-        return $this->pretty_final_price();
2485
-    }
2486
-
2487
-
2488
-    /**
2489
-     * Gets the primary datetime related to this registration via the related Event to this registration
2490
-     *
2491
-     * @deprecated 4.9.17
2492
-     * @return EE_Datetime
2493
-     * @throws EE_Error
2494
-     * @throws EntityNotFoundException
2495
-     * @throws InvalidArgumentException
2496
-     * @throws InvalidDataTypeException
2497
-     * @throws InvalidInterfaceException
2498
-     * @throws ReflectionException
2499
-     */
2500
-    public function get_related_primary_datetime()
2501
-    {
2502
-        EE_Error::doing_it_wrong(
2503
-            __METHOD__,
2504
-            esc_html__(
2505
-                'Use EE_Registration::get_latest_related_datetime() or EE_Registration::get_earliest_related_datetime()',
2506
-                'event_espresso'
2507
-            ),
2508
-            '4.9.17',
2509
-            '5.0.0'
2510
-        );
2511
-        return $this->event()->primary_datetime();
2512
-    }
2513
-
2514
-    /**
2515
-     * Returns the contact's name (or "Unknown" if there is no contact.)
2516
-     * @since 4.10.12.p
2517
-     * @return string
2518
-     * @throws EE_Error
2519
-     * @throws InvalidArgumentException
2520
-     * @throws InvalidDataTypeException
2521
-     * @throws InvalidInterfaceException
2522
-     * @throws ReflectionException
2523
-     */
2524
-    public function name()
2525
-    {
2526
-        return $this->attendeeName();
2527
-    }
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
+	 * calculate the amount remaining for this registration and return;
1348
+	 *
1349
+	 * @return float amount remaining
1350
+	 * @throws EE_Error
1351
+	 */
1352
+	public function remaining()
1353
+	{
1354
+		return $this->final_price() - $this->paid();
1355
+	}
1356
+
1357
+
1358
+	/**
1359
+	 * owes_monies_and_can_pay
1360
+	 * whether or not this registration has monies owing and it's' status allows payment
1361
+	 * will also return true if this is the primary registrant and there are monies owing on the TXN
1362
+	 *
1363
+	 * @param array $requires_payment
1364
+	 * @return bool
1365
+	 * @throws EE_Error
1366
+	 * @throws ReflectionException
1367
+	 */
1368
+	public function owes_monies_and_can_pay($requires_payment = array())
1369
+	{
1370
+		// these reg statuses require payment (if event is not free)
1371
+		$requires_payment = ! empty($requires_payment)
1372
+			? $requires_payment
1373
+			: EEM_Registration::reg_statuses_that_allow_payment();
1374
+		// if this registration has a status that requires payment AND...
1375
+		return in_array($this->status_ID(), $requires_payment)
1376
+			   && (
1377
+				   // ticket was not free and has not been fully paid for
1378
+				   ($this->final_price() > 0 && $this->remaining() > 0)
1379
+				   // OR this is the primary registrant and there are still monies owing on the TXN
1380
+				   || ($this->is_primary_registrant() && $this->transaction()->remaining() > 0)
1381
+			   );
1382
+	}
1383
+
1384
+
1385
+	/**
1386
+	 * Prints out the return value of $this->pretty_status()
1387
+	 *
1388
+	 * @param bool $show_icons
1389
+	 * @return void
1390
+	 * @throws EE_Error
1391
+	 * @throws InvalidArgumentException
1392
+	 * @throws InvalidDataTypeException
1393
+	 * @throws InvalidInterfaceException
1394
+	 * @throws ReflectionException
1395
+	 */
1396
+	public function e_pretty_status($show_icons = false)
1397
+	{
1398
+		echo wp_kses($this->pretty_status($show_icons), AllowedTags::getAllowedTags());
1399
+	}
1400
+
1401
+
1402
+	/**
1403
+	 * Returns a nice version of the status for displaying to customers
1404
+	 *
1405
+	 * @param bool $show_icons
1406
+	 * @return string
1407
+	 * @throws EE_Error
1408
+	 * @throws InvalidArgumentException
1409
+	 * @throws InvalidDataTypeException
1410
+	 * @throws InvalidInterfaceException
1411
+	 * @throws ReflectionException
1412
+	 */
1413
+	public function pretty_status($show_icons = false)
1414
+	{
1415
+		$status = EEM_Status::instance()->localized_status(
1416
+			array($this->status_ID() => esc_html__('unknown', 'event_espresso')),
1417
+			false,
1418
+			'sentence'
1419
+		);
1420
+		$icon = '';
1421
+		switch ($this->status_ID()) {
1422
+			case EEM_Registration::status_id_approved:
1423
+				$icon = $show_icons
1424
+					? '<span class="dashicons dashicons-star-filled ee-icon-size-16 green-text"></span>'
1425
+					: '';
1426
+				break;
1427
+			case EEM_Registration::status_id_pending_payment:
1428
+				$icon = $show_icons
1429
+					? '<span class="dashicons dashicons-star-half ee-icon-size-16 orange-text"></span>'
1430
+					: '';
1431
+				break;
1432
+			case EEM_Registration::status_id_not_approved:
1433
+				$icon = $show_icons
1434
+					? '<span class="dashicons dashicons-marker ee-icon-size-16 orange-text"></span>'
1435
+					: '';
1436
+				break;
1437
+			case EEM_Registration::status_id_cancelled:
1438
+				$icon = $show_icons
1439
+					? '<span class="dashicons dashicons-no ee-icon-size-16 lt-grey-text"></span>'
1440
+					: '';
1441
+				break;
1442
+			case EEM_Registration::status_id_incomplete:
1443
+				$icon = $show_icons
1444
+					? '<span class="dashicons dashicons-no ee-icon-size-16 lt-orange-text"></span>'
1445
+					: '';
1446
+				break;
1447
+			case EEM_Registration::status_id_declined:
1448
+				$icon = $show_icons
1449
+					? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>'
1450
+					: '';
1451
+				break;
1452
+			case EEM_Registration::status_id_wait_list:
1453
+				$icon = $show_icons
1454
+					? '<span class="dashicons dashicons-clipboard ee-icon-size-16 purple-text"></span>'
1455
+					: '';
1456
+				break;
1457
+		}
1458
+		return $icon . $status[ $this->status_ID() ];
1459
+	}
1460
+
1461
+
1462
+	/**
1463
+	 *        get Attendee Is Going
1464
+	 */
1465
+	public function att_is_going()
1466
+	{
1467
+		return $this->get('REG_att_is_going');
1468
+	}
1469
+
1470
+
1471
+	/**
1472
+	 * Gets related answers
1473
+	 *
1474
+	 * @param array $query_params @see
1475
+	 *                            https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1476
+	 * @return EE_Answer[]|EE_Base_Class[]
1477
+	 * @throws EE_Error
1478
+	 * @throws InvalidArgumentException
1479
+	 * @throws InvalidDataTypeException
1480
+	 * @throws InvalidInterfaceException
1481
+	 * @throws ReflectionException
1482
+	 */
1483
+	public function answers($query_params = null)
1484
+	{
1485
+		return $this->get_many_related('Answer', $query_params);
1486
+	}
1487
+
1488
+
1489
+	/**
1490
+	 * Gets the registration's answer value to the specified question
1491
+	 * (either the question's ID or a question object)
1492
+	 *
1493
+	 * @param EE_Question|int $question
1494
+	 * @param bool            $pretty_value
1495
+	 * @return array|string if pretty_value= true, the result will always be a string
1496
+	 * (because the answer might be an array of answer values, so passing pretty_value=true
1497
+	 * will convert it into some kind of string)
1498
+	 * @throws EE_Error
1499
+	 * @throws InvalidArgumentException
1500
+	 * @throws InvalidDataTypeException
1501
+	 * @throws InvalidInterfaceException
1502
+	 */
1503
+	public function answer_value_to_question($question, $pretty_value = true)
1504
+	{
1505
+		$question_id = EEM_Question::instance()->ensure_is_ID($question);
1506
+		return EEM_Answer::instance()->get_answer_value_to_question($this, $question_id, $pretty_value);
1507
+	}
1508
+
1509
+
1510
+	/**
1511
+	 * question_groups
1512
+	 * returns an array of EE_Question_Group objects for this registration
1513
+	 *
1514
+	 * @return EE_Question_Group[]
1515
+	 * @throws EE_Error
1516
+	 * @throws InvalidArgumentException
1517
+	 * @throws InvalidDataTypeException
1518
+	 * @throws InvalidInterfaceException
1519
+	 * @throws ReflectionException
1520
+	 */
1521
+	public function question_groups()
1522
+	{
1523
+		return EEM_Event::instance()->get_question_groups_for_event($this->event_ID(), $this);
1524
+	}
1525
+
1526
+
1527
+	/**
1528
+	 * count_question_groups
1529
+	 * returns a count of the number of EE_Question_Group objects for this registration
1530
+	 *
1531
+	 * @return int
1532
+	 * @throws EE_Error
1533
+	 * @throws EntityNotFoundException
1534
+	 * @throws InvalidArgumentException
1535
+	 * @throws InvalidDataTypeException
1536
+	 * @throws InvalidInterfaceException
1537
+	 * @throws ReflectionException
1538
+	 */
1539
+	public function count_question_groups()
1540
+	{
1541
+		return EEM_Event::instance()->count_related(
1542
+			$this->event_ID(),
1543
+			'Question_Group',
1544
+			[
1545
+				[
1546
+					'Event_Question_Group.'
1547
+					. EEM_Event_Question_Group::instance()->fieldNameForContext($this->is_primary_registrant()) => true,
1548
+				]
1549
+			]
1550
+		);
1551
+	}
1552
+
1553
+
1554
+	/**
1555
+	 * Returns the registration date in the 'standard' string format
1556
+	 * (function may be improved in the future to allow for different formats and timezones)
1557
+	 *
1558
+	 * @return string
1559
+	 * @throws EE_Error
1560
+	 * @throws InvalidArgumentException
1561
+	 * @throws InvalidDataTypeException
1562
+	 * @throws InvalidInterfaceException
1563
+	 * @throws ReflectionException
1564
+	 */
1565
+	public function reg_date()
1566
+	{
1567
+		return $this->get_datetime('REG_date');
1568
+	}
1569
+
1570
+
1571
+	/**
1572
+	 * Gets the datetime-ticket for this registration (ie, it can be used to isolate
1573
+	 * the ticket this registration purchased, or the datetime they have registered
1574
+	 * to attend)
1575
+	 *
1576
+	 * @return EE_Base_Class|EE_Datetime_Ticket
1577
+	 * @throws EE_Error
1578
+	 * @throws InvalidArgumentException
1579
+	 * @throws InvalidDataTypeException
1580
+	 * @throws InvalidInterfaceException
1581
+	 * @throws ReflectionException
1582
+	 */
1583
+	public function datetime_ticket()
1584
+	{
1585
+		return $this->get_first_related('Datetime_Ticket');
1586
+	}
1587
+
1588
+
1589
+	/**
1590
+	 * Sets the registration's datetime_ticket.
1591
+	 *
1592
+	 * @param EE_Datetime_Ticket $datetime_ticket
1593
+	 * @return EE_Base_Class|EE_Datetime_Ticket
1594
+	 * @throws EE_Error
1595
+	 * @throws InvalidArgumentException
1596
+	 * @throws InvalidDataTypeException
1597
+	 * @throws InvalidInterfaceException
1598
+	 * @throws ReflectionException
1599
+	 */
1600
+	public function set_datetime_ticket($datetime_ticket)
1601
+	{
1602
+		return $this->_add_relation_to($datetime_ticket, 'Datetime_Ticket');
1603
+	}
1604
+
1605
+
1606
+	/**
1607
+	 * Gets deleted
1608
+	 *
1609
+	 * @return bool
1610
+	 * @throws EE_Error
1611
+	 * @throws InvalidArgumentException
1612
+	 * @throws InvalidDataTypeException
1613
+	 * @throws InvalidInterfaceException
1614
+	 * @throws ReflectionException
1615
+	 */
1616
+	public function deleted()
1617
+	{
1618
+		return $this->get('REG_deleted');
1619
+	}
1620
+
1621
+
1622
+	/**
1623
+	 * Sets deleted
1624
+	 *
1625
+	 * @param boolean $deleted
1626
+	 * @return void
1627
+	 * @throws DomainException
1628
+	 * @throws EE_Error
1629
+	 * @throws EntityNotFoundException
1630
+	 * @throws InvalidArgumentException
1631
+	 * @throws InvalidDataTypeException
1632
+	 * @throws InvalidInterfaceException
1633
+	 * @throws ReflectionException
1634
+	 * @throws RuntimeException
1635
+	 * @throws UnexpectedEntityException
1636
+	 */
1637
+	public function set_deleted($deleted)
1638
+	{
1639
+		if ($deleted) {
1640
+			$this->delete();
1641
+		} else {
1642
+			$this->restore();
1643
+		}
1644
+	}
1645
+
1646
+
1647
+	/**
1648
+	 * Get the status object of this object
1649
+	 *
1650
+	 * @return EE_Base_Class|EE_Status
1651
+	 * @throws EE_Error
1652
+	 * @throws InvalidArgumentException
1653
+	 * @throws InvalidDataTypeException
1654
+	 * @throws InvalidInterfaceException
1655
+	 * @throws ReflectionException
1656
+	 */
1657
+	public function status_obj()
1658
+	{
1659
+		return $this->get_first_related('Status');
1660
+	}
1661
+
1662
+
1663
+	/**
1664
+	 * Returns the number of times this registration has checked into any of the datetimes
1665
+	 * its available for
1666
+	 *
1667
+	 * @return int
1668
+	 * @throws EE_Error
1669
+	 * @throws InvalidArgumentException
1670
+	 * @throws InvalidDataTypeException
1671
+	 * @throws InvalidInterfaceException
1672
+	 * @throws ReflectionException
1673
+	 */
1674
+	public function count_checkins()
1675
+	{
1676
+		return $this->get_model()->count_related($this, 'Checkin');
1677
+	}
1678
+
1679
+
1680
+	/**
1681
+	 * Returns the number of current Check-ins this registration is checked into for any of the datetimes the
1682
+	 * registration is for.  Note, this is ONLY checked in (does not include checkedout)
1683
+	 *
1684
+	 * @return int
1685
+	 * @throws EE_Error
1686
+	 * @throws InvalidArgumentException
1687
+	 * @throws InvalidDataTypeException
1688
+	 * @throws InvalidInterfaceException
1689
+	 * @throws ReflectionException
1690
+	 */
1691
+	public function count_checkins_not_checkedout()
1692
+	{
1693
+		return $this->get_model()->count_related($this, 'Checkin', array(array('CHK_in' => 1)));
1694
+	}
1695
+
1696
+
1697
+	/**
1698
+	 * The purpose of this method is simply to check whether this registration can checkin to the given datetime.
1699
+	 *
1700
+	 * @param int | EE_Datetime $DTT_OR_ID      The datetime the registration is being checked against
1701
+	 * @param bool              $check_approved This is used to indicate whether the caller wants can_checkin to also
1702
+	 *                                          consider registration status as well as datetime access.
1703
+	 * @return bool
1704
+	 * @throws EE_Error
1705
+	 * @throws InvalidArgumentException
1706
+	 * @throws InvalidDataTypeException
1707
+	 * @throws InvalidInterfaceException
1708
+	 * @throws ReflectionException
1709
+	 */
1710
+	public function can_checkin($DTT_OR_ID, $check_approved = true)
1711
+	{
1712
+		$DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1713
+		// first check registration status
1714
+		if (! $DTT_ID || ($check_approved && ! $this->is_approved())) {
1715
+			return false;
1716
+		}
1717
+		// is there a datetime ticket that matches this dtt_ID?
1718
+		if (
1719
+			! (EEM_Datetime_Ticket::instance()->exists(
1720
+				array(
1721
+					array(
1722
+						'TKT_ID' => $this->get('TKT_ID'),
1723
+						'DTT_ID' => $DTT_ID,
1724
+					),
1725
+				)
1726
+			))
1727
+		) {
1728
+			return false;
1729
+		}
1730
+
1731
+		// final check is against TKT_uses
1732
+		return $this->verify_can_checkin_against_TKT_uses($DTT_ID);
1733
+	}
1734
+
1735
+
1736
+	/**
1737
+	 * This method verifies whether the user can checkin for the given datetime considering the max uses value set on
1738
+	 * the ticket. To do this,  a query is done to get the count of the datetime records already checked into.  If the
1739
+	 * datetime given does not have a check-in record and checking in for that datetime will exceed the allowed uses,
1740
+	 * then return false.  Otherwise return true.
1741
+	 *
1742
+	 * @param int | EE_Datetime $DTT_OR_ID The datetime the registration is being checked against
1743
+	 * @return bool true means can checkin.  false means cannot checkin.
1744
+	 * @throws EE_Error
1745
+	 * @throws InvalidArgumentException
1746
+	 * @throws InvalidDataTypeException
1747
+	 * @throws InvalidInterfaceException
1748
+	 * @throws ReflectionException
1749
+	 */
1750
+	public function verify_can_checkin_against_TKT_uses($DTT_OR_ID)
1751
+	{
1752
+		$DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1753
+
1754
+		if (! $DTT_ID) {
1755
+			return false;
1756
+		}
1757
+
1758
+		$max_uses = $this->ticket() instanceof EE_Ticket ? $this->ticket()->uses() : EE_INF;
1759
+
1760
+		// if max uses is not set or equals infinity then return true cause its not a factor for whether user can
1761
+		// check-in or not.
1762
+		if (! $max_uses || $max_uses === EE_INF) {
1763
+			return true;
1764
+		}
1765
+
1766
+		// does this datetime have a checkin record?  If so, then the dtt count has already been verified so we can just
1767
+		// go ahead and toggle.
1768
+		if (EEM_Checkin::instance()->exists(array(array('REG_ID' => $this->ID(), 'DTT_ID' => $DTT_ID)))) {
1769
+			return true;
1770
+		}
1771
+
1772
+		// made it here so the last check is whether the number of checkins per unique datetime on this registration
1773
+		// disallows further check-ins.
1774
+		$count_unique_dtt_checkins = EEM_Checkin::instance()->count(
1775
+			array(
1776
+				array(
1777
+					'REG_ID' => $this->ID(),
1778
+					'CHK_in' => true,
1779
+				),
1780
+			),
1781
+			'DTT_ID',
1782
+			true
1783
+		);
1784
+		// checkins have already reached their max number of uses
1785
+		// so registrant can NOT checkin
1786
+		if ($count_unique_dtt_checkins >= $max_uses) {
1787
+			EE_Error::add_error(
1788
+				esc_html__(
1789
+					'Check-in denied because number of datetime uses for the ticket has been reached or exceeded.',
1790
+					'event_espresso'
1791
+				),
1792
+				__FILE__,
1793
+				__FUNCTION__,
1794
+				__LINE__
1795
+			);
1796
+			return false;
1797
+		}
1798
+		return true;
1799
+	}
1800
+
1801
+
1802
+	/**
1803
+	 * toggle Check-in status for this registration
1804
+	 * Check-ins are toggled in the following order:
1805
+	 * never checked in -> checked in
1806
+	 * checked in -> checked out
1807
+	 * checked out -> checked in
1808
+	 *
1809
+	 * @param  int $DTT_ID  include specific datetime to toggle Check-in for.
1810
+	 *                      If not included or null, then it is assumed latest datetime is being toggled.
1811
+	 * @param bool $verify  If true then can_checkin() is used to verify whether the person
1812
+	 *                      can be checked in or not.  Otherwise this forces change in checkin status.
1813
+	 * @return bool|int     the chk_in status toggled to OR false if nothing got changed.
1814
+	 * @throws EE_Error
1815
+	 * @throws InvalidArgumentException
1816
+	 * @throws InvalidDataTypeException
1817
+	 * @throws InvalidInterfaceException
1818
+	 * @throws ReflectionException
1819
+	 */
1820
+	public function toggle_checkin_status($DTT_ID = null, $verify = false)
1821
+	{
1822
+		if (empty($DTT_ID)) {
1823
+			$datetime = $this->get_latest_related_datetime();
1824
+			$DTT_ID = $datetime instanceof EE_Datetime ? $datetime->ID() : 0;
1825
+			// verify the registration can checkin for the given DTT_ID
1826
+		} elseif (! $this->can_checkin($DTT_ID, $verify)) {
1827
+			EE_Error::add_error(
1828
+				sprintf(
1829
+					esc_html__(
1830
+						'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',
1831
+						'event_espresso'
1832
+					),
1833
+					$this->ID(),
1834
+					$DTT_ID
1835
+				),
1836
+				__FILE__,
1837
+				__FUNCTION__,
1838
+				__LINE__
1839
+			);
1840
+			return false;
1841
+		}
1842
+		$status_paths = array(
1843
+			EE_Checkin::status_checked_never => EE_Checkin::status_checked_in,
1844
+			EE_Checkin::status_checked_in    => EE_Checkin::status_checked_out,
1845
+			EE_Checkin::status_checked_out   => EE_Checkin::status_checked_in,
1846
+		);
1847
+		// start by getting the current status so we know what status we'll be changing to.
1848
+		$cur_status = $this->check_in_status_for_datetime($DTT_ID);
1849
+		$status_to = $status_paths[ $cur_status ];
1850
+		// database only records true for checked IN or false for checked OUT
1851
+		// no record ( null ) means checked in NEVER, but we obviously don't save that
1852
+		$new_status = $status_to === EE_Checkin::status_checked_in;
1853
+		// add relation - note Check-ins are always creating new rows
1854
+		// because we are keeping track of Check-ins over time.
1855
+		// Eventually we'll probably want to show a list table
1856
+		// for the individual Check-ins so that they can be managed.
1857
+		$checkin = EE_Checkin::new_instance(
1858
+			array(
1859
+				'REG_ID' => $this->ID(),
1860
+				'DTT_ID' => $DTT_ID,
1861
+				'CHK_in' => $new_status,
1862
+			)
1863
+		);
1864
+		// if the record could not be saved then return false
1865
+		if ($checkin->save() === 0) {
1866
+			if (WP_DEBUG) {
1867
+				global $wpdb;
1868
+				$error = sprintf(
1869
+					esc_html__(
1870
+						'Registration check in update failed because of the following database error: %1$s%2$s',
1871
+						'event_espresso'
1872
+					),
1873
+					'<br />',
1874
+					$wpdb->last_error
1875
+				);
1876
+			} else {
1877
+				$error = esc_html__(
1878
+					'Registration check in update failed because of an unknown database error',
1879
+					'event_espresso'
1880
+				);
1881
+			}
1882
+			EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
1883
+			return false;
1884
+		}
1885
+		// Fire a checked_in and checkout_out action.
1886
+		$checked_status = $status_to === EE_Checkin::status_checked_in ? 'checked_in' : 'checked_out';
1887
+		do_action("AHEE__EE_Registration__toggle_checkin_status__{$checked_status}", $this, $DTT_ID);
1888
+		return $status_to;
1889
+	}
1890
+
1891
+
1892
+	/**
1893
+	 * Returns the latest datetime related to this registration (via the ticket attached to the registration).
1894
+	 * "Latest" is defined by the `DTT_EVT_start` column.
1895
+	 *
1896
+	 * @return EE_Datetime|null
1897
+	 * @throws EE_Error
1898
+	 * @throws InvalidArgumentException
1899
+	 * @throws InvalidDataTypeException
1900
+	 * @throws InvalidInterfaceException
1901
+	 * @throws ReflectionException
1902
+	 */
1903
+	public function get_latest_related_datetime()
1904
+	{
1905
+		return EEM_Datetime::instance()->get_one(
1906
+			array(
1907
+				array(
1908
+					'Ticket.Registration.REG_ID' => $this->ID(),
1909
+				),
1910
+				'order_by' => array('DTT_EVT_start' => 'DESC'),
1911
+			)
1912
+		);
1913
+	}
1914
+
1915
+
1916
+	/**
1917
+	 * Returns the earliest datetime related to this registration (via the ticket attached to the registration).
1918
+	 * "Earliest" is defined by the `DTT_EVT_start` column.
1919
+	 *
1920
+	 * @return EE_Base_Class|EE_Soft_Delete_Base_Class|NULL
1921
+	 * @throws EE_Error
1922
+	 * @throws InvalidArgumentException
1923
+	 * @throws InvalidDataTypeException
1924
+	 * @throws InvalidInterfaceException
1925
+	 * @throws ReflectionException
1926
+	 */
1927
+	public function get_earliest_related_datetime()
1928
+	{
1929
+		return EEM_Datetime::instance()->get_one(
1930
+			array(
1931
+				array(
1932
+					'Ticket.Registration.REG_ID' => $this->ID(),
1933
+				),
1934
+				'order_by' => array('DTT_EVT_start' => 'ASC'),
1935
+			)
1936
+		);
1937
+	}
1938
+
1939
+
1940
+	/**
1941
+	 * This method simply returns the check-in status for this registration and the given datetime.
1942
+	 * If neither the datetime nor the checkin values are provided as arguments,
1943
+	 * then this will return the LATEST check-in status for the registration across all datetimes it belongs to.
1944
+	 *
1945
+	 * @param  int       $DTT_ID  The ID of the datetime we're checking against
1946
+	 *                            (if empty we'll get the primary datetime for
1947
+	 *                            this registration (via event) and use it's ID);
1948
+	 * @param EE_Checkin $checkin If present, we use the given checkin object rather than the dtt_id.
1949
+	 * @return int                Integer representing Check-in status.
1950
+	 * @throws EE_Error
1951
+	 * @throws InvalidArgumentException
1952
+	 * @throws InvalidDataTypeException
1953
+	 * @throws InvalidInterfaceException
1954
+	 * @throws ReflectionException
1955
+	 */
1956
+	public function check_in_status_for_datetime($DTT_ID = 0, $checkin = null)
1957
+	{
1958
+		$checkin_query_params = array(
1959
+			'order_by' => array('CHK_timestamp' => 'DESC'),
1960
+		);
1961
+
1962
+		if ($DTT_ID > 0) {
1963
+			$checkin_query_params[0] = array('DTT_ID' => $DTT_ID);
1964
+		}
1965
+
1966
+		// get checkin object (if exists)
1967
+		$checkin = $checkin instanceof EE_Checkin
1968
+			? $checkin
1969
+			: $this->get_first_related('Checkin', $checkin_query_params);
1970
+		if ($checkin instanceof EE_Checkin) {
1971
+			if ($checkin->get('CHK_in')) {
1972
+				return EE_Checkin::status_checked_in; // checked in
1973
+			}
1974
+			return EE_Checkin::status_checked_out; // had checked in but is now checked out.
1975
+		}
1976
+		return EE_Checkin::status_checked_never; // never been checked in
1977
+	}
1978
+
1979
+
1980
+	/**
1981
+	 * This method returns a localized message for the toggled Check-in message.
1982
+	 *
1983
+	 * @param  int $DTT_ID include specific datetime to get the correct Check-in message.  If not included or null,
1984
+	 *                     then it is assumed Check-in for primary datetime was toggled.
1985
+	 * @param bool $error  This just flags that you want an error message returned. This is put in so that the error
1986
+	 *                     message can be customized with the attendee name.
1987
+	 * @return string internationalized message
1988
+	 * @throws EE_Error
1989
+	 * @throws InvalidArgumentException
1990
+	 * @throws InvalidDataTypeException
1991
+	 * @throws InvalidInterfaceException
1992
+	 * @throws ReflectionException
1993
+	 */
1994
+	public function get_checkin_msg($DTT_ID, $error = false)
1995
+	{
1996
+		// let's get the attendee first so we can include the name of the attendee
1997
+		$attendee = $this->get_first_related('Attendee');
1998
+		if ($attendee instanceof EE_Attendee) {
1999
+			if ($error) {
2000
+				return sprintf(
2001
+					esc_html__("%s's check-in status was not changed.", "event_espresso"),
2002
+					$attendee->full_name()
2003
+				);
2004
+			}
2005
+			$cur_status = $this->check_in_status_for_datetime($DTT_ID);
2006
+			// what is the status message going to be?
2007
+			switch ($cur_status) {
2008
+				case EE_Checkin::status_checked_never:
2009
+					return sprintf(
2010
+						esc_html__('%s has been removed from Check-in records', 'event_espresso'),
2011
+						$attendee->full_name()
2012
+					);
2013
+					break;
2014
+				case EE_Checkin::status_checked_in:
2015
+					return sprintf(esc_html__('%s has been checked in', 'event_espresso'), $attendee->full_name());
2016
+					break;
2017
+				case EE_Checkin::status_checked_out:
2018
+					return sprintf(esc_html__('%s has been checked out', 'event_espresso'), $attendee->full_name());
2019
+					break;
2020
+			}
2021
+		}
2022
+		return esc_html__('The check-in status could not be determined.', 'event_espresso');
2023
+	}
2024
+
2025
+
2026
+	/**
2027
+	 * Returns the related EE_Transaction to this registration
2028
+	 *
2029
+	 * @return EE_Transaction
2030
+	 * @throws EE_Error
2031
+	 * @throws EntityNotFoundException
2032
+	 * @throws InvalidArgumentException
2033
+	 * @throws InvalidDataTypeException
2034
+	 * @throws InvalidInterfaceException
2035
+	 * @throws ReflectionException
2036
+	 */
2037
+	public function transaction()
2038
+	{
2039
+		$transaction = $this->get_first_related('Transaction');
2040
+		if (! $transaction instanceof \EE_Transaction) {
2041
+			throw new EntityNotFoundException('Transaction ID', $this->transaction_ID());
2042
+		}
2043
+		return $transaction;
2044
+	}
2045
+
2046
+
2047
+	/**
2048
+	 * get Registration Code
2049
+	 *
2050
+	 * @return mixed
2051
+	 * @throws EE_Error
2052
+	 * @throws InvalidArgumentException
2053
+	 * @throws InvalidDataTypeException
2054
+	 * @throws InvalidInterfaceException
2055
+	 * @throws ReflectionException
2056
+	 */
2057
+	public function reg_code()
2058
+	{
2059
+		return $this->get('REG_code');
2060
+	}
2061
+
2062
+
2063
+	/**
2064
+	 * @return mixed
2065
+	 * @throws EE_Error
2066
+	 * @throws InvalidArgumentException
2067
+	 * @throws InvalidDataTypeException
2068
+	 * @throws InvalidInterfaceException
2069
+	 * @throws ReflectionException
2070
+	 */
2071
+	public function transaction_ID()
2072
+	{
2073
+		return $this->get('TXN_ID');
2074
+	}
2075
+
2076
+
2077
+	/**
2078
+	 * @return int
2079
+	 * @throws EE_Error
2080
+	 * @throws InvalidArgumentException
2081
+	 * @throws InvalidDataTypeException
2082
+	 * @throws InvalidInterfaceException
2083
+	 * @throws ReflectionException
2084
+	 */
2085
+	public function ticket_ID()
2086
+	{
2087
+		return $this->get('TKT_ID');
2088
+	}
2089
+
2090
+
2091
+	/**
2092
+	 * Set Registration Code
2093
+	 *
2094
+	 * @param    string  $REG_code Registration Code
2095
+	 * @param    boolean $use_default
2096
+	 * @throws EE_Error
2097
+	 * @throws InvalidArgumentException
2098
+	 * @throws InvalidDataTypeException
2099
+	 * @throws InvalidInterfaceException
2100
+	 * @throws ReflectionException
2101
+	 */
2102
+	public function set_reg_code($REG_code, $use_default = false)
2103
+	{
2104
+		if (empty($REG_code)) {
2105
+			EE_Error::add_error(
2106
+				esc_html__('REG_code can not be empty.', 'event_espresso'),
2107
+				__FILE__,
2108
+				__FUNCTION__,
2109
+				__LINE__
2110
+			);
2111
+			return;
2112
+		}
2113
+		if (! $this->reg_code()) {
2114
+			parent::set('REG_code', $REG_code, $use_default);
2115
+		} else {
2116
+			EE_Error::doing_it_wrong(
2117
+				__CLASS__ . '::' . __FUNCTION__,
2118
+				esc_html__('Can not change a registration REG_code once it has been set.', 'event_espresso'),
2119
+				'4.6.0'
2120
+			);
2121
+		}
2122
+	}
2123
+
2124
+
2125
+	/**
2126
+	 * Returns all other registrations in the same group as this registrant who have the same ticket option.
2127
+	 * Note, if you want to just get all registrations in the same transaction (group), use:
2128
+	 *    $registration->transaction()->registrations();
2129
+	 *
2130
+	 * @since 4.5.0
2131
+	 * @return EE_Registration[] or empty array if this isn't a group registration.
2132
+	 * @throws EE_Error
2133
+	 * @throws InvalidArgumentException
2134
+	 * @throws InvalidDataTypeException
2135
+	 * @throws InvalidInterfaceException
2136
+	 * @throws ReflectionException
2137
+	 */
2138
+	public function get_all_other_registrations_in_group()
2139
+	{
2140
+		if ($this->group_size() < 2) {
2141
+			return array();
2142
+		}
2143
+
2144
+		$query[0] = array(
2145
+			'TXN_ID' => $this->transaction_ID(),
2146
+			'REG_ID' => array('!=', $this->ID()),
2147
+			'TKT_ID' => $this->ticket_ID(),
2148
+		);
2149
+		/** @var EE_Registration[] $registrations */
2150
+		$registrations = $this->get_model()->get_all($query);
2151
+		return $registrations;
2152
+	}
2153
+
2154
+
2155
+	/**
2156
+	 * Return the link to the admin details for the object.
2157
+	 *
2158
+	 * @return string
2159
+	 * @throws EE_Error
2160
+	 * @throws InvalidArgumentException
2161
+	 * @throws InvalidDataTypeException
2162
+	 * @throws InvalidInterfaceException
2163
+	 * @throws ReflectionException
2164
+	 */
2165
+	public function get_admin_details_link()
2166
+	{
2167
+		EE_Registry::instance()->load_helper('URL');
2168
+		return EEH_URL::add_query_args_and_nonce(
2169
+			array(
2170
+				'page'    => 'espresso_registrations',
2171
+				'action'  => 'view_registration',
2172
+				'_REG_ID' => $this->ID(),
2173
+			),
2174
+			admin_url('admin.php')
2175
+		);
2176
+	}
2177
+
2178
+
2179
+	/**
2180
+	 * Returns the link to the editor for the object.  Sometimes this is the same as the details.
2181
+	 *
2182
+	 * @return string
2183
+	 * @throws EE_Error
2184
+	 * @throws InvalidArgumentException
2185
+	 * @throws InvalidDataTypeException
2186
+	 * @throws InvalidInterfaceException
2187
+	 * @throws ReflectionException
2188
+	 */
2189
+	public function get_admin_edit_link()
2190
+	{
2191
+		return $this->get_admin_details_link();
2192
+	}
2193
+
2194
+
2195
+	/**
2196
+	 * Returns the link to a settings page for the object.
2197
+	 *
2198
+	 * @return string
2199
+	 * @throws EE_Error
2200
+	 * @throws InvalidArgumentException
2201
+	 * @throws InvalidDataTypeException
2202
+	 * @throws InvalidInterfaceException
2203
+	 * @throws ReflectionException
2204
+	 */
2205
+	public function get_admin_settings_link()
2206
+	{
2207
+		return $this->get_admin_details_link();
2208
+	}
2209
+
2210
+
2211
+	/**
2212
+	 * Returns the link to the "overview" for the object (typically the "list table" view).
2213
+	 *
2214
+	 * @return string
2215
+	 * @throws EE_Error
2216
+	 * @throws InvalidArgumentException
2217
+	 * @throws InvalidDataTypeException
2218
+	 * @throws InvalidInterfaceException
2219
+	 * @throws ReflectionException
2220
+	 */
2221
+	public function get_admin_overview_link()
2222
+	{
2223
+		EE_Registry::instance()->load_helper('URL');
2224
+		return EEH_URL::add_query_args_and_nonce(
2225
+			array(
2226
+				'page' => 'espresso_registrations',
2227
+			),
2228
+			admin_url('admin.php')
2229
+		);
2230
+	}
2231
+
2232
+
2233
+	/**
2234
+	 * @param array $query_params
2235
+	 * @return EE_Base_Class[]|EE_Registration[]
2236
+	 * @throws EE_Error
2237
+	 * @throws InvalidArgumentException
2238
+	 * @throws InvalidDataTypeException
2239
+	 * @throws InvalidInterfaceException
2240
+	 * @throws ReflectionException
2241
+	 */
2242
+	public function payments($query_params = array())
2243
+	{
2244
+		return $this->get_many_related('Payment', $query_params);
2245
+	}
2246
+
2247
+
2248
+	/**
2249
+	 * @param array $query_params
2250
+	 * @return EE_Base_Class[]|EE_Registration_Payment[]
2251
+	 * @throws EE_Error
2252
+	 * @throws InvalidArgumentException
2253
+	 * @throws InvalidDataTypeException
2254
+	 * @throws InvalidInterfaceException
2255
+	 * @throws ReflectionException
2256
+	 */
2257
+	public function registration_payments($query_params = array())
2258
+	{
2259
+		return $this->get_many_related('Registration_Payment', $query_params);
2260
+	}
2261
+
2262
+
2263
+	/**
2264
+	 * This grabs the payment method corresponding to the last payment made for the amount owing on the registration.
2265
+	 * Note: if there are no payments on the registration there will be no payment method returned.
2266
+	 *
2267
+	 * @return EE_Payment|EE_Payment_Method|null
2268
+	 * @throws EE_Error
2269
+	 * @throws InvalidArgumentException
2270
+	 * @throws InvalidDataTypeException
2271
+	 * @throws InvalidInterfaceException
2272
+	 */
2273
+	public function payment_method()
2274
+	{
2275
+		return EEM_Payment_Method::instance()->get_last_used_for_registration($this);
2276
+	}
2277
+
2278
+
2279
+	/**
2280
+	 * @return \EE_Line_Item
2281
+	 * @throws EE_Error
2282
+	 * @throws EntityNotFoundException
2283
+	 * @throws InvalidArgumentException
2284
+	 * @throws InvalidDataTypeException
2285
+	 * @throws InvalidInterfaceException
2286
+	 * @throws ReflectionException
2287
+	 */
2288
+	public function ticket_line_item()
2289
+	{
2290
+		$ticket = $this->ticket();
2291
+		$transaction = $this->transaction();
2292
+		$line_item = null;
2293
+		$ticket_line_items = \EEH_Line_Item::get_line_items_by_object_type_and_IDs(
2294
+			$transaction->total_line_item(),
2295
+			'Ticket',
2296
+			array($ticket->ID())
2297
+		);
2298
+		foreach ($ticket_line_items as $ticket_line_item) {
2299
+			if (
2300
+				$ticket_line_item instanceof \EE_Line_Item
2301
+				&& $ticket_line_item->OBJ_type() === 'Ticket'
2302
+				&& $ticket_line_item->OBJ_ID() === $ticket->ID()
2303
+			) {
2304
+				$line_item = $ticket_line_item;
2305
+				break;
2306
+			}
2307
+		}
2308
+		if (! ($line_item instanceof \EE_Line_Item && $line_item->OBJ_type() === 'Ticket')) {
2309
+			throw new EntityNotFoundException('Line Item Ticket ID', $ticket->ID());
2310
+		}
2311
+		return $line_item;
2312
+	}
2313
+
2314
+
2315
+	/**
2316
+	 * Soft Deletes this model object.
2317
+	 *
2318
+	 * @param string $source function name that called this method
2319
+	 * @return boolean | int
2320
+	 * @throws DomainException
2321
+	 * @throws EE_Error
2322
+	 * @throws EntityNotFoundException
2323
+	 * @throws InvalidArgumentException
2324
+	 * @throws InvalidDataTypeException
2325
+	 * @throws InvalidInterfaceException
2326
+	 * @throws ReflectionException
2327
+	 * @throws RuntimeException
2328
+	 * @throws UnexpectedEntityException
2329
+	 */
2330
+	public function delete()
2331
+	{
2332
+		if ($this->update_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY, $this->status_ID()) === true) {
2333
+			$this->set_status(EEM_Registration::status_id_cancelled);
2334
+		}
2335
+		return parent::delete();
2336
+	}
2337
+
2338
+
2339
+	/**
2340
+	 * Restores whatever the previous status was on a registration before it was trashed (if possible)
2341
+	 *
2342
+	 * @param string $source function name that called this method
2343
+	 * @return bool|int
2344
+	 * @throws DomainException
2345
+	 * @throws EE_Error
2346
+	 * @throws EntityNotFoundException
2347
+	 * @throws InvalidArgumentException
2348
+	 * @throws InvalidDataTypeException
2349
+	 * @throws InvalidInterfaceException
2350
+	 * @throws ReflectionException
2351
+	 * @throws RuntimeException
2352
+	 * @throws UnexpectedEntityException
2353
+	 */
2354
+	public function restore()
2355
+	{
2356
+		$previous_status = $this->get_extra_meta(
2357
+			EE_Registration::PRE_TRASH_REG_STATUS_KEY,
2358
+			true,
2359
+			EEM_Registration::status_id_cancelled
2360
+		);
2361
+		if ($previous_status) {
2362
+			$this->delete_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY);
2363
+			$this->set_status($previous_status);
2364
+		}
2365
+		return parent::restore();
2366
+	}
2367
+
2368
+
2369
+	/**
2370
+	 * possibly toggle Registration status based on comparison of REG_paid vs REG_final_price
2371
+	 *
2372
+	 * @param  boolean $trigger_set_status_logic EE_Registration::set_status() can trigger additional logic
2373
+	 *                                           depending on whether the reg status changes to or from "Approved"
2374
+	 * @return boolean whether the Registration status was updated
2375
+	 * @throws DomainException
2376
+	 * @throws EE_Error
2377
+	 * @throws EntityNotFoundException
2378
+	 * @throws InvalidArgumentException
2379
+	 * @throws InvalidDataTypeException
2380
+	 * @throws InvalidInterfaceException
2381
+	 * @throws ReflectionException
2382
+	 * @throws RuntimeException
2383
+	 * @throws UnexpectedEntityException
2384
+	 */
2385
+	public function updateStatusBasedOnTotalPaid($trigger_set_status_logic = true)
2386
+	{
2387
+		$paid = $this->paid();
2388
+		$price = $this->final_price();
2389
+		switch (true) {
2390
+			// overpaid or paid
2391
+			case EEH_Money::compare_floats($paid, $price, '>'):
2392
+			case EEH_Money::compare_floats($paid, $price):
2393
+				$new_status = EEM_Registration::status_id_approved;
2394
+				break;
2395
+			//  underpaid
2396
+			case EEH_Money::compare_floats($paid, $price, '<'):
2397
+				$new_status = EEM_Registration::status_id_pending_payment;
2398
+				break;
2399
+			// uhhh Houston...
2400
+			default:
2401
+				throw new RuntimeException(
2402
+					esc_html__('The total paid calculation for this registration is inaccurate.', 'event_espresso')
2403
+				);
2404
+		}
2405
+		if ($new_status !== $this->status_ID()) {
2406
+			if ($trigger_set_status_logic) {
2407
+				return $this->set_status($new_status);
2408
+			}
2409
+			parent::set('STS_ID', $new_status);
2410
+			return true;
2411
+		}
2412
+		return false;
2413
+	}
2414
+
2415
+
2416
+	/*************************** DEPRECATED ***************************/
2417
+
2418
+
2419
+	/**
2420
+	 * @deprecated
2421
+	 * @since     4.7.0
2422
+	 */
2423
+	public function price_paid()
2424
+	{
2425
+		EE_Error::doing_it_wrong(
2426
+			'EE_Registration::price_paid()',
2427
+			esc_html__(
2428
+				'This method is deprecated, please use EE_Registration::final_price() instead.',
2429
+				'event_espresso'
2430
+			),
2431
+			'4.7.0'
2432
+		);
2433
+		return $this->final_price();
2434
+	}
2435
+
2436
+
2437
+	/**
2438
+	 * @deprecated
2439
+	 * @since     4.7.0
2440
+	 * @param    float $REG_final_price
2441
+	 * @throws EE_Error
2442
+	 * @throws EntityNotFoundException
2443
+	 * @throws InvalidArgumentException
2444
+	 * @throws InvalidDataTypeException
2445
+	 * @throws InvalidInterfaceException
2446
+	 * @throws ReflectionException
2447
+	 * @throws RuntimeException
2448
+	 * @throws DomainException
2449
+	 */
2450
+	public function set_price_paid($REG_final_price = 0.00)
2451
+	{
2452
+		EE_Error::doing_it_wrong(
2453
+			'EE_Registration::set_price_paid()',
2454
+			esc_html__(
2455
+				'This method is deprecated, please use EE_Registration::set_final_price() instead.',
2456
+				'event_espresso'
2457
+			),
2458
+			'4.7.0'
2459
+		);
2460
+		$this->set_final_price($REG_final_price);
2461
+	}
2462
+
2463
+
2464
+	/**
2465
+	 * @deprecated
2466
+	 * @since 4.7.0
2467
+	 * @return string
2468
+	 * @throws EE_Error
2469
+	 * @throws InvalidArgumentException
2470
+	 * @throws InvalidDataTypeException
2471
+	 * @throws InvalidInterfaceException
2472
+	 * @throws ReflectionException
2473
+	 */
2474
+	public function pretty_price_paid()
2475
+	{
2476
+		EE_Error::doing_it_wrong(
2477
+			'EE_Registration::pretty_price_paid()',
2478
+			esc_html__(
2479
+				'This method is deprecated, please use EE_Registration::pretty_final_price() instead.',
2480
+				'event_espresso'
2481
+			),
2482
+			'4.7.0'
2483
+		);
2484
+		return $this->pretty_final_price();
2485
+	}
2486
+
2487
+
2488
+	/**
2489
+	 * Gets the primary datetime related to this registration via the related Event to this registration
2490
+	 *
2491
+	 * @deprecated 4.9.17
2492
+	 * @return EE_Datetime
2493
+	 * @throws EE_Error
2494
+	 * @throws EntityNotFoundException
2495
+	 * @throws InvalidArgumentException
2496
+	 * @throws InvalidDataTypeException
2497
+	 * @throws InvalidInterfaceException
2498
+	 * @throws ReflectionException
2499
+	 */
2500
+	public function get_related_primary_datetime()
2501
+	{
2502
+		EE_Error::doing_it_wrong(
2503
+			__METHOD__,
2504
+			esc_html__(
2505
+				'Use EE_Registration::get_latest_related_datetime() or EE_Registration::get_earliest_related_datetime()',
2506
+				'event_espresso'
2507
+			),
2508
+			'4.9.17',
2509
+			'5.0.0'
2510
+		);
2511
+		return $this->event()->primary_datetime();
2512
+	}
2513
+
2514
+	/**
2515
+	 * Returns the contact's name (or "Unknown" if there is no contact.)
2516
+	 * @since 4.10.12.p
2517
+	 * @return string
2518
+	 * @throws EE_Error
2519
+	 * @throws InvalidArgumentException
2520
+	 * @throws InvalidDataTypeException
2521
+	 * @throws InvalidInterfaceException
2522
+	 * @throws ReflectionException
2523
+	 */
2524
+	public function name()
2525
+	{
2526
+		return $this->attendeeName();
2527
+	}
2528 2528
 }
Please login to merge, or discard this patch.