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