Completed
Branch models-cleanup/main (0d2dda)
by
unknown
09:34
created
core/db_classes/EE_Payment.class.php 1 patch
Indentation   +852 added lines, -852 removed lines patch added patch discarded remove patch
@@ -10,856 +10,856 @@
 block discarded – undo
10 10
 class EE_Payment extends EE_Base_Class implements EEI_Payment
11 11
 {
12 12
 
13
-    /**
14
-     * @param array  $props_n_values          incoming values
15
-     * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
16
-     *                                        used.)
17
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
18
-     *                                        date_format and the second value is the time format
19
-     * @return EE_Payment
20
-     * @throws \EE_Error
21
-     */
22
-    public static function new_instance($props_n_values = array(), $timezone = '', $date_formats = array())
23
-    {
24
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
25
-        return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
26
-    }
27
-
28
-
29
-    /**
30
-     * @param array  $props_n_values  incoming values from the database
31
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
32
-     *                                the website will be used.
33
-     * @return EE_Payment
34
-     * @throws \EE_Error
35
-     */
36
-    public static function new_instance_from_db($props_n_values = array(), $timezone = '')
37
-    {
38
-        return new self($props_n_values, true, $timezone);
39
-    }
40
-
41
-
42
-    /**
43
-     * Set Transaction ID
44
-     *
45
-     * @access public
46
-     * @param int $TXN_ID
47
-     * @throws \EE_Error
48
-     */
49
-    public function set_transaction_id($TXN_ID = 0)
50
-    {
51
-        $this->set('TXN_ID', $TXN_ID);
52
-    }
53
-
54
-
55
-    /**
56
-     * Gets the transaction related to this payment
57
-     *
58
-     * @return EE_Transaction
59
-     * @throws \EE_Error
60
-     */
61
-    public function transaction()
62
-    {
63
-        return $this->get_first_related('Transaction');
64
-    }
65
-
66
-
67
-    /**
68
-     * Set Status
69
-     *
70
-     * @access public
71
-     * @param string $STS_ID
72
-     * @throws \EE_Error
73
-     */
74
-    public function set_status($STS_ID = '')
75
-    {
76
-        $this->set('STS_ID', $STS_ID);
77
-    }
78
-
79
-
80
-    /**
81
-     * Set Payment Timestamp
82
-     *
83
-     * @access public
84
-     * @param int $timestamp
85
-     * @throws \EE_Error
86
-     */
87
-    public function set_timestamp($timestamp = 0)
88
-    {
89
-        $this->set('PAY_timestamp', $timestamp);
90
-    }
91
-
92
-
93
-    /**
94
-     * Set Payment Method
95
-     *
96
-     * @access public
97
-     * @param string $PAY_source
98
-     * @throws \EE_Error
99
-     */
100
-    public function set_source($PAY_source = '')
101
-    {
102
-        $this->set('PAY_source', $PAY_source);
103
-    }
104
-
105
-
106
-    /**
107
-     * Set Payment Amount
108
-     *
109
-     * @access public
110
-     * @param float $amount
111
-     * @throws \EE_Error
112
-     */
113
-    public function set_amount($amount = 0.00)
114
-    {
115
-        $this->set('PAY_amount', (float) $amount);
116
-    }
117
-
118
-
119
-    /**
120
-     * Set Payment Gateway Response
121
-     *
122
-     * @access public
123
-     * @param string $gateway_response
124
-     * @throws \EE_Error
125
-     */
126
-    public function set_gateway_response($gateway_response = '')
127
-    {
128
-        $this->set('PAY_gateway_response', $gateway_response);
129
-    }
130
-
131
-
132
-    /**
133
-     * Returns the name of the payment method used on this payment (previously known merely as 'gateway')
134
-     * but since 4.6.0, payment methods are models and the payment keeps a foreign key to the payment method
135
-     * used on it
136
-     *
137
-     * @deprecated
138
-     * @return string
139
-     * @throws \EE_Error
140
-     */
141
-    public function gateway()
142
-    {
143
-        EE_Error::doing_it_wrong(
144
-            'EE_Payment::gateway',
145
-            __(
146
-                'The method EE_Payment::gateway() has been deprecated. Consider instead using EE_Payment::payment_method()->name()',
147
-                'event_espresso'
148
-            ),
149
-            '4.6.0'
150
-        );
151
-        return $this->payment_method() ? $this->payment_method()->name() : __('Unknown', 'event_espresso');
152
-    }
153
-
154
-
155
-    /**
156
-     * Set Gateway Transaction ID
157
-     *
158
-     * @access public
159
-     * @param string $txn_id_chq_nmbr
160
-     * @throws \EE_Error
161
-     */
162
-    public function set_txn_id_chq_nmbr($txn_id_chq_nmbr = '')
163
-    {
164
-        $this->set('PAY_txn_id_chq_nmbr', $txn_id_chq_nmbr);
165
-    }
166
-
167
-
168
-    /**
169
-     * Set Purchase Order Number
170
-     *
171
-     * @access public
172
-     * @param string $po_number
173
-     * @throws \EE_Error
174
-     */
175
-    public function set_po_number($po_number = '')
176
-    {
177
-        $this->set('PAY_po_number', $po_number);
178
-    }
179
-
180
-
181
-    /**
182
-     * Set Extra Accounting Field
183
-     *
184
-     * @access public
185
-     * @param string $extra_accntng
186
-     * @throws \EE_Error
187
-     */
188
-    public function set_extra_accntng($extra_accntng = '')
189
-    {
190
-        $this->set('PAY_extra_accntng', $extra_accntng);
191
-    }
192
-
193
-
194
-    /**
195
-     * Set Payment made via admin flag
196
-     *
197
-     * @access public
198
-     * @param bool $via_admin
199
-     * @throws \EE_Error
200
-     */
201
-    public function set_payment_made_via_admin($via_admin = false)
202
-    {
203
-        if ($via_admin) {
204
-            $this->set('PAY_source', EEM_Payment_Method::scope_admin);
205
-        } else {
206
-            $this->set('PAY_source', EEM_Payment_Method::scope_cart);
207
-        }
208
-    }
209
-
210
-
211
-    /**
212
-     * Set Payment Details
213
-     *
214
-     * @access public
215
-     * @param string|array $details
216
-     * @throws \EE_Error
217
-     */
218
-    public function set_details($details = '')
219
-    {
220
-        if (is_array($details)) {
221
-            array_walk_recursive($details, array($this, '_strip_all_tags_within_array'));
222
-        } else {
223
-            $details = wp_strip_all_tags($details);
224
-        }
225
-        $this->set('PAY_details', $details);
226
-    }
227
-
228
-
229
-    /**
230
-     * Sets redirect_url
231
-     *
232
-     * @param string $redirect_url
233
-     * @throws \EE_Error
234
-     */
235
-    public function set_redirect_url($redirect_url)
236
-    {
237
-        $this->set('PAY_redirect_url', $redirect_url);
238
-    }
239
-
240
-
241
-    /**
242
-     * Sets redirect_args
243
-     *
244
-     * @param array $redirect_args
245
-     * @throws \EE_Error
246
-     */
247
-    public function set_redirect_args($redirect_args)
248
-    {
249
-        $this->set('PAY_redirect_args', $redirect_args);
250
-    }
251
-
252
-
253
-    /**
254
-     * get Payment Transaction ID
255
-     *
256
-     * @access public
257
-     * @throws \EE_Error
258
-     */
259
-    public function TXN_ID()
260
-    {
261
-        return $this->get('TXN_ID');
262
-    }
263
-
264
-
265
-    /**
266
-     * get Payment Status
267
-     *
268
-     * @access public
269
-     * @throws \EE_Error
270
-     */
271
-    public function status()
272
-    {
273
-        return $this->get('STS_ID');
274
-    }
275
-
276
-
277
-    /**
278
-     * get Payment Status
279
-     *
280
-     * @access public
281
-     * @throws \EE_Error
282
-     */
283
-    public function STS_ID()
284
-    {
285
-        return $this->get('STS_ID');
286
-    }
287
-
288
-
289
-    /**
290
-     * get Payment Timestamp
291
-     *
292
-     * @access public
293
-     * @param string $dt_frmt
294
-     * @param string $tm_frmt
295
-     * @return string
296
-     * @throws \EE_Error
297
-     */
298
-    public function timestamp($dt_frmt = '', $tm_frmt = '')
299
-    {
300
-        return $this->get_i18n_datetime('PAY_timestamp', trim($dt_frmt . ' ' . $tm_frmt));
301
-    }
302
-
303
-
304
-    /**
305
-     * get Payment Source
306
-     *
307
-     * @access public
308
-     * @throws \EE_Error
309
-     */
310
-    public function source()
311
-    {
312
-        return $this->get('PAY_source');
313
-    }
314
-
315
-
316
-    /**
317
-     * get Payment Amount
318
-     *
319
-     * @access public
320
-     * @return float
321
-     * @throws \EE_Error
322
-     */
323
-    public function amount()
324
-    {
325
-        return (float) $this->get('PAY_amount');
326
-    }
327
-
328
-
329
-    /**
330
-     * @return mixed
331
-     * @throws \EE_Error
332
-     */
333
-    public function amount_no_code()
334
-    {
335
-        return $this->get_pretty('PAY_amount', 'no_currency_code');
336
-    }
337
-
338
-
339
-    /**
340
-     * get Payment Gateway Response
341
-     *
342
-     * @access public
343
-     * @throws \EE_Error
344
-     */
345
-    public function gateway_response()
346
-    {
347
-        return $this->get('PAY_gateway_response');
348
-    }
349
-
350
-
351
-    /**
352
-     * get Payment Gateway Transaction ID
353
-     *
354
-     * @access public
355
-     * @throws \EE_Error
356
-     */
357
-    public function txn_id_chq_nmbr()
358
-    {
359
-        return $this->get('PAY_txn_id_chq_nmbr');
360
-    }
361
-
362
-
363
-    /**
364
-     * get Purchase Order Number
365
-     *
366
-     * @access public
367
-     * @throws \EE_Error
368
-     */
369
-    public function po_number()
370
-    {
371
-        return $this->get('PAY_po_number');
372
-    }
373
-
374
-
375
-    /**
376
-     * get Extra Accounting Field
377
-     *
378
-     * @access public
379
-     * @throws \EE_Error
380
-     */
381
-    public function extra_accntng()
382
-    {
383
-        return $this->get('PAY_extra_accntng');
384
-    }
385
-
386
-
387
-    /**
388
-     * get Payment made via admin source
389
-     *
390
-     * @access public
391
-     * @throws \EE_Error
392
-     */
393
-    public function payment_made_via_admin()
394
-    {
395
-        return ($this->get('PAY_source') === EEM_Payment_Method::scope_admin);
396
-    }
397
-
398
-
399
-    /**
400
-     * get Payment Details
401
-     *
402
-     * @access public
403
-     * @throws \EE_Error
404
-     */
405
-    public function details()
406
-    {
407
-        return $this->get('PAY_details');
408
-    }
409
-
410
-
411
-    /**
412
-     * Gets redirect_url
413
-     *
414
-     * @return string
415
-     * @throws \EE_Error
416
-     */
417
-    public function redirect_url()
418
-    {
419
-        return $this->get('PAY_redirect_url');
420
-    }
421
-
422
-
423
-    /**
424
-     * Gets redirect_args
425
-     *
426
-     * @return array
427
-     * @throws \EE_Error
428
-     */
429
-    public function redirect_args()
430
-    {
431
-        return $this->get('PAY_redirect_args');
432
-    }
433
-
434
-
435
-    /**
436
-     * echoes $this->pretty_status()
437
-     *
438
-     * @param bool $show_icons
439
-     * @return void
440
-     * @throws \EE_Error
441
-     */
442
-    public function e_pretty_status($show_icons = false)
443
-    {
444
-        echo $this->pretty_status($show_icons);
445
-    }
446
-
447
-
448
-    /**
449
-     * returns a pretty version of the status, good for displaying to users
450
-     *
451
-     * @param bool $show_icons
452
-     * @return string
453
-     * @throws \EE_Error
454
-     */
455
-    public function pretty_status($show_icons = false)
456
-    {
457
-        $status = EEM_Status::instance()->localized_status(
458
-            array($this->STS_ID() => __('unknown', 'event_espresso')),
459
-            false,
460
-            'sentence'
461
-        );
462
-        $icon = '';
463
-        switch ($this->STS_ID()) {
464
-            case EEM_Payment::status_id_approved:
465
-                $icon = $show_icons
466
-                    ? '<span class="dashicons dashicons-yes ee-icon-size-24 green-text"></span>'
467
-                    : '';
468
-                break;
469
-            case EEM_Payment::status_id_pending:
470
-                $icon = $show_icons
471
-                    ? '<span class="dashicons dashicons-clock ee-icon-size-16 orange-text"></span>'
472
-                    : '';
473
-                break;
474
-            case EEM_Payment::status_id_cancelled:
475
-                $icon = $show_icons
476
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 lt-grey-text"></span>'
477
-                    : '';
478
-                break;
479
-            case EEM_Payment::status_id_declined:
480
-                $icon = $show_icons
481
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>'
482
-                    : '';
483
-                break;
484
-        }
485
-        return $icon . $status[ $this->STS_ID() ];
486
-    }
487
-
488
-
489
-    /**
490
-     * For determining the status of the payment
491
-     *
492
-     * @return boolean whether the payment is approved or not
493
-     * @throws \EE_Error
494
-     */
495
-    public function is_approved()
496
-    {
497
-        return $this->status_is(EEM_Payment::status_id_approved);
498
-    }
499
-
500
-
501
-    /**
502
-     * Generally determines if the status of this payment equals
503
-     * the $STS_ID string
504
-     *
505
-     * @param string $STS_ID an ID from the esp_status table/
506
-     *                       one of the status_id_* on the EEM_Payment model
507
-     * @return boolean whether the status of this payment equals the status id
508
-     * @throws \EE_Error
509
-     */
510
-    protected function status_is($STS_ID)
511
-    {
512
-        return $STS_ID === $this->STS_ID() ? true : false;
513
-    }
514
-
515
-
516
-    /**
517
-     * For determining the status of the payment
518
-     *
519
-     * @return boolean whether the payment is pending or not
520
-     * @throws \EE_Error
521
-     */
522
-    public function is_pending()
523
-    {
524
-        return $this->status_is(EEM_Payment::status_id_pending);
525
-    }
526
-
527
-
528
-    /**
529
-     * For determining the status of the payment
530
-     *
531
-     * @return boolean
532
-     * @throws \EE_Error
533
-     */
534
-    public function is_cancelled()
535
-    {
536
-        return $this->status_is(EEM_Payment::status_id_cancelled);
537
-    }
538
-
539
-
540
-    /**
541
-     * For determining the status of the payment
542
-     *
543
-     * @return boolean
544
-     * @throws \EE_Error
545
-     */
546
-    public function is_declined()
547
-    {
548
-        return $this->status_is(EEM_Payment::status_id_declined);
549
-    }
550
-
551
-
552
-    /**
553
-     * For determining the status of the payment
554
-     *
555
-     * @return boolean
556
-     * @throws \EE_Error
557
-     */
558
-    public function is_failed()
559
-    {
560
-        return $this->status_is(EEM_Payment::status_id_failed);
561
-    }
562
-
563
-
564
-    /**
565
-     * For determining if the payment is actually a refund ( ie: has a negative value )
566
-     *
567
-     * @return boolean
568
-     * @throws \EE_Error
569
-     */
570
-    public function is_a_refund()
571
-    {
572
-        return $this->amount() < 0 ? true : false;
573
-    }
574
-
575
-
576
-    /**
577
-     * Get the status object of this object
578
-     *
579
-     * @return EE_Status
580
-     * @throws \EE_Error
581
-     */
582
-    public function status_obj()
583
-    {
584
-        return $this->get_first_related('Status');
585
-    }
586
-
587
-
588
-    /**
589
-     * Gets all the extra meta info on this payment
590
-     *
591
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
592
-     * @return EE_Extra_Meta
593
-     * @throws \EE_Error
594
-     */
595
-    public function extra_meta($query_params = array())
596
-    {
597
-        return $this->get_many_related('Extra_Meta', $query_params);
598
-    }
599
-
600
-
601
-    /**
602
-     * Gets the last-used payment method on this transaction
603
-     * (we COULD just use the last-made payment, but some payment methods, namely
604
-     * offline ones, dont' create payments)
605
-     *
606
-     * @return EE_Payment_Method
607
-     * @throws \EE_Error
608
-     */
609
-    public function payment_method()
610
-    {
611
-        return $this->get_first_related('Payment_Method');
612
-    }
613
-
614
-
615
-    /**
616
-     * Gets the HTML for redirecting the user to an offsite gateway
617
-     * You can pass it special content to put inside the form, or use
618
-     * the default inner content (or possibly generate this all yourself using
619
-     * redirect_url() and redirect_args() or redirect_args_as_inputs()).
620
-     * Creates a POST request by default, but if no redirect args are specified, creates a GET request instead
621
-     * (and any querystring variables in the redirect_url are converted into html inputs
622
-     * so browsers submit them properly)
623
-     *
624
-     * @param string $inside_form_html
625
-     * @return string html
626
-     * @throws \EE_Error
627
-     */
628
-    public function redirect_form($inside_form_html = null)
629
-    {
630
-        $redirect_url = $this->redirect_url();
631
-        if (! empty($redirect_url)) {
632
-            // what ? no inner form content?
633
-            if ($inside_form_html === null) {
634
-                $inside_form_html = EEH_HTML::p(
635
-                    sprintf(
636
-                        __(
637
-                            'If you are not automatically redirected to the payment website within 10 seconds... %1$s %2$s Click Here %3$s',
638
-                            'event_espresso'
639
-                        ),
640
-                        EEH_HTML::br(2),
641
-                        '<input type="submit" value="',
642
-                        '">'
643
-                    ),
644
-                    '',
645
-                    '',
646
-                    'text-align:center;'
647
-                );
648
-            }
649
-            $method = apply_filters(
650
-                'FHEE__EE_Payment__redirect_form__method',
651
-                $this->redirect_args() ? 'POST' : 'GET',
652
-                $this
653
-            );
654
-            // if it's a GET request, we need to remove all the GET params in the querystring
655
-            // and put them into the form instead
656
-            if ($method === 'GET') {
657
-                $querystring = parse_url($redirect_url, PHP_URL_QUERY);
658
-                $get_params = null;
659
-                parse_str($querystring, $get_params);
660
-                $inside_form_html .= $this->_args_as_inputs($get_params);
661
-                $redirect_url = str_replace('?' . $querystring, '', $redirect_url);
662
-            }
663
-            $form = EEH_HTML::nl(1)
664
-                    . '<form method="'
665
-                    . $method
666
-                    . '" name="gateway_form" action="'
667
-                    . $redirect_url
668
-                    . '">';
669
-            $form .= EEH_HTML::nl(1) . $this->redirect_args_as_inputs();
670
-            $form .= $inside_form_html;
671
-            $form .= EEH_HTML::nl(-1) . '</form>' . EEH_HTML::nl(-1);
672
-            return $form;
673
-        } else {
674
-            return null;
675
-        }
676
-    }
677
-
678
-
679
-    /**
680
-     * Changes all the name-value pairs of the redirect args into html inputs
681
-     * and returns the html as a string
682
-     *
683
-     * @return string
684
-     * @throws \EE_Error
685
-     */
686
-    public function redirect_args_as_inputs()
687
-    {
688
-        return $this->_args_as_inputs($this->redirect_args());
689
-    }
690
-
691
-
692
-    /**
693
-     * Converts a 1d array of key-value pairs into html hidden inputs
694
-     * and returns the string of html
695
-     *
696
-     * @param array $args key-value pairs
697
-     * @return string
698
-     */
699
-    protected function _args_as_inputs($args)
700
-    {
701
-        $html = '';
702
-        if ($args !== null && is_array($args)) {
703
-            foreach ($args as $name => $value) {
704
-                $html .= EEH_HTML::nl(0)
705
-                         . '<input type="hidden" name="'
706
-                         . $name
707
-                         . '" value="'
708
-                         . esc_attr($value)
709
-                         . '"/>';
710
-            }
711
-        }
712
-        return $html;
713
-    }
714
-
715
-
716
-    /**
717
-     * Returns the currency of the payment.
718
-     * (At the time of writing, this will always be the currency in the configuration;
719
-     * however in the future it is anticipated that this will be stored on the payment
720
-     * object itself)
721
-     *
722
-     * @return string for the currency code
723
-     */
724
-    public function currency_code()
725
-    {
726
-        return EE_Config::instance()->currency->code;
727
-    }
728
-
729
-
730
-    /**
731
-     * apply wp_strip_all_tags to all elements within an array
732
-     *
733
-     * @access private
734
-     * @param mixed $item
735
-     */
736
-    private function _strip_all_tags_within_array(&$item)
737
-    {
738
-        if (is_object($item)) {
739
-            $item = (array) $item;
740
-        }
741
-        if (is_array($item)) {
742
-            array_walk_recursive($item, array($this, '_strip_all_tags_within_array'));
743
-        } else {
744
-            $item = wp_strip_all_tags($item);
745
-        }
746
-    }
747
-
748
-
749
-    /**
750
-     * Returns TRUE is this payment was set to approved during this request (or
751
-     * is approved and was created during this request). False otherwise.
752
-     *
753
-     * @return boolean
754
-     * @throws \EE_Error
755
-     */
756
-    public function just_approved()
757
-    {
758
-        $original_status = EEH_Array::is_set(
759
-            $this->_props_n_values_provided_in_constructor,
760
-            'STS_ID',
761
-            $this->get_model()->field_settings_for('STS_ID')->get_default_value()
762
-        );
763
-        $current_status = $this->status();
764
-        if (
765
-            $original_status !== EEM_Payment::status_id_approved
766
-            && $current_status === EEM_Payment::status_id_approved
767
-        ) {
768
-            return true;
769
-        } else {
770
-            return false;
771
-        }
772
-    }
773
-
774
-
775
-    /**
776
-     * Overrides parents' get_pretty() function just for legacy reasons
777
-     * (to allow ticket https://events.codebasehq.com/projects/event-espresso/tickets/7420)
778
-     *
779
-     * @param string $field_name
780
-     * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
781
-     *                                (in cases where the same property may be used for different outputs
782
-     *                                - i.e. datetime, money etc.)
783
-     * @return mixed
784
-     * @throws \EE_Error
785
-     */
786
-    public function get_pretty($field_name, $extra_cache_ref = null)
787
-    {
788
-        if ($field_name === 'PAY_gateway') {
789
-            return $this->payment_method() ? $this->payment_method()->name() : __('Unknown', 'event_espresso');
790
-        }
791
-        return $this->_get_cached_property($field_name, true, $extra_cache_ref);
792
-    }
793
-
794
-
795
-    /**
796
-     * Gets details regarding which registrations this payment was applied to
797
-     *
798
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
799
-     * @return EE_Registration_Payment[]
800
-     * @throws \EE_Error
801
-     */
802
-    public function registration_payments($query_params = array())
803
-    {
804
-        return $this->get_many_related('Registration_Payment', $query_params);
805
-    }
806
-
807
-
808
-    /**
809
-     * Gets the first event for this payment (it's possible that it could be for multiple)
810
-     *
811
-     * @return EE_Event|null
812
-     */
813
-    public function get_first_event()
814
-    {
815
-        $transaction = $this->transaction();
816
-        if ($transaction instanceof EE_Transaction) {
817
-            $primary_registrant = $transaction->primary_registration();
818
-            if ($primary_registrant instanceof EE_Registration) {
819
-                return $primary_registrant->event_obj();
820
-            }
821
-        }
822
-        return null;
823
-    }
824
-
825
-
826
-    /**
827
-     * Gets the name of the first event for which is being paid
828
-     *
829
-     * @return string
830
-     */
831
-    public function get_first_event_name()
832
-    {
833
-        $event = $this->get_first_event();
834
-        return $event instanceof EE_Event ? $event->name() : __('Event', 'event_espresso');
835
-    }
836
-
837
-
838
-    /**
839
-     * Returns the payment's transaction's primary registration
840
-     *
841
-     * @return EE_Registration|null
842
-     */
843
-    public function get_primary_registration()
844
-    {
845
-        if ($this->transaction() instanceof EE_Transaction) {
846
-            return $this->transaction()->primary_registration();
847
-        }
848
-        return null;
849
-    }
850
-
851
-
852
-    /**
853
-     * Gets the payment's transaction's primary registration's attendee, or null
854
-     *
855
-     * @return EE_Attendee|null
856
-     */
857
-    public function get_primary_attendee()
858
-    {
859
-        $primary_reg = $this->get_primary_registration();
860
-        if ($primary_reg instanceof EE_Registration) {
861
-            return $primary_reg->attendee();
862
-        }
863
-        return null;
864
-    }
13
+	/**
14
+	 * @param array  $props_n_values          incoming values
15
+	 * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
16
+	 *                                        used.)
17
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
18
+	 *                                        date_format and the second value is the time format
19
+	 * @return EE_Payment
20
+	 * @throws \EE_Error
21
+	 */
22
+	public static function new_instance($props_n_values = array(), $timezone = '', $date_formats = array())
23
+	{
24
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
25
+		return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
26
+	}
27
+
28
+
29
+	/**
30
+	 * @param array  $props_n_values  incoming values from the database
31
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
32
+	 *                                the website will be used.
33
+	 * @return EE_Payment
34
+	 * @throws \EE_Error
35
+	 */
36
+	public static function new_instance_from_db($props_n_values = array(), $timezone = '')
37
+	{
38
+		return new self($props_n_values, true, $timezone);
39
+	}
40
+
41
+
42
+	/**
43
+	 * Set Transaction ID
44
+	 *
45
+	 * @access public
46
+	 * @param int $TXN_ID
47
+	 * @throws \EE_Error
48
+	 */
49
+	public function set_transaction_id($TXN_ID = 0)
50
+	{
51
+		$this->set('TXN_ID', $TXN_ID);
52
+	}
53
+
54
+
55
+	/**
56
+	 * Gets the transaction related to this payment
57
+	 *
58
+	 * @return EE_Transaction
59
+	 * @throws \EE_Error
60
+	 */
61
+	public function transaction()
62
+	{
63
+		return $this->get_first_related('Transaction');
64
+	}
65
+
66
+
67
+	/**
68
+	 * Set Status
69
+	 *
70
+	 * @access public
71
+	 * @param string $STS_ID
72
+	 * @throws \EE_Error
73
+	 */
74
+	public function set_status($STS_ID = '')
75
+	{
76
+		$this->set('STS_ID', $STS_ID);
77
+	}
78
+
79
+
80
+	/**
81
+	 * Set Payment Timestamp
82
+	 *
83
+	 * @access public
84
+	 * @param int $timestamp
85
+	 * @throws \EE_Error
86
+	 */
87
+	public function set_timestamp($timestamp = 0)
88
+	{
89
+		$this->set('PAY_timestamp', $timestamp);
90
+	}
91
+
92
+
93
+	/**
94
+	 * Set Payment Method
95
+	 *
96
+	 * @access public
97
+	 * @param string $PAY_source
98
+	 * @throws \EE_Error
99
+	 */
100
+	public function set_source($PAY_source = '')
101
+	{
102
+		$this->set('PAY_source', $PAY_source);
103
+	}
104
+
105
+
106
+	/**
107
+	 * Set Payment Amount
108
+	 *
109
+	 * @access public
110
+	 * @param float $amount
111
+	 * @throws \EE_Error
112
+	 */
113
+	public function set_amount($amount = 0.00)
114
+	{
115
+		$this->set('PAY_amount', (float) $amount);
116
+	}
117
+
118
+
119
+	/**
120
+	 * Set Payment Gateway Response
121
+	 *
122
+	 * @access public
123
+	 * @param string $gateway_response
124
+	 * @throws \EE_Error
125
+	 */
126
+	public function set_gateway_response($gateway_response = '')
127
+	{
128
+		$this->set('PAY_gateway_response', $gateway_response);
129
+	}
130
+
131
+
132
+	/**
133
+	 * Returns the name of the payment method used on this payment (previously known merely as 'gateway')
134
+	 * but since 4.6.0, payment methods are models and the payment keeps a foreign key to the payment method
135
+	 * used on it
136
+	 *
137
+	 * @deprecated
138
+	 * @return string
139
+	 * @throws \EE_Error
140
+	 */
141
+	public function gateway()
142
+	{
143
+		EE_Error::doing_it_wrong(
144
+			'EE_Payment::gateway',
145
+			__(
146
+				'The method EE_Payment::gateway() has been deprecated. Consider instead using EE_Payment::payment_method()->name()',
147
+				'event_espresso'
148
+			),
149
+			'4.6.0'
150
+		);
151
+		return $this->payment_method() ? $this->payment_method()->name() : __('Unknown', 'event_espresso');
152
+	}
153
+
154
+
155
+	/**
156
+	 * Set Gateway Transaction ID
157
+	 *
158
+	 * @access public
159
+	 * @param string $txn_id_chq_nmbr
160
+	 * @throws \EE_Error
161
+	 */
162
+	public function set_txn_id_chq_nmbr($txn_id_chq_nmbr = '')
163
+	{
164
+		$this->set('PAY_txn_id_chq_nmbr', $txn_id_chq_nmbr);
165
+	}
166
+
167
+
168
+	/**
169
+	 * Set Purchase Order Number
170
+	 *
171
+	 * @access public
172
+	 * @param string $po_number
173
+	 * @throws \EE_Error
174
+	 */
175
+	public function set_po_number($po_number = '')
176
+	{
177
+		$this->set('PAY_po_number', $po_number);
178
+	}
179
+
180
+
181
+	/**
182
+	 * Set Extra Accounting Field
183
+	 *
184
+	 * @access public
185
+	 * @param string $extra_accntng
186
+	 * @throws \EE_Error
187
+	 */
188
+	public function set_extra_accntng($extra_accntng = '')
189
+	{
190
+		$this->set('PAY_extra_accntng', $extra_accntng);
191
+	}
192
+
193
+
194
+	/**
195
+	 * Set Payment made via admin flag
196
+	 *
197
+	 * @access public
198
+	 * @param bool $via_admin
199
+	 * @throws \EE_Error
200
+	 */
201
+	public function set_payment_made_via_admin($via_admin = false)
202
+	{
203
+		if ($via_admin) {
204
+			$this->set('PAY_source', EEM_Payment_Method::scope_admin);
205
+		} else {
206
+			$this->set('PAY_source', EEM_Payment_Method::scope_cart);
207
+		}
208
+	}
209
+
210
+
211
+	/**
212
+	 * Set Payment Details
213
+	 *
214
+	 * @access public
215
+	 * @param string|array $details
216
+	 * @throws \EE_Error
217
+	 */
218
+	public function set_details($details = '')
219
+	{
220
+		if (is_array($details)) {
221
+			array_walk_recursive($details, array($this, '_strip_all_tags_within_array'));
222
+		} else {
223
+			$details = wp_strip_all_tags($details);
224
+		}
225
+		$this->set('PAY_details', $details);
226
+	}
227
+
228
+
229
+	/**
230
+	 * Sets redirect_url
231
+	 *
232
+	 * @param string $redirect_url
233
+	 * @throws \EE_Error
234
+	 */
235
+	public function set_redirect_url($redirect_url)
236
+	{
237
+		$this->set('PAY_redirect_url', $redirect_url);
238
+	}
239
+
240
+
241
+	/**
242
+	 * Sets redirect_args
243
+	 *
244
+	 * @param array $redirect_args
245
+	 * @throws \EE_Error
246
+	 */
247
+	public function set_redirect_args($redirect_args)
248
+	{
249
+		$this->set('PAY_redirect_args', $redirect_args);
250
+	}
251
+
252
+
253
+	/**
254
+	 * get Payment Transaction ID
255
+	 *
256
+	 * @access public
257
+	 * @throws \EE_Error
258
+	 */
259
+	public function TXN_ID()
260
+	{
261
+		return $this->get('TXN_ID');
262
+	}
263
+
264
+
265
+	/**
266
+	 * get Payment Status
267
+	 *
268
+	 * @access public
269
+	 * @throws \EE_Error
270
+	 */
271
+	public function status()
272
+	{
273
+		return $this->get('STS_ID');
274
+	}
275
+
276
+
277
+	/**
278
+	 * get Payment Status
279
+	 *
280
+	 * @access public
281
+	 * @throws \EE_Error
282
+	 */
283
+	public function STS_ID()
284
+	{
285
+		return $this->get('STS_ID');
286
+	}
287
+
288
+
289
+	/**
290
+	 * get Payment Timestamp
291
+	 *
292
+	 * @access public
293
+	 * @param string $dt_frmt
294
+	 * @param string $tm_frmt
295
+	 * @return string
296
+	 * @throws \EE_Error
297
+	 */
298
+	public function timestamp($dt_frmt = '', $tm_frmt = '')
299
+	{
300
+		return $this->get_i18n_datetime('PAY_timestamp', trim($dt_frmt . ' ' . $tm_frmt));
301
+	}
302
+
303
+
304
+	/**
305
+	 * get Payment Source
306
+	 *
307
+	 * @access public
308
+	 * @throws \EE_Error
309
+	 */
310
+	public function source()
311
+	{
312
+		return $this->get('PAY_source');
313
+	}
314
+
315
+
316
+	/**
317
+	 * get Payment Amount
318
+	 *
319
+	 * @access public
320
+	 * @return float
321
+	 * @throws \EE_Error
322
+	 */
323
+	public function amount()
324
+	{
325
+		return (float) $this->get('PAY_amount');
326
+	}
327
+
328
+
329
+	/**
330
+	 * @return mixed
331
+	 * @throws \EE_Error
332
+	 */
333
+	public function amount_no_code()
334
+	{
335
+		return $this->get_pretty('PAY_amount', 'no_currency_code');
336
+	}
337
+
338
+
339
+	/**
340
+	 * get Payment Gateway Response
341
+	 *
342
+	 * @access public
343
+	 * @throws \EE_Error
344
+	 */
345
+	public function gateway_response()
346
+	{
347
+		return $this->get('PAY_gateway_response');
348
+	}
349
+
350
+
351
+	/**
352
+	 * get Payment Gateway Transaction ID
353
+	 *
354
+	 * @access public
355
+	 * @throws \EE_Error
356
+	 */
357
+	public function txn_id_chq_nmbr()
358
+	{
359
+		return $this->get('PAY_txn_id_chq_nmbr');
360
+	}
361
+
362
+
363
+	/**
364
+	 * get Purchase Order Number
365
+	 *
366
+	 * @access public
367
+	 * @throws \EE_Error
368
+	 */
369
+	public function po_number()
370
+	{
371
+		return $this->get('PAY_po_number');
372
+	}
373
+
374
+
375
+	/**
376
+	 * get Extra Accounting Field
377
+	 *
378
+	 * @access public
379
+	 * @throws \EE_Error
380
+	 */
381
+	public function extra_accntng()
382
+	{
383
+		return $this->get('PAY_extra_accntng');
384
+	}
385
+
386
+
387
+	/**
388
+	 * get Payment made via admin source
389
+	 *
390
+	 * @access public
391
+	 * @throws \EE_Error
392
+	 */
393
+	public function payment_made_via_admin()
394
+	{
395
+		return ($this->get('PAY_source') === EEM_Payment_Method::scope_admin);
396
+	}
397
+
398
+
399
+	/**
400
+	 * get Payment Details
401
+	 *
402
+	 * @access public
403
+	 * @throws \EE_Error
404
+	 */
405
+	public function details()
406
+	{
407
+		return $this->get('PAY_details');
408
+	}
409
+
410
+
411
+	/**
412
+	 * Gets redirect_url
413
+	 *
414
+	 * @return string
415
+	 * @throws \EE_Error
416
+	 */
417
+	public function redirect_url()
418
+	{
419
+		return $this->get('PAY_redirect_url');
420
+	}
421
+
422
+
423
+	/**
424
+	 * Gets redirect_args
425
+	 *
426
+	 * @return array
427
+	 * @throws \EE_Error
428
+	 */
429
+	public function redirect_args()
430
+	{
431
+		return $this->get('PAY_redirect_args');
432
+	}
433
+
434
+
435
+	/**
436
+	 * echoes $this->pretty_status()
437
+	 *
438
+	 * @param bool $show_icons
439
+	 * @return void
440
+	 * @throws \EE_Error
441
+	 */
442
+	public function e_pretty_status($show_icons = false)
443
+	{
444
+		echo $this->pretty_status($show_icons);
445
+	}
446
+
447
+
448
+	/**
449
+	 * returns a pretty version of the status, good for displaying to users
450
+	 *
451
+	 * @param bool $show_icons
452
+	 * @return string
453
+	 * @throws \EE_Error
454
+	 */
455
+	public function pretty_status($show_icons = false)
456
+	{
457
+		$status = EEM_Status::instance()->localized_status(
458
+			array($this->STS_ID() => __('unknown', 'event_espresso')),
459
+			false,
460
+			'sentence'
461
+		);
462
+		$icon = '';
463
+		switch ($this->STS_ID()) {
464
+			case EEM_Payment::status_id_approved:
465
+				$icon = $show_icons
466
+					? '<span class="dashicons dashicons-yes ee-icon-size-24 green-text"></span>'
467
+					: '';
468
+				break;
469
+			case EEM_Payment::status_id_pending:
470
+				$icon = $show_icons
471
+					? '<span class="dashicons dashicons-clock ee-icon-size-16 orange-text"></span>'
472
+					: '';
473
+				break;
474
+			case EEM_Payment::status_id_cancelled:
475
+				$icon = $show_icons
476
+					? '<span class="dashicons dashicons-no ee-icon-size-16 lt-grey-text"></span>'
477
+					: '';
478
+				break;
479
+			case EEM_Payment::status_id_declined:
480
+				$icon = $show_icons
481
+					? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>'
482
+					: '';
483
+				break;
484
+		}
485
+		return $icon . $status[ $this->STS_ID() ];
486
+	}
487
+
488
+
489
+	/**
490
+	 * For determining the status of the payment
491
+	 *
492
+	 * @return boolean whether the payment is approved or not
493
+	 * @throws \EE_Error
494
+	 */
495
+	public function is_approved()
496
+	{
497
+		return $this->status_is(EEM_Payment::status_id_approved);
498
+	}
499
+
500
+
501
+	/**
502
+	 * Generally determines if the status of this payment equals
503
+	 * the $STS_ID string
504
+	 *
505
+	 * @param string $STS_ID an ID from the esp_status table/
506
+	 *                       one of the status_id_* on the EEM_Payment model
507
+	 * @return boolean whether the status of this payment equals the status id
508
+	 * @throws \EE_Error
509
+	 */
510
+	protected function status_is($STS_ID)
511
+	{
512
+		return $STS_ID === $this->STS_ID() ? true : false;
513
+	}
514
+
515
+
516
+	/**
517
+	 * For determining the status of the payment
518
+	 *
519
+	 * @return boolean whether the payment is pending or not
520
+	 * @throws \EE_Error
521
+	 */
522
+	public function is_pending()
523
+	{
524
+		return $this->status_is(EEM_Payment::status_id_pending);
525
+	}
526
+
527
+
528
+	/**
529
+	 * For determining the status of the payment
530
+	 *
531
+	 * @return boolean
532
+	 * @throws \EE_Error
533
+	 */
534
+	public function is_cancelled()
535
+	{
536
+		return $this->status_is(EEM_Payment::status_id_cancelled);
537
+	}
538
+
539
+
540
+	/**
541
+	 * For determining the status of the payment
542
+	 *
543
+	 * @return boolean
544
+	 * @throws \EE_Error
545
+	 */
546
+	public function is_declined()
547
+	{
548
+		return $this->status_is(EEM_Payment::status_id_declined);
549
+	}
550
+
551
+
552
+	/**
553
+	 * For determining the status of the payment
554
+	 *
555
+	 * @return boolean
556
+	 * @throws \EE_Error
557
+	 */
558
+	public function is_failed()
559
+	{
560
+		return $this->status_is(EEM_Payment::status_id_failed);
561
+	}
562
+
563
+
564
+	/**
565
+	 * For determining if the payment is actually a refund ( ie: has a negative value )
566
+	 *
567
+	 * @return boolean
568
+	 * @throws \EE_Error
569
+	 */
570
+	public function is_a_refund()
571
+	{
572
+		return $this->amount() < 0 ? true : false;
573
+	}
574
+
575
+
576
+	/**
577
+	 * Get the status object of this object
578
+	 *
579
+	 * @return EE_Status
580
+	 * @throws \EE_Error
581
+	 */
582
+	public function status_obj()
583
+	{
584
+		return $this->get_first_related('Status');
585
+	}
586
+
587
+
588
+	/**
589
+	 * Gets all the extra meta info on this payment
590
+	 *
591
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
592
+	 * @return EE_Extra_Meta
593
+	 * @throws \EE_Error
594
+	 */
595
+	public function extra_meta($query_params = array())
596
+	{
597
+		return $this->get_many_related('Extra_Meta', $query_params);
598
+	}
599
+
600
+
601
+	/**
602
+	 * Gets the last-used payment method on this transaction
603
+	 * (we COULD just use the last-made payment, but some payment methods, namely
604
+	 * offline ones, dont' create payments)
605
+	 *
606
+	 * @return EE_Payment_Method
607
+	 * @throws \EE_Error
608
+	 */
609
+	public function payment_method()
610
+	{
611
+		return $this->get_first_related('Payment_Method');
612
+	}
613
+
614
+
615
+	/**
616
+	 * Gets the HTML for redirecting the user to an offsite gateway
617
+	 * You can pass it special content to put inside the form, or use
618
+	 * the default inner content (or possibly generate this all yourself using
619
+	 * redirect_url() and redirect_args() or redirect_args_as_inputs()).
620
+	 * Creates a POST request by default, but if no redirect args are specified, creates a GET request instead
621
+	 * (and any querystring variables in the redirect_url are converted into html inputs
622
+	 * so browsers submit them properly)
623
+	 *
624
+	 * @param string $inside_form_html
625
+	 * @return string html
626
+	 * @throws \EE_Error
627
+	 */
628
+	public function redirect_form($inside_form_html = null)
629
+	{
630
+		$redirect_url = $this->redirect_url();
631
+		if (! empty($redirect_url)) {
632
+			// what ? no inner form content?
633
+			if ($inside_form_html === null) {
634
+				$inside_form_html = EEH_HTML::p(
635
+					sprintf(
636
+						__(
637
+							'If you are not automatically redirected to the payment website within 10 seconds... %1$s %2$s Click Here %3$s',
638
+							'event_espresso'
639
+						),
640
+						EEH_HTML::br(2),
641
+						'<input type="submit" value="',
642
+						'">'
643
+					),
644
+					'',
645
+					'',
646
+					'text-align:center;'
647
+				);
648
+			}
649
+			$method = apply_filters(
650
+				'FHEE__EE_Payment__redirect_form__method',
651
+				$this->redirect_args() ? 'POST' : 'GET',
652
+				$this
653
+			);
654
+			// if it's a GET request, we need to remove all the GET params in the querystring
655
+			// and put them into the form instead
656
+			if ($method === 'GET') {
657
+				$querystring = parse_url($redirect_url, PHP_URL_QUERY);
658
+				$get_params = null;
659
+				parse_str($querystring, $get_params);
660
+				$inside_form_html .= $this->_args_as_inputs($get_params);
661
+				$redirect_url = str_replace('?' . $querystring, '', $redirect_url);
662
+			}
663
+			$form = EEH_HTML::nl(1)
664
+					. '<form method="'
665
+					. $method
666
+					. '" name="gateway_form" action="'
667
+					. $redirect_url
668
+					. '">';
669
+			$form .= EEH_HTML::nl(1) . $this->redirect_args_as_inputs();
670
+			$form .= $inside_form_html;
671
+			$form .= EEH_HTML::nl(-1) . '</form>' . EEH_HTML::nl(-1);
672
+			return $form;
673
+		} else {
674
+			return null;
675
+		}
676
+	}
677
+
678
+
679
+	/**
680
+	 * Changes all the name-value pairs of the redirect args into html inputs
681
+	 * and returns the html as a string
682
+	 *
683
+	 * @return string
684
+	 * @throws \EE_Error
685
+	 */
686
+	public function redirect_args_as_inputs()
687
+	{
688
+		return $this->_args_as_inputs($this->redirect_args());
689
+	}
690
+
691
+
692
+	/**
693
+	 * Converts a 1d array of key-value pairs into html hidden inputs
694
+	 * and returns the string of html
695
+	 *
696
+	 * @param array $args key-value pairs
697
+	 * @return string
698
+	 */
699
+	protected function _args_as_inputs($args)
700
+	{
701
+		$html = '';
702
+		if ($args !== null && is_array($args)) {
703
+			foreach ($args as $name => $value) {
704
+				$html .= EEH_HTML::nl(0)
705
+						 . '<input type="hidden" name="'
706
+						 . $name
707
+						 . '" value="'
708
+						 . esc_attr($value)
709
+						 . '"/>';
710
+			}
711
+		}
712
+		return $html;
713
+	}
714
+
715
+
716
+	/**
717
+	 * Returns the currency of the payment.
718
+	 * (At the time of writing, this will always be the currency in the configuration;
719
+	 * however in the future it is anticipated that this will be stored on the payment
720
+	 * object itself)
721
+	 *
722
+	 * @return string for the currency code
723
+	 */
724
+	public function currency_code()
725
+	{
726
+		return EE_Config::instance()->currency->code;
727
+	}
728
+
729
+
730
+	/**
731
+	 * apply wp_strip_all_tags to all elements within an array
732
+	 *
733
+	 * @access private
734
+	 * @param mixed $item
735
+	 */
736
+	private function _strip_all_tags_within_array(&$item)
737
+	{
738
+		if (is_object($item)) {
739
+			$item = (array) $item;
740
+		}
741
+		if (is_array($item)) {
742
+			array_walk_recursive($item, array($this, '_strip_all_tags_within_array'));
743
+		} else {
744
+			$item = wp_strip_all_tags($item);
745
+		}
746
+	}
747
+
748
+
749
+	/**
750
+	 * Returns TRUE is this payment was set to approved during this request (or
751
+	 * is approved and was created during this request). False otherwise.
752
+	 *
753
+	 * @return boolean
754
+	 * @throws \EE_Error
755
+	 */
756
+	public function just_approved()
757
+	{
758
+		$original_status = EEH_Array::is_set(
759
+			$this->_props_n_values_provided_in_constructor,
760
+			'STS_ID',
761
+			$this->get_model()->field_settings_for('STS_ID')->get_default_value()
762
+		);
763
+		$current_status = $this->status();
764
+		if (
765
+			$original_status !== EEM_Payment::status_id_approved
766
+			&& $current_status === EEM_Payment::status_id_approved
767
+		) {
768
+			return true;
769
+		} else {
770
+			return false;
771
+		}
772
+	}
773
+
774
+
775
+	/**
776
+	 * Overrides parents' get_pretty() function just for legacy reasons
777
+	 * (to allow ticket https://events.codebasehq.com/projects/event-espresso/tickets/7420)
778
+	 *
779
+	 * @param string $field_name
780
+	 * @param string $extra_cache_ref This allows the user to specify an extra cache ref for the given property
781
+	 *                                (in cases where the same property may be used for different outputs
782
+	 *                                - i.e. datetime, money etc.)
783
+	 * @return mixed
784
+	 * @throws \EE_Error
785
+	 */
786
+	public function get_pretty($field_name, $extra_cache_ref = null)
787
+	{
788
+		if ($field_name === 'PAY_gateway') {
789
+			return $this->payment_method() ? $this->payment_method()->name() : __('Unknown', 'event_espresso');
790
+		}
791
+		return $this->_get_cached_property($field_name, true, $extra_cache_ref);
792
+	}
793
+
794
+
795
+	/**
796
+	 * Gets details regarding which registrations this payment was applied to
797
+	 *
798
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
799
+	 * @return EE_Registration_Payment[]
800
+	 * @throws \EE_Error
801
+	 */
802
+	public function registration_payments($query_params = array())
803
+	{
804
+		return $this->get_many_related('Registration_Payment', $query_params);
805
+	}
806
+
807
+
808
+	/**
809
+	 * Gets the first event for this payment (it's possible that it could be for multiple)
810
+	 *
811
+	 * @return EE_Event|null
812
+	 */
813
+	public function get_first_event()
814
+	{
815
+		$transaction = $this->transaction();
816
+		if ($transaction instanceof EE_Transaction) {
817
+			$primary_registrant = $transaction->primary_registration();
818
+			if ($primary_registrant instanceof EE_Registration) {
819
+				return $primary_registrant->event_obj();
820
+			}
821
+		}
822
+		return null;
823
+	}
824
+
825
+
826
+	/**
827
+	 * Gets the name of the first event for which is being paid
828
+	 *
829
+	 * @return string
830
+	 */
831
+	public function get_first_event_name()
832
+	{
833
+		$event = $this->get_first_event();
834
+		return $event instanceof EE_Event ? $event->name() : __('Event', 'event_espresso');
835
+	}
836
+
837
+
838
+	/**
839
+	 * Returns the payment's transaction's primary registration
840
+	 *
841
+	 * @return EE_Registration|null
842
+	 */
843
+	public function get_primary_registration()
844
+	{
845
+		if ($this->transaction() instanceof EE_Transaction) {
846
+			return $this->transaction()->primary_registration();
847
+		}
848
+		return null;
849
+	}
850
+
851
+
852
+	/**
853
+	 * Gets the payment's transaction's primary registration's attendee, or null
854
+	 *
855
+	 * @return EE_Attendee|null
856
+	 */
857
+	public function get_primary_attendee()
858
+	{
859
+		$primary_reg = $this->get_primary_registration();
860
+		if ($primary_reg instanceof EE_Registration) {
861
+			return $primary_reg->attendee();
862
+		}
863
+		return null;
864
+	}
865 865
 }
Please login to merge, or discard this patch.
core/db_classes/EE_Message.class.php 1 patch
Indentation   +867 added lines, -867 removed lines patch added patch discarded remove patch
@@ -10,875 +10,875 @@
 block discarded – undo
10 10
 class EE_Message extends EE_Base_Class implements EEI_Admin_Links
11 11
 {
12 12
 
13
-    /**
14
-     * @deprecated 4.9.0  Added for backward compat with add-on's
15
-     * @type null
16
-     */
17
-    public $template_pack;
18
-
19
-    /**
20
-     * @deprecated 4.9.0 Added for backward compat with add-on's
21
-     * @type null
22
-     */
23
-    public $template_variation;
24
-
25
-    /**
26
-     * @deprecated 4.9.0 Added for backward compat with add-on's
27
-     * @type string
28
-     */
29
-    public $content = '';
30
-
31
-
32
-    /**
33
-     * @type EE_messenger $_messenger
34
-     */
35
-    protected $_messenger = null;
36
-
37
-    /**
38
-     * @type EE_message_type $_message_type
39
-     */
40
-    protected $_message_type = null;
41
-
42
-
43
-    /**
44
-     * @param array  $props_n_values
45
-     * @param string $timezone
46
-     * @param array  $date_formats incoming date formats in an array.  First value is the date_format, second is time
47
-     *                             format.
48
-     * @return EE_Message
49
-     */
50
-    public static function new_instance($props_n_values = array(), $timezone = '', $date_formats = array())
51
-    {
52
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__);
53
-        // if object doesn't exist, let's generate a unique token on instantiation so that its available even before saving to db.
54
-        if (! $has_object) {
55
-            EE_Registry::instance()->load_helper('URL');
56
-            $props_n_values['MSG_token'] = EEH_URL::generate_unique_token();
57
-        }
58
-        return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
59
-    }
60
-
61
-
62
-    /**
63
-     * @param array  $props_n_values
64
-     * @param string $timezone
65
-     * @return EE_Message
66
-     */
67
-    public static function new_instance_from_db($props_n_values = array(), $timezone = '')
68
-    {
69
-        return new self($props_n_values, true, $timezone);
70
-    }
71
-
72
-
73
-    /**
74
-     * Gets MSG_token
75
-     *
76
-     * @return int
77
-     */
78
-    public function MSG_token()
79
-    {
80
-        return $this->get('MSG_token');
81
-    }
82
-
83
-
84
-    /**
85
-     * Sets MSG_token
86
-     *
87
-     * @param int $MSG_token
88
-     */
89
-    public function set_MSG_token($MSG_token)
90
-    {
91
-        $this->set('MSG_token', $MSG_token);
92
-    }
93
-
94
-
95
-    /**
96
-     * Gets GRP_ID
97
-     *
98
-     * @return int
99
-     */
100
-    public function GRP_ID()
101
-    {
102
-        return $this->get('GRP_ID');
103
-    }
104
-
105
-
106
-    /**
107
-     * Sets GRP_ID
108
-     *
109
-     * @param int $GRP_ID
110
-     */
111
-    public function set_GRP_ID($GRP_ID)
112
-    {
113
-        $this->set('GRP_ID', $GRP_ID);
114
-    }
115
-
116
-
117
-    /**
118
-     * Gets TXN_ID
119
-     *
120
-     * @return int
121
-     */
122
-    public function TXN_ID()
123
-    {
124
-        return $this->get('TXN_ID');
125
-    }
126
-
127
-
128
-    /**
129
-     * Sets TXN_ID
130
-     *
131
-     * @param int $TXN_ID
132
-     */
133
-    public function set_TXN_ID($TXN_ID)
134
-    {
135
-        $this->set('TXN_ID', $TXN_ID);
136
-    }
137
-
138
-
139
-    /**
140
-     * Gets messenger
141
-     *
142
-     * @return string
143
-     */
144
-    public function messenger()
145
-    {
146
-        return $this->get('MSG_messenger');
147
-    }
148
-
149
-
150
-    /**
151
-     * Sets messenger
152
-     *
153
-     * @param string $messenger
154
-     */
155
-    public function set_messenger($messenger)
156
-    {
157
-        $this->set('MSG_messenger', $messenger);
158
-    }
159
-
160
-
161
-    /**
162
-     * Returns corresponding messenger object for the set messenger on this message
163
-     *
164
-     * @return EE_messenger | null
165
-     */
166
-    public function messenger_object()
167
-    {
168
-        return $this->_messenger;
169
-    }
170
-
171
-
172
-    /**
173
-     * Sets messenger
174
-     *
175
-     * @param EE_messenger $messenger
176
-     */
177
-    public function set_messenger_object(EE_messenger $messenger)
178
-    {
179
-        $this->_messenger = $messenger;
180
-    }
181
-
182
-
183
-    /**
184
-     * validates messenger
185
-     *
186
-     * @param bool $throw_exceptions
187
-     * @return bool
188
-     * @throws \EE_Error
189
-     */
190
-    public function valid_messenger($throw_exceptions = false)
191
-    {
192
-        if ($this->_messenger instanceof EE_messenger) {
193
-            return true;
194
-        }
195
-        if ($throw_exceptions) {
196
-            throw new EE_Error(
197
-                sprintf(
198
-                    __(
199
-                        'The "%1$s" messenger set for this message is missing or invalid. Please double-check the spelling and verify that the correct files exist.',
200
-                        'event_espresso'
201
-                    ),
202
-                    $this->messenger()
203
-                )
204
-            );
205
-        }
206
-        return false;
207
-    }
208
-
209
-
210
-    /**
211
-     * This returns the set localized label for the messenger on this message.
212
-     * Note, if unable to retrieve the EE_messenger object then will just return the messenger slug saved
213
-     * with this message.
214
-     *
215
-     * @param   bool $plural whether to return the plural label or not.
216
-     * @return string
217
-     */
218
-    public function messenger_label($plural = false)
219
-    {
220
-        $label_type = $plural ? 'plural' : 'singular';
221
-        $messenger = $this->messenger_object();
222
-        return $messenger instanceof EE_messenger ? $messenger->label[ $label_type ] : $this->messenger();
223
-    }
224
-
225
-
226
-    /**
227
-     * Gets message_type
228
-     *
229
-     * @return string
230
-     */
231
-    public function message_type()
232
-    {
233
-        return $this->get('MSG_message_type');
234
-    }
235
-
236
-
237
-    /**
238
-     * Sets message_type
239
-     *
240
-     * @param string $message_type
241
-     */
242
-    public function set_message_type($message_type)
243
-    {
244
-        $this->set('MSG_message_type', $message_type);
245
-    }
246
-
247
-
248
-    /**
249
-     * Returns the message type object for the set message type on this message
250
-     *
251
-     * @return EE_message_type | null
252
-     */
253
-    public function message_type_object()
254
-    {
255
-        return $this->_message_type;
256
-    }
257
-
258
-
259
-    /**
260
-     * Sets message_type
261
-     *
262
-     * @param EE_message_type $message_type
263
-     * @param bool            $set_priority   This indicates whether to set the priority to whatever the priority is on
264
-     *                                        the message type or not.
265
-     */
266
-    public function set_message_type_object(EE_message_type $message_type, $set_priority = false)
267
-    {
268
-        $this->_message_type = $message_type;
269
-        if ($set_priority) {
270
-            $this->set_priority($this->_message_type->get_priority());
271
-        }
272
-    }
273
-
274
-
275
-    /**
276
-     * validates message_type
277
-     *
278
-     * @param bool $throw_exceptions
279
-     * @return bool
280
-     * @throws \EE_Error
281
-     */
282
-    public function valid_message_type($throw_exceptions = false)
283
-    {
284
-        if ($this->_message_type instanceof EE_message_type) {
285
-            return true;
286
-        }
287
-        if ($throw_exceptions) {
288
-            throw new EE_Error(
289
-                sprintf(
290
-                    __(
291
-                        'The %1$s message type set for this message is missing or invalid. Please double-check the spelling and verify that the correct files exist.',
292
-                        'event_espresso'
293
-                    ),
294
-                    $this->message_type()
295
-                )
296
-            );
297
-        }
298
-        return false;
299
-    }
300
-
301
-
302
-    /**
303
-     * validates messenger and message_type (that they are valid EE_messenger and EE_message_type objects).
304
-     *
305
-     * @param bool $throw_exceptions
306
-     * @return bool
307
-     * @throws \EE_Error
308
-     */
309
-    public function is_valid($throw_exceptions = false)
310
-    {
311
-        if ($this->valid_messenger($throw_exceptions) && $this->valid_message_type($throw_exceptions)) {
312
-            return true;
313
-        }
314
-        return false;
315
-    }
316
-
317
-
318
-    /**
319
-     * This validates whether the internal messenger and message type objects are valid for sending.
320
-     * Three checks are done:
321
-     * 1. There is a valid messenger object.
322
-     * 2. There is a valid message type object.
323
-     * 3. The message type object is active for the messenger.
324
-     *
325
-     * @throws EE_Error  But only if $throw_exceptions is set to true.
326
-     * @param bool $throw_exceptions
327
-     * @return bool
328
-     */
329
-    public function is_valid_for_sending_or_generation($throw_exceptions = false)
330
-    {
331
-        $valid = false;
332
-        if ($this->is_valid($throw_exceptions)) {
333
-            /** @var EE_Message_Resource_Manager $message_resource_manager */
334
-            $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
335
-            $valid = $message_resource_manager->is_message_type_active_for_messenger(
336
-                $this->messenger(),
337
-                $this->message_type()
338
-            );
339
-            if (! $valid && $throw_exceptions) {
340
-                throw new EE_Error(
341
-                    sprintf(
342
-                        __(
343
-                            'The %1$s message type is not a valid message type for the %2$s messenger so it will not be sent.',
344
-                            'event_espresso'
345
-                        ),
346
-                        $this->message_type(),
347
-                        $this->messenger()
348
-                    )
349
-                );
350
-            }
351
-        }
352
-        return $valid;
353
-    }
354
-
355
-
356
-    /**
357
-     * This returns the set localized label for the message type on this message.
358
-     * Note, if unable to retrieve the EE_message_type object then will just return the message type slug saved
359
-     * with this message.
360
-     *
361
-     * @param   bool $plural whether to return the plural label or not.
362
-     * @return string
363
-     */
364
-    public function message_type_label($plural = false)
365
-    {
366
-        $label_type = $plural ? 'plural' : 'singular';
367
-        $message_type = $this->message_type_object();
368
-        return $message_type instanceof EE_message_type
369
-            ? $message_type->label[ $label_type ]
370
-            : str_replace(
371
-                '_',
372
-                ' ',
373
-                $this->message_type()
374
-            );
375
-    }
376
-
377
-
378
-    /**
379
-     * Gets context
380
-     *
381
-     * @return string
382
-     */
383
-    public function context()
384
-    {
385
-        return $this->get('MSG_context');
386
-    }
387
-
388
-
389
-    /**
390
-     * This returns the corresponding localized label for the given context slug, if possible from installed message
391
-     * types. Otherwise, this will just return the set context slug on this object.
392
-     *
393
-     * @return string
394
-     */
395
-    public function context_label()
396
-    {
397
-        /** @type EE_Message_Resource_Manager $message_resource_manager */
398
-        $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
399
-        $contexts = $message_resource_manager->get_all_contexts();
400
-        return isset($contexts[ $this->context() ]) ? $contexts[ $this->context() ] : $this->context();
401
-    }
402
-
403
-
404
-    /**
405
-     * Sets context
406
-     *
407
-     * @param string $context
408
-     */
409
-    public function set_context($context)
410
-    {
411
-        $this->set('MSG_context', $context);
412
-    }
413
-
414
-
415
-    /**
416
-     * Gets recipient_ID
417
-     *
418
-     * @return int
419
-     */
420
-    public function recipient_ID()
421
-    {
422
-        return $this->get('MSG_recipient_ID');
423
-    }
424
-
425
-
426
-    /**
427
-     * Sets recipient_ID
428
-     *
429
-     * @param string $recipient_ID
430
-     */
431
-    public function set_recipient_ID($recipient_ID)
432
-    {
433
-        $this->set('MSG_recipient_ID', $recipient_ID);
434
-    }
435
-
436
-
437
-    /**
438
-     * Gets recipient_type
439
-     *
440
-     * @return string
441
-     */
442
-    public function recipient_type()
443
-    {
444
-        return $this->get('MSG_recipient_type');
445
-    }
446
-
447
-
448
-    /**
449
-     * Return the related object matching the recipient type and ID.
450
-     *
451
-     * @return EE_Base_Class | null
452
-     */
453
-    public function recipient_object()
454
-    {
455
-        if (! $this->recipient_type() || ! $this->recipient_ID()) {
456
-            return null;
457
-        }
458
-
459
-        return $this->get_first_related($this->recipient_type());
460
-    }
461
-
462
-
463
-    /**
464
-     * Sets recipient_type
465
-     *
466
-     * @param string $recipient_type
467
-     */
468
-    public function set_recipient_type($recipient_type)
469
-    {
470
-        $this->set('MSG_recipient_type', $recipient_type);
471
-    }
472
-
473
-
474
-    /**
475
-     * Gets content
476
-     *
477
-     * @return string
478
-     */
479
-    public function content()
480
-    {
481
-        return $this->get('MSG_content');
482
-    }
483
-
484
-
485
-    /**
486
-     * Sets content
487
-     *
488
-     * @param string $content
489
-     */
490
-    public function set_content($content)
491
-    {
492
-        $this->set('MSG_content', $content);
493
-    }
494
-
495
-
496
-    /**
497
-     * Gets subject
498
-     *
499
-     * @return string
500
-     */
501
-    public function subject()
502
-    {
503
-        return $this->get('MSG_subject');
504
-    }
505
-
506
-
507
-    /**
508
-     * Sets subject
509
-     *
510
-     * @param string $subject
511
-     */
512
-    public function set_subject($subject)
513
-    {
514
-        $this->set('MSG_subject', $subject);
515
-    }
516
-
517
-
518
-    /**
519
-     * Gets to
520
-     *
521
-     * @return string
522
-     */
523
-    public function to()
524
-    {
525
-        $to = $this->get('MSG_to');
526
-        return empty($to) ? __('No recipient', 'event_espresso') : $to;
527
-    }
528
-
529
-
530
-    /**
531
-     * Sets to
532
-     *
533
-     * @param string $to
534
-     */
535
-    public function set_to($to)
536
-    {
537
-        $this->set('MSG_to', $to);
538
-    }
539
-
540
-
541
-    /**
542
-     * Gets from
543
-     *
544
-     * @return string
545
-     */
546
-    public function from()
547
-    {
548
-        return $this->get('MSG_from');
549
-    }
550
-
551
-
552
-    /**
553
-     * Sets from
554
-     *
555
-     * @param string $from
556
-     */
557
-    public function set_from($from)
558
-    {
559
-        $this->set('MSG_from', $from);
560
-    }
561
-
562
-
563
-    /**
564
-     * Gets priority
565
-     *
566
-     * @return int
567
-     */
568
-    public function priority()
569
-    {
570
-        return $this->get('MSG_priority');
571
-    }
572
-
573
-
574
-    /**
575
-     * Sets priority
576
-     * Note.  Send Now Messengers always override any priority that may be set on a Message.  So
577
-     * this method calls the send_now method to verify that.
578
-     *
579
-     * @param int $priority
580
-     */
581
-    public function set_priority($priority)
582
-    {
583
-        $priority = $this->send_now() ? EEM_Message::priority_high : $priority;
584
-        parent::set('MSG_priority', $priority);
585
-    }
586
-
587
-
588
-    /**
589
-     * Overrides parent::set method so we can capture any sets for priority.
590
-     *
591
-     * @see parent::set() for phpdocs
592
-     * @param string $field_name
593
-     * @param mixed  $field_value
594
-     * @param bool   $use_default
595
-     * @throws EE_Error
596
-     */
597
-    public function set($field_name, $field_value, $use_default = false)
598
-    {
599
-        if ($field_name === 'MSG_priority') {
600
-            $this->set_priority($field_value);
601
-        }
602
-        parent::set($field_name, $field_value, $use_default);
603
-    }
604
-
605
-
606
-    /**
607
-     * @return bool
608
-     * @throws \EE_Error
609
-     */
610
-    public function send_now()
611
-    {
612
-        $send_now = $this->valid_messenger() && $this->messenger_object()->send_now() ? EEM_Message::priority_high
613
-            : $this->priority();
614
-        return $send_now === EEM_Message::priority_high ? true : false;
615
-    }
616
-
617
-
618
-    /**
619
-     * Gets STS_ID
620
-     *
621
-     * @return string
622
-     */
623
-    public function STS_ID()
624
-    {
625
-        return $this->get('STS_ID');
626
-    }
627
-
628
-
629
-    /**
630
-     * Sets STS_ID
631
-     *
632
-     * @param string $STS_ID
633
-     */
634
-    public function set_STS_ID($STS_ID)
635
-    {
636
-        $this->set('STS_ID', $STS_ID);
637
-    }
638
-
639
-
640
-    /**
641
-     * Gets created
642
-     *
643
-     * @return string
644
-     */
645
-    public function created()
646
-    {
647
-        return $this->get('MSG_created');
648
-    }
649
-
650
-
651
-    /**
652
-     * Sets created
653
-     *
654
-     * @param string $created
655
-     */
656
-    public function set_created($created)
657
-    {
658
-        $this->set('MSG_created', $created);
659
-    }
660
-
661
-
662
-    /**
663
-     * Gets modified
664
-     *
665
-     * @return string
666
-     */
667
-    public function modified()
668
-    {
669
-        return $this->get('MSG_modified');
670
-    }
671
-
672
-
673
-    /**
674
-     * Sets modified
675
-     *
676
-     * @param string $modified
677
-     */
678
-    public function set_modified($modified)
679
-    {
680
-        $this->set('MSG_modified', $modified);
681
-    }
682
-
683
-
684
-    /**
685
-     * Sets generation data for this message.
686
-     *
687
-     * @param mixed $data
688
-     */
689
-    public function set_generation_data($data)
690
-    {
691
-        $this->set_field_or_extra_meta('MSG_generation_data', $data);
692
-    }
693
-
694
-
695
-    /**
696
-     * Returns any set generation data for this message.
697
-     *
698
-     * @return mixed|null
699
-     */
700
-    public function get_generation_data()
701
-    {
702
-        return $this->get_field_or_extra_meta('MSG_generation_data');
703
-    }
704
-
705
-
706
-    /**
707
-     * Gets any error message.
708
-     *
709
-     * @return mixed|null
710
-     */
711
-    public function error_message()
712
-    {
713
-        return $this->get_field_or_extra_meta('MSG_error');
714
-    }
715
-
716
-
717
-    /**
718
-     * Sets an error message.
719
-     *
720
-     * @param $message
721
-     * @return bool|int
722
-     */
723
-    public function set_error_message($message)
724
-    {
725
-        return $this->set_field_or_extra_meta('MSG_error', $message);
726
-    }
727
-
728
-
729
-    /**
730
-     * This retrieves the associated template pack with this message.
731
-     *
732
-     * @return EE_Messages_Template_Pack | null
733
-     */
734
-    public function get_template_pack()
735
-    {
736
-        /**
737
-         * This is deprecated functionality that will be removed eventually but included here now for backward compat.
738
-         */
739
-        if (! empty($this->template_pack)) {
740
-            return $this->template_pack;
741
-        }
742
-        /** @type EE_Message_Template_Group $grp */
743
-        $grp = $this->get_first_related('Message_Template_Group');
744
-        // if no group then let's try to get the first related group by internal messenger and message type (will use global grp).
745
-        if (! $grp instanceof EE_Message_Template_Group) {
746
-            $grp = EEM_Message_Template_Group::instance()->get_one(
747
-                array(
748
-                    array(
749
-                        'MTP_messenger'    => $this->messenger(),
750
-                        'MTP_message_type' => $this->message_type(),
751
-                        'MTP_is_global'    => true,
752
-                    ),
753
-                )
754
-            );
755
-        }
756
-
757
-        return $grp instanceof EE_Message_Template_Group ? $grp->get_template_pack() : null;
758
-    }
759
-
760
-
761
-    /**
762
-     * Retrieves the variation used for generating this message.
763
-     *
764
-     * @return string
765
-     */
766
-    public function get_template_pack_variation()
767
-    {
768
-        /**
769
-         * This is deprecated functionality that will be removed eventually but included here now for backward compat.
770
-         */
771
-        if (! empty($this->template_variation)) {
772
-            return $this->template_variation;
773
-        }
774
-
775
-        /** @type EE_Message_Template_Group $grp */
776
-        $grp = $this->get_first_related('Message_Template_Group');
777
-
778
-        // if no group then let's try to get the first related group by internal messenger and message type (will use global grp).
779
-        if (! $grp instanceof EE_Message_Template_Group) {
780
-            $grp = EEM_Message_Template_Group::instance()->get_one(
781
-                array(
782
-                    array(
783
-                        'MTP_messenger'    => $this->messenger(),
784
-                        'MTP_message_type' => $this->message_type(),
785
-                        'MTP_is_global'    => true,
786
-                    ),
787
-                )
788
-            );
789
-        }
790
-
791
-        return $grp instanceof EE_Message_Template_Group ? $grp->get_template_pack_variation() : '';
792
-    }
793
-
794
-    /**
795
-     * Return the link to the admin details for the object.
796
-     *
797
-     * @return string
798
-     */
799
-    public function get_admin_details_link()
800
-    {
801
-        EE_Registry::instance()->load_helper('URL');
802
-        EE_Registry::instance()->load_helper('MSG_Template');
803
-        switch ($this->STS_ID()) {
804
-            case EEM_Message::status_failed:
805
-            case EEM_Message::status_debug_only:
806
-                return EEH_MSG_Template::generate_error_display_trigger($this);
807
-                break;
808
-
809
-            case EEM_Message::status_sent:
810
-                return EEH_MSG_Template::generate_browser_trigger($this);
811
-                break;
812
-
813
-            default:
814
-                return '';
815
-        }
816
-    }
817
-
818
-    /**
819
-     * Returns the link to the editor for the object.  Sometimes this is the same as the details.
820
-     *
821
-     * @return string
822
-     */
823
-    public function get_admin_edit_link()
824
-    {
825
-        return $this->get_admin_details_link();
826
-    }
827
-
828
-    /**
829
-     * Returns the link to a settings page for the object.
830
-     *
831
-     * @return string
832
-     */
833
-    public function get_admin_settings_link()
834
-    {
835
-        EE_Registry::instance()->load_helper('URL');
836
-        return EEH_URL::add_query_args_and_nonce(
837
-            array(
838
-                'page'   => 'espresso_messages',
839
-                'action' => 'settings',
840
-            ),
841
-            admin_url('admin.php')
842
-        );
843
-    }
844
-
845
-    /**
846
-     * Returns the link to the "overview" for the object (typically the "list table" view).
847
-     *
848
-     * @return string
849
-     */
850
-    public function get_admin_overview_link()
851
-    {
852
-        EE_Registry::instance()->load_helper('URL');
853
-        return EEH_URL::add_query_args_and_nonce(
854
-            array(
855
-                'page'   => 'espresso_messages',
856
-                'action' => 'default',
857
-            ),
858
-            admin_url('admin.php')
859
-        );
860
-    }
861
-
862
-
863
-    /**
864
-     * This sets the EEM_Message::status_messenger_executing class on the message and the appropriate error message for
865
-     * it.
866
-     * Note this also SAVES the current message object to the db because it adds an error message to accompany the
867
-     * status.
868
-     *
869
-     */
870
-    public function set_messenger_is_executing()
871
-    {
872
-        $this->set_STS_ID(EEM_Message::status_messenger_executing);
873
-        $this->set_error_message(
874
-            esc_html__(
875
-                'A message with this status indicates that there was a problem that occurred while the message was being
13
+	/**
14
+	 * @deprecated 4.9.0  Added for backward compat with add-on's
15
+	 * @type null
16
+	 */
17
+	public $template_pack;
18
+
19
+	/**
20
+	 * @deprecated 4.9.0 Added for backward compat with add-on's
21
+	 * @type null
22
+	 */
23
+	public $template_variation;
24
+
25
+	/**
26
+	 * @deprecated 4.9.0 Added for backward compat with add-on's
27
+	 * @type string
28
+	 */
29
+	public $content = '';
30
+
31
+
32
+	/**
33
+	 * @type EE_messenger $_messenger
34
+	 */
35
+	protected $_messenger = null;
36
+
37
+	/**
38
+	 * @type EE_message_type $_message_type
39
+	 */
40
+	protected $_message_type = null;
41
+
42
+
43
+	/**
44
+	 * @param array  $props_n_values
45
+	 * @param string $timezone
46
+	 * @param array  $date_formats incoming date formats in an array.  First value is the date_format, second is time
47
+	 *                             format.
48
+	 * @return EE_Message
49
+	 */
50
+	public static function new_instance($props_n_values = array(), $timezone = '', $date_formats = array())
51
+	{
52
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__);
53
+		// if object doesn't exist, let's generate a unique token on instantiation so that its available even before saving to db.
54
+		if (! $has_object) {
55
+			EE_Registry::instance()->load_helper('URL');
56
+			$props_n_values['MSG_token'] = EEH_URL::generate_unique_token();
57
+		}
58
+		return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
59
+	}
60
+
61
+
62
+	/**
63
+	 * @param array  $props_n_values
64
+	 * @param string $timezone
65
+	 * @return EE_Message
66
+	 */
67
+	public static function new_instance_from_db($props_n_values = array(), $timezone = '')
68
+	{
69
+		return new self($props_n_values, true, $timezone);
70
+	}
71
+
72
+
73
+	/**
74
+	 * Gets MSG_token
75
+	 *
76
+	 * @return int
77
+	 */
78
+	public function MSG_token()
79
+	{
80
+		return $this->get('MSG_token');
81
+	}
82
+
83
+
84
+	/**
85
+	 * Sets MSG_token
86
+	 *
87
+	 * @param int $MSG_token
88
+	 */
89
+	public function set_MSG_token($MSG_token)
90
+	{
91
+		$this->set('MSG_token', $MSG_token);
92
+	}
93
+
94
+
95
+	/**
96
+	 * Gets GRP_ID
97
+	 *
98
+	 * @return int
99
+	 */
100
+	public function GRP_ID()
101
+	{
102
+		return $this->get('GRP_ID');
103
+	}
104
+
105
+
106
+	/**
107
+	 * Sets GRP_ID
108
+	 *
109
+	 * @param int $GRP_ID
110
+	 */
111
+	public function set_GRP_ID($GRP_ID)
112
+	{
113
+		$this->set('GRP_ID', $GRP_ID);
114
+	}
115
+
116
+
117
+	/**
118
+	 * Gets TXN_ID
119
+	 *
120
+	 * @return int
121
+	 */
122
+	public function TXN_ID()
123
+	{
124
+		return $this->get('TXN_ID');
125
+	}
126
+
127
+
128
+	/**
129
+	 * Sets TXN_ID
130
+	 *
131
+	 * @param int $TXN_ID
132
+	 */
133
+	public function set_TXN_ID($TXN_ID)
134
+	{
135
+		$this->set('TXN_ID', $TXN_ID);
136
+	}
137
+
138
+
139
+	/**
140
+	 * Gets messenger
141
+	 *
142
+	 * @return string
143
+	 */
144
+	public function messenger()
145
+	{
146
+		return $this->get('MSG_messenger');
147
+	}
148
+
149
+
150
+	/**
151
+	 * Sets messenger
152
+	 *
153
+	 * @param string $messenger
154
+	 */
155
+	public function set_messenger($messenger)
156
+	{
157
+		$this->set('MSG_messenger', $messenger);
158
+	}
159
+
160
+
161
+	/**
162
+	 * Returns corresponding messenger object for the set messenger on this message
163
+	 *
164
+	 * @return EE_messenger | null
165
+	 */
166
+	public function messenger_object()
167
+	{
168
+		return $this->_messenger;
169
+	}
170
+
171
+
172
+	/**
173
+	 * Sets messenger
174
+	 *
175
+	 * @param EE_messenger $messenger
176
+	 */
177
+	public function set_messenger_object(EE_messenger $messenger)
178
+	{
179
+		$this->_messenger = $messenger;
180
+	}
181
+
182
+
183
+	/**
184
+	 * validates messenger
185
+	 *
186
+	 * @param bool $throw_exceptions
187
+	 * @return bool
188
+	 * @throws \EE_Error
189
+	 */
190
+	public function valid_messenger($throw_exceptions = false)
191
+	{
192
+		if ($this->_messenger instanceof EE_messenger) {
193
+			return true;
194
+		}
195
+		if ($throw_exceptions) {
196
+			throw new EE_Error(
197
+				sprintf(
198
+					__(
199
+						'The "%1$s" messenger set for this message is missing or invalid. Please double-check the spelling and verify that the correct files exist.',
200
+						'event_espresso'
201
+					),
202
+					$this->messenger()
203
+				)
204
+			);
205
+		}
206
+		return false;
207
+	}
208
+
209
+
210
+	/**
211
+	 * This returns the set localized label for the messenger on this message.
212
+	 * Note, if unable to retrieve the EE_messenger object then will just return the messenger slug saved
213
+	 * with this message.
214
+	 *
215
+	 * @param   bool $plural whether to return the plural label or not.
216
+	 * @return string
217
+	 */
218
+	public function messenger_label($plural = false)
219
+	{
220
+		$label_type = $plural ? 'plural' : 'singular';
221
+		$messenger = $this->messenger_object();
222
+		return $messenger instanceof EE_messenger ? $messenger->label[ $label_type ] : $this->messenger();
223
+	}
224
+
225
+
226
+	/**
227
+	 * Gets message_type
228
+	 *
229
+	 * @return string
230
+	 */
231
+	public function message_type()
232
+	{
233
+		return $this->get('MSG_message_type');
234
+	}
235
+
236
+
237
+	/**
238
+	 * Sets message_type
239
+	 *
240
+	 * @param string $message_type
241
+	 */
242
+	public function set_message_type($message_type)
243
+	{
244
+		$this->set('MSG_message_type', $message_type);
245
+	}
246
+
247
+
248
+	/**
249
+	 * Returns the message type object for the set message type on this message
250
+	 *
251
+	 * @return EE_message_type | null
252
+	 */
253
+	public function message_type_object()
254
+	{
255
+		return $this->_message_type;
256
+	}
257
+
258
+
259
+	/**
260
+	 * Sets message_type
261
+	 *
262
+	 * @param EE_message_type $message_type
263
+	 * @param bool            $set_priority   This indicates whether to set the priority to whatever the priority is on
264
+	 *                                        the message type or not.
265
+	 */
266
+	public function set_message_type_object(EE_message_type $message_type, $set_priority = false)
267
+	{
268
+		$this->_message_type = $message_type;
269
+		if ($set_priority) {
270
+			$this->set_priority($this->_message_type->get_priority());
271
+		}
272
+	}
273
+
274
+
275
+	/**
276
+	 * validates message_type
277
+	 *
278
+	 * @param bool $throw_exceptions
279
+	 * @return bool
280
+	 * @throws \EE_Error
281
+	 */
282
+	public function valid_message_type($throw_exceptions = false)
283
+	{
284
+		if ($this->_message_type instanceof EE_message_type) {
285
+			return true;
286
+		}
287
+		if ($throw_exceptions) {
288
+			throw new EE_Error(
289
+				sprintf(
290
+					__(
291
+						'The %1$s message type set for this message is missing or invalid. Please double-check the spelling and verify that the correct files exist.',
292
+						'event_espresso'
293
+					),
294
+					$this->message_type()
295
+				)
296
+			);
297
+		}
298
+		return false;
299
+	}
300
+
301
+
302
+	/**
303
+	 * validates messenger and message_type (that they are valid EE_messenger and EE_message_type objects).
304
+	 *
305
+	 * @param bool $throw_exceptions
306
+	 * @return bool
307
+	 * @throws \EE_Error
308
+	 */
309
+	public function is_valid($throw_exceptions = false)
310
+	{
311
+		if ($this->valid_messenger($throw_exceptions) && $this->valid_message_type($throw_exceptions)) {
312
+			return true;
313
+		}
314
+		return false;
315
+	}
316
+
317
+
318
+	/**
319
+	 * This validates whether the internal messenger and message type objects are valid for sending.
320
+	 * Three checks are done:
321
+	 * 1. There is a valid messenger object.
322
+	 * 2. There is a valid message type object.
323
+	 * 3. The message type object is active for the messenger.
324
+	 *
325
+	 * @throws EE_Error  But only if $throw_exceptions is set to true.
326
+	 * @param bool $throw_exceptions
327
+	 * @return bool
328
+	 */
329
+	public function is_valid_for_sending_or_generation($throw_exceptions = false)
330
+	{
331
+		$valid = false;
332
+		if ($this->is_valid($throw_exceptions)) {
333
+			/** @var EE_Message_Resource_Manager $message_resource_manager */
334
+			$message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
335
+			$valid = $message_resource_manager->is_message_type_active_for_messenger(
336
+				$this->messenger(),
337
+				$this->message_type()
338
+			);
339
+			if (! $valid && $throw_exceptions) {
340
+				throw new EE_Error(
341
+					sprintf(
342
+						__(
343
+							'The %1$s message type is not a valid message type for the %2$s messenger so it will not be sent.',
344
+							'event_espresso'
345
+						),
346
+						$this->message_type(),
347
+						$this->messenger()
348
+					)
349
+				);
350
+			}
351
+		}
352
+		return $valid;
353
+	}
354
+
355
+
356
+	/**
357
+	 * This returns the set localized label for the message type on this message.
358
+	 * Note, if unable to retrieve the EE_message_type object then will just return the message type slug saved
359
+	 * with this message.
360
+	 *
361
+	 * @param   bool $plural whether to return the plural label or not.
362
+	 * @return string
363
+	 */
364
+	public function message_type_label($plural = false)
365
+	{
366
+		$label_type = $plural ? 'plural' : 'singular';
367
+		$message_type = $this->message_type_object();
368
+		return $message_type instanceof EE_message_type
369
+			? $message_type->label[ $label_type ]
370
+			: str_replace(
371
+				'_',
372
+				' ',
373
+				$this->message_type()
374
+			);
375
+	}
376
+
377
+
378
+	/**
379
+	 * Gets context
380
+	 *
381
+	 * @return string
382
+	 */
383
+	public function context()
384
+	{
385
+		return $this->get('MSG_context');
386
+	}
387
+
388
+
389
+	/**
390
+	 * This returns the corresponding localized label for the given context slug, if possible from installed message
391
+	 * types. Otherwise, this will just return the set context slug on this object.
392
+	 *
393
+	 * @return string
394
+	 */
395
+	public function context_label()
396
+	{
397
+		/** @type EE_Message_Resource_Manager $message_resource_manager */
398
+		$message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
399
+		$contexts = $message_resource_manager->get_all_contexts();
400
+		return isset($contexts[ $this->context() ]) ? $contexts[ $this->context() ] : $this->context();
401
+	}
402
+
403
+
404
+	/**
405
+	 * Sets context
406
+	 *
407
+	 * @param string $context
408
+	 */
409
+	public function set_context($context)
410
+	{
411
+		$this->set('MSG_context', $context);
412
+	}
413
+
414
+
415
+	/**
416
+	 * Gets recipient_ID
417
+	 *
418
+	 * @return int
419
+	 */
420
+	public function recipient_ID()
421
+	{
422
+		return $this->get('MSG_recipient_ID');
423
+	}
424
+
425
+
426
+	/**
427
+	 * Sets recipient_ID
428
+	 *
429
+	 * @param string $recipient_ID
430
+	 */
431
+	public function set_recipient_ID($recipient_ID)
432
+	{
433
+		$this->set('MSG_recipient_ID', $recipient_ID);
434
+	}
435
+
436
+
437
+	/**
438
+	 * Gets recipient_type
439
+	 *
440
+	 * @return string
441
+	 */
442
+	public function recipient_type()
443
+	{
444
+		return $this->get('MSG_recipient_type');
445
+	}
446
+
447
+
448
+	/**
449
+	 * Return the related object matching the recipient type and ID.
450
+	 *
451
+	 * @return EE_Base_Class | null
452
+	 */
453
+	public function recipient_object()
454
+	{
455
+		if (! $this->recipient_type() || ! $this->recipient_ID()) {
456
+			return null;
457
+		}
458
+
459
+		return $this->get_first_related($this->recipient_type());
460
+	}
461
+
462
+
463
+	/**
464
+	 * Sets recipient_type
465
+	 *
466
+	 * @param string $recipient_type
467
+	 */
468
+	public function set_recipient_type($recipient_type)
469
+	{
470
+		$this->set('MSG_recipient_type', $recipient_type);
471
+	}
472
+
473
+
474
+	/**
475
+	 * Gets content
476
+	 *
477
+	 * @return string
478
+	 */
479
+	public function content()
480
+	{
481
+		return $this->get('MSG_content');
482
+	}
483
+
484
+
485
+	/**
486
+	 * Sets content
487
+	 *
488
+	 * @param string $content
489
+	 */
490
+	public function set_content($content)
491
+	{
492
+		$this->set('MSG_content', $content);
493
+	}
494
+
495
+
496
+	/**
497
+	 * Gets subject
498
+	 *
499
+	 * @return string
500
+	 */
501
+	public function subject()
502
+	{
503
+		return $this->get('MSG_subject');
504
+	}
505
+
506
+
507
+	/**
508
+	 * Sets subject
509
+	 *
510
+	 * @param string $subject
511
+	 */
512
+	public function set_subject($subject)
513
+	{
514
+		$this->set('MSG_subject', $subject);
515
+	}
516
+
517
+
518
+	/**
519
+	 * Gets to
520
+	 *
521
+	 * @return string
522
+	 */
523
+	public function to()
524
+	{
525
+		$to = $this->get('MSG_to');
526
+		return empty($to) ? __('No recipient', 'event_espresso') : $to;
527
+	}
528
+
529
+
530
+	/**
531
+	 * Sets to
532
+	 *
533
+	 * @param string $to
534
+	 */
535
+	public function set_to($to)
536
+	{
537
+		$this->set('MSG_to', $to);
538
+	}
539
+
540
+
541
+	/**
542
+	 * Gets from
543
+	 *
544
+	 * @return string
545
+	 */
546
+	public function from()
547
+	{
548
+		return $this->get('MSG_from');
549
+	}
550
+
551
+
552
+	/**
553
+	 * Sets from
554
+	 *
555
+	 * @param string $from
556
+	 */
557
+	public function set_from($from)
558
+	{
559
+		$this->set('MSG_from', $from);
560
+	}
561
+
562
+
563
+	/**
564
+	 * Gets priority
565
+	 *
566
+	 * @return int
567
+	 */
568
+	public function priority()
569
+	{
570
+		return $this->get('MSG_priority');
571
+	}
572
+
573
+
574
+	/**
575
+	 * Sets priority
576
+	 * Note.  Send Now Messengers always override any priority that may be set on a Message.  So
577
+	 * this method calls the send_now method to verify that.
578
+	 *
579
+	 * @param int $priority
580
+	 */
581
+	public function set_priority($priority)
582
+	{
583
+		$priority = $this->send_now() ? EEM_Message::priority_high : $priority;
584
+		parent::set('MSG_priority', $priority);
585
+	}
586
+
587
+
588
+	/**
589
+	 * Overrides parent::set method so we can capture any sets for priority.
590
+	 *
591
+	 * @see parent::set() for phpdocs
592
+	 * @param string $field_name
593
+	 * @param mixed  $field_value
594
+	 * @param bool   $use_default
595
+	 * @throws EE_Error
596
+	 */
597
+	public function set($field_name, $field_value, $use_default = false)
598
+	{
599
+		if ($field_name === 'MSG_priority') {
600
+			$this->set_priority($field_value);
601
+		}
602
+		parent::set($field_name, $field_value, $use_default);
603
+	}
604
+
605
+
606
+	/**
607
+	 * @return bool
608
+	 * @throws \EE_Error
609
+	 */
610
+	public function send_now()
611
+	{
612
+		$send_now = $this->valid_messenger() && $this->messenger_object()->send_now() ? EEM_Message::priority_high
613
+			: $this->priority();
614
+		return $send_now === EEM_Message::priority_high ? true : false;
615
+	}
616
+
617
+
618
+	/**
619
+	 * Gets STS_ID
620
+	 *
621
+	 * @return string
622
+	 */
623
+	public function STS_ID()
624
+	{
625
+		return $this->get('STS_ID');
626
+	}
627
+
628
+
629
+	/**
630
+	 * Sets STS_ID
631
+	 *
632
+	 * @param string $STS_ID
633
+	 */
634
+	public function set_STS_ID($STS_ID)
635
+	{
636
+		$this->set('STS_ID', $STS_ID);
637
+	}
638
+
639
+
640
+	/**
641
+	 * Gets created
642
+	 *
643
+	 * @return string
644
+	 */
645
+	public function created()
646
+	{
647
+		return $this->get('MSG_created');
648
+	}
649
+
650
+
651
+	/**
652
+	 * Sets created
653
+	 *
654
+	 * @param string $created
655
+	 */
656
+	public function set_created($created)
657
+	{
658
+		$this->set('MSG_created', $created);
659
+	}
660
+
661
+
662
+	/**
663
+	 * Gets modified
664
+	 *
665
+	 * @return string
666
+	 */
667
+	public function modified()
668
+	{
669
+		return $this->get('MSG_modified');
670
+	}
671
+
672
+
673
+	/**
674
+	 * Sets modified
675
+	 *
676
+	 * @param string $modified
677
+	 */
678
+	public function set_modified($modified)
679
+	{
680
+		$this->set('MSG_modified', $modified);
681
+	}
682
+
683
+
684
+	/**
685
+	 * Sets generation data for this message.
686
+	 *
687
+	 * @param mixed $data
688
+	 */
689
+	public function set_generation_data($data)
690
+	{
691
+		$this->set_field_or_extra_meta('MSG_generation_data', $data);
692
+	}
693
+
694
+
695
+	/**
696
+	 * Returns any set generation data for this message.
697
+	 *
698
+	 * @return mixed|null
699
+	 */
700
+	public function get_generation_data()
701
+	{
702
+		return $this->get_field_or_extra_meta('MSG_generation_data');
703
+	}
704
+
705
+
706
+	/**
707
+	 * Gets any error message.
708
+	 *
709
+	 * @return mixed|null
710
+	 */
711
+	public function error_message()
712
+	{
713
+		return $this->get_field_or_extra_meta('MSG_error');
714
+	}
715
+
716
+
717
+	/**
718
+	 * Sets an error message.
719
+	 *
720
+	 * @param $message
721
+	 * @return bool|int
722
+	 */
723
+	public function set_error_message($message)
724
+	{
725
+		return $this->set_field_or_extra_meta('MSG_error', $message);
726
+	}
727
+
728
+
729
+	/**
730
+	 * This retrieves the associated template pack with this message.
731
+	 *
732
+	 * @return EE_Messages_Template_Pack | null
733
+	 */
734
+	public function get_template_pack()
735
+	{
736
+		/**
737
+		 * This is deprecated functionality that will be removed eventually but included here now for backward compat.
738
+		 */
739
+		if (! empty($this->template_pack)) {
740
+			return $this->template_pack;
741
+		}
742
+		/** @type EE_Message_Template_Group $grp */
743
+		$grp = $this->get_first_related('Message_Template_Group');
744
+		// if no group then let's try to get the first related group by internal messenger and message type (will use global grp).
745
+		if (! $grp instanceof EE_Message_Template_Group) {
746
+			$grp = EEM_Message_Template_Group::instance()->get_one(
747
+				array(
748
+					array(
749
+						'MTP_messenger'    => $this->messenger(),
750
+						'MTP_message_type' => $this->message_type(),
751
+						'MTP_is_global'    => true,
752
+					),
753
+				)
754
+			);
755
+		}
756
+
757
+		return $grp instanceof EE_Message_Template_Group ? $grp->get_template_pack() : null;
758
+	}
759
+
760
+
761
+	/**
762
+	 * Retrieves the variation used for generating this message.
763
+	 *
764
+	 * @return string
765
+	 */
766
+	public function get_template_pack_variation()
767
+	{
768
+		/**
769
+		 * This is deprecated functionality that will be removed eventually but included here now for backward compat.
770
+		 */
771
+		if (! empty($this->template_variation)) {
772
+			return $this->template_variation;
773
+		}
774
+
775
+		/** @type EE_Message_Template_Group $grp */
776
+		$grp = $this->get_first_related('Message_Template_Group');
777
+
778
+		// if no group then let's try to get the first related group by internal messenger and message type (will use global grp).
779
+		if (! $grp instanceof EE_Message_Template_Group) {
780
+			$grp = EEM_Message_Template_Group::instance()->get_one(
781
+				array(
782
+					array(
783
+						'MTP_messenger'    => $this->messenger(),
784
+						'MTP_message_type' => $this->message_type(),
785
+						'MTP_is_global'    => true,
786
+					),
787
+				)
788
+			);
789
+		}
790
+
791
+		return $grp instanceof EE_Message_Template_Group ? $grp->get_template_pack_variation() : '';
792
+	}
793
+
794
+	/**
795
+	 * Return the link to the admin details for the object.
796
+	 *
797
+	 * @return string
798
+	 */
799
+	public function get_admin_details_link()
800
+	{
801
+		EE_Registry::instance()->load_helper('URL');
802
+		EE_Registry::instance()->load_helper('MSG_Template');
803
+		switch ($this->STS_ID()) {
804
+			case EEM_Message::status_failed:
805
+			case EEM_Message::status_debug_only:
806
+				return EEH_MSG_Template::generate_error_display_trigger($this);
807
+				break;
808
+
809
+			case EEM_Message::status_sent:
810
+				return EEH_MSG_Template::generate_browser_trigger($this);
811
+				break;
812
+
813
+			default:
814
+				return '';
815
+		}
816
+	}
817
+
818
+	/**
819
+	 * Returns the link to the editor for the object.  Sometimes this is the same as the details.
820
+	 *
821
+	 * @return string
822
+	 */
823
+	public function get_admin_edit_link()
824
+	{
825
+		return $this->get_admin_details_link();
826
+	}
827
+
828
+	/**
829
+	 * Returns the link to a settings page for the object.
830
+	 *
831
+	 * @return string
832
+	 */
833
+	public function get_admin_settings_link()
834
+	{
835
+		EE_Registry::instance()->load_helper('URL');
836
+		return EEH_URL::add_query_args_and_nonce(
837
+			array(
838
+				'page'   => 'espresso_messages',
839
+				'action' => 'settings',
840
+			),
841
+			admin_url('admin.php')
842
+		);
843
+	}
844
+
845
+	/**
846
+	 * Returns the link to the "overview" for the object (typically the "list table" view).
847
+	 *
848
+	 * @return string
849
+	 */
850
+	public function get_admin_overview_link()
851
+	{
852
+		EE_Registry::instance()->load_helper('URL');
853
+		return EEH_URL::add_query_args_and_nonce(
854
+			array(
855
+				'page'   => 'espresso_messages',
856
+				'action' => 'default',
857
+			),
858
+			admin_url('admin.php')
859
+		);
860
+	}
861
+
862
+
863
+	/**
864
+	 * This sets the EEM_Message::status_messenger_executing class on the message and the appropriate error message for
865
+	 * it.
866
+	 * Note this also SAVES the current message object to the db because it adds an error message to accompany the
867
+	 * status.
868
+	 *
869
+	 */
870
+	public function set_messenger_is_executing()
871
+	{
872
+		$this->set_STS_ID(EEM_Message::status_messenger_executing);
873
+		$this->set_error_message(
874
+			esc_html__(
875
+				'A message with this status indicates that there was a problem that occurred while the message was being
876 876
                 processed by the messenger.  It is still possible that the message was sent successfully, but at some
877 877
                 point during the processing there was a failure.  This usually is indicative of a timeout issue with PHP 
878 878
                 or memory limits being reached.  If you see this repeatedly you may want to consider upgrading the memory 
879 879
                 available to PHP on your server.',
880
-                'event_espresso'
881
-            )
882
-        );
883
-    }
880
+				'event_espresso'
881
+			)
882
+		);
883
+	}
884 884
 }
Please login to merge, or discard this patch.
core/db_classes/EE_Transaction.class.php 1 patch
Indentation   +1701 added lines, -1701 removed lines patch added patch discarded remove patch
@@ -13,1705 +13,1705 @@
 block discarded – undo
13 13
 class EE_Transaction extends EE_Base_Class implements EEI_Transaction
14 14
 {
15 15
 
16
-    /**
17
-     * The length of time in seconds that a lock is applied before being considered expired.
18
-     * It is not long because a transaction should only be locked for the duration of the request that locked it
19
-     */
20
-    const LOCK_EXPIRATION = 2;
21
-
22
-    /**
23
-     * txn status upon initial construction.
24
-     *
25
-     * @var string
26
-     */
27
-    protected $_old_txn_status;
28
-
29
-
30
-    /**
31
-     * @param array  $props_n_values          incoming values
32
-     * @param string $timezone                incoming timezone
33
-     *                                        (if not set the timezone set for the website will be used.)
34
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
35
-     *                                        date_format and the second value is the time format
36
-     * @return EE_Transaction
37
-     * @throws EE_Error
38
-     * @throws InvalidArgumentException
39
-     * @throws InvalidDataTypeException
40
-     * @throws InvalidInterfaceException
41
-     * @throws ReflectionException
42
-     */
43
-    public static function new_instance($props_n_values = array(), $timezone = '', $date_formats = array())
44
-    {
45
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
46
-        $txn = $has_object
47
-            ? $has_object
48
-            : new self($props_n_values, false, $timezone, $date_formats);
49
-        if (! $has_object) {
50
-            $txn->set_old_txn_status($txn->status_ID());
51
-        }
52
-        return $txn;
53
-    }
54
-
55
-
56
-    /**
57
-     * @param array  $props_n_values  incoming values from the database
58
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
59
-     *                                the website will be used.
60
-     * @return EE_Transaction
61
-     * @throws EE_Error
62
-     * @throws InvalidArgumentException
63
-     * @throws InvalidDataTypeException
64
-     * @throws InvalidInterfaceException
65
-     * @throws ReflectionException
66
-     */
67
-    public static function new_instance_from_db($props_n_values = array(), $timezone = '')
68
-    {
69
-        $txn = new self($props_n_values, true, $timezone);
70
-        $txn->set_old_txn_status($txn->status_ID());
71
-        return $txn;
72
-    }
73
-
74
-
75
-    /**
76
-     * Sets a meta field indicating that this TXN is locked and should not be updated in the db.
77
-     * If a lock has already been set, then we will attempt to remove it in case it has expired.
78
-     * If that also fails, then an exception is thrown.
79
-     *
80
-     * @throws EE_Error
81
-     * @throws InvalidArgumentException
82
-     * @throws InvalidDataTypeException
83
-     * @throws InvalidInterfaceException
84
-     * @throws ReflectionException
85
-     */
86
-    public function lock()
87
-    {
88
-        // attempt to set lock, but if that fails...
89
-        if (! $this->add_extra_meta('lock', time(), true)) {
90
-            // then attempt to remove the lock in case it is expired
91
-            if ($this->_remove_expired_lock()) {
92
-                // if removal was successful, then try setting lock again
93
-                $this->lock();
94
-            } else {
95
-                // but if the lock can not be removed, then throw an exception
96
-                throw new EE_Error(
97
-                    sprintf(
98
-                        __(
99
-                            'Could not lock Transaction %1$d because it is already locked, meaning another part of the system is currently editing it. It should already be unlocked by the time you read this, so please refresh the page and try again.',
100
-                            'event_espresso'
101
-                        ),
102
-                        $this->ID()
103
-                    )
104
-                );
105
-            }
106
-        }
107
-    }
108
-
109
-
110
-    /**
111
-     * removes transaction lock applied in EE_Transaction::lock()
112
-     *
113
-     * @return int
114
-     * @throws EE_Error
115
-     * @throws InvalidArgumentException
116
-     * @throws InvalidDataTypeException
117
-     * @throws InvalidInterfaceException
118
-     * @throws ReflectionException
119
-     */
120
-    public function unlock()
121
-    {
122
-        return $this->delete_extra_meta('lock');
123
-    }
124
-
125
-
126
-    /**
127
-     * Decides whether or not now is the right time to update the transaction.
128
-     * This is useful because we don't always know if it is safe to update the transaction
129
-     * and its related data. why?
130
-     * because it's possible that the transaction is being used in another
131
-     * request and could overwrite anything we save.
132
-     * So we want to only update the txn once we know that won't happen.
133
-     * We also check that the lock isn't expired, and remove it if it is
134
-     *
135
-     * @return boolean
136
-     * @throws EE_Error
137
-     * @throws InvalidArgumentException
138
-     * @throws InvalidDataTypeException
139
-     * @throws InvalidInterfaceException
140
-     * @throws ReflectionException
141
-     */
142
-    public function is_locked()
143
-    {
144
-        // if TXN is not locked, then return false immediately
145
-        if (! $this->_get_lock()) {
146
-            return false;
147
-        }
148
-        // if not, then let's try and remove the lock in case it's expired...
149
-        // _remove_expired_lock() returns 0 when lock is valid (ie: removed = false)
150
-        // and a positive number if the lock was removed (ie: number of locks deleted),
151
-        // so we need to return the opposite
152
-        return ! $this->_remove_expired_lock() ? true : false;
153
-    }
154
-
155
-
156
-    /**
157
-     * Gets the meta field indicating that this TXN is locked
158
-     *
159
-     * @return int
160
-     * @throws EE_Error
161
-     * @throws InvalidArgumentException
162
-     * @throws InvalidDataTypeException
163
-     * @throws InvalidInterfaceException
164
-     * @throws ReflectionException
165
-     */
166
-    protected function _get_lock()
167
-    {
168
-        return (int) $this->get_extra_meta('lock', true, 0);
169
-    }
170
-
171
-
172
-    /**
173
-     * If the lock on this transaction is expired, then we want to remove it so that the transaction can be updated
174
-     *
175
-     * @return int
176
-     * @throws EE_Error
177
-     * @throws InvalidArgumentException
178
-     * @throws InvalidDataTypeException
179
-     * @throws InvalidInterfaceException
180
-     * @throws ReflectionException
181
-     */
182
-    protected function _remove_expired_lock()
183
-    {
184
-        $locked = $this->_get_lock();
185
-        if ($locked && time() - EE_Transaction::LOCK_EXPIRATION > $locked) {
186
-            return $this->unlock();
187
-        }
188
-        return 0;
189
-    }
190
-
191
-
192
-    /**
193
-     * Set transaction total
194
-     *
195
-     * @param float $total total value of transaction
196
-     * @throws EE_Error
197
-     * @throws InvalidArgumentException
198
-     * @throws InvalidDataTypeException
199
-     * @throws InvalidInterfaceException
200
-     * @throws ReflectionException
201
-     */
202
-    public function set_total($total = 0.00)
203
-    {
204
-        $this->set('TXN_total', (float) $total);
205
-    }
206
-
207
-
208
-    /**
209
-     * Set Total Amount Paid to Date
210
-     *
211
-     * @param float $total_paid total amount paid to date (sum of all payments)
212
-     * @throws EE_Error
213
-     * @throws InvalidArgumentException
214
-     * @throws InvalidDataTypeException
215
-     * @throws InvalidInterfaceException
216
-     * @throws ReflectionException
217
-     */
218
-    public function set_paid($total_paid = 0.00)
219
-    {
220
-        $this->set('TXN_paid', (float) $total_paid);
221
-    }
222
-
223
-
224
-    /**
225
-     * Set transaction status
226
-     *
227
-     * @param string $status        whether the transaction is open, declined, accepted,
228
-     *                              or any number of custom values that can be set
229
-     * @throws EE_Error
230
-     * @throws InvalidArgumentException
231
-     * @throws InvalidDataTypeException
232
-     * @throws InvalidInterfaceException
233
-     * @throws ReflectionException
234
-     */
235
-    public function set_status($status = '')
236
-    {
237
-        $this->set('STS_ID', $status);
238
-    }
239
-
240
-
241
-    /**
242
-     * Set hash salt
243
-     *
244
-     * @param string $hash_salt required for some payment gateways
245
-     * @throws EE_Error
246
-     * @throws InvalidArgumentException
247
-     * @throws InvalidDataTypeException
248
-     * @throws InvalidInterfaceException
249
-     * @throws ReflectionException
250
-     */
251
-    public function set_hash_salt($hash_salt = '')
252
-    {
253
-        $this->set('TXN_hash_salt', $hash_salt);
254
-    }
255
-
256
-
257
-    /**
258
-     * Sets TXN_reg_steps array
259
-     *
260
-     * @param array $txn_reg_steps
261
-     * @throws EE_Error
262
-     * @throws InvalidArgumentException
263
-     * @throws InvalidDataTypeException
264
-     * @throws InvalidInterfaceException
265
-     * @throws ReflectionException
266
-     */
267
-    public function set_reg_steps(array $txn_reg_steps)
268
-    {
269
-        $this->set('TXN_reg_steps', $txn_reg_steps);
270
-    }
271
-
272
-
273
-    /**
274
-     * Gets TXN_reg_steps
275
-     *
276
-     * @return array
277
-     * @throws EE_Error
278
-     * @throws InvalidArgumentException
279
-     * @throws InvalidDataTypeException
280
-     * @throws InvalidInterfaceException
281
-     * @throws ReflectionException
282
-     */
283
-    public function reg_steps()
284
-    {
285
-        $TXN_reg_steps = $this->get('TXN_reg_steps');
286
-        return is_array($TXN_reg_steps) ? (array) $TXN_reg_steps : array();
287
-    }
288
-
289
-
290
-    /**
291
-     * @return string of transaction's total cost, with currency symbol and decimal
292
-     * @throws EE_Error
293
-     * @throws InvalidArgumentException
294
-     * @throws InvalidDataTypeException
295
-     * @throws InvalidInterfaceException
296
-     * @throws ReflectionException
297
-     */
298
-    public function pretty_total()
299
-    {
300
-        return $this->get_pretty('TXN_total');
301
-    }
302
-
303
-
304
-    /**
305
-     * Gets the amount paid in a pretty string (formatted and with currency symbol)
306
-     *
307
-     * @return string
308
-     * @throws EE_Error
309
-     * @throws InvalidArgumentException
310
-     * @throws InvalidDataTypeException
311
-     * @throws InvalidInterfaceException
312
-     * @throws ReflectionException
313
-     */
314
-    public function pretty_paid()
315
-    {
316
-        return $this->get_pretty('TXN_paid');
317
-    }
318
-
319
-
320
-    /**
321
-     * calculate the amount remaining for this transaction and return;
322
-     *
323
-     * @return float amount remaining
324
-     * @throws EE_Error
325
-     * @throws InvalidArgumentException
326
-     * @throws InvalidDataTypeException
327
-     * @throws InvalidInterfaceException
328
-     * @throws ReflectionException
329
-     */
330
-    public function remaining()
331
-    {
332
-        return $this->total() - $this->paid();
333
-    }
334
-
335
-
336
-    /**
337
-     * get Transaction Total
338
-     *
339
-     * @return float
340
-     * @throws EE_Error
341
-     * @throws InvalidArgumentException
342
-     * @throws InvalidDataTypeException
343
-     * @throws InvalidInterfaceException
344
-     * @throws ReflectionException
345
-     */
346
-    public function total()
347
-    {
348
-        return (float) $this->get('TXN_total');
349
-    }
350
-
351
-
352
-    /**
353
-     * get Total Amount Paid to Date
354
-     *
355
-     * @return float
356
-     * @throws EE_Error
357
-     * @throws InvalidArgumentException
358
-     * @throws InvalidDataTypeException
359
-     * @throws InvalidInterfaceException
360
-     * @throws ReflectionException
361
-     */
362
-    public function paid()
363
-    {
364
-        return (float) $this->get('TXN_paid');
365
-    }
366
-
367
-
368
-    /**
369
-     * @return mixed|null
370
-     * @throws EE_Error
371
-     * @throws InvalidArgumentException
372
-     * @throws InvalidDataTypeException
373
-     * @throws InvalidInterfaceException
374
-     * @throws ReflectionException
375
-     */
376
-    public function get_cart_session()
377
-    {
378
-        $session_data = (array) $this->get('TXN_session_data');
379
-        return isset($session_data['cart']) && $session_data['cart'] instanceof EE_Cart
380
-            ? $session_data['cart']
381
-            : null;
382
-    }
383
-
384
-
385
-    /**
386
-     * get Transaction session data
387
-     *
388
-     * @return array|mixed
389
-     * @throws EE_Error
390
-     * @throws InvalidArgumentException
391
-     * @throws InvalidDataTypeException
392
-     * @throws InvalidInterfaceException
393
-     * @throws ReflectionException
394
-     */
395
-    public function session_data()
396
-    {
397
-        $session_data = $this->get('TXN_session_data');
398
-        if (empty($session_data)) {
399
-            $session_data = array(
400
-                'id'            => null,
401
-                'user_id'       => null,
402
-                'ip_address'    => null,
403
-                'user_agent'    => null,
404
-                'init_access'   => null,
405
-                'last_access'   => null,
406
-                'pages_visited' => array(),
407
-            );
408
-        }
409
-        return $session_data;
410
-    }
411
-
412
-
413
-    /**
414
-     * Set session data within the TXN object
415
-     *
416
-     * @param EE_Session|array $session_data
417
-     * @throws EE_Error
418
-     * @throws InvalidArgumentException
419
-     * @throws InvalidDataTypeException
420
-     * @throws InvalidInterfaceException
421
-     * @throws ReflectionException
422
-     */
423
-    public function set_txn_session_data($session_data)
424
-    {
425
-        if ($session_data instanceof EE_Session) {
426
-            $this->set('TXN_session_data', $session_data->get_session_data(null, true));
427
-        } else {
428
-            $this->set('TXN_session_data', $session_data);
429
-        }
430
-    }
431
-
432
-
433
-    /**
434
-     * get Transaction hash salt
435
-     *
436
-     * @return mixed
437
-     * @throws EE_Error
438
-     * @throws InvalidArgumentException
439
-     * @throws InvalidDataTypeException
440
-     * @throws InvalidInterfaceException
441
-     * @throws ReflectionException
442
-     */
443
-    public function hash_salt_()
444
-    {
445
-        return $this->get('TXN_hash_salt');
446
-    }
447
-
448
-
449
-    /**
450
-     * Returns the transaction datetime as either:
451
-     *            - unix timestamp format ($format = false, $gmt = true)
452
-     *            - formatted date string including the UTC (timezone) offset ($format = true ($gmt
453
-     *              has no affect with this option)), this also may include a timezone abbreviation if the
454
-     *              set timezone in this class differs from what the timezone is on the blog.
455
-     *            - formatted date string including the UTC (timezone) offset (default).
456
-     *
457
-     * @param boolean $format   - whether to return a unix timestamp (default) or formatted date string
458
-     * @param boolean $gmt      - whether to return a unix timestamp with UTC offset applied (default)
459
-     *                          or no UTC offset applied
460
-     * @return string | int
461
-     * @throws EE_Error
462
-     * @throws InvalidArgumentException
463
-     * @throws InvalidDataTypeException
464
-     * @throws InvalidInterfaceException
465
-     * @throws ReflectionException
466
-     */
467
-    public function datetime($format = false, $gmt = false)
468
-    {
469
-        if ($format) {
470
-            return $this->get_pretty('TXN_timestamp');
471
-        }
472
-        if ($gmt) {
473
-            return $this->get_raw('TXN_timestamp');
474
-        }
475
-        return $this->get('TXN_timestamp');
476
-    }
477
-
478
-
479
-    /**
480
-     * Gets registrations on this transaction
481
-     *
482
-     * @param array   $query_params array of query parameters
483
-     * @param boolean $get_cached   TRUE to retrieve cached registrations or FALSE to pull from the db
484
-     * @return EE_Base_Class[]|EE_Registration[]
485
-     * @throws EE_Error
486
-     * @throws InvalidArgumentException
487
-     * @throws InvalidDataTypeException
488
-     * @throws InvalidInterfaceException
489
-     * @throws ReflectionException
490
-     */
491
-    public function registrations($query_params = array(), $get_cached = false)
492
-    {
493
-        $query_params = (empty($query_params) || ! is_array($query_params))
494
-            ? array(
495
-                'order_by' => array(
496
-                    'Event.EVT_name'     => 'ASC',
497
-                    'Attendee.ATT_lname' => 'ASC',
498
-                    'Attendee.ATT_fname' => 'ASC',
499
-                ),
500
-            )
501
-            : $query_params;
502
-        $query_params = $get_cached ? array() : $query_params;
503
-        return $this->get_many_related('Registration', $query_params);
504
-    }
505
-
506
-
507
-    /**
508
-     * Gets all the attendees for this transaction (handy for use with EE_Attendee's get_registrations_for_event
509
-     * function for getting attendees and how many registrations they each have for an event)
510
-     *
511
-     * @return mixed EE_Attendee[] by default, int if $output is set to 'COUNT'
512
-     * @throws EE_Error
513
-     * @throws InvalidArgumentException
514
-     * @throws InvalidDataTypeException
515
-     * @throws InvalidInterfaceException
516
-     * @throws ReflectionException
517
-     */
518
-    public function attendees()
519
-    {
520
-        return $this->get_many_related('Attendee', array(array('Registration.Transaction.TXN_ID' => $this->ID())));
521
-    }
522
-
523
-
524
-    /**
525
-     * Gets payments for this transaction. Unlike other such functions, order by 'DESC' by default
526
-     *
527
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
528
-     * @return EE_Base_Class[]|EE_Payment[]
529
-     * @throws EE_Error
530
-     * @throws InvalidArgumentException
531
-     * @throws InvalidDataTypeException
532
-     * @throws InvalidInterfaceException
533
-     * @throws ReflectionException
534
-     */
535
-    public function payments($query_params = array())
536
-    {
537
-        return $this->get_many_related('Payment', $query_params);
538
-    }
539
-
540
-
541
-    /**
542
-     * gets only approved payments for this transaction
543
-     *
544
-     * @return EE_Base_Class[]|EE_Payment[]
545
-     * @throws EE_Error
546
-     * @throws InvalidArgumentException
547
-     * @throws ReflectionException
548
-     * @throws InvalidDataTypeException
549
-     * @throws InvalidInterfaceException
550
-     */
551
-    public function approved_payments()
552
-    {
553
-        EE_Registry::instance()->load_model('Payment');
554
-        return $this->get_many_related(
555
-            'Payment',
556
-            array(
557
-                array('STS_ID' => EEM_Payment::status_id_approved),
558
-                'order_by' => array('PAY_timestamp' => 'DESC'),
559
-            )
560
-        );
561
-    }
562
-
563
-
564
-    /**
565
-     * Gets all payments which have not been approved
566
-     *
567
-     * @return EE_Base_Class[]|EEI_Payment[]
568
-     * @throws EE_Error if a model is misconfigured somehow
569
-     * @throws InvalidArgumentException
570
-     * @throws InvalidDataTypeException
571
-     * @throws InvalidInterfaceException
572
-     * @throws ReflectionException
573
-     */
574
-    public function pending_payments()
575
-    {
576
-        return $this->get_many_related(
577
-            'Payment',
578
-            array(
579
-                array(
580
-                    'STS_ID' => EEM_Payment::status_id_pending,
581
-                ),
582
-                'order_by' => array(
583
-                    'PAY_timestamp' => 'DESC',
584
-                ),
585
-            )
586
-        );
587
-    }
588
-
589
-
590
-    /**
591
-     * echoes $this->pretty_status()
592
-     *
593
-     * @param bool $show_icons
594
-     * @throws EE_Error
595
-     * @throws InvalidArgumentException
596
-     * @throws InvalidDataTypeException
597
-     * @throws InvalidInterfaceException
598
-     * @throws ReflectionException
599
-     */
600
-    public function e_pretty_status($show_icons = false)
601
-    {
602
-        echo $this->pretty_status($show_icons);
603
-    }
604
-
605
-
606
-    /**
607
-     * returns a pretty version of the status, good for displaying to users
608
-     *
609
-     * @param bool $show_icons
610
-     * @return string
611
-     * @throws EE_Error
612
-     * @throws InvalidArgumentException
613
-     * @throws InvalidDataTypeException
614
-     * @throws InvalidInterfaceException
615
-     * @throws ReflectionException
616
-     */
617
-    public function pretty_status($show_icons = false)
618
-    {
619
-        $status = EEM_Status::instance()->localized_status(
620
-            array($this->status_ID() => __('unknown', 'event_espresso')),
621
-            false,
622
-            'sentence'
623
-        );
624
-        $icon = '';
625
-        switch ($this->status_ID()) {
626
-            case EEM_Transaction::complete_status_code:
627
-                $icon = $show_icons ? '<span class="dashicons dashicons-yes ee-icon-size-24 green-text"></span>' : '';
628
-                break;
629
-            case EEM_Transaction::incomplete_status_code:
630
-                $icon = $show_icons ? '<span class="dashicons dashicons-marker ee-icon-size-16 lt-blue-text"></span>'
631
-                    : '';
632
-                break;
633
-            case EEM_Transaction::abandoned_status_code:
634
-                $icon = $show_icons ? '<span class="dashicons dashicons-marker ee-icon-size-16 red-text"></span>' : '';
635
-                break;
636
-            case EEM_Transaction::failed_status_code:
637
-                $icon = $show_icons ? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>' : '';
638
-                break;
639
-            case EEM_Transaction::overpaid_status_code:
640
-                $icon = $show_icons ? '<span class="dashicons dashicons-plus ee-icon-size-16 orange-text"></span>' : '';
641
-                break;
642
-        }
643
-        return $icon . $status[ $this->status_ID() ];
644
-    }
645
-
646
-
647
-    /**
648
-     * get Transaction Status
649
-     *
650
-     * @return mixed
651
-     * @throws EE_Error
652
-     * @throws InvalidArgumentException
653
-     * @throws InvalidDataTypeException
654
-     * @throws InvalidInterfaceException
655
-     * @throws ReflectionException
656
-     */
657
-    public function status_ID()
658
-    {
659
-        return $this->get('STS_ID');
660
-    }
661
-
662
-
663
-    /**
664
-     * Returns TRUE or FALSE for whether or not this transaction cost any money
665
-     *
666
-     * @return boolean
667
-     * @throws EE_Error
668
-     * @throws InvalidArgumentException
669
-     * @throws InvalidDataTypeException
670
-     * @throws InvalidInterfaceException
671
-     * @throws ReflectionException
672
-     */
673
-    public function is_free()
674
-    {
675
-        return EEH_Money::compare_floats($this->get('TXN_total'), 0, '==');
676
-    }
677
-
678
-
679
-    /**
680
-     * Returns whether this transaction is complete
681
-     * Useful in templates and other logic for deciding if we should ask for another payment...
682
-     *
683
-     * @return boolean
684
-     * @throws EE_Error
685
-     * @throws InvalidArgumentException
686
-     * @throws InvalidDataTypeException
687
-     * @throws InvalidInterfaceException
688
-     * @throws ReflectionException
689
-     */
690
-    public function is_completed()
691
-    {
692
-        return $this->status_ID() === EEM_Transaction::complete_status_code;
693
-    }
694
-
695
-
696
-    /**
697
-     * Returns whether this transaction is incomplete
698
-     * Useful in templates and other logic for deciding if we should ask for another payment...
699
-     *
700
-     * @return boolean
701
-     * @throws EE_Error
702
-     * @throws InvalidArgumentException
703
-     * @throws InvalidDataTypeException
704
-     * @throws InvalidInterfaceException
705
-     * @throws ReflectionException
706
-     */
707
-    public function is_incomplete()
708
-    {
709
-        return $this->status_ID() === EEM_Transaction::incomplete_status_code;
710
-    }
711
-
712
-
713
-    /**
714
-     * Returns whether this transaction is overpaid
715
-     * Useful in templates and other logic for deciding if monies need to be refunded
716
-     *
717
-     * @return boolean
718
-     * @throws EE_Error
719
-     * @throws InvalidArgumentException
720
-     * @throws InvalidDataTypeException
721
-     * @throws InvalidInterfaceException
722
-     * @throws ReflectionException
723
-     */
724
-    public function is_overpaid()
725
-    {
726
-        return $this->status_ID() === EEM_Transaction::overpaid_status_code;
727
-    }
728
-
729
-
730
-    /**
731
-     * Returns whether this transaction was abandoned
732
-     * meaning that the transaction/registration process was somehow interrupted and never completed
733
-     * but that contact information exists for at least one registrant
734
-     *
735
-     * @return boolean
736
-     * @throws EE_Error
737
-     * @throws InvalidArgumentException
738
-     * @throws InvalidDataTypeException
739
-     * @throws InvalidInterfaceException
740
-     * @throws ReflectionException
741
-     */
742
-    public function is_abandoned()
743
-    {
744
-        return $this->status_ID() === EEM_Transaction::abandoned_status_code;
745
-    }
746
-
747
-
748
-    /**
749
-     * Returns whether this transaction failed
750
-     * meaning that the transaction/registration process was somehow interrupted and never completed
751
-     * and that NO contact information exists for any registrants
752
-     *
753
-     * @return boolean
754
-     * @throws EE_Error
755
-     * @throws InvalidArgumentException
756
-     * @throws InvalidDataTypeException
757
-     * @throws InvalidInterfaceException
758
-     * @throws ReflectionException
759
-     */
760
-    public function failed()
761
-    {
762
-        return $this->status_ID() === EEM_Transaction::failed_status_code;
763
-    }
764
-
765
-
766
-    /**
767
-     * This returns the url for the invoice of this transaction
768
-     *
769
-     * @param string $type 'html' or 'pdf' (default is pdf)
770
-     * @return string
771
-     * @throws EE_Error
772
-     * @throws InvalidArgumentException
773
-     * @throws InvalidDataTypeException
774
-     * @throws InvalidInterfaceException
775
-     * @throws ReflectionException
776
-     */
777
-    public function invoice_url($type = 'html')
778
-    {
779
-        $REG = $this->primary_registration();
780
-        if (! $REG instanceof EE_Registration) {
781
-            return '';
782
-        }
783
-        return $REG->invoice_url($type);
784
-    }
785
-
786
-
787
-    /**
788
-     * Gets the primary registration only
789
-     *
790
-     * @return EE_Base_Class|EE_Registration
791
-     * @throws EE_Error
792
-     * @throws InvalidArgumentException
793
-     * @throws InvalidDataTypeException
794
-     * @throws InvalidInterfaceException
795
-     * @throws ReflectionException
796
-     */
797
-    public function primary_registration()
798
-    {
799
-        $registrations = (array) $this->get_many_related(
800
-            'Registration',
801
-            array(array('REG_count' => EEM_Registration::PRIMARY_REGISTRANT_COUNT))
802
-        );
803
-        foreach ($registrations as $registration) {
804
-            // valid registration that is NOT cancelled or declined ?
805
-            if (
806
-                $registration instanceof EE_Registration
807
-                && ! in_array($registration->status_ID(), EEM_Registration::closed_reg_statuses(), true)
808
-            ) {
809
-                return $registration;
810
-            }
811
-        }
812
-        // nothing valid found, so just return first thing from array of results
813
-        return reset($registrations);
814
-    }
815
-
816
-
817
-    /**
818
-     * Gets the URL for viewing the receipt
819
-     *
820
-     * @param string $type 'pdf' or 'html' (default is 'html')
821
-     * @return string
822
-     * @throws EE_Error
823
-     * @throws InvalidArgumentException
824
-     * @throws InvalidDataTypeException
825
-     * @throws InvalidInterfaceException
826
-     * @throws ReflectionException
827
-     */
828
-    public function receipt_url($type = 'html')
829
-    {
830
-        $REG = $this->primary_registration();
831
-        if (! $REG instanceof EE_Registration) {
832
-            return '';
833
-        }
834
-        return $REG->receipt_url($type);
835
-    }
836
-
837
-
838
-    /**
839
-     * Gets the URL of the thank you page with this registration REG_url_link added as
840
-     * a query parameter
841
-     *
842
-     * @return string
843
-     * @throws EE_Error
844
-     * @throws InvalidArgumentException
845
-     * @throws InvalidDataTypeException
846
-     * @throws InvalidInterfaceException
847
-     * @throws ReflectionException
848
-     */
849
-    public function payment_overview_url()
850
-    {
851
-        $primary_registration = $this->primary_registration();
852
-        return $primary_registration instanceof EE_Registration ? $primary_registration->payment_overview_url() : false;
853
-    }
854
-
855
-
856
-    /**
857
-     * @return string
858
-     * @throws EE_Error
859
-     * @throws InvalidArgumentException
860
-     * @throws InvalidDataTypeException
861
-     * @throws InvalidInterfaceException
862
-     * @throws ReflectionException
863
-     */
864
-    public function gateway_response_on_transaction()
865
-    {
866
-        $payment = $this->get_first_related('Payment');
867
-        return $payment instanceof EE_Payment ? $payment->gateway_response() : '';
868
-    }
869
-
870
-
871
-    /**
872
-     * Get the status object of this object
873
-     *
874
-     * @return EE_Base_Class|EE_Status
875
-     * @throws EE_Error
876
-     * @throws InvalidArgumentException
877
-     * @throws InvalidDataTypeException
878
-     * @throws InvalidInterfaceException
879
-     * @throws ReflectionException
880
-     */
881
-    public function status_obj()
882
-    {
883
-        return $this->get_first_related('Status');
884
-    }
885
-
886
-
887
-    /**
888
-     * Gets all the extra meta info on this payment
889
-     *
890
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
891
-     * @return EE_Base_Class[]|EE_Extra_Meta
892
-     * @throws EE_Error
893
-     * @throws InvalidArgumentException
894
-     * @throws InvalidDataTypeException
895
-     * @throws InvalidInterfaceException
896
-     * @throws ReflectionException
897
-     */
898
-    public function extra_meta($query_params = array())
899
-    {
900
-        return $this->get_many_related('Extra_Meta', $query_params);
901
-    }
902
-
903
-
904
-    /**
905
-     * Wrapper for _add_relation_to
906
-     *
907
-     * @param EE_Registration $registration
908
-     * @return EE_Base_Class the relation was added to
909
-     * @throws EE_Error
910
-     * @throws InvalidArgumentException
911
-     * @throws InvalidDataTypeException
912
-     * @throws InvalidInterfaceException
913
-     * @throws ReflectionException
914
-     */
915
-    public function add_registration(EE_Registration $registration)
916
-    {
917
-        return $this->_add_relation_to($registration, 'Registration');
918
-    }
919
-
920
-
921
-    /**
922
-     * Removes the given registration from being related (even before saving this transaction).
923
-     * If an ID/index is provided and this transaction isn't saved yet, removes it from list of cached relations
924
-     *
925
-     * @param int $registration_or_id
926
-     * @return EE_Base_Class that was removed from being related
927
-     * @throws EE_Error
928
-     * @throws InvalidArgumentException
929
-     * @throws InvalidDataTypeException
930
-     * @throws InvalidInterfaceException
931
-     * @throws ReflectionException
932
-     */
933
-    public function remove_registration_with_id($registration_or_id)
934
-    {
935
-        return $this->_remove_relation_to($registration_or_id, 'Registration');
936
-    }
937
-
938
-
939
-    /**
940
-     * Gets all the line items which are for ACTUAL items
941
-     *
942
-     * @return EE_Line_Item[]
943
-     * @throws EE_Error
944
-     * @throws InvalidArgumentException
945
-     * @throws InvalidDataTypeException
946
-     * @throws InvalidInterfaceException
947
-     * @throws ReflectionException
948
-     */
949
-    public function items_purchased()
950
-    {
951
-        return $this->line_items(array(array('LIN_type' => EEM_Line_Item::type_line_item)));
952
-    }
953
-
954
-
955
-    /**
956
-     * Wrapper for _add_relation_to
957
-     *
958
-     * @param EE_Line_Item $line_item
959
-     * @return EE_Base_Class the relation was added to
960
-     * @throws EE_Error
961
-     * @throws InvalidArgumentException
962
-     * @throws InvalidDataTypeException
963
-     * @throws InvalidInterfaceException
964
-     * @throws ReflectionException
965
-     */
966
-    public function add_line_item(EE_Line_Item $line_item)
967
-    {
968
-        return $this->_add_relation_to($line_item, 'Line_Item');
969
-    }
970
-
971
-
972
-    /**
973
-     * Gets ALL the line items related to this transaction (unstructured)
974
-     *
975
-     * @param array $query_params
976
-     * @return EE_Base_Class[]|EE_Line_Item[]
977
-     * @throws EE_Error
978
-     * @throws InvalidArgumentException
979
-     * @throws InvalidDataTypeException
980
-     * @throws InvalidInterfaceException
981
-     * @throws ReflectionException
982
-     */
983
-    public function line_items($query_params = array())
984
-    {
985
-        return $this->get_many_related('Line_Item', $query_params);
986
-    }
987
-
988
-
989
-    /**
990
-     * Gets all the line items which are taxes on the total
991
-     *
992
-     * @return EE_Line_Item[]
993
-     * @throws EE_Error
994
-     * @throws InvalidArgumentException
995
-     * @throws InvalidDataTypeException
996
-     * @throws InvalidInterfaceException
997
-     * @throws ReflectionException
998
-     */
999
-    public function tax_items()
1000
-    {
1001
-        return $this->line_items(array(array('LIN_type' => EEM_Line_Item::type_tax)));
1002
-    }
1003
-
1004
-
1005
-    /**
1006
-     * Gets the total line item (which is a parent of all other related line items,
1007
-     * meaning it takes them all into account on its total)
1008
-     *
1009
-     * @param bool $create_if_not_found
1010
-     * @return \EE_Line_Item
1011
-     * @throws EE_Error
1012
-     * @throws InvalidArgumentException
1013
-     * @throws InvalidDataTypeException
1014
-     * @throws InvalidInterfaceException
1015
-     * @throws ReflectionException
1016
-     */
1017
-    public function total_line_item($create_if_not_found = true)
1018
-    {
1019
-        $item = $this->get_first_related('Line_Item', array(array('LIN_type' => EEM_Line_Item::type_total)));
1020
-        if (! $item && $create_if_not_found) {
1021
-            $item = EEH_Line_Item::create_total_line_item($this);
1022
-        }
1023
-        return $item;
1024
-    }
1025
-
1026
-
1027
-    /**
1028
-     * Returns the total amount of tax on this transaction
1029
-     * (assumes there's only one tax subtotal line item)
1030
-     *
1031
-     * @return float
1032
-     * @throws EE_Error
1033
-     * @throws InvalidArgumentException
1034
-     * @throws InvalidDataTypeException
1035
-     * @throws InvalidInterfaceException
1036
-     * @throws ReflectionException
1037
-     */
1038
-    public function tax_total()
1039
-    {
1040
-        $tax_line_item = $this->tax_total_line_item();
1041
-        if ($tax_line_item) {
1042
-            return (float) $tax_line_item->total();
1043
-        }
1044
-        return (float) 0;
1045
-    }
1046
-
1047
-
1048
-    /**
1049
-     * Gets the tax subtotal line item (assumes there's only one)
1050
-     *
1051
-     * @return EE_Line_Item
1052
-     * @throws EE_Error
1053
-     * @throws InvalidArgumentException
1054
-     * @throws InvalidDataTypeException
1055
-     * @throws InvalidInterfaceException
1056
-     * @throws ReflectionException
1057
-     */
1058
-    public function tax_total_line_item()
1059
-    {
1060
-        return EEH_Line_Item::get_taxes_subtotal($this->total_line_item());
1061
-    }
1062
-
1063
-
1064
-    /**
1065
-     * Gets the array of billing info for the gateway and for this transaction's primary registration's attendee.
1066
-     *
1067
-     * @return EE_Form_Section_Proper
1068
-     * @throws EE_Error
1069
-     * @throws InvalidArgumentException
1070
-     * @throws InvalidDataTypeException
1071
-     * @throws InvalidInterfaceException
1072
-     * @throws ReflectionException
1073
-     */
1074
-    public function billing_info()
1075
-    {
1076
-        $payment_method = $this->payment_method();
1077
-        if (! $payment_method) {
1078
-            EE_Error::add_error(
1079
-                __(
1080
-                    'Could not find billing info for transaction because no gateway has been used for it yet',
1081
-                    'event_espresso'
1082
-                ),
1083
-                __FILE__,
1084
-                __FUNCTION__,
1085
-                __LINE__
1086
-            );
1087
-            return null;
1088
-        }
1089
-        $primary_reg = $this->primary_registration();
1090
-        if (! $primary_reg) {
1091
-            EE_Error::add_error(
1092
-                __(
1093
-                    'Cannot get billing info for gateway %s on transaction because no primary registration exists',
1094
-                    'event_espresso'
1095
-                ),
1096
-                __FILE__,
1097
-                __FUNCTION__,
1098
-                __LINE__
1099
-            );
1100
-            return null;
1101
-        }
1102
-        $attendee = $primary_reg->attendee();
1103
-        if (! $attendee) {
1104
-            EE_Error::add_error(
1105
-                __(
1106
-                    'Cannot get billing info for gateway %s on transaction because the primary registration has no attendee exists',
1107
-                    'event_espresso'
1108
-                ),
1109
-                __FILE__,
1110
-                __FUNCTION__,
1111
-                __LINE__
1112
-            );
1113
-            return null;
1114
-        }
1115
-        return $attendee->billing_info_for_payment_method($payment_method);
1116
-    }
1117
-
1118
-
1119
-    /**
1120
-     * Gets PMD_ID
1121
-     *
1122
-     * @return int
1123
-     * @throws EE_Error
1124
-     * @throws InvalidArgumentException
1125
-     * @throws InvalidDataTypeException
1126
-     * @throws InvalidInterfaceException
1127
-     * @throws ReflectionException
1128
-     */
1129
-    public function payment_method_ID()
1130
-    {
1131
-        return $this->get('PMD_ID');
1132
-    }
1133
-
1134
-
1135
-    /**
1136
-     * Sets PMD_ID
1137
-     *
1138
-     * @param int $PMD_ID
1139
-     * @throws EE_Error
1140
-     * @throws InvalidArgumentException
1141
-     * @throws InvalidDataTypeException
1142
-     * @throws InvalidInterfaceException
1143
-     * @throws ReflectionException
1144
-     */
1145
-    public function set_payment_method_ID($PMD_ID)
1146
-    {
1147
-        $this->set('PMD_ID', $PMD_ID);
1148
-    }
1149
-
1150
-
1151
-    /**
1152
-     * Gets the last-used payment method on this transaction
1153
-     * (we COULD just use the last-made payment, but some payment methods, namely
1154
-     * offline ones, dont' create payments)
1155
-     *
1156
-     * @return EE_Payment_Method
1157
-     * @throws EE_Error
1158
-     * @throws InvalidArgumentException
1159
-     * @throws InvalidDataTypeException
1160
-     * @throws InvalidInterfaceException
1161
-     * @throws ReflectionException
1162
-     */
1163
-    public function payment_method()
1164
-    {
1165
-        $pm = $this->get_first_related('Payment_Method');
1166
-        if ($pm instanceof EE_Payment_Method) {
1167
-            return $pm;
1168
-        }
1169
-        $last_payment = $this->last_payment();
1170
-        if ($last_payment instanceof EE_Payment && $last_payment->payment_method()) {
1171
-            return $last_payment->payment_method();
1172
-        }
1173
-        return null;
1174
-    }
1175
-
1176
-
1177
-    /**
1178
-     * Gets the last payment made
1179
-     *
1180
-     * @return EE_Base_Class|EE_Payment
1181
-     * @throws EE_Error
1182
-     * @throws InvalidArgumentException
1183
-     * @throws InvalidDataTypeException
1184
-     * @throws InvalidInterfaceException
1185
-     * @throws ReflectionException
1186
-     */
1187
-    public function last_payment()
1188
-    {
1189
-        return $this->get_first_related('Payment', array('order_by' => array('PAY_ID' => 'desc')));
1190
-    }
1191
-
1192
-
1193
-    /**
1194
-     * Gets all the line items which are unrelated to tickets on this transaction
1195
-     *
1196
-     * @return EE_Line_Item[]
1197
-     * @throws EE_Error
1198
-     * @throws InvalidArgumentException
1199
-     * @throws InvalidDataTypeException
1200
-     * @throws InvalidInterfaceException
1201
-     * @throws ReflectionException
1202
-     */
1203
-    public function non_ticket_line_items()
1204
-    {
1205
-        return EEM_Line_Item::instance()->get_all_non_ticket_line_items_for_transaction($this->ID());
1206
-    }
1207
-
1208
-
1209
-    /**
1210
-     * possibly toggles TXN status
1211
-     *
1212
-     * @param  boolean $update whether to save the TXN
1213
-     * @return bool whether the TXN was saved
1214
-     * @throws EE_Error
1215
-     * @throws InvalidArgumentException
1216
-     * @throws InvalidDataTypeException
1217
-     * @throws InvalidInterfaceException
1218
-     * @throws ReflectionException
1219
-     * @throws RuntimeException
1220
-     */
1221
-    public function update_status_based_on_total_paid($update = true)
1222
-    {
1223
-        // set transaction status based on comparison of TXN_paid vs TXN_total
1224
-        if (EEH_Money::compare_floats($this->paid(), $this->total(), '>')) {
1225
-            $new_txn_status = EEM_Transaction::overpaid_status_code;
1226
-        } elseif (EEH_Money::compare_floats($this->paid(), $this->total())) {
1227
-            $new_txn_status = EEM_Transaction::complete_status_code;
1228
-        } elseif (EEH_Money::compare_floats($this->paid(), $this->total(), '<')) {
1229
-            $new_txn_status = EEM_Transaction::incomplete_status_code;
1230
-        } else {
1231
-            throw new RuntimeException(
1232
-                __('The total paid calculation for this transaction is inaccurate.', 'event_espresso')
1233
-            );
1234
-        }
1235
-        if ($new_txn_status !== $this->status_ID()) {
1236
-            $this->set_status($new_txn_status);
1237
-            if ($update) {
1238
-                return $this->save() ? true : false;
1239
-            }
1240
-        }
1241
-        return false;
1242
-    }
1243
-
1244
-
1245
-    /**
1246
-     * Updates the transaction's status and total_paid based on all the payments
1247
-     * that apply to it
1248
-     *
1249
-     * @deprecated
1250
-     * @return array|bool
1251
-     * @throws EE_Error
1252
-     * @throws InvalidArgumentException
1253
-     * @throws ReflectionException
1254
-     * @throws InvalidDataTypeException
1255
-     * @throws InvalidInterfaceException
1256
-     */
1257
-    public function update_based_on_payments()
1258
-    {
1259
-        EE_Error::doing_it_wrong(
1260
-            __CLASS__ . '::' . __FUNCTION__,
1261
-            sprintf(
1262
-                __('This method is deprecated. Please use "%s" instead', 'event_espresso'),
1263
-                'EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()'
1264
-            ),
1265
-            '4.6.0'
1266
-        );
1267
-        /** @type EE_Transaction_Processor $transaction_processor */
1268
-        $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
1269
-        return $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment($this);
1270
-    }
1271
-
1272
-
1273
-    /**
1274
-     * @return string
1275
-     */
1276
-    public function old_txn_status()
1277
-    {
1278
-        return $this->_old_txn_status;
1279
-    }
1280
-
1281
-
1282
-    /**
1283
-     * @param string $old_txn_status
1284
-     */
1285
-    public function set_old_txn_status($old_txn_status)
1286
-    {
1287
-        // only set the first time
1288
-        if ($this->_old_txn_status === null) {
1289
-            $this->_old_txn_status = $old_txn_status;
1290
-        }
1291
-    }
1292
-
1293
-
1294
-    /**
1295
-     * reg_status_updated
1296
-     *
1297
-     * @return bool
1298
-     * @throws EE_Error
1299
-     * @throws InvalidArgumentException
1300
-     * @throws InvalidDataTypeException
1301
-     * @throws InvalidInterfaceException
1302
-     * @throws ReflectionException
1303
-     */
1304
-    public function txn_status_updated()
1305
-    {
1306
-        return $this->status_ID() !== $this->_old_txn_status && $this->_old_txn_status !== null;
1307
-    }
1308
-
1309
-
1310
-    /**
1311
-     * _reg_steps_completed
1312
-     * if $check_all is TRUE, then returns TRUE if ALL reg steps have been marked as completed,
1313
-     * if a $reg_step_slug is provided, then this step will be skipped when testing for completion
1314
-     * if $check_all is FALSE and a $reg_step_slug is provided, then ONLY that reg step will be tested for completion
1315
-     *
1316
-     * @param string $reg_step_slug
1317
-     * @param bool   $check_all
1318
-     * @return bool|int
1319
-     * @throws EE_Error
1320
-     * @throws InvalidArgumentException
1321
-     * @throws InvalidDataTypeException
1322
-     * @throws InvalidInterfaceException
1323
-     * @throws ReflectionException
1324
-     */
1325
-    private function _reg_steps_completed($reg_step_slug = '', $check_all = true)
1326
-    {
1327
-        $reg_steps = $this->reg_steps();
1328
-        if (! is_array($reg_steps) || empty($reg_steps)) {
1329
-            return false;
1330
-        }
1331
-        // loop thru reg steps array)
1332
-        foreach ($reg_steps as $slug => $reg_step_completed) {
1333
-            // if NOT checking ALL steps (only checking one step)
1334
-            if (! $check_all) {
1335
-                // and this is the one
1336
-                if ($slug === $reg_step_slug) {
1337
-                    return $reg_step_completed;
1338
-                }
1339
-                // skip to next reg step in loop
1340
-                continue;
1341
-            }
1342
-            // $check_all must be true, else we would never have gotten to this point
1343
-            if ($slug === $reg_step_slug) {
1344
-                // if we reach this point, then we are testing either:
1345
-                // all_reg_steps_completed_except() or
1346
-                // all_reg_steps_completed_except_final_step(),
1347
-                // and since this is the reg step EXCEPTION being tested
1348
-                // we want to return true (yes true) if this reg step is NOT completed
1349
-                // ie: "is everything completed except the final step?"
1350
-                // "that is correct... the final step is not completed, but all others are."
1351
-                return $reg_step_completed !== true;
1352
-            }
1353
-            if ($reg_step_completed !== true) {
1354
-                // if any reg step is NOT completed, then ALL steps are not completed
1355
-                return false;
1356
-            }
1357
-        }
1358
-        return true;
1359
-    }
1360
-
1361
-
1362
-    /**
1363
-     * all_reg_steps_completed
1364
-     * returns:
1365
-     *    true if ALL reg steps have been marked as completed
1366
-     *        or false if any step is not completed
1367
-     *
1368
-     * @return bool
1369
-     * @throws EE_Error
1370
-     * @throws InvalidArgumentException
1371
-     * @throws InvalidDataTypeException
1372
-     * @throws InvalidInterfaceException
1373
-     * @throws ReflectionException
1374
-     */
1375
-    public function all_reg_steps_completed()
1376
-    {
1377
-        return $this->_reg_steps_completed();
1378
-    }
1379
-
1380
-
1381
-    /**
1382
-     * all_reg_steps_completed_except
1383
-     * returns:
1384
-     *        true if ALL reg steps, except a particular step that you wish to skip over, have been marked as completed
1385
-     *        or false if any other step is not completed
1386
-     *        or false if ALL steps are completed including the exception you are testing !!!
1387
-     *
1388
-     * @param string $exception
1389
-     * @return bool
1390
-     * @throws EE_Error
1391
-     * @throws InvalidArgumentException
1392
-     * @throws InvalidDataTypeException
1393
-     * @throws InvalidInterfaceException
1394
-     * @throws ReflectionException
1395
-     */
1396
-    public function all_reg_steps_completed_except($exception = '')
1397
-    {
1398
-        return $this->_reg_steps_completed($exception);
1399
-    }
1400
-
1401
-
1402
-    /**
1403
-     * all_reg_steps_completed_except
1404
-     * returns:
1405
-     *        true if ALL reg steps, except the final step, have been marked as completed
1406
-     *        or false if any step is not completed
1407
-     *    or false if ALL steps are completed including the final step !!!
1408
-     *
1409
-     * @return bool
1410
-     * @throws EE_Error
1411
-     * @throws InvalidArgumentException
1412
-     * @throws InvalidDataTypeException
1413
-     * @throws InvalidInterfaceException
1414
-     * @throws ReflectionException
1415
-     */
1416
-    public function all_reg_steps_completed_except_final_step()
1417
-    {
1418
-        return $this->_reg_steps_completed('finalize_registration');
1419
-    }
1420
-
1421
-
1422
-    /**
1423
-     * reg_step_completed
1424
-     * returns:
1425
-     *    true if a specific reg step has been marked as completed
1426
-     *    a Unix timestamp if it has been initialized but not yet completed,
1427
-     *    or false if it has not yet been initialized
1428
-     *
1429
-     * @param string $reg_step_slug
1430
-     * @return bool|int
1431
-     * @throws EE_Error
1432
-     * @throws InvalidArgumentException
1433
-     * @throws InvalidDataTypeException
1434
-     * @throws InvalidInterfaceException
1435
-     * @throws ReflectionException
1436
-     */
1437
-    public function reg_step_completed($reg_step_slug)
1438
-    {
1439
-        return $this->_reg_steps_completed($reg_step_slug, false);
1440
-    }
1441
-
1442
-
1443
-    /**
1444
-     * completed_final_reg_step
1445
-     * returns:
1446
-     *    true if the finalize_registration reg step has been marked as completed
1447
-     *    a Unix timestamp if it has been initialized but not yet completed,
1448
-     *    or false if it has not yet been initialized
1449
-     *
1450
-     * @return bool|int
1451
-     * @throws EE_Error
1452
-     * @throws InvalidArgumentException
1453
-     * @throws InvalidDataTypeException
1454
-     * @throws InvalidInterfaceException
1455
-     * @throws ReflectionException
1456
-     */
1457
-    public function final_reg_step_completed()
1458
-    {
1459
-        return $this->_reg_steps_completed('finalize_registration', false);
1460
-    }
1461
-
1462
-
1463
-    /**
1464
-     * set_reg_step_initiated
1465
-     * given a valid TXN_reg_step, this sets it's value to a unix timestamp
1466
-     *
1467
-     * @param string $reg_step_slug
1468
-     * @return boolean
1469
-     * @throws EE_Error
1470
-     * @throws InvalidArgumentException
1471
-     * @throws InvalidDataTypeException
1472
-     * @throws InvalidInterfaceException
1473
-     * @throws ReflectionException
1474
-     */
1475
-    public function set_reg_step_initiated($reg_step_slug)
1476
-    {
1477
-        return $this->_set_reg_step_completed_status($reg_step_slug, time());
1478
-    }
1479
-
1480
-
1481
-    /**
1482
-     * set_reg_step_completed
1483
-     * given a valid TXN_reg_step, this sets the step as completed
1484
-     *
1485
-     * @param string $reg_step_slug
1486
-     * @return boolean
1487
-     * @throws EE_Error
1488
-     * @throws InvalidArgumentException
1489
-     * @throws InvalidDataTypeException
1490
-     * @throws InvalidInterfaceException
1491
-     * @throws ReflectionException
1492
-     */
1493
-    public function set_reg_step_completed($reg_step_slug)
1494
-    {
1495
-        return $this->_set_reg_step_completed_status($reg_step_slug, true);
1496
-    }
1497
-
1498
-
1499
-    /**
1500
-     * set_reg_step_completed
1501
-     * given a valid TXN_reg_step slug, this sets the step as NOT completed
1502
-     *
1503
-     * @param string $reg_step_slug
1504
-     * @return boolean
1505
-     * @throws EE_Error
1506
-     * @throws InvalidArgumentException
1507
-     * @throws InvalidDataTypeException
1508
-     * @throws InvalidInterfaceException
1509
-     * @throws ReflectionException
1510
-     */
1511
-    public function set_reg_step_not_completed($reg_step_slug)
1512
-    {
1513
-        return $this->_set_reg_step_completed_status($reg_step_slug, false);
1514
-    }
1515
-
1516
-
1517
-    /**
1518
-     * set_reg_step_completed
1519
-     * given a valid reg step slug, this sets the TXN_reg_step completed status which is either:
1520
-     *
1521
-     * @param  string      $reg_step_slug
1522
-     * @param  boolean|int $status
1523
-     * @return boolean
1524
-     * @throws EE_Error
1525
-     * @throws InvalidArgumentException
1526
-     * @throws InvalidDataTypeException
1527
-     * @throws InvalidInterfaceException
1528
-     * @throws ReflectionException
1529
-     */
1530
-    private function _set_reg_step_completed_status($reg_step_slug, $status)
1531
-    {
1532
-        // validate status
1533
-        $status = is_bool($status) || is_int($status) ? $status : false;
1534
-        // get reg steps array
1535
-        $txn_reg_steps = $this->reg_steps();
1536
-        // if reg step does NOT exist
1537
-        if (! isset($txn_reg_steps[ $reg_step_slug ])) {
1538
-            return false;
1539
-        }
1540
-        // if  we're trying to complete a step that is already completed
1541
-        if ($txn_reg_steps[ $reg_step_slug ] === true) {
1542
-            return true;
1543
-        }
1544
-        // if  we're trying to complete a step that hasn't even started
1545
-        if ($status === true && $txn_reg_steps[ $reg_step_slug ] === false) {
1546
-            return false;
1547
-        }
1548
-        // if current status value matches the incoming value (no change)
1549
-        // type casting as int means values should collapse to either 0, 1, or a timestamp like 1234567890
1550
-        if ((int) $txn_reg_steps[ $reg_step_slug ] === (int) $status) {
1551
-            // this will happen in cases where multiple AJAX requests occur during the same step
1552
-            return true;
1553
-        }
1554
-        // if we're trying to set a start time, but it has already been set...
1555
-        if (is_numeric($status) && is_numeric($txn_reg_steps[ $reg_step_slug ])) {
1556
-            // skip the update below, but don't return FALSE so that errors won't be displayed
1557
-            return true;
1558
-        }
1559
-        // update completed status
1560
-        $txn_reg_steps[ $reg_step_slug ] = $status;
1561
-        $this->set_reg_steps($txn_reg_steps);
1562
-        $this->save();
1563
-        return true;
1564
-    }
1565
-
1566
-
1567
-    /**
1568
-     * remove_reg_step
1569
-     * given a valid TXN_reg_step slug, this will remove (unset)
1570
-     * the reg step from the TXN reg step array
1571
-     *
1572
-     * @param string $reg_step_slug
1573
-     * @return void
1574
-     * @throws EE_Error
1575
-     * @throws InvalidArgumentException
1576
-     * @throws InvalidDataTypeException
1577
-     * @throws InvalidInterfaceException
1578
-     * @throws ReflectionException
1579
-     */
1580
-    public function remove_reg_step($reg_step_slug)
1581
-    {
1582
-        // get reg steps array
1583
-        $txn_reg_steps = $this->reg_steps();
1584
-        unset($txn_reg_steps[ $reg_step_slug ]);
1585
-        $this->set_reg_steps($txn_reg_steps);
1586
-    }
1587
-
1588
-
1589
-    /**
1590
-     * toggle_failed_transaction_status
1591
-     * upgrades a TXNs status from failed to abandoned,
1592
-     * meaning that contact information has been captured for at least one registrant
1593
-     *
1594
-     * @param bool $save
1595
-     * @return bool
1596
-     * @throws EE_Error
1597
-     * @throws InvalidArgumentException
1598
-     * @throws InvalidDataTypeException
1599
-     * @throws InvalidInterfaceException
1600
-     * @throws ReflectionException
1601
-     */
1602
-    public function toggle_failed_transaction_status($save = true)
1603
-    {
1604
-        // if TXN status is still set as "failed"...
1605
-        if ($this->status_ID() === EEM_Transaction::failed_status_code) {
1606
-            $this->set_status(EEM_Transaction::abandoned_status_code);
1607
-            if ($save) {
1608
-                $this->save();
1609
-            }
1610
-            return true;
1611
-        }
1612
-        return false;
1613
-    }
1614
-
1615
-
1616
-    /**
1617
-     * toggle_abandoned_transaction_status
1618
-     * upgrades a TXNs status from failed or abandoned to incomplete
1619
-     *
1620
-     * @return bool
1621
-     * @throws EE_Error
1622
-     * @throws InvalidArgumentException
1623
-     * @throws InvalidDataTypeException
1624
-     * @throws InvalidInterfaceException
1625
-     * @throws ReflectionException
1626
-     */
1627
-    public function toggle_abandoned_transaction_status()
1628
-    {
1629
-        // if TXN status has not been updated already due to a payment, and is still set as "failed" or "abandoned"...
1630
-        $txn_status = $this->status_ID();
1631
-        if (
1632
-            $txn_status === EEM_Transaction::failed_status_code
1633
-            || $txn_status === EEM_Transaction::abandoned_status_code
1634
-        ) {
1635
-            // if a contact record for the primary registrant has been created
1636
-            if (
1637
-                $this->primary_registration() instanceof EE_Registration
1638
-                && $this->primary_registration()->attendee() instanceof EE_Attendee
1639
-            ) {
1640
-                $this->set_status(EEM_Transaction::incomplete_status_code);
1641
-            } else {
1642
-                // no contact record? yer abandoned!
1643
-                $this->set_status(EEM_Transaction::abandoned_status_code);
1644
-            }
1645
-            return true;
1646
-        }
1647
-        return false;
1648
-    }
1649
-
1650
-
1651
-    /**
1652
-     * checks if an Abandoned TXN has any related payments, and if so,
1653
-     * updates the TXN status based on the amount paid
1654
-     *
1655
-     * @throws EE_Error
1656
-     * @throws InvalidDataTypeException
1657
-     * @throws InvalidInterfaceException
1658
-     * @throws InvalidArgumentException
1659
-     * @throws RuntimeException
1660
-     * @throws ReflectionException
1661
-     */
1662
-    public function verify_abandoned_transaction_status()
1663
-    {
1664
-        if ($this->status_ID() !== EEM_Transaction::abandoned_status_code) {
1665
-            return;
1666
-        }
1667
-        $payments = $this->get_many_related('Payment');
1668
-        if (! empty($payments)) {
1669
-            foreach ($payments as $payment) {
1670
-                if ($payment instanceof EE_Payment) {
1671
-                    // kk this TXN should NOT be abandoned
1672
-                    $this->update_status_based_on_total_paid();
1673
-                    if (! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) {
1674
-                        EE_Error::add_attention(
1675
-                            sprintf(
1676
-                                esc_html__(
1677
-                                    'The status for Transaction #%1$d has been updated from "Abandoned" to "%2$s", because at least one payment has been made towards it. If the payment appears in the "Payment Details" table below, you may need to edit its status and/or other details as well.',
1678
-                                    'event_espresso'
1679
-                                ),
1680
-                                $this->ID(),
1681
-                                $this->pretty_status()
1682
-                            )
1683
-                        );
1684
-                    }
1685
-                    // get final reg step status
1686
-                    $finalized = $this->final_reg_step_completed();
1687
-                    // if the 'finalize_registration' step has been initiated (has a timestamp)
1688
-                    // but has not yet been fully completed (TRUE)
1689
-                    if (is_int($finalized) && $finalized !== false && $finalized !== true) {
1690
-                        $this->set_reg_step_completed('finalize_registration');
1691
-                        $this->save();
1692
-                    }
1693
-                }
1694
-            }
1695
-        }
1696
-    }
1697
-
1698
-
1699
-    /**
1700
-     * @since 4.10.4.p
1701
-     * @throws EE_Error
1702
-     * @throws InvalidArgumentException
1703
-     * @throws InvalidDataTypeException
1704
-     * @throws InvalidInterfaceException
1705
-     * @throws ReflectionException
1706
-     * @throws RuntimeException
1707
-     */
1708
-    public function recalculateLineItems()
1709
-    {
1710
-        $total_line_item = $this->total_line_item(false);
1711
-        if ($total_line_item instanceof EE_Line_Item) {
1712
-            EEH_Line_Item::resetIsTaxableForTickets($total_line_item);
1713
-            return EEH_Line_Item::apply_taxes($total_line_item, true);
1714
-        }
1715
-        return false;
1716
-    }
16
+	/**
17
+	 * The length of time in seconds that a lock is applied before being considered expired.
18
+	 * It is not long because a transaction should only be locked for the duration of the request that locked it
19
+	 */
20
+	const LOCK_EXPIRATION = 2;
21
+
22
+	/**
23
+	 * txn status upon initial construction.
24
+	 *
25
+	 * @var string
26
+	 */
27
+	protected $_old_txn_status;
28
+
29
+
30
+	/**
31
+	 * @param array  $props_n_values          incoming values
32
+	 * @param string $timezone                incoming timezone
33
+	 *                                        (if not set the timezone set for the website will be used.)
34
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
35
+	 *                                        date_format and the second value is the time format
36
+	 * @return EE_Transaction
37
+	 * @throws EE_Error
38
+	 * @throws InvalidArgumentException
39
+	 * @throws InvalidDataTypeException
40
+	 * @throws InvalidInterfaceException
41
+	 * @throws ReflectionException
42
+	 */
43
+	public static function new_instance($props_n_values = array(), $timezone = '', $date_formats = array())
44
+	{
45
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
46
+		$txn = $has_object
47
+			? $has_object
48
+			: new self($props_n_values, false, $timezone, $date_formats);
49
+		if (! $has_object) {
50
+			$txn->set_old_txn_status($txn->status_ID());
51
+		}
52
+		return $txn;
53
+	}
54
+
55
+
56
+	/**
57
+	 * @param array  $props_n_values  incoming values from the database
58
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
59
+	 *                                the website will be used.
60
+	 * @return EE_Transaction
61
+	 * @throws EE_Error
62
+	 * @throws InvalidArgumentException
63
+	 * @throws InvalidDataTypeException
64
+	 * @throws InvalidInterfaceException
65
+	 * @throws ReflectionException
66
+	 */
67
+	public static function new_instance_from_db($props_n_values = array(), $timezone = '')
68
+	{
69
+		$txn = new self($props_n_values, true, $timezone);
70
+		$txn->set_old_txn_status($txn->status_ID());
71
+		return $txn;
72
+	}
73
+
74
+
75
+	/**
76
+	 * Sets a meta field indicating that this TXN is locked and should not be updated in the db.
77
+	 * If a lock has already been set, then we will attempt to remove it in case it has expired.
78
+	 * If that also fails, then an exception is thrown.
79
+	 *
80
+	 * @throws EE_Error
81
+	 * @throws InvalidArgumentException
82
+	 * @throws InvalidDataTypeException
83
+	 * @throws InvalidInterfaceException
84
+	 * @throws ReflectionException
85
+	 */
86
+	public function lock()
87
+	{
88
+		// attempt to set lock, but if that fails...
89
+		if (! $this->add_extra_meta('lock', time(), true)) {
90
+			// then attempt to remove the lock in case it is expired
91
+			if ($this->_remove_expired_lock()) {
92
+				// if removal was successful, then try setting lock again
93
+				$this->lock();
94
+			} else {
95
+				// but if the lock can not be removed, then throw an exception
96
+				throw new EE_Error(
97
+					sprintf(
98
+						__(
99
+							'Could not lock Transaction %1$d because it is already locked, meaning another part of the system is currently editing it. It should already be unlocked by the time you read this, so please refresh the page and try again.',
100
+							'event_espresso'
101
+						),
102
+						$this->ID()
103
+					)
104
+				);
105
+			}
106
+		}
107
+	}
108
+
109
+
110
+	/**
111
+	 * removes transaction lock applied in EE_Transaction::lock()
112
+	 *
113
+	 * @return int
114
+	 * @throws EE_Error
115
+	 * @throws InvalidArgumentException
116
+	 * @throws InvalidDataTypeException
117
+	 * @throws InvalidInterfaceException
118
+	 * @throws ReflectionException
119
+	 */
120
+	public function unlock()
121
+	{
122
+		return $this->delete_extra_meta('lock');
123
+	}
124
+
125
+
126
+	/**
127
+	 * Decides whether or not now is the right time to update the transaction.
128
+	 * This is useful because we don't always know if it is safe to update the transaction
129
+	 * and its related data. why?
130
+	 * because it's possible that the transaction is being used in another
131
+	 * request and could overwrite anything we save.
132
+	 * So we want to only update the txn once we know that won't happen.
133
+	 * We also check that the lock isn't expired, and remove it if it is
134
+	 *
135
+	 * @return boolean
136
+	 * @throws EE_Error
137
+	 * @throws InvalidArgumentException
138
+	 * @throws InvalidDataTypeException
139
+	 * @throws InvalidInterfaceException
140
+	 * @throws ReflectionException
141
+	 */
142
+	public function is_locked()
143
+	{
144
+		// if TXN is not locked, then return false immediately
145
+		if (! $this->_get_lock()) {
146
+			return false;
147
+		}
148
+		// if not, then let's try and remove the lock in case it's expired...
149
+		// _remove_expired_lock() returns 0 when lock is valid (ie: removed = false)
150
+		// and a positive number if the lock was removed (ie: number of locks deleted),
151
+		// so we need to return the opposite
152
+		return ! $this->_remove_expired_lock() ? true : false;
153
+	}
154
+
155
+
156
+	/**
157
+	 * Gets the meta field indicating that this TXN is locked
158
+	 *
159
+	 * @return int
160
+	 * @throws EE_Error
161
+	 * @throws InvalidArgumentException
162
+	 * @throws InvalidDataTypeException
163
+	 * @throws InvalidInterfaceException
164
+	 * @throws ReflectionException
165
+	 */
166
+	protected function _get_lock()
167
+	{
168
+		return (int) $this->get_extra_meta('lock', true, 0);
169
+	}
170
+
171
+
172
+	/**
173
+	 * If the lock on this transaction is expired, then we want to remove it so that the transaction can be updated
174
+	 *
175
+	 * @return int
176
+	 * @throws EE_Error
177
+	 * @throws InvalidArgumentException
178
+	 * @throws InvalidDataTypeException
179
+	 * @throws InvalidInterfaceException
180
+	 * @throws ReflectionException
181
+	 */
182
+	protected function _remove_expired_lock()
183
+	{
184
+		$locked = $this->_get_lock();
185
+		if ($locked && time() - EE_Transaction::LOCK_EXPIRATION > $locked) {
186
+			return $this->unlock();
187
+		}
188
+		return 0;
189
+	}
190
+
191
+
192
+	/**
193
+	 * Set transaction total
194
+	 *
195
+	 * @param float $total total value of transaction
196
+	 * @throws EE_Error
197
+	 * @throws InvalidArgumentException
198
+	 * @throws InvalidDataTypeException
199
+	 * @throws InvalidInterfaceException
200
+	 * @throws ReflectionException
201
+	 */
202
+	public function set_total($total = 0.00)
203
+	{
204
+		$this->set('TXN_total', (float) $total);
205
+	}
206
+
207
+
208
+	/**
209
+	 * Set Total Amount Paid to Date
210
+	 *
211
+	 * @param float $total_paid total amount paid to date (sum of all payments)
212
+	 * @throws EE_Error
213
+	 * @throws InvalidArgumentException
214
+	 * @throws InvalidDataTypeException
215
+	 * @throws InvalidInterfaceException
216
+	 * @throws ReflectionException
217
+	 */
218
+	public function set_paid($total_paid = 0.00)
219
+	{
220
+		$this->set('TXN_paid', (float) $total_paid);
221
+	}
222
+
223
+
224
+	/**
225
+	 * Set transaction status
226
+	 *
227
+	 * @param string $status        whether the transaction is open, declined, accepted,
228
+	 *                              or any number of custom values that can be set
229
+	 * @throws EE_Error
230
+	 * @throws InvalidArgumentException
231
+	 * @throws InvalidDataTypeException
232
+	 * @throws InvalidInterfaceException
233
+	 * @throws ReflectionException
234
+	 */
235
+	public function set_status($status = '')
236
+	{
237
+		$this->set('STS_ID', $status);
238
+	}
239
+
240
+
241
+	/**
242
+	 * Set hash salt
243
+	 *
244
+	 * @param string $hash_salt required for some payment gateways
245
+	 * @throws EE_Error
246
+	 * @throws InvalidArgumentException
247
+	 * @throws InvalidDataTypeException
248
+	 * @throws InvalidInterfaceException
249
+	 * @throws ReflectionException
250
+	 */
251
+	public function set_hash_salt($hash_salt = '')
252
+	{
253
+		$this->set('TXN_hash_salt', $hash_salt);
254
+	}
255
+
256
+
257
+	/**
258
+	 * Sets TXN_reg_steps array
259
+	 *
260
+	 * @param array $txn_reg_steps
261
+	 * @throws EE_Error
262
+	 * @throws InvalidArgumentException
263
+	 * @throws InvalidDataTypeException
264
+	 * @throws InvalidInterfaceException
265
+	 * @throws ReflectionException
266
+	 */
267
+	public function set_reg_steps(array $txn_reg_steps)
268
+	{
269
+		$this->set('TXN_reg_steps', $txn_reg_steps);
270
+	}
271
+
272
+
273
+	/**
274
+	 * Gets TXN_reg_steps
275
+	 *
276
+	 * @return array
277
+	 * @throws EE_Error
278
+	 * @throws InvalidArgumentException
279
+	 * @throws InvalidDataTypeException
280
+	 * @throws InvalidInterfaceException
281
+	 * @throws ReflectionException
282
+	 */
283
+	public function reg_steps()
284
+	{
285
+		$TXN_reg_steps = $this->get('TXN_reg_steps');
286
+		return is_array($TXN_reg_steps) ? (array) $TXN_reg_steps : array();
287
+	}
288
+
289
+
290
+	/**
291
+	 * @return string of transaction's total cost, with currency symbol and decimal
292
+	 * @throws EE_Error
293
+	 * @throws InvalidArgumentException
294
+	 * @throws InvalidDataTypeException
295
+	 * @throws InvalidInterfaceException
296
+	 * @throws ReflectionException
297
+	 */
298
+	public function pretty_total()
299
+	{
300
+		return $this->get_pretty('TXN_total');
301
+	}
302
+
303
+
304
+	/**
305
+	 * Gets the amount paid in a pretty string (formatted and with currency symbol)
306
+	 *
307
+	 * @return string
308
+	 * @throws EE_Error
309
+	 * @throws InvalidArgumentException
310
+	 * @throws InvalidDataTypeException
311
+	 * @throws InvalidInterfaceException
312
+	 * @throws ReflectionException
313
+	 */
314
+	public function pretty_paid()
315
+	{
316
+		return $this->get_pretty('TXN_paid');
317
+	}
318
+
319
+
320
+	/**
321
+	 * calculate the amount remaining for this transaction and return;
322
+	 *
323
+	 * @return float amount remaining
324
+	 * @throws EE_Error
325
+	 * @throws InvalidArgumentException
326
+	 * @throws InvalidDataTypeException
327
+	 * @throws InvalidInterfaceException
328
+	 * @throws ReflectionException
329
+	 */
330
+	public function remaining()
331
+	{
332
+		return $this->total() - $this->paid();
333
+	}
334
+
335
+
336
+	/**
337
+	 * get Transaction Total
338
+	 *
339
+	 * @return float
340
+	 * @throws EE_Error
341
+	 * @throws InvalidArgumentException
342
+	 * @throws InvalidDataTypeException
343
+	 * @throws InvalidInterfaceException
344
+	 * @throws ReflectionException
345
+	 */
346
+	public function total()
347
+	{
348
+		return (float) $this->get('TXN_total');
349
+	}
350
+
351
+
352
+	/**
353
+	 * get Total Amount Paid to Date
354
+	 *
355
+	 * @return float
356
+	 * @throws EE_Error
357
+	 * @throws InvalidArgumentException
358
+	 * @throws InvalidDataTypeException
359
+	 * @throws InvalidInterfaceException
360
+	 * @throws ReflectionException
361
+	 */
362
+	public function paid()
363
+	{
364
+		return (float) $this->get('TXN_paid');
365
+	}
366
+
367
+
368
+	/**
369
+	 * @return mixed|null
370
+	 * @throws EE_Error
371
+	 * @throws InvalidArgumentException
372
+	 * @throws InvalidDataTypeException
373
+	 * @throws InvalidInterfaceException
374
+	 * @throws ReflectionException
375
+	 */
376
+	public function get_cart_session()
377
+	{
378
+		$session_data = (array) $this->get('TXN_session_data');
379
+		return isset($session_data['cart']) && $session_data['cart'] instanceof EE_Cart
380
+			? $session_data['cart']
381
+			: null;
382
+	}
383
+
384
+
385
+	/**
386
+	 * get Transaction session data
387
+	 *
388
+	 * @return array|mixed
389
+	 * @throws EE_Error
390
+	 * @throws InvalidArgumentException
391
+	 * @throws InvalidDataTypeException
392
+	 * @throws InvalidInterfaceException
393
+	 * @throws ReflectionException
394
+	 */
395
+	public function session_data()
396
+	{
397
+		$session_data = $this->get('TXN_session_data');
398
+		if (empty($session_data)) {
399
+			$session_data = array(
400
+				'id'            => null,
401
+				'user_id'       => null,
402
+				'ip_address'    => null,
403
+				'user_agent'    => null,
404
+				'init_access'   => null,
405
+				'last_access'   => null,
406
+				'pages_visited' => array(),
407
+			);
408
+		}
409
+		return $session_data;
410
+	}
411
+
412
+
413
+	/**
414
+	 * Set session data within the TXN object
415
+	 *
416
+	 * @param EE_Session|array $session_data
417
+	 * @throws EE_Error
418
+	 * @throws InvalidArgumentException
419
+	 * @throws InvalidDataTypeException
420
+	 * @throws InvalidInterfaceException
421
+	 * @throws ReflectionException
422
+	 */
423
+	public function set_txn_session_data($session_data)
424
+	{
425
+		if ($session_data instanceof EE_Session) {
426
+			$this->set('TXN_session_data', $session_data->get_session_data(null, true));
427
+		} else {
428
+			$this->set('TXN_session_data', $session_data);
429
+		}
430
+	}
431
+
432
+
433
+	/**
434
+	 * get Transaction hash salt
435
+	 *
436
+	 * @return mixed
437
+	 * @throws EE_Error
438
+	 * @throws InvalidArgumentException
439
+	 * @throws InvalidDataTypeException
440
+	 * @throws InvalidInterfaceException
441
+	 * @throws ReflectionException
442
+	 */
443
+	public function hash_salt_()
444
+	{
445
+		return $this->get('TXN_hash_salt');
446
+	}
447
+
448
+
449
+	/**
450
+	 * Returns the transaction datetime as either:
451
+	 *            - unix timestamp format ($format = false, $gmt = true)
452
+	 *            - formatted date string including the UTC (timezone) offset ($format = true ($gmt
453
+	 *              has no affect with this option)), this also may include a timezone abbreviation if the
454
+	 *              set timezone in this class differs from what the timezone is on the blog.
455
+	 *            - formatted date string including the UTC (timezone) offset (default).
456
+	 *
457
+	 * @param boolean $format   - whether to return a unix timestamp (default) or formatted date string
458
+	 * @param boolean $gmt      - whether to return a unix timestamp with UTC offset applied (default)
459
+	 *                          or no UTC offset applied
460
+	 * @return string | int
461
+	 * @throws EE_Error
462
+	 * @throws InvalidArgumentException
463
+	 * @throws InvalidDataTypeException
464
+	 * @throws InvalidInterfaceException
465
+	 * @throws ReflectionException
466
+	 */
467
+	public function datetime($format = false, $gmt = false)
468
+	{
469
+		if ($format) {
470
+			return $this->get_pretty('TXN_timestamp');
471
+		}
472
+		if ($gmt) {
473
+			return $this->get_raw('TXN_timestamp');
474
+		}
475
+		return $this->get('TXN_timestamp');
476
+	}
477
+
478
+
479
+	/**
480
+	 * Gets registrations on this transaction
481
+	 *
482
+	 * @param array   $query_params array of query parameters
483
+	 * @param boolean $get_cached   TRUE to retrieve cached registrations or FALSE to pull from the db
484
+	 * @return EE_Base_Class[]|EE_Registration[]
485
+	 * @throws EE_Error
486
+	 * @throws InvalidArgumentException
487
+	 * @throws InvalidDataTypeException
488
+	 * @throws InvalidInterfaceException
489
+	 * @throws ReflectionException
490
+	 */
491
+	public function registrations($query_params = array(), $get_cached = false)
492
+	{
493
+		$query_params = (empty($query_params) || ! is_array($query_params))
494
+			? array(
495
+				'order_by' => array(
496
+					'Event.EVT_name'     => 'ASC',
497
+					'Attendee.ATT_lname' => 'ASC',
498
+					'Attendee.ATT_fname' => 'ASC',
499
+				),
500
+			)
501
+			: $query_params;
502
+		$query_params = $get_cached ? array() : $query_params;
503
+		return $this->get_many_related('Registration', $query_params);
504
+	}
505
+
506
+
507
+	/**
508
+	 * Gets all the attendees for this transaction (handy for use with EE_Attendee's get_registrations_for_event
509
+	 * function for getting attendees and how many registrations they each have for an event)
510
+	 *
511
+	 * @return mixed EE_Attendee[] by default, int if $output is set to 'COUNT'
512
+	 * @throws EE_Error
513
+	 * @throws InvalidArgumentException
514
+	 * @throws InvalidDataTypeException
515
+	 * @throws InvalidInterfaceException
516
+	 * @throws ReflectionException
517
+	 */
518
+	public function attendees()
519
+	{
520
+		return $this->get_many_related('Attendee', array(array('Registration.Transaction.TXN_ID' => $this->ID())));
521
+	}
522
+
523
+
524
+	/**
525
+	 * Gets payments for this transaction. Unlike other such functions, order by 'DESC' by default
526
+	 *
527
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
528
+	 * @return EE_Base_Class[]|EE_Payment[]
529
+	 * @throws EE_Error
530
+	 * @throws InvalidArgumentException
531
+	 * @throws InvalidDataTypeException
532
+	 * @throws InvalidInterfaceException
533
+	 * @throws ReflectionException
534
+	 */
535
+	public function payments($query_params = array())
536
+	{
537
+		return $this->get_many_related('Payment', $query_params);
538
+	}
539
+
540
+
541
+	/**
542
+	 * gets only approved payments for this transaction
543
+	 *
544
+	 * @return EE_Base_Class[]|EE_Payment[]
545
+	 * @throws EE_Error
546
+	 * @throws InvalidArgumentException
547
+	 * @throws ReflectionException
548
+	 * @throws InvalidDataTypeException
549
+	 * @throws InvalidInterfaceException
550
+	 */
551
+	public function approved_payments()
552
+	{
553
+		EE_Registry::instance()->load_model('Payment');
554
+		return $this->get_many_related(
555
+			'Payment',
556
+			array(
557
+				array('STS_ID' => EEM_Payment::status_id_approved),
558
+				'order_by' => array('PAY_timestamp' => 'DESC'),
559
+			)
560
+		);
561
+	}
562
+
563
+
564
+	/**
565
+	 * Gets all payments which have not been approved
566
+	 *
567
+	 * @return EE_Base_Class[]|EEI_Payment[]
568
+	 * @throws EE_Error if a model is misconfigured somehow
569
+	 * @throws InvalidArgumentException
570
+	 * @throws InvalidDataTypeException
571
+	 * @throws InvalidInterfaceException
572
+	 * @throws ReflectionException
573
+	 */
574
+	public function pending_payments()
575
+	{
576
+		return $this->get_many_related(
577
+			'Payment',
578
+			array(
579
+				array(
580
+					'STS_ID' => EEM_Payment::status_id_pending,
581
+				),
582
+				'order_by' => array(
583
+					'PAY_timestamp' => 'DESC',
584
+				),
585
+			)
586
+		);
587
+	}
588
+
589
+
590
+	/**
591
+	 * echoes $this->pretty_status()
592
+	 *
593
+	 * @param bool $show_icons
594
+	 * @throws EE_Error
595
+	 * @throws InvalidArgumentException
596
+	 * @throws InvalidDataTypeException
597
+	 * @throws InvalidInterfaceException
598
+	 * @throws ReflectionException
599
+	 */
600
+	public function e_pretty_status($show_icons = false)
601
+	{
602
+		echo $this->pretty_status($show_icons);
603
+	}
604
+
605
+
606
+	/**
607
+	 * returns a pretty version of the status, good for displaying to users
608
+	 *
609
+	 * @param bool $show_icons
610
+	 * @return string
611
+	 * @throws EE_Error
612
+	 * @throws InvalidArgumentException
613
+	 * @throws InvalidDataTypeException
614
+	 * @throws InvalidInterfaceException
615
+	 * @throws ReflectionException
616
+	 */
617
+	public function pretty_status($show_icons = false)
618
+	{
619
+		$status = EEM_Status::instance()->localized_status(
620
+			array($this->status_ID() => __('unknown', 'event_espresso')),
621
+			false,
622
+			'sentence'
623
+		);
624
+		$icon = '';
625
+		switch ($this->status_ID()) {
626
+			case EEM_Transaction::complete_status_code:
627
+				$icon = $show_icons ? '<span class="dashicons dashicons-yes ee-icon-size-24 green-text"></span>' : '';
628
+				break;
629
+			case EEM_Transaction::incomplete_status_code:
630
+				$icon = $show_icons ? '<span class="dashicons dashicons-marker ee-icon-size-16 lt-blue-text"></span>'
631
+					: '';
632
+				break;
633
+			case EEM_Transaction::abandoned_status_code:
634
+				$icon = $show_icons ? '<span class="dashicons dashicons-marker ee-icon-size-16 red-text"></span>' : '';
635
+				break;
636
+			case EEM_Transaction::failed_status_code:
637
+				$icon = $show_icons ? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>' : '';
638
+				break;
639
+			case EEM_Transaction::overpaid_status_code:
640
+				$icon = $show_icons ? '<span class="dashicons dashicons-plus ee-icon-size-16 orange-text"></span>' : '';
641
+				break;
642
+		}
643
+		return $icon . $status[ $this->status_ID() ];
644
+	}
645
+
646
+
647
+	/**
648
+	 * get Transaction Status
649
+	 *
650
+	 * @return mixed
651
+	 * @throws EE_Error
652
+	 * @throws InvalidArgumentException
653
+	 * @throws InvalidDataTypeException
654
+	 * @throws InvalidInterfaceException
655
+	 * @throws ReflectionException
656
+	 */
657
+	public function status_ID()
658
+	{
659
+		return $this->get('STS_ID');
660
+	}
661
+
662
+
663
+	/**
664
+	 * Returns TRUE or FALSE for whether or not this transaction cost any money
665
+	 *
666
+	 * @return boolean
667
+	 * @throws EE_Error
668
+	 * @throws InvalidArgumentException
669
+	 * @throws InvalidDataTypeException
670
+	 * @throws InvalidInterfaceException
671
+	 * @throws ReflectionException
672
+	 */
673
+	public function is_free()
674
+	{
675
+		return EEH_Money::compare_floats($this->get('TXN_total'), 0, '==');
676
+	}
677
+
678
+
679
+	/**
680
+	 * Returns whether this transaction is complete
681
+	 * Useful in templates and other logic for deciding if we should ask for another payment...
682
+	 *
683
+	 * @return boolean
684
+	 * @throws EE_Error
685
+	 * @throws InvalidArgumentException
686
+	 * @throws InvalidDataTypeException
687
+	 * @throws InvalidInterfaceException
688
+	 * @throws ReflectionException
689
+	 */
690
+	public function is_completed()
691
+	{
692
+		return $this->status_ID() === EEM_Transaction::complete_status_code;
693
+	}
694
+
695
+
696
+	/**
697
+	 * Returns whether this transaction is incomplete
698
+	 * Useful in templates and other logic for deciding if we should ask for another payment...
699
+	 *
700
+	 * @return boolean
701
+	 * @throws EE_Error
702
+	 * @throws InvalidArgumentException
703
+	 * @throws InvalidDataTypeException
704
+	 * @throws InvalidInterfaceException
705
+	 * @throws ReflectionException
706
+	 */
707
+	public function is_incomplete()
708
+	{
709
+		return $this->status_ID() === EEM_Transaction::incomplete_status_code;
710
+	}
711
+
712
+
713
+	/**
714
+	 * Returns whether this transaction is overpaid
715
+	 * Useful in templates and other logic for deciding if monies need to be refunded
716
+	 *
717
+	 * @return boolean
718
+	 * @throws EE_Error
719
+	 * @throws InvalidArgumentException
720
+	 * @throws InvalidDataTypeException
721
+	 * @throws InvalidInterfaceException
722
+	 * @throws ReflectionException
723
+	 */
724
+	public function is_overpaid()
725
+	{
726
+		return $this->status_ID() === EEM_Transaction::overpaid_status_code;
727
+	}
728
+
729
+
730
+	/**
731
+	 * Returns whether this transaction was abandoned
732
+	 * meaning that the transaction/registration process was somehow interrupted and never completed
733
+	 * but that contact information exists for at least one registrant
734
+	 *
735
+	 * @return boolean
736
+	 * @throws EE_Error
737
+	 * @throws InvalidArgumentException
738
+	 * @throws InvalidDataTypeException
739
+	 * @throws InvalidInterfaceException
740
+	 * @throws ReflectionException
741
+	 */
742
+	public function is_abandoned()
743
+	{
744
+		return $this->status_ID() === EEM_Transaction::abandoned_status_code;
745
+	}
746
+
747
+
748
+	/**
749
+	 * Returns whether this transaction failed
750
+	 * meaning that the transaction/registration process was somehow interrupted and never completed
751
+	 * and that NO contact information exists for any registrants
752
+	 *
753
+	 * @return boolean
754
+	 * @throws EE_Error
755
+	 * @throws InvalidArgumentException
756
+	 * @throws InvalidDataTypeException
757
+	 * @throws InvalidInterfaceException
758
+	 * @throws ReflectionException
759
+	 */
760
+	public function failed()
761
+	{
762
+		return $this->status_ID() === EEM_Transaction::failed_status_code;
763
+	}
764
+
765
+
766
+	/**
767
+	 * This returns the url for the invoice of this transaction
768
+	 *
769
+	 * @param string $type 'html' or 'pdf' (default is pdf)
770
+	 * @return string
771
+	 * @throws EE_Error
772
+	 * @throws InvalidArgumentException
773
+	 * @throws InvalidDataTypeException
774
+	 * @throws InvalidInterfaceException
775
+	 * @throws ReflectionException
776
+	 */
777
+	public function invoice_url($type = 'html')
778
+	{
779
+		$REG = $this->primary_registration();
780
+		if (! $REG instanceof EE_Registration) {
781
+			return '';
782
+		}
783
+		return $REG->invoice_url($type);
784
+	}
785
+
786
+
787
+	/**
788
+	 * Gets the primary registration only
789
+	 *
790
+	 * @return EE_Base_Class|EE_Registration
791
+	 * @throws EE_Error
792
+	 * @throws InvalidArgumentException
793
+	 * @throws InvalidDataTypeException
794
+	 * @throws InvalidInterfaceException
795
+	 * @throws ReflectionException
796
+	 */
797
+	public function primary_registration()
798
+	{
799
+		$registrations = (array) $this->get_many_related(
800
+			'Registration',
801
+			array(array('REG_count' => EEM_Registration::PRIMARY_REGISTRANT_COUNT))
802
+		);
803
+		foreach ($registrations as $registration) {
804
+			// valid registration that is NOT cancelled or declined ?
805
+			if (
806
+				$registration instanceof EE_Registration
807
+				&& ! in_array($registration->status_ID(), EEM_Registration::closed_reg_statuses(), true)
808
+			) {
809
+				return $registration;
810
+			}
811
+		}
812
+		// nothing valid found, so just return first thing from array of results
813
+		return reset($registrations);
814
+	}
815
+
816
+
817
+	/**
818
+	 * Gets the URL for viewing the receipt
819
+	 *
820
+	 * @param string $type 'pdf' or 'html' (default is 'html')
821
+	 * @return string
822
+	 * @throws EE_Error
823
+	 * @throws InvalidArgumentException
824
+	 * @throws InvalidDataTypeException
825
+	 * @throws InvalidInterfaceException
826
+	 * @throws ReflectionException
827
+	 */
828
+	public function receipt_url($type = 'html')
829
+	{
830
+		$REG = $this->primary_registration();
831
+		if (! $REG instanceof EE_Registration) {
832
+			return '';
833
+		}
834
+		return $REG->receipt_url($type);
835
+	}
836
+
837
+
838
+	/**
839
+	 * Gets the URL of the thank you page with this registration REG_url_link added as
840
+	 * a query parameter
841
+	 *
842
+	 * @return string
843
+	 * @throws EE_Error
844
+	 * @throws InvalidArgumentException
845
+	 * @throws InvalidDataTypeException
846
+	 * @throws InvalidInterfaceException
847
+	 * @throws ReflectionException
848
+	 */
849
+	public function payment_overview_url()
850
+	{
851
+		$primary_registration = $this->primary_registration();
852
+		return $primary_registration instanceof EE_Registration ? $primary_registration->payment_overview_url() : false;
853
+	}
854
+
855
+
856
+	/**
857
+	 * @return string
858
+	 * @throws EE_Error
859
+	 * @throws InvalidArgumentException
860
+	 * @throws InvalidDataTypeException
861
+	 * @throws InvalidInterfaceException
862
+	 * @throws ReflectionException
863
+	 */
864
+	public function gateway_response_on_transaction()
865
+	{
866
+		$payment = $this->get_first_related('Payment');
867
+		return $payment instanceof EE_Payment ? $payment->gateway_response() : '';
868
+	}
869
+
870
+
871
+	/**
872
+	 * Get the status object of this object
873
+	 *
874
+	 * @return EE_Base_Class|EE_Status
875
+	 * @throws EE_Error
876
+	 * @throws InvalidArgumentException
877
+	 * @throws InvalidDataTypeException
878
+	 * @throws InvalidInterfaceException
879
+	 * @throws ReflectionException
880
+	 */
881
+	public function status_obj()
882
+	{
883
+		return $this->get_first_related('Status');
884
+	}
885
+
886
+
887
+	/**
888
+	 * Gets all the extra meta info on this payment
889
+	 *
890
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
891
+	 * @return EE_Base_Class[]|EE_Extra_Meta
892
+	 * @throws EE_Error
893
+	 * @throws InvalidArgumentException
894
+	 * @throws InvalidDataTypeException
895
+	 * @throws InvalidInterfaceException
896
+	 * @throws ReflectionException
897
+	 */
898
+	public function extra_meta($query_params = array())
899
+	{
900
+		return $this->get_many_related('Extra_Meta', $query_params);
901
+	}
902
+
903
+
904
+	/**
905
+	 * Wrapper for _add_relation_to
906
+	 *
907
+	 * @param EE_Registration $registration
908
+	 * @return EE_Base_Class the relation was added to
909
+	 * @throws EE_Error
910
+	 * @throws InvalidArgumentException
911
+	 * @throws InvalidDataTypeException
912
+	 * @throws InvalidInterfaceException
913
+	 * @throws ReflectionException
914
+	 */
915
+	public function add_registration(EE_Registration $registration)
916
+	{
917
+		return $this->_add_relation_to($registration, 'Registration');
918
+	}
919
+
920
+
921
+	/**
922
+	 * Removes the given registration from being related (even before saving this transaction).
923
+	 * If an ID/index is provided and this transaction isn't saved yet, removes it from list of cached relations
924
+	 *
925
+	 * @param int $registration_or_id
926
+	 * @return EE_Base_Class that was removed from being related
927
+	 * @throws EE_Error
928
+	 * @throws InvalidArgumentException
929
+	 * @throws InvalidDataTypeException
930
+	 * @throws InvalidInterfaceException
931
+	 * @throws ReflectionException
932
+	 */
933
+	public function remove_registration_with_id($registration_or_id)
934
+	{
935
+		return $this->_remove_relation_to($registration_or_id, 'Registration');
936
+	}
937
+
938
+
939
+	/**
940
+	 * Gets all the line items which are for ACTUAL items
941
+	 *
942
+	 * @return EE_Line_Item[]
943
+	 * @throws EE_Error
944
+	 * @throws InvalidArgumentException
945
+	 * @throws InvalidDataTypeException
946
+	 * @throws InvalidInterfaceException
947
+	 * @throws ReflectionException
948
+	 */
949
+	public function items_purchased()
950
+	{
951
+		return $this->line_items(array(array('LIN_type' => EEM_Line_Item::type_line_item)));
952
+	}
953
+
954
+
955
+	/**
956
+	 * Wrapper for _add_relation_to
957
+	 *
958
+	 * @param EE_Line_Item $line_item
959
+	 * @return EE_Base_Class the relation was added to
960
+	 * @throws EE_Error
961
+	 * @throws InvalidArgumentException
962
+	 * @throws InvalidDataTypeException
963
+	 * @throws InvalidInterfaceException
964
+	 * @throws ReflectionException
965
+	 */
966
+	public function add_line_item(EE_Line_Item $line_item)
967
+	{
968
+		return $this->_add_relation_to($line_item, 'Line_Item');
969
+	}
970
+
971
+
972
+	/**
973
+	 * Gets ALL the line items related to this transaction (unstructured)
974
+	 *
975
+	 * @param array $query_params
976
+	 * @return EE_Base_Class[]|EE_Line_Item[]
977
+	 * @throws EE_Error
978
+	 * @throws InvalidArgumentException
979
+	 * @throws InvalidDataTypeException
980
+	 * @throws InvalidInterfaceException
981
+	 * @throws ReflectionException
982
+	 */
983
+	public function line_items($query_params = array())
984
+	{
985
+		return $this->get_many_related('Line_Item', $query_params);
986
+	}
987
+
988
+
989
+	/**
990
+	 * Gets all the line items which are taxes on the total
991
+	 *
992
+	 * @return EE_Line_Item[]
993
+	 * @throws EE_Error
994
+	 * @throws InvalidArgumentException
995
+	 * @throws InvalidDataTypeException
996
+	 * @throws InvalidInterfaceException
997
+	 * @throws ReflectionException
998
+	 */
999
+	public function tax_items()
1000
+	{
1001
+		return $this->line_items(array(array('LIN_type' => EEM_Line_Item::type_tax)));
1002
+	}
1003
+
1004
+
1005
+	/**
1006
+	 * Gets the total line item (which is a parent of all other related line items,
1007
+	 * meaning it takes them all into account on its total)
1008
+	 *
1009
+	 * @param bool $create_if_not_found
1010
+	 * @return \EE_Line_Item
1011
+	 * @throws EE_Error
1012
+	 * @throws InvalidArgumentException
1013
+	 * @throws InvalidDataTypeException
1014
+	 * @throws InvalidInterfaceException
1015
+	 * @throws ReflectionException
1016
+	 */
1017
+	public function total_line_item($create_if_not_found = true)
1018
+	{
1019
+		$item = $this->get_first_related('Line_Item', array(array('LIN_type' => EEM_Line_Item::type_total)));
1020
+		if (! $item && $create_if_not_found) {
1021
+			$item = EEH_Line_Item::create_total_line_item($this);
1022
+		}
1023
+		return $item;
1024
+	}
1025
+
1026
+
1027
+	/**
1028
+	 * Returns the total amount of tax on this transaction
1029
+	 * (assumes there's only one tax subtotal line item)
1030
+	 *
1031
+	 * @return float
1032
+	 * @throws EE_Error
1033
+	 * @throws InvalidArgumentException
1034
+	 * @throws InvalidDataTypeException
1035
+	 * @throws InvalidInterfaceException
1036
+	 * @throws ReflectionException
1037
+	 */
1038
+	public function tax_total()
1039
+	{
1040
+		$tax_line_item = $this->tax_total_line_item();
1041
+		if ($tax_line_item) {
1042
+			return (float) $tax_line_item->total();
1043
+		}
1044
+		return (float) 0;
1045
+	}
1046
+
1047
+
1048
+	/**
1049
+	 * Gets the tax subtotal line item (assumes there's only one)
1050
+	 *
1051
+	 * @return EE_Line_Item
1052
+	 * @throws EE_Error
1053
+	 * @throws InvalidArgumentException
1054
+	 * @throws InvalidDataTypeException
1055
+	 * @throws InvalidInterfaceException
1056
+	 * @throws ReflectionException
1057
+	 */
1058
+	public function tax_total_line_item()
1059
+	{
1060
+		return EEH_Line_Item::get_taxes_subtotal($this->total_line_item());
1061
+	}
1062
+
1063
+
1064
+	/**
1065
+	 * Gets the array of billing info for the gateway and for this transaction's primary registration's attendee.
1066
+	 *
1067
+	 * @return EE_Form_Section_Proper
1068
+	 * @throws EE_Error
1069
+	 * @throws InvalidArgumentException
1070
+	 * @throws InvalidDataTypeException
1071
+	 * @throws InvalidInterfaceException
1072
+	 * @throws ReflectionException
1073
+	 */
1074
+	public function billing_info()
1075
+	{
1076
+		$payment_method = $this->payment_method();
1077
+		if (! $payment_method) {
1078
+			EE_Error::add_error(
1079
+				__(
1080
+					'Could not find billing info for transaction because no gateway has been used for it yet',
1081
+					'event_espresso'
1082
+				),
1083
+				__FILE__,
1084
+				__FUNCTION__,
1085
+				__LINE__
1086
+			);
1087
+			return null;
1088
+		}
1089
+		$primary_reg = $this->primary_registration();
1090
+		if (! $primary_reg) {
1091
+			EE_Error::add_error(
1092
+				__(
1093
+					'Cannot get billing info for gateway %s on transaction because no primary registration exists',
1094
+					'event_espresso'
1095
+				),
1096
+				__FILE__,
1097
+				__FUNCTION__,
1098
+				__LINE__
1099
+			);
1100
+			return null;
1101
+		}
1102
+		$attendee = $primary_reg->attendee();
1103
+		if (! $attendee) {
1104
+			EE_Error::add_error(
1105
+				__(
1106
+					'Cannot get billing info for gateway %s on transaction because the primary registration has no attendee exists',
1107
+					'event_espresso'
1108
+				),
1109
+				__FILE__,
1110
+				__FUNCTION__,
1111
+				__LINE__
1112
+			);
1113
+			return null;
1114
+		}
1115
+		return $attendee->billing_info_for_payment_method($payment_method);
1116
+	}
1117
+
1118
+
1119
+	/**
1120
+	 * Gets PMD_ID
1121
+	 *
1122
+	 * @return int
1123
+	 * @throws EE_Error
1124
+	 * @throws InvalidArgumentException
1125
+	 * @throws InvalidDataTypeException
1126
+	 * @throws InvalidInterfaceException
1127
+	 * @throws ReflectionException
1128
+	 */
1129
+	public function payment_method_ID()
1130
+	{
1131
+		return $this->get('PMD_ID');
1132
+	}
1133
+
1134
+
1135
+	/**
1136
+	 * Sets PMD_ID
1137
+	 *
1138
+	 * @param int $PMD_ID
1139
+	 * @throws EE_Error
1140
+	 * @throws InvalidArgumentException
1141
+	 * @throws InvalidDataTypeException
1142
+	 * @throws InvalidInterfaceException
1143
+	 * @throws ReflectionException
1144
+	 */
1145
+	public function set_payment_method_ID($PMD_ID)
1146
+	{
1147
+		$this->set('PMD_ID', $PMD_ID);
1148
+	}
1149
+
1150
+
1151
+	/**
1152
+	 * Gets the last-used payment method on this transaction
1153
+	 * (we COULD just use the last-made payment, but some payment methods, namely
1154
+	 * offline ones, dont' create payments)
1155
+	 *
1156
+	 * @return EE_Payment_Method
1157
+	 * @throws EE_Error
1158
+	 * @throws InvalidArgumentException
1159
+	 * @throws InvalidDataTypeException
1160
+	 * @throws InvalidInterfaceException
1161
+	 * @throws ReflectionException
1162
+	 */
1163
+	public function payment_method()
1164
+	{
1165
+		$pm = $this->get_first_related('Payment_Method');
1166
+		if ($pm instanceof EE_Payment_Method) {
1167
+			return $pm;
1168
+		}
1169
+		$last_payment = $this->last_payment();
1170
+		if ($last_payment instanceof EE_Payment && $last_payment->payment_method()) {
1171
+			return $last_payment->payment_method();
1172
+		}
1173
+		return null;
1174
+	}
1175
+
1176
+
1177
+	/**
1178
+	 * Gets the last payment made
1179
+	 *
1180
+	 * @return EE_Base_Class|EE_Payment
1181
+	 * @throws EE_Error
1182
+	 * @throws InvalidArgumentException
1183
+	 * @throws InvalidDataTypeException
1184
+	 * @throws InvalidInterfaceException
1185
+	 * @throws ReflectionException
1186
+	 */
1187
+	public function last_payment()
1188
+	{
1189
+		return $this->get_first_related('Payment', array('order_by' => array('PAY_ID' => 'desc')));
1190
+	}
1191
+
1192
+
1193
+	/**
1194
+	 * Gets all the line items which are unrelated to tickets on this transaction
1195
+	 *
1196
+	 * @return EE_Line_Item[]
1197
+	 * @throws EE_Error
1198
+	 * @throws InvalidArgumentException
1199
+	 * @throws InvalidDataTypeException
1200
+	 * @throws InvalidInterfaceException
1201
+	 * @throws ReflectionException
1202
+	 */
1203
+	public function non_ticket_line_items()
1204
+	{
1205
+		return EEM_Line_Item::instance()->get_all_non_ticket_line_items_for_transaction($this->ID());
1206
+	}
1207
+
1208
+
1209
+	/**
1210
+	 * possibly toggles TXN status
1211
+	 *
1212
+	 * @param  boolean $update whether to save the TXN
1213
+	 * @return bool whether the TXN was saved
1214
+	 * @throws EE_Error
1215
+	 * @throws InvalidArgumentException
1216
+	 * @throws InvalidDataTypeException
1217
+	 * @throws InvalidInterfaceException
1218
+	 * @throws ReflectionException
1219
+	 * @throws RuntimeException
1220
+	 */
1221
+	public function update_status_based_on_total_paid($update = true)
1222
+	{
1223
+		// set transaction status based on comparison of TXN_paid vs TXN_total
1224
+		if (EEH_Money::compare_floats($this->paid(), $this->total(), '>')) {
1225
+			$new_txn_status = EEM_Transaction::overpaid_status_code;
1226
+		} elseif (EEH_Money::compare_floats($this->paid(), $this->total())) {
1227
+			$new_txn_status = EEM_Transaction::complete_status_code;
1228
+		} elseif (EEH_Money::compare_floats($this->paid(), $this->total(), '<')) {
1229
+			$new_txn_status = EEM_Transaction::incomplete_status_code;
1230
+		} else {
1231
+			throw new RuntimeException(
1232
+				__('The total paid calculation for this transaction is inaccurate.', 'event_espresso')
1233
+			);
1234
+		}
1235
+		if ($new_txn_status !== $this->status_ID()) {
1236
+			$this->set_status($new_txn_status);
1237
+			if ($update) {
1238
+				return $this->save() ? true : false;
1239
+			}
1240
+		}
1241
+		return false;
1242
+	}
1243
+
1244
+
1245
+	/**
1246
+	 * Updates the transaction's status and total_paid based on all the payments
1247
+	 * that apply to it
1248
+	 *
1249
+	 * @deprecated
1250
+	 * @return array|bool
1251
+	 * @throws EE_Error
1252
+	 * @throws InvalidArgumentException
1253
+	 * @throws ReflectionException
1254
+	 * @throws InvalidDataTypeException
1255
+	 * @throws InvalidInterfaceException
1256
+	 */
1257
+	public function update_based_on_payments()
1258
+	{
1259
+		EE_Error::doing_it_wrong(
1260
+			__CLASS__ . '::' . __FUNCTION__,
1261
+			sprintf(
1262
+				__('This method is deprecated. Please use "%s" instead', 'event_espresso'),
1263
+				'EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()'
1264
+			),
1265
+			'4.6.0'
1266
+		);
1267
+		/** @type EE_Transaction_Processor $transaction_processor */
1268
+		$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
1269
+		return $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment($this);
1270
+	}
1271
+
1272
+
1273
+	/**
1274
+	 * @return string
1275
+	 */
1276
+	public function old_txn_status()
1277
+	{
1278
+		return $this->_old_txn_status;
1279
+	}
1280
+
1281
+
1282
+	/**
1283
+	 * @param string $old_txn_status
1284
+	 */
1285
+	public function set_old_txn_status($old_txn_status)
1286
+	{
1287
+		// only set the first time
1288
+		if ($this->_old_txn_status === null) {
1289
+			$this->_old_txn_status = $old_txn_status;
1290
+		}
1291
+	}
1292
+
1293
+
1294
+	/**
1295
+	 * reg_status_updated
1296
+	 *
1297
+	 * @return bool
1298
+	 * @throws EE_Error
1299
+	 * @throws InvalidArgumentException
1300
+	 * @throws InvalidDataTypeException
1301
+	 * @throws InvalidInterfaceException
1302
+	 * @throws ReflectionException
1303
+	 */
1304
+	public function txn_status_updated()
1305
+	{
1306
+		return $this->status_ID() !== $this->_old_txn_status && $this->_old_txn_status !== null;
1307
+	}
1308
+
1309
+
1310
+	/**
1311
+	 * _reg_steps_completed
1312
+	 * if $check_all is TRUE, then returns TRUE if ALL reg steps have been marked as completed,
1313
+	 * if a $reg_step_slug is provided, then this step will be skipped when testing for completion
1314
+	 * if $check_all is FALSE and a $reg_step_slug is provided, then ONLY that reg step will be tested for completion
1315
+	 *
1316
+	 * @param string $reg_step_slug
1317
+	 * @param bool   $check_all
1318
+	 * @return bool|int
1319
+	 * @throws EE_Error
1320
+	 * @throws InvalidArgumentException
1321
+	 * @throws InvalidDataTypeException
1322
+	 * @throws InvalidInterfaceException
1323
+	 * @throws ReflectionException
1324
+	 */
1325
+	private function _reg_steps_completed($reg_step_slug = '', $check_all = true)
1326
+	{
1327
+		$reg_steps = $this->reg_steps();
1328
+		if (! is_array($reg_steps) || empty($reg_steps)) {
1329
+			return false;
1330
+		}
1331
+		// loop thru reg steps array)
1332
+		foreach ($reg_steps as $slug => $reg_step_completed) {
1333
+			// if NOT checking ALL steps (only checking one step)
1334
+			if (! $check_all) {
1335
+				// and this is the one
1336
+				if ($slug === $reg_step_slug) {
1337
+					return $reg_step_completed;
1338
+				}
1339
+				// skip to next reg step in loop
1340
+				continue;
1341
+			}
1342
+			// $check_all must be true, else we would never have gotten to this point
1343
+			if ($slug === $reg_step_slug) {
1344
+				// if we reach this point, then we are testing either:
1345
+				// all_reg_steps_completed_except() or
1346
+				// all_reg_steps_completed_except_final_step(),
1347
+				// and since this is the reg step EXCEPTION being tested
1348
+				// we want to return true (yes true) if this reg step is NOT completed
1349
+				// ie: "is everything completed except the final step?"
1350
+				// "that is correct... the final step is not completed, but all others are."
1351
+				return $reg_step_completed !== true;
1352
+			}
1353
+			if ($reg_step_completed !== true) {
1354
+				// if any reg step is NOT completed, then ALL steps are not completed
1355
+				return false;
1356
+			}
1357
+		}
1358
+		return true;
1359
+	}
1360
+
1361
+
1362
+	/**
1363
+	 * all_reg_steps_completed
1364
+	 * returns:
1365
+	 *    true if ALL reg steps have been marked as completed
1366
+	 *        or false if any step is not completed
1367
+	 *
1368
+	 * @return bool
1369
+	 * @throws EE_Error
1370
+	 * @throws InvalidArgumentException
1371
+	 * @throws InvalidDataTypeException
1372
+	 * @throws InvalidInterfaceException
1373
+	 * @throws ReflectionException
1374
+	 */
1375
+	public function all_reg_steps_completed()
1376
+	{
1377
+		return $this->_reg_steps_completed();
1378
+	}
1379
+
1380
+
1381
+	/**
1382
+	 * all_reg_steps_completed_except
1383
+	 * returns:
1384
+	 *        true if ALL reg steps, except a particular step that you wish to skip over, have been marked as completed
1385
+	 *        or false if any other step is not completed
1386
+	 *        or false if ALL steps are completed including the exception you are testing !!!
1387
+	 *
1388
+	 * @param string $exception
1389
+	 * @return bool
1390
+	 * @throws EE_Error
1391
+	 * @throws InvalidArgumentException
1392
+	 * @throws InvalidDataTypeException
1393
+	 * @throws InvalidInterfaceException
1394
+	 * @throws ReflectionException
1395
+	 */
1396
+	public function all_reg_steps_completed_except($exception = '')
1397
+	{
1398
+		return $this->_reg_steps_completed($exception);
1399
+	}
1400
+
1401
+
1402
+	/**
1403
+	 * all_reg_steps_completed_except
1404
+	 * returns:
1405
+	 *        true if ALL reg steps, except the final step, have been marked as completed
1406
+	 *        or false if any step is not completed
1407
+	 *    or false if ALL steps are completed including the final step !!!
1408
+	 *
1409
+	 * @return bool
1410
+	 * @throws EE_Error
1411
+	 * @throws InvalidArgumentException
1412
+	 * @throws InvalidDataTypeException
1413
+	 * @throws InvalidInterfaceException
1414
+	 * @throws ReflectionException
1415
+	 */
1416
+	public function all_reg_steps_completed_except_final_step()
1417
+	{
1418
+		return $this->_reg_steps_completed('finalize_registration');
1419
+	}
1420
+
1421
+
1422
+	/**
1423
+	 * reg_step_completed
1424
+	 * returns:
1425
+	 *    true if a specific reg step has been marked as completed
1426
+	 *    a Unix timestamp if it has been initialized but not yet completed,
1427
+	 *    or false if it has not yet been initialized
1428
+	 *
1429
+	 * @param string $reg_step_slug
1430
+	 * @return bool|int
1431
+	 * @throws EE_Error
1432
+	 * @throws InvalidArgumentException
1433
+	 * @throws InvalidDataTypeException
1434
+	 * @throws InvalidInterfaceException
1435
+	 * @throws ReflectionException
1436
+	 */
1437
+	public function reg_step_completed($reg_step_slug)
1438
+	{
1439
+		return $this->_reg_steps_completed($reg_step_slug, false);
1440
+	}
1441
+
1442
+
1443
+	/**
1444
+	 * completed_final_reg_step
1445
+	 * returns:
1446
+	 *    true if the finalize_registration reg step has been marked as completed
1447
+	 *    a Unix timestamp if it has been initialized but not yet completed,
1448
+	 *    or false if it has not yet been initialized
1449
+	 *
1450
+	 * @return bool|int
1451
+	 * @throws EE_Error
1452
+	 * @throws InvalidArgumentException
1453
+	 * @throws InvalidDataTypeException
1454
+	 * @throws InvalidInterfaceException
1455
+	 * @throws ReflectionException
1456
+	 */
1457
+	public function final_reg_step_completed()
1458
+	{
1459
+		return $this->_reg_steps_completed('finalize_registration', false);
1460
+	}
1461
+
1462
+
1463
+	/**
1464
+	 * set_reg_step_initiated
1465
+	 * given a valid TXN_reg_step, this sets it's value to a unix timestamp
1466
+	 *
1467
+	 * @param string $reg_step_slug
1468
+	 * @return boolean
1469
+	 * @throws EE_Error
1470
+	 * @throws InvalidArgumentException
1471
+	 * @throws InvalidDataTypeException
1472
+	 * @throws InvalidInterfaceException
1473
+	 * @throws ReflectionException
1474
+	 */
1475
+	public function set_reg_step_initiated($reg_step_slug)
1476
+	{
1477
+		return $this->_set_reg_step_completed_status($reg_step_slug, time());
1478
+	}
1479
+
1480
+
1481
+	/**
1482
+	 * set_reg_step_completed
1483
+	 * given a valid TXN_reg_step, this sets the step as completed
1484
+	 *
1485
+	 * @param string $reg_step_slug
1486
+	 * @return boolean
1487
+	 * @throws EE_Error
1488
+	 * @throws InvalidArgumentException
1489
+	 * @throws InvalidDataTypeException
1490
+	 * @throws InvalidInterfaceException
1491
+	 * @throws ReflectionException
1492
+	 */
1493
+	public function set_reg_step_completed($reg_step_slug)
1494
+	{
1495
+		return $this->_set_reg_step_completed_status($reg_step_slug, true);
1496
+	}
1497
+
1498
+
1499
+	/**
1500
+	 * set_reg_step_completed
1501
+	 * given a valid TXN_reg_step slug, this sets the step as NOT completed
1502
+	 *
1503
+	 * @param string $reg_step_slug
1504
+	 * @return boolean
1505
+	 * @throws EE_Error
1506
+	 * @throws InvalidArgumentException
1507
+	 * @throws InvalidDataTypeException
1508
+	 * @throws InvalidInterfaceException
1509
+	 * @throws ReflectionException
1510
+	 */
1511
+	public function set_reg_step_not_completed($reg_step_slug)
1512
+	{
1513
+		return $this->_set_reg_step_completed_status($reg_step_slug, false);
1514
+	}
1515
+
1516
+
1517
+	/**
1518
+	 * set_reg_step_completed
1519
+	 * given a valid reg step slug, this sets the TXN_reg_step completed status which is either:
1520
+	 *
1521
+	 * @param  string      $reg_step_slug
1522
+	 * @param  boolean|int $status
1523
+	 * @return boolean
1524
+	 * @throws EE_Error
1525
+	 * @throws InvalidArgumentException
1526
+	 * @throws InvalidDataTypeException
1527
+	 * @throws InvalidInterfaceException
1528
+	 * @throws ReflectionException
1529
+	 */
1530
+	private function _set_reg_step_completed_status($reg_step_slug, $status)
1531
+	{
1532
+		// validate status
1533
+		$status = is_bool($status) || is_int($status) ? $status : false;
1534
+		// get reg steps array
1535
+		$txn_reg_steps = $this->reg_steps();
1536
+		// if reg step does NOT exist
1537
+		if (! isset($txn_reg_steps[ $reg_step_slug ])) {
1538
+			return false;
1539
+		}
1540
+		// if  we're trying to complete a step that is already completed
1541
+		if ($txn_reg_steps[ $reg_step_slug ] === true) {
1542
+			return true;
1543
+		}
1544
+		// if  we're trying to complete a step that hasn't even started
1545
+		if ($status === true && $txn_reg_steps[ $reg_step_slug ] === false) {
1546
+			return false;
1547
+		}
1548
+		// if current status value matches the incoming value (no change)
1549
+		// type casting as int means values should collapse to either 0, 1, or a timestamp like 1234567890
1550
+		if ((int) $txn_reg_steps[ $reg_step_slug ] === (int) $status) {
1551
+			// this will happen in cases where multiple AJAX requests occur during the same step
1552
+			return true;
1553
+		}
1554
+		// if we're trying to set a start time, but it has already been set...
1555
+		if (is_numeric($status) && is_numeric($txn_reg_steps[ $reg_step_slug ])) {
1556
+			// skip the update below, but don't return FALSE so that errors won't be displayed
1557
+			return true;
1558
+		}
1559
+		// update completed status
1560
+		$txn_reg_steps[ $reg_step_slug ] = $status;
1561
+		$this->set_reg_steps($txn_reg_steps);
1562
+		$this->save();
1563
+		return true;
1564
+	}
1565
+
1566
+
1567
+	/**
1568
+	 * remove_reg_step
1569
+	 * given a valid TXN_reg_step slug, this will remove (unset)
1570
+	 * the reg step from the TXN reg step array
1571
+	 *
1572
+	 * @param string $reg_step_slug
1573
+	 * @return void
1574
+	 * @throws EE_Error
1575
+	 * @throws InvalidArgumentException
1576
+	 * @throws InvalidDataTypeException
1577
+	 * @throws InvalidInterfaceException
1578
+	 * @throws ReflectionException
1579
+	 */
1580
+	public function remove_reg_step($reg_step_slug)
1581
+	{
1582
+		// get reg steps array
1583
+		$txn_reg_steps = $this->reg_steps();
1584
+		unset($txn_reg_steps[ $reg_step_slug ]);
1585
+		$this->set_reg_steps($txn_reg_steps);
1586
+	}
1587
+
1588
+
1589
+	/**
1590
+	 * toggle_failed_transaction_status
1591
+	 * upgrades a TXNs status from failed to abandoned,
1592
+	 * meaning that contact information has been captured for at least one registrant
1593
+	 *
1594
+	 * @param bool $save
1595
+	 * @return bool
1596
+	 * @throws EE_Error
1597
+	 * @throws InvalidArgumentException
1598
+	 * @throws InvalidDataTypeException
1599
+	 * @throws InvalidInterfaceException
1600
+	 * @throws ReflectionException
1601
+	 */
1602
+	public function toggle_failed_transaction_status($save = true)
1603
+	{
1604
+		// if TXN status is still set as "failed"...
1605
+		if ($this->status_ID() === EEM_Transaction::failed_status_code) {
1606
+			$this->set_status(EEM_Transaction::abandoned_status_code);
1607
+			if ($save) {
1608
+				$this->save();
1609
+			}
1610
+			return true;
1611
+		}
1612
+		return false;
1613
+	}
1614
+
1615
+
1616
+	/**
1617
+	 * toggle_abandoned_transaction_status
1618
+	 * upgrades a TXNs status from failed or abandoned to incomplete
1619
+	 *
1620
+	 * @return bool
1621
+	 * @throws EE_Error
1622
+	 * @throws InvalidArgumentException
1623
+	 * @throws InvalidDataTypeException
1624
+	 * @throws InvalidInterfaceException
1625
+	 * @throws ReflectionException
1626
+	 */
1627
+	public function toggle_abandoned_transaction_status()
1628
+	{
1629
+		// if TXN status has not been updated already due to a payment, and is still set as "failed" or "abandoned"...
1630
+		$txn_status = $this->status_ID();
1631
+		if (
1632
+			$txn_status === EEM_Transaction::failed_status_code
1633
+			|| $txn_status === EEM_Transaction::abandoned_status_code
1634
+		) {
1635
+			// if a contact record for the primary registrant has been created
1636
+			if (
1637
+				$this->primary_registration() instanceof EE_Registration
1638
+				&& $this->primary_registration()->attendee() instanceof EE_Attendee
1639
+			) {
1640
+				$this->set_status(EEM_Transaction::incomplete_status_code);
1641
+			} else {
1642
+				// no contact record? yer abandoned!
1643
+				$this->set_status(EEM_Transaction::abandoned_status_code);
1644
+			}
1645
+			return true;
1646
+		}
1647
+		return false;
1648
+	}
1649
+
1650
+
1651
+	/**
1652
+	 * checks if an Abandoned TXN has any related payments, and if so,
1653
+	 * updates the TXN status based on the amount paid
1654
+	 *
1655
+	 * @throws EE_Error
1656
+	 * @throws InvalidDataTypeException
1657
+	 * @throws InvalidInterfaceException
1658
+	 * @throws InvalidArgumentException
1659
+	 * @throws RuntimeException
1660
+	 * @throws ReflectionException
1661
+	 */
1662
+	public function verify_abandoned_transaction_status()
1663
+	{
1664
+		if ($this->status_ID() !== EEM_Transaction::abandoned_status_code) {
1665
+			return;
1666
+		}
1667
+		$payments = $this->get_many_related('Payment');
1668
+		if (! empty($payments)) {
1669
+			foreach ($payments as $payment) {
1670
+				if ($payment instanceof EE_Payment) {
1671
+					// kk this TXN should NOT be abandoned
1672
+					$this->update_status_based_on_total_paid();
1673
+					if (! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) {
1674
+						EE_Error::add_attention(
1675
+							sprintf(
1676
+								esc_html__(
1677
+									'The status for Transaction #%1$d has been updated from "Abandoned" to "%2$s", because at least one payment has been made towards it. If the payment appears in the "Payment Details" table below, you may need to edit its status and/or other details as well.',
1678
+									'event_espresso'
1679
+								),
1680
+								$this->ID(),
1681
+								$this->pretty_status()
1682
+							)
1683
+						);
1684
+					}
1685
+					// get final reg step status
1686
+					$finalized = $this->final_reg_step_completed();
1687
+					// if the 'finalize_registration' step has been initiated (has a timestamp)
1688
+					// but has not yet been fully completed (TRUE)
1689
+					if (is_int($finalized) && $finalized !== false && $finalized !== true) {
1690
+						$this->set_reg_step_completed('finalize_registration');
1691
+						$this->save();
1692
+					}
1693
+				}
1694
+			}
1695
+		}
1696
+	}
1697
+
1698
+
1699
+	/**
1700
+	 * @since 4.10.4.p
1701
+	 * @throws EE_Error
1702
+	 * @throws InvalidArgumentException
1703
+	 * @throws InvalidDataTypeException
1704
+	 * @throws InvalidInterfaceException
1705
+	 * @throws ReflectionException
1706
+	 * @throws RuntimeException
1707
+	 */
1708
+	public function recalculateLineItems()
1709
+	{
1710
+		$total_line_item = $this->total_line_item(false);
1711
+		if ($total_line_item instanceof EE_Line_Item) {
1712
+			EEH_Line_Item::resetIsTaxableForTickets($total_line_item);
1713
+			return EEH_Line_Item::apply_taxes($total_line_item, true);
1714
+		}
1715
+		return false;
1716
+	}
1717 1717
 }
Please login to merge, or discard this patch.
core/db_classes/EE_Question.class.php 1 patch
Indentation   +664 added lines, -664 removed lines patch added patch discarded remove patch
@@ -14,668 +14,668 @@
 block discarded – undo
14 14
 class EE_Question extends EE_Soft_Delete_Base_Class implements EEI_Duplicatable
15 15
 {
16 16
 
17
-    /**
18
-     *
19
-     * @param array  $props_n_values          incoming values
20
-     * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
21
-     *                                        used.)
22
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
23
-     *                                        date_format and the second value is the time format
24
-     * @return EE_Question
25
-     */
26
-    public static function new_instance($props_n_values = array(), $timezone = '', $date_formats = array())
27
-    {
28
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
29
-        return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
30
-    }
31
-
32
-
33
-    /**
34
-     * @param array  $props_n_values  incoming values from the database
35
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
36
-     *                                the website will be used.
37
-     * @return EE_Question
38
-     */
39
-    public static function new_instance_from_db($props_n_values = array(), $timezone = '')
40
-    {
41
-        return new self($props_n_values, true, $timezone);
42
-    }
43
-
44
-
45
-    /**
46
-     *        Set    Question display text
47
-     *
48
-     * @access        public
49
-     * @param string $QST_display_text
50
-     */
51
-    public function set_display_text($QST_display_text = '')
52
-    {
53
-        $this->set('QST_display_text', $QST_display_text);
54
-    }
55
-
56
-
57
-    /**
58
-     *        Set    Question admin text
59
-     *
60
-     * @access        public
61
-     * @param        string $QST_admin_label
62
-     */
63
-    public function set_admin_label($QST_admin_label = '')
64
-    {
65
-        $this->set('QST_admin_label', $QST_admin_label);
66
-    }
67
-
68
-
69
-    /**
70
-     *        Set    system name
71
-     *
72
-     * @access        public
73
-     * @param        mixed $QST_system
74
-     */
75
-    public function set_system_ID($QST_system = '')
76
-    {
77
-        $this->set('QST_system', $QST_system);
78
-    }
79
-
80
-
81
-    /**
82
-     *        Set    question's type
83
-     *
84
-     * @access        public
85
-     * @param        string $QST_type
86
-     */
87
-    public function set_question_type($QST_type = '')
88
-    {
89
-        $this->set('QST_type', $QST_type);
90
-    }
91
-
92
-
93
-    /**
94
-     *        Sets whether this question must be answered when presented in a form
95
-     *
96
-     * @access        public
97
-     * @param        bool $QST_required
98
-     */
99
-    public function set_required($QST_required = false)
100
-    {
101
-        $this->set('QST_required', $QST_required);
102
-    }
103
-
104
-
105
-    /**
106
-     *        Set    Question display text
107
-     *
108
-     * @access        public
109
-     * @param        string $QST_required_text
110
-     */
111
-    public function set_required_text($QST_required_text = '')
112
-    {
113
-        $this->set('QST_required_text', $QST_required_text);
114
-    }
115
-
116
-
117
-    /**
118
-     *        Sets the order of this question when placed in a sequence of questions
119
-     *
120
-     * @access        public
121
-     * @param        int $QST_order
122
-     */
123
-    public function set_order($QST_order = 0)
124
-    {
125
-        $this->set('QST_order', $QST_order);
126
-    }
127
-
128
-
129
-    /**
130
-     *        Sets whether the question is admin-only
131
-     *
132
-     * @access        public
133
-     * @param        bool $QST_admin_only
134
-     */
135
-    public function set_admin_only($QST_admin_only = false)
136
-    {
137
-        $this->set('QST_admin_only', $QST_admin_only);
138
-    }
139
-
140
-
141
-    /**
142
-     *        Sets the wordpress user ID on the question
143
-     *
144
-     * @access        public
145
-     * @param        int $QST_wp_user
146
-     */
147
-    public function set_wp_user($QST_wp_user = 1)
148
-    {
149
-        $this->set('QST_wp_user', $QST_wp_user);
150
-    }
151
-
152
-
153
-    /**
154
-     *        Sets whether the question has been deleted
155
-     *        (we use this boolean instead of actually
156
-     *        deleting it because when users delete this question
157
-     *        they really want to remove the question from future
158
-     *        forms, BUT keep their old answers which depend
159
-     *        on this record actually existing.
160
-     *
161
-     * @access        public
162
-     * @param    bool $QST_deleted
163
-     */
164
-    public function set_deleted($QST_deleted = false)
165
-    {
166
-        $this->set('QST_deleted', $QST_deleted);
167
-    }
168
-
169
-
170
-    /**
171
-     * returns the text for displaying the question to users
172
-     *
173
-     * @access public
174
-     * @return string
175
-     */
176
-    public function display_text()
177
-    {
178
-        return $this->get('QST_display_text');
179
-    }
180
-
181
-
182
-    /**
183
-     * returns the text for the administrative label
184
-     *
185
-     * @access public
186
-     * @return string
187
-     */
188
-    public function admin_label()
189
-    {
190
-        return $this->get('QST_admin_label');
191
-    }
192
-
193
-
194
-    /**
195
-     * returns the attendee column name for this question
196
-     *
197
-     * @access public
198
-     * @return string
199
-     */
200
-    public function system_ID()
201
-    {
202
-        return $this->get('QST_system');
203
-    }
204
-
205
-
206
-    /**
207
-     * returns either a string of 'text', 'textfield', etc.
208
-     *
209
-     * @access public
210
-     * @return boolean
211
-     */
212
-    public function required()
213
-    {
214
-        return $this->get('QST_required');
215
-    }
216
-
217
-
218
-    /**
219
-     * returns the text which should be displayed when a user
220
-     * doesn't answer this question in a form
221
-     *
222
-     * @access public
223
-     * @return string
224
-     */
225
-    public function required_text()
226
-    {
227
-        return $this->get('QST_required_text');
228
-    }
229
-
230
-
231
-    /**
232
-     * returns the type of this question
233
-     *
234
-     * @access public
235
-     * @return string
236
-     */
237
-    public function type()
238
-    {
239
-        return $this->get('QST_type');
240
-    }
241
-
242
-
243
-    /**
244
-     * returns an integer showing where this question should
245
-     * be placed in a sequence of questions
246
-     *
247
-     * @access public
248
-     * @return int
249
-     */
250
-    public function order()
251
-    {
252
-        return $this->get('QST_order');
253
-    }
254
-
255
-
256
-    /**
257
-     * returns whether this question should only appears to admins,
258
-     * or to everyone
259
-     *
260
-     * @access public
261
-     * @return boolean
262
-     */
263
-    public function admin_only()
264
-    {
265
-        return $this->get('QST_admin_only');
266
-    }
267
-
268
-
269
-    /**
270
-     * returns the id the wordpress user who created this question
271
-     *
272
-     * @access public
273
-     * @return int
274
-     */
275
-    public function wp_user()
276
-    {
277
-        return $this->get('QST_wp_user');
278
-    }
279
-
280
-
281
-    /**
282
-     * returns whether this question has been marked as 'deleted'
283
-     *
284
-     * @access public
285
-     * @return boolean
286
-     */
287
-    public function deleted()
288
-    {
289
-        return $this->get('QST_deleted');
290
-    }
291
-
292
-
293
-    /**
294
-     * Gets an array of related EE_Answer  to this EE_Question
295
-     *
296
-     * @return EE_Answer[]
297
-     */
298
-    public function answers()
299
-    {
300
-        return $this->get_many_related('Answer');
301
-    }
302
-
303
-
304
-    /**
305
-     * Boolean check for if there are answers on this question in th db
306
-     *
307
-     * @return boolean true = has answers, false = no answers.
308
-     */
309
-    public function has_answers()
310
-    {
311
-        return $this->count_related('Answer') > 0 ? true : false;
312
-    }
313
-
314
-
315
-    /**
316
-     * gets an array of EE_Question_Group which relate to this question
317
-     *
318
-     * @return EE_Question_Group[]
319
-     */
320
-    public function question_groups()
321
-    {
322
-        return $this->get_many_related('Question_Group');
323
-    }
324
-
325
-
326
-    /**
327
-     * Returns all the options for this question. By default, it returns only the not-yet-deleted ones.
328
-     *
329
-     * @param boolean      $notDeletedOptionsOnly            1
330
-     *                                                       whether to return ALL options, or only the ones which have
331
-     *                                                       not yet been deleleted
332
-     * @param string|array $selected_value_to_always_include , when retrieving options to an ANSWERED question,
333
-     *                                                       we want to usually only show non-deleted options AND the
334
-     *                                                       value that was selected for the answer, whether it was
335
-     *                                                       trashed or not.
336
-     * @return EE_Question_Option[]
337
-     */
338
-    public function options($notDeletedOptionsOnly = true, $selected_value_to_always_include = null)
339
-    {
340
-        if (! $this->ID()) {
341
-            return array();
342
-        }
343
-        $query_params = array();
344
-        if ($selected_value_to_always_include) {
345
-            if (is_array($selected_value_to_always_include)) {
346
-                $query_params[0]['OR*options-query']['QSO_value'] = array('IN', $selected_value_to_always_include);
347
-            } else {
348
-                $query_params[0]['OR*options-query']['QSO_value'] = $selected_value_to_always_include;
349
-            }
350
-        }
351
-        if ($notDeletedOptionsOnly) {
352
-            $query_params[0]['OR*options-query']['QSO_deleted'] = false;
353
-        }
354
-        // order by QSO_order
355
-        $query_params['order_by'] = array('QSO_order' => 'ASC');
356
-        return $this->get_many_related('Question_Option', $query_params);
357
-    }
358
-
359
-
360
-    /**
361
-     * returns an array of EE_Question_Options which relate to this question
362
-     *
363
-     * @return \EE_Question_Option[]
364
-     */
365
-    public function temp_options()
366
-    {
367
-        return $this->_model_relations['Question_Option'];
368
-    }
369
-
370
-
371
-    /**
372
-     * Adds an option for this question. Note: if the option were previously associated with a different
373
-     * Question, that relationship will be overwritten.
374
-     *
375
-     * @param EE_Question_Option $option
376
-     * @return boolean success
377
-     */
378
-    public function add_option(EE_Question_Option $option)
379
-    {
380
-        return $this->_add_relation_to($option, 'Question_Option');
381
-    }
382
-
383
-
384
-    /**
385
-     * Adds an option directly to this question without saving to the db
386
-     *
387
-     * @param EE_Question_Option $option
388
-     * @return boolean success
389
-     */
390
-    public function add_temp_option(EE_Question_Option $option)
391
-    {
392
-        $this->_model_relations['Question_Option'][] = $option;
393
-        return true;
394
-    }
395
-
396
-
397
-    /**
398
-     * Marks the option as deleted.
399
-     *
400
-     * @param EE_Question_Option $option
401
-     * @return boolean success
402
-     */
403
-    public function remove_option(EE_Question_Option $option)
404
-    {
405
-        return $this->_remove_relation_to($option, 'Question_Option');
406
-    }
407
-
408
-
409
-    /**
410
-     * @return bool
411
-     */
412
-    public function is_system_question()
413
-    {
414
-        $system_ID = $this->get('QST_system');
415
-        return ! empty($system_ID) ? true : false;
416
-    }
417
-
418
-
419
-    /**
420
-     * The purpose of this method is set the question order this question order to be the max out of all questions
421
-     *
422
-     * @access public
423
-     * @return void
424
-     */
425
-    public function set_order_to_latest()
426
-    {
427
-        $latest_order = $this->get_model()->get_latest_question_order();
428
-        $latest_order++;
429
-        $this->set('QST_order', $latest_order);
430
-    }
431
-
432
-
433
-    /**
434
-     * Retrieves the list of allowed question types from the model.
435
-     *
436
-     * @return string[]
437
-     */
438
-    private function _allowed_question_types()
439
-    {
440
-        $questionModel = $this->get_model();
441
-        /* @var $questionModel EEM_Question */
442
-        return $questionModel->allowed_question_types();
443
-    }
444
-
445
-    /**
446
-     * Duplicates this question and its question options
447
-     *
448
-     * @return \EE_Question
449
-     */
450
-    public function duplicate($options = array())
451
-    {
452
-        $new_question = clone $this;
453
-        $new_question->set('QST_ID', null);
454
-        $new_question->set_display_text(sprintf(__('%s **Duplicate**', 'event_espresso'), $this->display_text()));
455
-        $new_question->set_admin_label(sprintf(__('%s **Duplicate**', 'event_espresso'), $this->admin_label()));
456
-        $new_question->set_system_ID(null);
457
-        $new_question->set_wp_user(get_current_user_id());
458
-        // if we're duplicating a trashed question, assume we don't want the new one to be trashed
459
-        $new_question->set_deleted(false);
460
-        $success = $new_question->save();
461
-        if ($success) {
462
-            // we don't totally want to duplicate the question options, because we want them to be for the NEW question
463
-            foreach ($this->options() as $question_option) {
464
-                $question_option->duplicate(array('QST_ID' => $new_question->ID()));
465
-            }
466
-            return $new_question;
467
-        } else {
468
-            return null;
469
-        }
470
-    }
471
-
472
-    /**
473
-     * Returns the question's maximum allowed response size
474
-     *
475
-     * @return int|float
476
-     */
477
-    public function max()
478
-    {
479
-        return $this->get('QST_max');
480
-    }
481
-
482
-    /**
483
-     * Sets the question's maximum allowed response size
484
-     *
485
-     * @param int|float $new_max
486
-     * @return void
487
-     */
488
-    public function set_max($new_max)
489
-    {
490
-        $this->set('QST_max', $new_max);
491
-    }
492
-
493
-
494
-    /**
495
-     * Creates a form input from this question which can be used in HTML forms
496
-     *
497
-     * @param EE_Registration $registration
498
-     * @param EE_Answer       $answer
499
-     * @param array           $input_constructor_args
500
-     * @return EE_Form_Input_Base
501
-     */
502
-    public function generate_form_input($registration = null, $answer = null, $input_constructor_args = array())
503
-    {
504
-        $identifier = $this->is_system_question() ? $this->system_ID() : $this->ID();
505
-
506
-        $input_constructor_args = array_merge(
507
-            array(
508
-                'required'                          => $this->required() ? true : false,
509
-                'html_label_text'                   => $this->display_text(),
510
-                'required_validation_error_message' => $this->required_text(),
511
-            ),
512
-            $input_constructor_args
513
-        );
514
-        if (! $answer instanceof EE_Answer && $registration instanceof EE_Registration) {
515
-            $answer = EEM_Answer::instance()->get_registration_question_answer_object($registration, $this->ID());
516
-        }
517
-        // has this question been answered ?
518
-        if (
519
-            $answer instanceof EE_Answer
520
-            && $answer->value() !== ''
521
-        ) {
522
-            // answer gets htmlspecialchars called on it, undo that please
523
-            // because the form input's display strategy may call esc_attr too
524
-            // which also does html special characters
525
-            $values_with_html_special_chars = $answer->value();
526
-            if (is_array($values_with_html_special_chars)) {
527
-                $default_value = array_map('htmlspecialchars_decode', $values_with_html_special_chars);
528
-            } else {
529
-                $default_value = htmlspecialchars_decode($values_with_html_special_chars);
530
-            }
531
-            $input_constructor_args['default'] = $default_value;
532
-        }
533
-        $max_max_for_question = EEM_Question::instance()->absolute_max_for_system_question($this->system_ID());
534
-        if (
535
-            in_array(
536
-                $this->type(),
537
-                EEM_Question::instance()->questionTypesWithMaxLength(),
538
-                true
539
-            )
540
-        ) {
541
-            $input_constructor_args['validation_strategies'][] = new EE_Max_Length_Validation_Strategy(
542
-                null,
543
-                min($max_max_for_question, $this->max())
544
-            );
545
-        }
546
-        $input_constructor_args = apply_filters(
547
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__input_constructor_args',
548
-            $input_constructor_args,
549
-            $registration,
550
-            $this,
551
-            $answer
552
-        );
553
-
554
-        $result = null;
555
-        switch ($this->type()) {
556
-            // Text
557
-            case EEM_Question::QST_type_text:
558
-                $result = new EE_Text_Input($input_constructor_args);
559
-                break;
560
-            // Textarea
561
-            case EEM_Question::QST_type_textarea:
562
-                $result = new EE_Text_Area_Input($input_constructor_args);
563
-                break;
564
-            // Radio Buttons
565
-            case EEM_Question::QST_type_radio:
566
-                $result = new EE_Radio_Button_Input($this->options(), $input_constructor_args);
567
-                break;
568
-            // Dropdown
569
-            case EEM_Question::QST_type_dropdown:
570
-                $result = new EE_Select_Input($this->options(), $input_constructor_args);
571
-                break;
572
-            // State Dropdown
573
-            case EEM_Question::QST_type_state:
574
-                $state_options = apply_filters(
575
-                    'FHEE__EE_Question__generate_form_input__state_options',
576
-                    null,
577
-                    $this,
578
-                    $registration,
579
-                    $answer
580
-                );
581
-                $result = new EE_State_Select_Input($state_options, $input_constructor_args);
582
-                break;
583
-            // Country Dropdown
584
-            case EEM_Question::QST_type_country:
585
-                $country_options = apply_filters(
586
-                    'FHEE__EE_Question__generate_form_input__country_options',
587
-                    null,
588
-                    $this,
589
-                    $registration,
590
-                    $answer
591
-                );
592
-                $result = new EE_Country_Select_Input($country_options, $input_constructor_args);
593
-                break;
594
-            // Checkboxes
595
-            case EEM_Question::QST_type_checkbox:
596
-                $result = new EE_Checkbox_Multi_Input($this->options(), $input_constructor_args);
597
-                break;
598
-            // Date
599
-            case EEM_Question::QST_type_date:
600
-                $result = new EE_Datepicker_Input($input_constructor_args);
601
-                break;
602
-            case EEM_Question::QST_type_html_textarea:
603
-                $input_constructor_args['validation_strategies'][] = new EE_Simple_HTML_Validation_Strategy();
604
-                $result = new EE_Text_Area_Input($input_constructor_args);
605
-                $result->remove_validation_strategy('EE_Plaintext_Validation_Strategy');
606
-                break;
607
-            case EEM_Question::QST_type_email:
608
-                    $result = new EE_Email_Input($input_constructor_args);
609
-                break;
610
-            // Email confirm
611
-            case EEM_Question::QST_type_email_confirm:
612
-                $result = new EE_Email_Confirm_Input($input_constructor_args);
613
-                break;
614
-            case EEM_Question::QST_type_us_phone:
615
-                $result = new EE_Phone_Input($input_constructor_args);
616
-                break;
617
-            case EEM_Question::QST_type_int:
618
-                $result = new EE_Integer_Input($input_constructor_args);
619
-                break;
620
-            case EEM_Question::QST_type_decimal:
621
-                $result = new EE_Float_Input($input_constructor_args);
622
-                break;
623
-            case EEM_Question::QST_type_url:
624
-                $input_constructor_args['validation_strategies'][] = LoaderFactory::getLoader()->getNew('EE_URL_Validation_Strategy');
625
-                $result = new EE_Text_Input($input_constructor_args);
626
-                break;
627
-            case EEM_Question::QST_type_year:
628
-                $result = new EE_Year_Input(
629
-                    $input_constructor_args,
630
-                    apply_filters(
631
-                        'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__year_question__four_digit',
632
-                        true,
633
-                        $this
634
-                    ),
635
-                    apply_filters(
636
-                        'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__year_question__early_range',
637
-                        100,
638
-                        $this
639
-                    ),
640
-                    apply_filters(
641
-                        'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__year_question__end_range',
642
-                        100,
643
-                        $this
644
-                    )
645
-                );
646
-                break;
647
-            case EEM_Question::QST_type_multi_select:
648
-                $result = new EE_Select_Multiple_Input($this->options(), $input_constructor_args);
649
-                break;
650
-            // fallback
651
-            default:
652
-                $default_input = apply_filters(
653
-                    'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__default',
654
-                    null,
655
-                    $this->type(),
656
-                    $this,
657
-                    $input_constructor_args
658
-                );
659
-                if (! $default_input) {
660
-                    $default_input = new EE_Text_Input($input_constructor_args);
661
-                }
662
-                $result = $default_input;
663
-        }
664
-        return apply_filters('FHEE__EE_Question__generate_form_input__return', $result, $registration, $this, $answer);
665
-    }
666
-
667
-
668
-    /**
669
-     * Returns whether or not this question type should have question option entries
670
-     *
671
-     * @return bool
672
-     */
673
-    public function should_have_question_options()
674
-    {
675
-        return in_array(
676
-            $this->type(),
677
-            $this->_model->question_types_with_options(),
678
-            true
679
-        );
680
-    }
17
+	/**
18
+	 *
19
+	 * @param array  $props_n_values          incoming values
20
+	 * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
21
+	 *                                        used.)
22
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
23
+	 *                                        date_format and the second value is the time format
24
+	 * @return EE_Question
25
+	 */
26
+	public static function new_instance($props_n_values = array(), $timezone = '', $date_formats = array())
27
+	{
28
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
29
+		return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
30
+	}
31
+
32
+
33
+	/**
34
+	 * @param array  $props_n_values  incoming values from the database
35
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
36
+	 *                                the website will be used.
37
+	 * @return EE_Question
38
+	 */
39
+	public static function new_instance_from_db($props_n_values = array(), $timezone = '')
40
+	{
41
+		return new self($props_n_values, true, $timezone);
42
+	}
43
+
44
+
45
+	/**
46
+	 *        Set    Question display text
47
+	 *
48
+	 * @access        public
49
+	 * @param string $QST_display_text
50
+	 */
51
+	public function set_display_text($QST_display_text = '')
52
+	{
53
+		$this->set('QST_display_text', $QST_display_text);
54
+	}
55
+
56
+
57
+	/**
58
+	 *        Set    Question admin text
59
+	 *
60
+	 * @access        public
61
+	 * @param        string $QST_admin_label
62
+	 */
63
+	public function set_admin_label($QST_admin_label = '')
64
+	{
65
+		$this->set('QST_admin_label', $QST_admin_label);
66
+	}
67
+
68
+
69
+	/**
70
+	 *        Set    system name
71
+	 *
72
+	 * @access        public
73
+	 * @param        mixed $QST_system
74
+	 */
75
+	public function set_system_ID($QST_system = '')
76
+	{
77
+		$this->set('QST_system', $QST_system);
78
+	}
79
+
80
+
81
+	/**
82
+	 *        Set    question's type
83
+	 *
84
+	 * @access        public
85
+	 * @param        string $QST_type
86
+	 */
87
+	public function set_question_type($QST_type = '')
88
+	{
89
+		$this->set('QST_type', $QST_type);
90
+	}
91
+
92
+
93
+	/**
94
+	 *        Sets whether this question must be answered when presented in a form
95
+	 *
96
+	 * @access        public
97
+	 * @param        bool $QST_required
98
+	 */
99
+	public function set_required($QST_required = false)
100
+	{
101
+		$this->set('QST_required', $QST_required);
102
+	}
103
+
104
+
105
+	/**
106
+	 *        Set    Question display text
107
+	 *
108
+	 * @access        public
109
+	 * @param        string $QST_required_text
110
+	 */
111
+	public function set_required_text($QST_required_text = '')
112
+	{
113
+		$this->set('QST_required_text', $QST_required_text);
114
+	}
115
+
116
+
117
+	/**
118
+	 *        Sets the order of this question when placed in a sequence of questions
119
+	 *
120
+	 * @access        public
121
+	 * @param        int $QST_order
122
+	 */
123
+	public function set_order($QST_order = 0)
124
+	{
125
+		$this->set('QST_order', $QST_order);
126
+	}
127
+
128
+
129
+	/**
130
+	 *        Sets whether the question is admin-only
131
+	 *
132
+	 * @access        public
133
+	 * @param        bool $QST_admin_only
134
+	 */
135
+	public function set_admin_only($QST_admin_only = false)
136
+	{
137
+		$this->set('QST_admin_only', $QST_admin_only);
138
+	}
139
+
140
+
141
+	/**
142
+	 *        Sets the wordpress user ID on the question
143
+	 *
144
+	 * @access        public
145
+	 * @param        int $QST_wp_user
146
+	 */
147
+	public function set_wp_user($QST_wp_user = 1)
148
+	{
149
+		$this->set('QST_wp_user', $QST_wp_user);
150
+	}
151
+
152
+
153
+	/**
154
+	 *        Sets whether the question has been deleted
155
+	 *        (we use this boolean instead of actually
156
+	 *        deleting it because when users delete this question
157
+	 *        they really want to remove the question from future
158
+	 *        forms, BUT keep their old answers which depend
159
+	 *        on this record actually existing.
160
+	 *
161
+	 * @access        public
162
+	 * @param    bool $QST_deleted
163
+	 */
164
+	public function set_deleted($QST_deleted = false)
165
+	{
166
+		$this->set('QST_deleted', $QST_deleted);
167
+	}
168
+
169
+
170
+	/**
171
+	 * returns the text for displaying the question to users
172
+	 *
173
+	 * @access public
174
+	 * @return string
175
+	 */
176
+	public function display_text()
177
+	{
178
+		return $this->get('QST_display_text');
179
+	}
180
+
181
+
182
+	/**
183
+	 * returns the text for the administrative label
184
+	 *
185
+	 * @access public
186
+	 * @return string
187
+	 */
188
+	public function admin_label()
189
+	{
190
+		return $this->get('QST_admin_label');
191
+	}
192
+
193
+
194
+	/**
195
+	 * returns the attendee column name for this question
196
+	 *
197
+	 * @access public
198
+	 * @return string
199
+	 */
200
+	public function system_ID()
201
+	{
202
+		return $this->get('QST_system');
203
+	}
204
+
205
+
206
+	/**
207
+	 * returns either a string of 'text', 'textfield', etc.
208
+	 *
209
+	 * @access public
210
+	 * @return boolean
211
+	 */
212
+	public function required()
213
+	{
214
+		return $this->get('QST_required');
215
+	}
216
+
217
+
218
+	/**
219
+	 * returns the text which should be displayed when a user
220
+	 * doesn't answer this question in a form
221
+	 *
222
+	 * @access public
223
+	 * @return string
224
+	 */
225
+	public function required_text()
226
+	{
227
+		return $this->get('QST_required_text');
228
+	}
229
+
230
+
231
+	/**
232
+	 * returns the type of this question
233
+	 *
234
+	 * @access public
235
+	 * @return string
236
+	 */
237
+	public function type()
238
+	{
239
+		return $this->get('QST_type');
240
+	}
241
+
242
+
243
+	/**
244
+	 * returns an integer showing where this question should
245
+	 * be placed in a sequence of questions
246
+	 *
247
+	 * @access public
248
+	 * @return int
249
+	 */
250
+	public function order()
251
+	{
252
+		return $this->get('QST_order');
253
+	}
254
+
255
+
256
+	/**
257
+	 * returns whether this question should only appears to admins,
258
+	 * or to everyone
259
+	 *
260
+	 * @access public
261
+	 * @return boolean
262
+	 */
263
+	public function admin_only()
264
+	{
265
+		return $this->get('QST_admin_only');
266
+	}
267
+
268
+
269
+	/**
270
+	 * returns the id the wordpress user who created this question
271
+	 *
272
+	 * @access public
273
+	 * @return int
274
+	 */
275
+	public function wp_user()
276
+	{
277
+		return $this->get('QST_wp_user');
278
+	}
279
+
280
+
281
+	/**
282
+	 * returns whether this question has been marked as 'deleted'
283
+	 *
284
+	 * @access public
285
+	 * @return boolean
286
+	 */
287
+	public function deleted()
288
+	{
289
+		return $this->get('QST_deleted');
290
+	}
291
+
292
+
293
+	/**
294
+	 * Gets an array of related EE_Answer  to this EE_Question
295
+	 *
296
+	 * @return EE_Answer[]
297
+	 */
298
+	public function answers()
299
+	{
300
+		return $this->get_many_related('Answer');
301
+	}
302
+
303
+
304
+	/**
305
+	 * Boolean check for if there are answers on this question in th db
306
+	 *
307
+	 * @return boolean true = has answers, false = no answers.
308
+	 */
309
+	public function has_answers()
310
+	{
311
+		return $this->count_related('Answer') > 0 ? true : false;
312
+	}
313
+
314
+
315
+	/**
316
+	 * gets an array of EE_Question_Group which relate to this question
317
+	 *
318
+	 * @return EE_Question_Group[]
319
+	 */
320
+	public function question_groups()
321
+	{
322
+		return $this->get_many_related('Question_Group');
323
+	}
324
+
325
+
326
+	/**
327
+	 * Returns all the options for this question. By default, it returns only the not-yet-deleted ones.
328
+	 *
329
+	 * @param boolean      $notDeletedOptionsOnly            1
330
+	 *                                                       whether to return ALL options, or only the ones which have
331
+	 *                                                       not yet been deleleted
332
+	 * @param string|array $selected_value_to_always_include , when retrieving options to an ANSWERED question,
333
+	 *                                                       we want to usually only show non-deleted options AND the
334
+	 *                                                       value that was selected for the answer, whether it was
335
+	 *                                                       trashed or not.
336
+	 * @return EE_Question_Option[]
337
+	 */
338
+	public function options($notDeletedOptionsOnly = true, $selected_value_to_always_include = null)
339
+	{
340
+		if (! $this->ID()) {
341
+			return array();
342
+		}
343
+		$query_params = array();
344
+		if ($selected_value_to_always_include) {
345
+			if (is_array($selected_value_to_always_include)) {
346
+				$query_params[0]['OR*options-query']['QSO_value'] = array('IN', $selected_value_to_always_include);
347
+			} else {
348
+				$query_params[0]['OR*options-query']['QSO_value'] = $selected_value_to_always_include;
349
+			}
350
+		}
351
+		if ($notDeletedOptionsOnly) {
352
+			$query_params[0]['OR*options-query']['QSO_deleted'] = false;
353
+		}
354
+		// order by QSO_order
355
+		$query_params['order_by'] = array('QSO_order' => 'ASC');
356
+		return $this->get_many_related('Question_Option', $query_params);
357
+	}
358
+
359
+
360
+	/**
361
+	 * returns an array of EE_Question_Options which relate to this question
362
+	 *
363
+	 * @return \EE_Question_Option[]
364
+	 */
365
+	public function temp_options()
366
+	{
367
+		return $this->_model_relations['Question_Option'];
368
+	}
369
+
370
+
371
+	/**
372
+	 * Adds an option for this question. Note: if the option were previously associated with a different
373
+	 * Question, that relationship will be overwritten.
374
+	 *
375
+	 * @param EE_Question_Option $option
376
+	 * @return boolean success
377
+	 */
378
+	public function add_option(EE_Question_Option $option)
379
+	{
380
+		return $this->_add_relation_to($option, 'Question_Option');
381
+	}
382
+
383
+
384
+	/**
385
+	 * Adds an option directly to this question without saving to the db
386
+	 *
387
+	 * @param EE_Question_Option $option
388
+	 * @return boolean success
389
+	 */
390
+	public function add_temp_option(EE_Question_Option $option)
391
+	{
392
+		$this->_model_relations['Question_Option'][] = $option;
393
+		return true;
394
+	}
395
+
396
+
397
+	/**
398
+	 * Marks the option as deleted.
399
+	 *
400
+	 * @param EE_Question_Option $option
401
+	 * @return boolean success
402
+	 */
403
+	public function remove_option(EE_Question_Option $option)
404
+	{
405
+		return $this->_remove_relation_to($option, 'Question_Option');
406
+	}
407
+
408
+
409
+	/**
410
+	 * @return bool
411
+	 */
412
+	public function is_system_question()
413
+	{
414
+		$system_ID = $this->get('QST_system');
415
+		return ! empty($system_ID) ? true : false;
416
+	}
417
+
418
+
419
+	/**
420
+	 * The purpose of this method is set the question order this question order to be the max out of all questions
421
+	 *
422
+	 * @access public
423
+	 * @return void
424
+	 */
425
+	public function set_order_to_latest()
426
+	{
427
+		$latest_order = $this->get_model()->get_latest_question_order();
428
+		$latest_order++;
429
+		$this->set('QST_order', $latest_order);
430
+	}
431
+
432
+
433
+	/**
434
+	 * Retrieves the list of allowed question types from the model.
435
+	 *
436
+	 * @return string[]
437
+	 */
438
+	private function _allowed_question_types()
439
+	{
440
+		$questionModel = $this->get_model();
441
+		/* @var $questionModel EEM_Question */
442
+		return $questionModel->allowed_question_types();
443
+	}
444
+
445
+	/**
446
+	 * Duplicates this question and its question options
447
+	 *
448
+	 * @return \EE_Question
449
+	 */
450
+	public function duplicate($options = array())
451
+	{
452
+		$new_question = clone $this;
453
+		$new_question->set('QST_ID', null);
454
+		$new_question->set_display_text(sprintf(__('%s **Duplicate**', 'event_espresso'), $this->display_text()));
455
+		$new_question->set_admin_label(sprintf(__('%s **Duplicate**', 'event_espresso'), $this->admin_label()));
456
+		$new_question->set_system_ID(null);
457
+		$new_question->set_wp_user(get_current_user_id());
458
+		// if we're duplicating a trashed question, assume we don't want the new one to be trashed
459
+		$new_question->set_deleted(false);
460
+		$success = $new_question->save();
461
+		if ($success) {
462
+			// we don't totally want to duplicate the question options, because we want them to be for the NEW question
463
+			foreach ($this->options() as $question_option) {
464
+				$question_option->duplicate(array('QST_ID' => $new_question->ID()));
465
+			}
466
+			return $new_question;
467
+		} else {
468
+			return null;
469
+		}
470
+	}
471
+
472
+	/**
473
+	 * Returns the question's maximum allowed response size
474
+	 *
475
+	 * @return int|float
476
+	 */
477
+	public function max()
478
+	{
479
+		return $this->get('QST_max');
480
+	}
481
+
482
+	/**
483
+	 * Sets the question's maximum allowed response size
484
+	 *
485
+	 * @param int|float $new_max
486
+	 * @return void
487
+	 */
488
+	public function set_max($new_max)
489
+	{
490
+		$this->set('QST_max', $new_max);
491
+	}
492
+
493
+
494
+	/**
495
+	 * Creates a form input from this question which can be used in HTML forms
496
+	 *
497
+	 * @param EE_Registration $registration
498
+	 * @param EE_Answer       $answer
499
+	 * @param array           $input_constructor_args
500
+	 * @return EE_Form_Input_Base
501
+	 */
502
+	public function generate_form_input($registration = null, $answer = null, $input_constructor_args = array())
503
+	{
504
+		$identifier = $this->is_system_question() ? $this->system_ID() : $this->ID();
505
+
506
+		$input_constructor_args = array_merge(
507
+			array(
508
+				'required'                          => $this->required() ? true : false,
509
+				'html_label_text'                   => $this->display_text(),
510
+				'required_validation_error_message' => $this->required_text(),
511
+			),
512
+			$input_constructor_args
513
+		);
514
+		if (! $answer instanceof EE_Answer && $registration instanceof EE_Registration) {
515
+			$answer = EEM_Answer::instance()->get_registration_question_answer_object($registration, $this->ID());
516
+		}
517
+		// has this question been answered ?
518
+		if (
519
+			$answer instanceof EE_Answer
520
+			&& $answer->value() !== ''
521
+		) {
522
+			// answer gets htmlspecialchars called on it, undo that please
523
+			// because the form input's display strategy may call esc_attr too
524
+			// which also does html special characters
525
+			$values_with_html_special_chars = $answer->value();
526
+			if (is_array($values_with_html_special_chars)) {
527
+				$default_value = array_map('htmlspecialchars_decode', $values_with_html_special_chars);
528
+			} else {
529
+				$default_value = htmlspecialchars_decode($values_with_html_special_chars);
530
+			}
531
+			$input_constructor_args['default'] = $default_value;
532
+		}
533
+		$max_max_for_question = EEM_Question::instance()->absolute_max_for_system_question($this->system_ID());
534
+		if (
535
+			in_array(
536
+				$this->type(),
537
+				EEM_Question::instance()->questionTypesWithMaxLength(),
538
+				true
539
+			)
540
+		) {
541
+			$input_constructor_args['validation_strategies'][] = new EE_Max_Length_Validation_Strategy(
542
+				null,
543
+				min($max_max_for_question, $this->max())
544
+			);
545
+		}
546
+		$input_constructor_args = apply_filters(
547
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__input_constructor_args',
548
+			$input_constructor_args,
549
+			$registration,
550
+			$this,
551
+			$answer
552
+		);
553
+
554
+		$result = null;
555
+		switch ($this->type()) {
556
+			// Text
557
+			case EEM_Question::QST_type_text:
558
+				$result = new EE_Text_Input($input_constructor_args);
559
+				break;
560
+			// Textarea
561
+			case EEM_Question::QST_type_textarea:
562
+				$result = new EE_Text_Area_Input($input_constructor_args);
563
+				break;
564
+			// Radio Buttons
565
+			case EEM_Question::QST_type_radio:
566
+				$result = new EE_Radio_Button_Input($this->options(), $input_constructor_args);
567
+				break;
568
+			// Dropdown
569
+			case EEM_Question::QST_type_dropdown:
570
+				$result = new EE_Select_Input($this->options(), $input_constructor_args);
571
+				break;
572
+			// State Dropdown
573
+			case EEM_Question::QST_type_state:
574
+				$state_options = apply_filters(
575
+					'FHEE__EE_Question__generate_form_input__state_options',
576
+					null,
577
+					$this,
578
+					$registration,
579
+					$answer
580
+				);
581
+				$result = new EE_State_Select_Input($state_options, $input_constructor_args);
582
+				break;
583
+			// Country Dropdown
584
+			case EEM_Question::QST_type_country:
585
+				$country_options = apply_filters(
586
+					'FHEE__EE_Question__generate_form_input__country_options',
587
+					null,
588
+					$this,
589
+					$registration,
590
+					$answer
591
+				);
592
+				$result = new EE_Country_Select_Input($country_options, $input_constructor_args);
593
+				break;
594
+			// Checkboxes
595
+			case EEM_Question::QST_type_checkbox:
596
+				$result = new EE_Checkbox_Multi_Input($this->options(), $input_constructor_args);
597
+				break;
598
+			// Date
599
+			case EEM_Question::QST_type_date:
600
+				$result = new EE_Datepicker_Input($input_constructor_args);
601
+				break;
602
+			case EEM_Question::QST_type_html_textarea:
603
+				$input_constructor_args['validation_strategies'][] = new EE_Simple_HTML_Validation_Strategy();
604
+				$result = new EE_Text_Area_Input($input_constructor_args);
605
+				$result->remove_validation_strategy('EE_Plaintext_Validation_Strategy');
606
+				break;
607
+			case EEM_Question::QST_type_email:
608
+					$result = new EE_Email_Input($input_constructor_args);
609
+				break;
610
+			// Email confirm
611
+			case EEM_Question::QST_type_email_confirm:
612
+				$result = new EE_Email_Confirm_Input($input_constructor_args);
613
+				break;
614
+			case EEM_Question::QST_type_us_phone:
615
+				$result = new EE_Phone_Input($input_constructor_args);
616
+				break;
617
+			case EEM_Question::QST_type_int:
618
+				$result = new EE_Integer_Input($input_constructor_args);
619
+				break;
620
+			case EEM_Question::QST_type_decimal:
621
+				$result = new EE_Float_Input($input_constructor_args);
622
+				break;
623
+			case EEM_Question::QST_type_url:
624
+				$input_constructor_args['validation_strategies'][] = LoaderFactory::getLoader()->getNew('EE_URL_Validation_Strategy');
625
+				$result = new EE_Text_Input($input_constructor_args);
626
+				break;
627
+			case EEM_Question::QST_type_year:
628
+				$result = new EE_Year_Input(
629
+					$input_constructor_args,
630
+					apply_filters(
631
+						'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__year_question__four_digit',
632
+						true,
633
+						$this
634
+					),
635
+					apply_filters(
636
+						'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__year_question__early_range',
637
+						100,
638
+						$this
639
+					),
640
+					apply_filters(
641
+						'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__year_question__end_range',
642
+						100,
643
+						$this
644
+					)
645
+				);
646
+				break;
647
+			case EEM_Question::QST_type_multi_select:
648
+				$result = new EE_Select_Multiple_Input($this->options(), $input_constructor_args);
649
+				break;
650
+			// fallback
651
+			default:
652
+				$default_input = apply_filters(
653
+					'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__default',
654
+					null,
655
+					$this->type(),
656
+					$this,
657
+					$input_constructor_args
658
+				);
659
+				if (! $default_input) {
660
+					$default_input = new EE_Text_Input($input_constructor_args);
661
+				}
662
+				$result = $default_input;
663
+		}
664
+		return apply_filters('FHEE__EE_Question__generate_form_input__return', $result, $registration, $this, $answer);
665
+	}
666
+
667
+
668
+	/**
669
+	 * Returns whether or not this question type should have question option entries
670
+	 *
671
+	 * @return bool
672
+	 */
673
+	public function should_have_question_options()
674
+	{
675
+		return in_array(
676
+			$this->type(),
677
+			$this->_model->question_types_with_options(),
678
+			true
679
+		);
680
+	}
681 681
 }
Please login to merge, or discard this patch.
core/db_classes/EE_Price.class.php 1 patch
Indentation   +442 added lines, -442 removed lines patch added patch discarded remove patch
@@ -13,446 +13,446 @@
 block discarded – undo
13 13
 class EE_Price extends EE_Soft_Delete_Base_Class
14 14
 {
15 15
 
16
-    /**
17
-     * @param array  $props_n_values          incoming values
18
-     * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
19
-     *                                        used.)
20
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
21
-     *                                        date_format and the second value is the time format
22
-     * @return EE_Price
23
-     * @throws EE_Error
24
-     * @throws InvalidArgumentException
25
-     * @throws ReflectionException
26
-     * @throws InvalidDataTypeException
27
-     * @throws InvalidInterfaceException
28
-     */
29
-    public static function new_instance($props_n_values = array(), $timezone = '', $date_formats = array())
30
-    {
31
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
32
-        return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
33
-    }
34
-
35
-
36
-    /**
37
-     * @param array  $props_n_values  incoming values from the database
38
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
39
-     *                                the website will be used.
40
-     * @return EE_Price
41
-     * @throws EE_Error
42
-     * @throws InvalidArgumentException
43
-     * @throws ReflectionException
44
-     * @throws InvalidDataTypeException
45
-     * @throws InvalidInterfaceException
46
-     */
47
-    public static function new_instance_from_db($props_n_values = array(), $timezone = '')
48
-    {
49
-        return new self($props_n_values, true, $timezone);
50
-    }
51
-
52
-
53
-    /**
54
-     * Set Price type ID
55
-     *
56
-     * @param int $PRT_ID
57
-     * @throws EE_Error
58
-     * @throws InvalidArgumentException
59
-     * @throws ReflectionException
60
-     * @throws InvalidDataTypeException
61
-     * @throws InvalidInterfaceException
62
-     */
63
-    public function set_type($PRT_ID = 0)
64
-    {
65
-        $this->set('PRT_ID', $PRT_ID);
66
-    }
67
-
68
-
69
-    /**
70
-     * Set Price Amount
71
-     *
72
-     * @param float $PRC_amount
73
-     * @throws EE_Error
74
-     * @throws InvalidArgumentException
75
-     * @throws ReflectionException
76
-     * @throws InvalidDataTypeException
77
-     * @throws InvalidInterfaceException
78
-     */
79
-    public function set_amount($PRC_amount = 0.00)
80
-    {
81
-        $this->set('PRC_amount', $PRC_amount);
82
-    }
83
-
84
-
85
-    /**
86
-     * Set Price Name
87
-     *
88
-     * @param string $PRC_name
89
-     * @throws EE_Error
90
-     * @throws InvalidArgumentException
91
-     * @throws ReflectionException
92
-     * @throws InvalidDataTypeException
93
-     * @throws InvalidInterfaceException
94
-     */
95
-    public function set_name($PRC_name = '')
96
-    {
97
-        $this->set('PRC_name', $PRC_name);
98
-    }
99
-
100
-
101
-    /**
102
-     * Set Price Description
103
-     *
104
-     * @param string $PRC_desc
105
-     * @throws EE_Error
106
-     * @throws InvalidArgumentException
107
-     * @throws ReflectionException
108
-     * @throws InvalidDataTypeException
109
-     * @throws InvalidInterfaceException
110
-     */
111
-    public function set_description($PRC_desc = '')
112
-    {
113
-        $this->Set('PRC_desc', $PRC_desc);
114
-    }
115
-
116
-
117
-    /**
118
-     * set is_default
119
-     *
120
-     * @param bool $PRC_is_default
121
-     * @throws EE_Error
122
-     * @throws InvalidArgumentException
123
-     * @throws ReflectionException
124
-     * @throws InvalidDataTypeException
125
-     * @throws InvalidInterfaceException
126
-     */
127
-    public function set_is_default($PRC_is_default = false)
128
-    {
129
-        $this->set('PRC_is_default', $PRC_is_default);
130
-    }
131
-
132
-
133
-    /**
134
-     * set deleted
135
-     *
136
-     * @param bool $PRC_deleted
137
-     * @throws EE_Error
138
-     * @throws InvalidArgumentException
139
-     * @throws ReflectionException
140
-     * @throws InvalidDataTypeException
141
-     * @throws InvalidInterfaceException
142
-     */
143
-    public function set_deleted($PRC_deleted = null)
144
-    {
145
-        $this->set('PRC_deleted', $PRC_deleted);
146
-    }
147
-
148
-
149
-    /**
150
-     * get Price type
151
-     *
152
-     * @return        int
153
-     * @throws EE_Error
154
-     * @throws InvalidArgumentException
155
-     * @throws ReflectionException
156
-     * @throws InvalidDataTypeException
157
-     * @throws InvalidInterfaceException
158
-     */
159
-    public function type()
160
-    {
161
-        return $this->get('PRT_ID');
162
-    }
163
-
164
-
165
-    /**
166
-     * get Price Amount
167
-     *
168
-     * @return        float
169
-     * @throws EE_Error
170
-     * @throws InvalidArgumentException
171
-     * @throws ReflectionException
172
-     * @throws InvalidDataTypeException
173
-     * @throws InvalidInterfaceException
174
-     */
175
-    public function amount()
176
-    {
177
-        return $this->get('PRC_amount');
178
-    }
179
-
180
-
181
-    /**
182
-     * get Price Name
183
-     *
184
-     * @return        string
185
-     * @throws EE_Error
186
-     * @throws InvalidArgumentException
187
-     * @throws ReflectionException
188
-     * @throws InvalidDataTypeException
189
-     * @throws InvalidInterfaceException
190
-     */
191
-    public function name()
192
-    {
193
-        return $this->get('PRC_name');
194
-    }
195
-
196
-
197
-    /**
198
-     * get Price description
199
-     *
200
-     * @return        string
201
-     * @throws EE_Error
202
-     * @throws InvalidArgumentException
203
-     * @throws ReflectionException
204
-     * @throws InvalidDataTypeException
205
-     * @throws InvalidInterfaceException
206
-     */
207
-    public function desc()
208
-    {
209
-        return $this->get('PRC_desc');
210
-    }
211
-
212
-
213
-    /**
214
-     * get overrides
215
-     *
216
-     * @return        int
217
-     * @throws EE_Error
218
-     * @throws InvalidArgumentException
219
-     * @throws ReflectionException
220
-     * @throws InvalidDataTypeException
221
-     * @throws InvalidInterfaceException
222
-     */
223
-    public function overrides()
224
-    {
225
-        return $this->get('PRC_overrides');
226
-    }
227
-
228
-
229
-    /**
230
-     * get order
231
-     *
232
-     * @return int
233
-     * @throws EE_Error
234
-     * @throws InvalidArgumentException
235
-     * @throws ReflectionException
236
-     * @throws InvalidDataTypeException
237
-     * @throws InvalidInterfaceException
238
-     */
239
-    public function order()
240
-    {
241
-        return $this->get('PRC_order');
242
-    }
243
-
244
-
245
-    /**
246
-     * get the author of the price
247
-     *
248
-     * @return int
249
-     * @throws EE_Error
250
-     * @throws InvalidArgumentException
251
-     * @throws ReflectionException
252
-     * @throws InvalidDataTypeException
253
-     * @throws InvalidInterfaceException
254
-     * @since 4.5.0
255
-     */
256
-    public function wp_user()
257
-    {
258
-        return $this->get('PRC_wp_user');
259
-    }
260
-
261
-
262
-    /**
263
-     * get is_default
264
-     *
265
-     * @return bool
266
-     * @throws EE_Error
267
-     * @throws InvalidArgumentException
268
-     * @throws ReflectionException
269
-     * @throws InvalidDataTypeException
270
-     * @throws InvalidInterfaceException
271
-     */
272
-    public function is_default()
273
-    {
274
-        return $this->get('PRC_is_default');
275
-    }
276
-
277
-
278
-    /**
279
-     * get deleted
280
-     *
281
-     * @return bool
282
-     * @throws EE_Error
283
-     * @throws InvalidArgumentException
284
-     * @throws ReflectionException
285
-     * @throws InvalidDataTypeException
286
-     * @throws InvalidInterfaceException
287
-     */
288
-    public function deleted()
289
-    {
290
-        return $this->get('PRC_deleted');
291
-    }
292
-
293
-
294
-    /**
295
-     * @return bool
296
-     * @throws EE_Error
297
-     * @throws InvalidArgumentException
298
-     * @throws ReflectionException
299
-     * @throws InvalidDataTypeException
300
-     * @throws InvalidInterfaceException
301
-     */
302
-    public function parent()
303
-    {
304
-        return $this->get('PRC_parent');
305
-    }
306
-
307
-
308
-    // some helper methods for getting info on the price_type for this price
309
-
310
-
311
-    /**
312
-     * return whether the price is a base price or not
313
-     *
314
-     * @return boolean
315
-     * @throws EE_Error
316
-     * @throws InvalidArgumentException
317
-     * @throws InvalidDataTypeException
318
-     * @throws InvalidInterfaceException
319
-     * @throws ReflectionException
320
-     */
321
-    public function is_base_price()
322
-    {
323
-        $price_type = $this->type_obj();
324
-        return $price_type->is_base_price();
325
-    }
326
-
327
-
328
-    /**
329
-     * @return EE_Base_Class|EE_Price_Type
330
-     * @throws EE_Error
331
-     * @throws InvalidArgumentException
332
-     * @throws ReflectionException
333
-     * @throws InvalidDataTypeException
334
-     * @throws InvalidInterfaceException
335
-     */
336
-    public function type_obj()
337
-    {
338
-        return $this->get_first_related('Price_Type');
339
-    }
340
-
341
-
342
-    /**
343
-     * @return int
344
-     * @throws EE_Error
345
-     * @throws InvalidArgumentException
346
-     * @throws ReflectionException
347
-     * @throws InvalidDataTypeException
348
-     * @throws InvalidInterfaceException
349
-     */
350
-    public function type_order()
351
-    {
352
-        return $this->get_first_related('Price_Type')->order();
353
-    }
354
-
355
-
356
-    /**
357
-     * Simply indicates whether this price increases or decreases the total
358
-     *
359
-     * @return boolean true = discount, otherwise adds to the total
360
-     * @throws EE_Error
361
-     * @throws InvalidArgumentException
362
-     * @throws ReflectionException
363
-     * @throws InvalidDataTypeException
364
-     * @throws InvalidInterfaceException
365
-     */
366
-    public function is_discount()
367
-    {
368
-        $price_type = $this->type_obj();
369
-        return $price_type->is_discount();
370
-    }
371
-
372
-
373
-    /**
374
-     * whether the price is a percentage or not
375
-     *
376
-     * @return boolean
377
-     * @throws EE_Error
378
-     * @throws InvalidArgumentException
379
-     * @throws InvalidDataTypeException
380
-     * @throws InvalidInterfaceException
381
-     * @throws ReflectionException
382
-     */
383
-    public function is_percent()
384
-    {
385
-        $price_type = $this->type_obj();
386
-        return $price_type->is_percent();
387
-    }
388
-
389
-
390
-    /**
391
-     * whether the price is a percentage or not
392
-     *
393
-     * @return boolean
394
-     * @throws EE_Error
395
-     * @throws InvalidArgumentException
396
-     * @throws ReflectionException
397
-     * @throws InvalidDataTypeException
398
-     * @throws InvalidInterfaceException
399
-     */
400
-    public function is_surcharge()
401
-    {
402
-        $price_type = $this->type_obj();
403
-        return $price_type->is_surcharge();
404
-    }
405
-
406
-    /**
407
-     * whether the price is a percentage or not
408
-     *
409
-     * @return boolean
410
-     * @throws EE_Error
411
-     * @throws InvalidArgumentException
412
-     * @throws ReflectionException
413
-     * @throws InvalidDataTypeException
414
-     * @throws InvalidInterfaceException
415
-     */
416
-    public function is_tax()
417
-    {
418
-        $price_type = $this->type_obj();
419
-        return $price_type->is_tax();
420
-    }
421
-
422
-
423
-    /**
424
-     * return pretty price dependant on whether its a dollar or percent.
425
-     *
426
-     * @return string
427
-     * @throws EE_Error
428
-     * @throws InvalidArgumentException
429
-     * @throws ReflectionException
430
-     * @throws InvalidDataTypeException
431
-     * @throws InvalidInterfaceException
432
-     * @since 4.4.0
433
-     */
434
-    public function pretty_price()
435
-    {
436
-        return ! $this->is_percent()
437
-            ? $this->get_pretty('PRC_amount')
438
-            : $this->get('PRC_amount') . '%';
439
-    }
440
-
441
-
442
-    /**
443
-     * @return mixed
444
-     * @throws EE_Error
445
-     * @throws InvalidArgumentException
446
-     * @throws ReflectionException
447
-     * @throws InvalidDataTypeException
448
-     * @throws InvalidInterfaceException
449
-     */
450
-    public function get_price_without_currency_symbol()
451
-    {
452
-        return str_replace(
453
-            EE_Registry::instance()->CFG->currency->sign,
454
-            '',
455
-            $this->get_pretty('PRC_amount')
456
-        );
457
-    }
16
+	/**
17
+	 * @param array  $props_n_values          incoming values
18
+	 * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
19
+	 *                                        used.)
20
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
21
+	 *                                        date_format and the second value is the time format
22
+	 * @return EE_Price
23
+	 * @throws EE_Error
24
+	 * @throws InvalidArgumentException
25
+	 * @throws ReflectionException
26
+	 * @throws InvalidDataTypeException
27
+	 * @throws InvalidInterfaceException
28
+	 */
29
+	public static function new_instance($props_n_values = array(), $timezone = '', $date_formats = array())
30
+	{
31
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
32
+		return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
33
+	}
34
+
35
+
36
+	/**
37
+	 * @param array  $props_n_values  incoming values from the database
38
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
39
+	 *                                the website will be used.
40
+	 * @return EE_Price
41
+	 * @throws EE_Error
42
+	 * @throws InvalidArgumentException
43
+	 * @throws ReflectionException
44
+	 * @throws InvalidDataTypeException
45
+	 * @throws InvalidInterfaceException
46
+	 */
47
+	public static function new_instance_from_db($props_n_values = array(), $timezone = '')
48
+	{
49
+		return new self($props_n_values, true, $timezone);
50
+	}
51
+
52
+
53
+	/**
54
+	 * Set Price type ID
55
+	 *
56
+	 * @param int $PRT_ID
57
+	 * @throws EE_Error
58
+	 * @throws InvalidArgumentException
59
+	 * @throws ReflectionException
60
+	 * @throws InvalidDataTypeException
61
+	 * @throws InvalidInterfaceException
62
+	 */
63
+	public function set_type($PRT_ID = 0)
64
+	{
65
+		$this->set('PRT_ID', $PRT_ID);
66
+	}
67
+
68
+
69
+	/**
70
+	 * Set Price Amount
71
+	 *
72
+	 * @param float $PRC_amount
73
+	 * @throws EE_Error
74
+	 * @throws InvalidArgumentException
75
+	 * @throws ReflectionException
76
+	 * @throws InvalidDataTypeException
77
+	 * @throws InvalidInterfaceException
78
+	 */
79
+	public function set_amount($PRC_amount = 0.00)
80
+	{
81
+		$this->set('PRC_amount', $PRC_amount);
82
+	}
83
+
84
+
85
+	/**
86
+	 * Set Price Name
87
+	 *
88
+	 * @param string $PRC_name
89
+	 * @throws EE_Error
90
+	 * @throws InvalidArgumentException
91
+	 * @throws ReflectionException
92
+	 * @throws InvalidDataTypeException
93
+	 * @throws InvalidInterfaceException
94
+	 */
95
+	public function set_name($PRC_name = '')
96
+	{
97
+		$this->set('PRC_name', $PRC_name);
98
+	}
99
+
100
+
101
+	/**
102
+	 * Set Price Description
103
+	 *
104
+	 * @param string $PRC_desc
105
+	 * @throws EE_Error
106
+	 * @throws InvalidArgumentException
107
+	 * @throws ReflectionException
108
+	 * @throws InvalidDataTypeException
109
+	 * @throws InvalidInterfaceException
110
+	 */
111
+	public function set_description($PRC_desc = '')
112
+	{
113
+		$this->Set('PRC_desc', $PRC_desc);
114
+	}
115
+
116
+
117
+	/**
118
+	 * set is_default
119
+	 *
120
+	 * @param bool $PRC_is_default
121
+	 * @throws EE_Error
122
+	 * @throws InvalidArgumentException
123
+	 * @throws ReflectionException
124
+	 * @throws InvalidDataTypeException
125
+	 * @throws InvalidInterfaceException
126
+	 */
127
+	public function set_is_default($PRC_is_default = false)
128
+	{
129
+		$this->set('PRC_is_default', $PRC_is_default);
130
+	}
131
+
132
+
133
+	/**
134
+	 * set deleted
135
+	 *
136
+	 * @param bool $PRC_deleted
137
+	 * @throws EE_Error
138
+	 * @throws InvalidArgumentException
139
+	 * @throws ReflectionException
140
+	 * @throws InvalidDataTypeException
141
+	 * @throws InvalidInterfaceException
142
+	 */
143
+	public function set_deleted($PRC_deleted = null)
144
+	{
145
+		$this->set('PRC_deleted', $PRC_deleted);
146
+	}
147
+
148
+
149
+	/**
150
+	 * get Price type
151
+	 *
152
+	 * @return        int
153
+	 * @throws EE_Error
154
+	 * @throws InvalidArgumentException
155
+	 * @throws ReflectionException
156
+	 * @throws InvalidDataTypeException
157
+	 * @throws InvalidInterfaceException
158
+	 */
159
+	public function type()
160
+	{
161
+		return $this->get('PRT_ID');
162
+	}
163
+
164
+
165
+	/**
166
+	 * get Price Amount
167
+	 *
168
+	 * @return        float
169
+	 * @throws EE_Error
170
+	 * @throws InvalidArgumentException
171
+	 * @throws ReflectionException
172
+	 * @throws InvalidDataTypeException
173
+	 * @throws InvalidInterfaceException
174
+	 */
175
+	public function amount()
176
+	{
177
+		return $this->get('PRC_amount');
178
+	}
179
+
180
+
181
+	/**
182
+	 * get Price Name
183
+	 *
184
+	 * @return        string
185
+	 * @throws EE_Error
186
+	 * @throws InvalidArgumentException
187
+	 * @throws ReflectionException
188
+	 * @throws InvalidDataTypeException
189
+	 * @throws InvalidInterfaceException
190
+	 */
191
+	public function name()
192
+	{
193
+		return $this->get('PRC_name');
194
+	}
195
+
196
+
197
+	/**
198
+	 * get Price description
199
+	 *
200
+	 * @return        string
201
+	 * @throws EE_Error
202
+	 * @throws InvalidArgumentException
203
+	 * @throws ReflectionException
204
+	 * @throws InvalidDataTypeException
205
+	 * @throws InvalidInterfaceException
206
+	 */
207
+	public function desc()
208
+	{
209
+		return $this->get('PRC_desc');
210
+	}
211
+
212
+
213
+	/**
214
+	 * get overrides
215
+	 *
216
+	 * @return        int
217
+	 * @throws EE_Error
218
+	 * @throws InvalidArgumentException
219
+	 * @throws ReflectionException
220
+	 * @throws InvalidDataTypeException
221
+	 * @throws InvalidInterfaceException
222
+	 */
223
+	public function overrides()
224
+	{
225
+		return $this->get('PRC_overrides');
226
+	}
227
+
228
+
229
+	/**
230
+	 * get order
231
+	 *
232
+	 * @return int
233
+	 * @throws EE_Error
234
+	 * @throws InvalidArgumentException
235
+	 * @throws ReflectionException
236
+	 * @throws InvalidDataTypeException
237
+	 * @throws InvalidInterfaceException
238
+	 */
239
+	public function order()
240
+	{
241
+		return $this->get('PRC_order');
242
+	}
243
+
244
+
245
+	/**
246
+	 * get the author of the price
247
+	 *
248
+	 * @return int
249
+	 * @throws EE_Error
250
+	 * @throws InvalidArgumentException
251
+	 * @throws ReflectionException
252
+	 * @throws InvalidDataTypeException
253
+	 * @throws InvalidInterfaceException
254
+	 * @since 4.5.0
255
+	 */
256
+	public function wp_user()
257
+	{
258
+		return $this->get('PRC_wp_user');
259
+	}
260
+
261
+
262
+	/**
263
+	 * get is_default
264
+	 *
265
+	 * @return bool
266
+	 * @throws EE_Error
267
+	 * @throws InvalidArgumentException
268
+	 * @throws ReflectionException
269
+	 * @throws InvalidDataTypeException
270
+	 * @throws InvalidInterfaceException
271
+	 */
272
+	public function is_default()
273
+	{
274
+		return $this->get('PRC_is_default');
275
+	}
276
+
277
+
278
+	/**
279
+	 * get deleted
280
+	 *
281
+	 * @return bool
282
+	 * @throws EE_Error
283
+	 * @throws InvalidArgumentException
284
+	 * @throws ReflectionException
285
+	 * @throws InvalidDataTypeException
286
+	 * @throws InvalidInterfaceException
287
+	 */
288
+	public function deleted()
289
+	{
290
+		return $this->get('PRC_deleted');
291
+	}
292
+
293
+
294
+	/**
295
+	 * @return bool
296
+	 * @throws EE_Error
297
+	 * @throws InvalidArgumentException
298
+	 * @throws ReflectionException
299
+	 * @throws InvalidDataTypeException
300
+	 * @throws InvalidInterfaceException
301
+	 */
302
+	public function parent()
303
+	{
304
+		return $this->get('PRC_parent');
305
+	}
306
+
307
+
308
+	// some helper methods for getting info on the price_type for this price
309
+
310
+
311
+	/**
312
+	 * return whether the price is a base price or not
313
+	 *
314
+	 * @return boolean
315
+	 * @throws EE_Error
316
+	 * @throws InvalidArgumentException
317
+	 * @throws InvalidDataTypeException
318
+	 * @throws InvalidInterfaceException
319
+	 * @throws ReflectionException
320
+	 */
321
+	public function is_base_price()
322
+	{
323
+		$price_type = $this->type_obj();
324
+		return $price_type->is_base_price();
325
+	}
326
+
327
+
328
+	/**
329
+	 * @return EE_Base_Class|EE_Price_Type
330
+	 * @throws EE_Error
331
+	 * @throws InvalidArgumentException
332
+	 * @throws ReflectionException
333
+	 * @throws InvalidDataTypeException
334
+	 * @throws InvalidInterfaceException
335
+	 */
336
+	public function type_obj()
337
+	{
338
+		return $this->get_first_related('Price_Type');
339
+	}
340
+
341
+
342
+	/**
343
+	 * @return int
344
+	 * @throws EE_Error
345
+	 * @throws InvalidArgumentException
346
+	 * @throws ReflectionException
347
+	 * @throws InvalidDataTypeException
348
+	 * @throws InvalidInterfaceException
349
+	 */
350
+	public function type_order()
351
+	{
352
+		return $this->get_first_related('Price_Type')->order();
353
+	}
354
+
355
+
356
+	/**
357
+	 * Simply indicates whether this price increases or decreases the total
358
+	 *
359
+	 * @return boolean true = discount, otherwise adds to the total
360
+	 * @throws EE_Error
361
+	 * @throws InvalidArgumentException
362
+	 * @throws ReflectionException
363
+	 * @throws InvalidDataTypeException
364
+	 * @throws InvalidInterfaceException
365
+	 */
366
+	public function is_discount()
367
+	{
368
+		$price_type = $this->type_obj();
369
+		return $price_type->is_discount();
370
+	}
371
+
372
+
373
+	/**
374
+	 * whether the price is a percentage or not
375
+	 *
376
+	 * @return boolean
377
+	 * @throws EE_Error
378
+	 * @throws InvalidArgumentException
379
+	 * @throws InvalidDataTypeException
380
+	 * @throws InvalidInterfaceException
381
+	 * @throws ReflectionException
382
+	 */
383
+	public function is_percent()
384
+	{
385
+		$price_type = $this->type_obj();
386
+		return $price_type->is_percent();
387
+	}
388
+
389
+
390
+	/**
391
+	 * whether the price is a percentage or not
392
+	 *
393
+	 * @return boolean
394
+	 * @throws EE_Error
395
+	 * @throws InvalidArgumentException
396
+	 * @throws ReflectionException
397
+	 * @throws InvalidDataTypeException
398
+	 * @throws InvalidInterfaceException
399
+	 */
400
+	public function is_surcharge()
401
+	{
402
+		$price_type = $this->type_obj();
403
+		return $price_type->is_surcharge();
404
+	}
405
+
406
+	/**
407
+	 * whether the price is a percentage or not
408
+	 *
409
+	 * @return boolean
410
+	 * @throws EE_Error
411
+	 * @throws InvalidArgumentException
412
+	 * @throws ReflectionException
413
+	 * @throws InvalidDataTypeException
414
+	 * @throws InvalidInterfaceException
415
+	 */
416
+	public function is_tax()
417
+	{
418
+		$price_type = $this->type_obj();
419
+		return $price_type->is_tax();
420
+	}
421
+
422
+
423
+	/**
424
+	 * return pretty price dependant on whether its a dollar or percent.
425
+	 *
426
+	 * @return string
427
+	 * @throws EE_Error
428
+	 * @throws InvalidArgumentException
429
+	 * @throws ReflectionException
430
+	 * @throws InvalidDataTypeException
431
+	 * @throws InvalidInterfaceException
432
+	 * @since 4.4.0
433
+	 */
434
+	public function pretty_price()
435
+	{
436
+		return ! $this->is_percent()
437
+			? $this->get_pretty('PRC_amount')
438
+			: $this->get('PRC_amount') . '%';
439
+	}
440
+
441
+
442
+	/**
443
+	 * @return mixed
444
+	 * @throws EE_Error
445
+	 * @throws InvalidArgumentException
446
+	 * @throws ReflectionException
447
+	 * @throws InvalidDataTypeException
448
+	 * @throws InvalidInterfaceException
449
+	 */
450
+	public function get_price_without_currency_symbol()
451
+	{
452
+		return str_replace(
453
+			EE_Registry::instance()->CFG->currency->sign,
454
+			'',
455
+			$this->get_pretty('PRC_amount')
456
+		);
457
+	}
458 458
 }
Please login to merge, or discard this patch.
core/db_classes/EE_Checkin.class.php 1 patch
Indentation   +103 added lines, -103 removed lines patch added patch discarded remove patch
@@ -11,107 +11,107 @@
 block discarded – undo
11 11
 {
12 12
 
13 13
 
14
-    /**
15
-     * Used to reference when a registration has been checked out.
16
-     *
17
-     * @type int
18
-     */
19
-    const status_checked_out = 0;
20
-
21
-    /**
22
-     * Used to reference when a registration has been checked in.
23
-     *
24
-     * @type int
25
-     */
26
-    const status_checked_in = 1;
27
-
28
-    /**
29
-     * Used to reference when a registration has never been checked in.
30
-     *
31
-     * @type int
32
-     */
33
-    const status_checked_never = 2;
34
-
35
-
36
-    /**
37
-     * @param array  $props_n_values    incoming values
38
-     * @param string $timezone          incoming timezone (if not set the timezone set for the website will be used.)
39
-     * @param array  $date_formats      incoming date_formats in an array
40
-     *                                  where the first value is the date_format
41
-     *                                  and the second value is the time format
42
-     * @return EE_Checkin
43
-     * @throws EE_Error
44
-     * @throws ReflectionException
45
-     */
46
-    public static function new_instance($props_n_values = [], $timezone = '', $date_formats = [])
47
-    {
48
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
49
-        return $has_object
50
-            ? $has_object
51
-            : new self($props_n_values, false, $timezone, $date_formats);
52
-    }
53
-
54
-
55
-    /**
56
-     * @param array  $props_n_values  incoming values from the database
57
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
58
-     *                                the website will be used.
59
-     * @return EE_Checkin
60
-     * @throws EE_Error
61
-     * @throws ReflectionException
62
-     */
63
-    public static function new_instance_from_db($props_n_values = [], $timezone = '')
64
-    {
65
-        return new self($props_n_values, true, $timezone);
66
-    }
67
-
68
-
69
-    /**
70
-     * @return mixed
71
-     * @throws EE_Error
72
-     */
73
-    public function ID()
74
-    {
75
-        return $this->get('CHK_ID');
76
-    }
77
-
78
-
79
-    /**
80
-     * @return mixed
81
-     * @throws EE_Error
82
-     */
83
-    public function registration_id()
84
-    {
85
-        return $this->get('REG_ID');
86
-    }
87
-
88
-
89
-    /**
90
-     * @return mixed
91
-     * @throws EE_Error
92
-     */
93
-    public function datetime_id()
94
-    {
95
-        return $this->get('DTT_ID');
96
-    }
97
-
98
-
99
-    /**
100
-     * @return mixed
101
-     * @throws EE_Error
102
-     */
103
-    public function status()
104
-    {
105
-        return $this->get('CHK_in');
106
-    }
107
-
108
-
109
-    /**
110
-     * @return mixed
111
-     * @throws EE_Error
112
-     */
113
-    public function timestamp()
114
-    {
115
-        return $this->get('CHK_timestamp');
116
-    }
14
+	/**
15
+	 * Used to reference when a registration has been checked out.
16
+	 *
17
+	 * @type int
18
+	 */
19
+	const status_checked_out = 0;
20
+
21
+	/**
22
+	 * Used to reference when a registration has been checked in.
23
+	 *
24
+	 * @type int
25
+	 */
26
+	const status_checked_in = 1;
27
+
28
+	/**
29
+	 * Used to reference when a registration has never been checked in.
30
+	 *
31
+	 * @type int
32
+	 */
33
+	const status_checked_never = 2;
34
+
35
+
36
+	/**
37
+	 * @param array  $props_n_values    incoming values
38
+	 * @param string $timezone          incoming timezone (if not set the timezone set for the website will be used.)
39
+	 * @param array  $date_formats      incoming date_formats in an array
40
+	 *                                  where the first value is the date_format
41
+	 *                                  and the second value is the time format
42
+	 * @return EE_Checkin
43
+	 * @throws EE_Error
44
+	 * @throws ReflectionException
45
+	 */
46
+	public static function new_instance($props_n_values = [], $timezone = '', $date_formats = [])
47
+	{
48
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
49
+		return $has_object
50
+			? $has_object
51
+			: new self($props_n_values, false, $timezone, $date_formats);
52
+	}
53
+
54
+
55
+	/**
56
+	 * @param array  $props_n_values  incoming values from the database
57
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
58
+	 *                                the website will be used.
59
+	 * @return EE_Checkin
60
+	 * @throws EE_Error
61
+	 * @throws ReflectionException
62
+	 */
63
+	public static function new_instance_from_db($props_n_values = [], $timezone = '')
64
+	{
65
+		return new self($props_n_values, true, $timezone);
66
+	}
67
+
68
+
69
+	/**
70
+	 * @return mixed
71
+	 * @throws EE_Error
72
+	 */
73
+	public function ID()
74
+	{
75
+		return $this->get('CHK_ID');
76
+	}
77
+
78
+
79
+	/**
80
+	 * @return mixed
81
+	 * @throws EE_Error
82
+	 */
83
+	public function registration_id()
84
+	{
85
+		return $this->get('REG_ID');
86
+	}
87
+
88
+
89
+	/**
90
+	 * @return mixed
91
+	 * @throws EE_Error
92
+	 */
93
+	public function datetime_id()
94
+	{
95
+		return $this->get('DTT_ID');
96
+	}
97
+
98
+
99
+	/**
100
+	 * @return mixed
101
+	 * @throws EE_Error
102
+	 */
103
+	public function status()
104
+	{
105
+		return $this->get('CHK_in');
106
+	}
107
+
108
+
109
+	/**
110
+	 * @return mixed
111
+	 * @throws EE_Error
112
+	 */
113
+	public function timestamp()
114
+	{
115
+		return $this->get('CHK_timestamp');
116
+	}
117 117
 }
Please login to merge, or discard this patch.
core/db_classes/EE_Ticket.class.php 1 patch
Indentation   +1871 added lines, -1871 removed lines patch added patch discarded remove patch
@@ -14,1879 +14,1879 @@
 block discarded – undo
14 14
 class EE_Ticket extends EE_Soft_Delete_Base_Class implements EEI_Line_Item_Object, EEI_Event_Relation, EEI_Has_Icon
15 15
 {
16 16
 
17
-    /**
18
-     * TicKet Sold out:
19
-     * constant used by ticket_status() to indicate that a ticket is sold out
20
-     * and no longer available for purchases
21
-     */
22
-    const sold_out = 'TKS';
23
-
24
-    /**
25
-     * TicKet Expired:
26
-     * constant used by ticket_status() to indicate that a ticket is expired
27
-     * and no longer available for purchase
28
-     */
29
-    const expired = 'TKE';
30
-
31
-    /**
32
-     * TicKet Archived:
33
-     * constant used by ticket_status() to indicate that a ticket is archived
34
-     * and no longer available for purchase
35
-     */
36
-    const archived = 'TKA';
37
-
38
-    /**
39
-     * TicKet Pending:
40
-     * constant used by ticket_status() to indicate that a ticket is pending
41
-     * and is NOT YET available for purchase
42
-     */
43
-    const pending = 'TKP';
44
-
45
-    /**
46
-     * TicKet On sale:
47
-     * constant used by ticket_status() to indicate that a ticket is On Sale
48
-     * and IS available for purchase
49
-     */
50
-    const onsale = 'TKO';
51
-
52
-    /**
53
-     * extra meta key for tracking ticket reservations
54
-     *
55
-     * @type string
56
-     */
57
-    const META_KEY_TICKET_RESERVATIONS = 'ticket_reservations';
58
-
59
-    /**
60
-     * cached result from method of the same name
61
-     *
62
-     * @var float $_ticket_total_with_taxes
63
-     */
64
-    private $_ticket_total_with_taxes;
65
-
66
-
67
-    /**
68
-     * @param array  $props_n_values          incoming values
69
-     * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
70
-     *                                        used.)
71
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
72
-     *                                        date_format and the second value is the time format
73
-     * @return EE_Ticket
74
-     * @throws EE_Error
75
-     * @throws ReflectionException
76
-     */
77
-    public static function new_instance($props_n_values = [], $timezone = '', $date_formats = [])
78
-    {
79
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
80
-        return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
81
-    }
82
-
83
-
84
-    /**
85
-     * @param array  $props_n_values  incoming values from the database
86
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
87
-     *                                the website will be used.
88
-     * @return EE_Ticket
89
-     * @throws EE_Error
90
-     * @throws ReflectionException
91
-     */
92
-    public static function new_instance_from_db($props_n_values = [], $timezone = '')
93
-    {
94
-        return new self($props_n_values, true, $timezone);
95
-    }
96
-
97
-
98
-    /**
99
-     * @return bool
100
-     * @throws EE_Error
101
-     * @throws ReflectionException
102
-     */
103
-    public function parent()
104
-    {
105
-        return $this->get('TKT_parent');
106
-    }
107
-
108
-
109
-    /**
110
-     * return if a ticket has quantities available for purchase
111
-     *
112
-     * @param int $DTT_ID the primary key for a particular datetime
113
-     * @return boolean
114
-     * @throws EE_Error
115
-     * @throws ReflectionException
116
-     */
117
-    public function available($DTT_ID = 0)
118
-    {
119
-        // are we checking availability for a particular datetime ?
120
-        if ($DTT_ID) {
121
-            // get that datetime object
122
-            $datetime = $this->get_first_related('Datetime', [['DTT_ID' => $DTT_ID]]);
123
-            // if  ticket sales for this datetime have exceeded the reg limit...
124
-            if ($datetime instanceof EE_Datetime && $datetime->sold_out()) {
125
-                return false;
126
-            }
127
-        }
128
-        // datetime is still open for registration, but is this ticket sold out ?
129
-        return $this->qty() < 1 || $this->qty() > $this->sold();
130
-    }
131
-
132
-
133
-    /**
134
-     * Using the start date and end date this method calculates whether the ticket is On Sale, Pending, or Expired
135
-     *
136
-     * @param bool        $display   true = we'll return a localized string, otherwise we just return the value of the
137
-     *                               relevant status const
138
-     * @param bool | null $remaining if it is already known that tickets are available, then simply pass a bool to save
139
-     *                               further processing
140
-     * @return mixed status int if the display string isn't requested
141
-     * @throws EE_Error
142
-     * @throws ReflectionException
143
-     */
144
-    public function ticket_status($display = false, $remaining = null)
145
-    {
146
-        $remaining = is_bool($remaining) ? $remaining : $this->is_remaining();
147
-        if (! $remaining) {
148
-            return $display ? EEH_Template::pretty_status(EE_Ticket::sold_out, false, 'sentence') : EE_Ticket::sold_out;
149
-        }
150
-        if ($this->get('TKT_deleted')) {
151
-            return $display ? EEH_Template::pretty_status(EE_Ticket::archived, false, 'sentence') : EE_Ticket::archived;
152
-        }
153
-        if ($this->is_expired()) {
154
-            return $display ? EEH_Template::pretty_status(EE_Ticket::expired, false, 'sentence') : EE_Ticket::expired;
155
-        }
156
-        if ($this->is_pending()) {
157
-            return $display ? EEH_Template::pretty_status(EE_Ticket::pending, false, 'sentence') : EE_Ticket::pending;
158
-        }
159
-        if ($this->is_on_sale()) {
160
-            return $display ? EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence') : EE_Ticket::onsale;
161
-        }
162
-        return '';
163
-    }
164
-
165
-
166
-    /**
167
-     * The purpose of this method is to simply return a boolean for whether there are any tickets remaining for sale
168
-     * considering ALL the factors used for figuring that out.
169
-     *
170
-     * @access public
171
-     * @param int $DTT_ID if an int above 0 is included here then we get a specific dtt.
172
-     * @return boolean         true = tickets remaining, false not.
173
-     * @throws EE_Error
174
-     * @throws ReflectionException
175
-     */
176
-    public function is_remaining($DTT_ID = 0)
177
-    {
178
-        $num_remaining = $this->remaining($DTT_ID);
179
-        if ($num_remaining === 0) {
180
-            return false;
181
-        }
182
-        if ($num_remaining > 0 && $num_remaining < $this->min()) {
183
-            return false;
184
-        }
185
-        return true;
186
-    }
187
-
188
-
189
-    /**
190
-     * return the total number of tickets available for purchase
191
-     *
192
-     * @param int $DTT_ID  the primary key for a particular datetime.
193
-     *                     set to 0 for all related datetimes
194
-     * @return int
195
-     * @throws EE_Error
196
-     * @throws ReflectionException
197
-     */
198
-    public function remaining($DTT_ID = 0)
199
-    {
200
-        return $this->real_quantity_on_ticket('saleable', $DTT_ID);
201
-    }
202
-
203
-
204
-    /**
205
-     * Gets min
206
-     *
207
-     * @return int
208
-     * @throws EE_Error
209
-     * @throws ReflectionException
210
-     */
211
-    public function min()
212
-    {
213
-        return $this->get('TKT_min');
214
-    }
215
-
216
-
217
-    /**
218
-     * return if a ticket is no longer available cause its available dates have expired.
219
-     *
220
-     * @return boolean
221
-     * @throws EE_Error
222
-     * @throws ReflectionException
223
-     */
224
-    public function is_expired()
225
-    {
226
-        return ($this->get_raw('TKT_end_date') < time());
227
-    }
228
-
229
-
230
-    /**
231
-     * Return if a ticket is yet to go on sale or not
232
-     *
233
-     * @return boolean
234
-     * @throws EE_Error
235
-     * @throws ReflectionException
236
-     */
237
-    public function is_pending()
238
-    {
239
-        return ($this->get_raw('TKT_start_date') >= time());
240
-    }
241
-
242
-
243
-    /**
244
-     * Return if a ticket is on sale or not
245
-     *
246
-     * @return boolean
247
-     * @throws EE_Error
248
-     * @throws ReflectionException
249
-     */
250
-    public function is_on_sale()
251
-    {
252
-        return ($this->get_raw('TKT_start_date') <= time() && $this->get_raw('TKT_end_date') >= time());
253
-    }
254
-
255
-
256
-    /**
257
-     * This returns the chronologically last datetime that this ticket is associated with
258
-     *
259
-     * @param string $date_format
260
-     * @param string $conjunction - conjunction junction what's your function ? this string joins the start date with
261
-     *                            the end date ie: Jan 01 "to" Dec 31
262
-     * @return string
263
-     * @throws EE_Error
264
-     * @throws ReflectionException
265
-     */
266
-    public function date_range($date_format = '', $conjunction = ' - ')
267
-    {
268
-        $date_format = ! empty($date_format) ? $date_format : $this->_dt_frmt;
269
-        $first_date  = $this->first_datetime() instanceof EE_Datetime
270
-            ? $this->first_datetime()->get_i18n_datetime('DTT_EVT_start', $date_format)
271
-            : '';
272
-        $last_date   = $this->last_datetime() instanceof EE_Datetime
273
-            ? $this->last_datetime()->get_i18n_datetime('DTT_EVT_end', $date_format)
274
-            : '';
275
-
276
-        return $first_date && $last_date ? $first_date . $conjunction . $last_date : '';
277
-    }
278
-
279
-
280
-    /**
281
-     * This returns the chronologically first datetime that this ticket is associated with
282
-     *
283
-     * @return EE_Datetime
284
-     * @throws EE_Error
285
-     * @throws ReflectionException
286
-     */
287
-    public function first_datetime()
288
-    {
289
-        $datetimes = $this->datetimes(['limit' => 1]);
290
-        return reset($datetimes);
291
-    }
292
-
293
-
294
-    /**
295
-     * Gets all the datetimes this ticket can be used for attending.
296
-     * Unless otherwise specified, orders datetimes by start date.
297
-     *
298
-     * @param array $query_params @see
299
-     *                            https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
300
-     * @return EE_Datetime[]|EE_Base_Class[]
301
-     * @throws EE_Error
302
-     * @throws ReflectionException
303
-     */
304
-    public function datetimes($query_params = [])
305
-    {
306
-        if (! isset($query_params['order_by'])) {
307
-            $query_params['order_by']['DTT_order'] = 'ASC';
308
-        }
309
-        return $this->get_many_related('Datetime', $query_params);
310
-    }
311
-
312
-
313
-    /**
314
-     * This returns the chronologically last datetime that this ticket is associated with
315
-     *
316
-     * @return EE_Datetime
317
-     * @throws EE_Error
318
-     * @throws ReflectionException
319
-     */
320
-    public function last_datetime()
321
-    {
322
-        $datetimes = $this->datetimes(['limit' => 1, 'order_by' => ['DTT_EVT_start' => 'DESC']]);
323
-        return end($datetimes);
324
-    }
325
-
326
-
327
-    /**
328
-     * This returns the total tickets sold depending on the given parameters.
329
-     *
330
-     * @param string $what    Can be one of two options: 'ticket', 'datetime'.
331
-     *                        'ticket' = total ticket sales for all datetimes this ticket is related to
332
-     *                        'datetime' = total ticket sales for a specified datetime (required $dtt_id)
333
-     *                        'datetime' = total ticket sales in the datetime_ticket table.
334
-     *                        If $dtt_id is not given then we return an array of sales indexed by datetime.
335
-     *                        If $dtt_id IS given then we return the tickets sold for that given datetime.
336
-     * @param int    $dtt_id  [optional] include the dtt_id with $what = 'datetime'.
337
-     * @return mixed (array|int)          how many tickets have sold
338
-     * @throws EE_Error
339
-     * @throws ReflectionException
340
-     */
341
-    public function tickets_sold($what = 'ticket', $dtt_id = null)
342
-    {
343
-        $total        = 0;
344
-        $tickets_sold = $this->_all_tickets_sold();
345
-        switch ($what) {
346
-            case 'ticket':
347
-                return $tickets_sold['ticket'];
348
-                break;
349
-            case 'datetime':
350
-                if (empty($tickets_sold['datetime'])) {
351
-                    return $total;
352
-                }
353
-                if (! empty($dtt_id) && ! isset($tickets_sold['datetime'][ $dtt_id ])) {
354
-                    EE_Error::add_error(
355
-                        __(
356
-                            'You\'ve requested the amount of tickets sold for a given ticket and datetime, however there are no records for the datetime id you included.  Are you SURE that is a datetime related to this ticket?',
357
-                            'event_espresso'
358
-                        ),
359
-                        __FILE__,
360
-                        __FUNCTION__,
361
-                        __LINE__
362
-                    );
363
-                    return $total;
364
-                }
365
-                return empty($dtt_id) ? $tickets_sold['datetime'] : $tickets_sold['datetime'][ $dtt_id ];
366
-                break;
367
-            default:
368
-                return $total;
369
-        }
370
-    }
371
-
372
-
373
-    /**
374
-     * This returns an array indexed by datetime_id for tickets sold with this ticket.
375
-     *
376
-     * @return EE_Ticket[]
377
-     * @throws EE_Error
378
-     * @throws ReflectionException
379
-     */
380
-    protected function _all_tickets_sold()
381
-    {
382
-        $datetimes    = $this->get_many_related('Datetime');
383
-        $tickets_sold = [];
384
-        if (! empty($datetimes)) {
385
-            foreach ($datetimes as $datetime) {
386
-                $tickets_sold['datetime'][ $datetime->ID() ] = $datetime->get('DTT_sold');
387
-            }
388
-        }
389
-        // Tickets sold
390
-        $tickets_sold['ticket'] = $this->sold();
391
-        return $tickets_sold;
392
-    }
393
-
394
-
395
-    /**
396
-     * This returns the base price object for the ticket.
397
-     *
398
-     * @param bool $return_array whether to return as an array indexed by price id or just the object.
399
-     * @return EE_Price|EE_Base_Class|EE_Price[]|EE_Base_Class[]
400
-     * @throws EE_Error
401
-     * @throws ReflectionException
402
-     */
403
-    public function base_price($return_array = false)
404
-    {
405
-        $_where = ['Price_Type.PBT_ID' => EEM_Price_Type::base_type_base_price];
406
-        return $return_array
407
-            ? $this->get_many_related('Price', [$_where])
408
-            : $this->get_first_related('Price', [$_where]);
409
-    }
410
-
411
-
412
-    /**
413
-     * This returns ONLY the price modifiers for the ticket (i.e. no taxes or base price)
414
-     *
415
-     * @access public
416
-     * @return EE_Price[]
417
-     * @throws EE_Error
418
-     * @throws ReflectionException
419
-     */
420
-    public function price_modifiers()
421
-    {
422
-        $query_params = [
423
-            0 => [
424
-                'Price_Type.PBT_ID' => [
425
-                    'NOT IN',
426
-                    [EEM_Price_Type::base_type_base_price, EEM_Price_Type::base_type_tax],
427
-                ],
428
-            ],
429
-        ];
430
-        return $this->prices($query_params);
431
-    }
432
-
433
-
434
-    /**
435
-     * This returns ONLY the price modifiers for the ticket (i.e. no taxes or base price)
436
-     *
437
-     * @access public
438
-     * @return EE_Price[]
439
-     * @throws EE_Error
440
-     * @throws ReflectionException
441
-     */
442
-    public function tax_price_modifiers()
443
-    {
444
-        $query_params = [
445
-            0 => [
446
-                'Price_Type.PBT_ID' => EEM_Price_Type::base_type_tax,
447
-            ],
448
-        ];
449
-        return $this->prices($query_params);
450
-    }
451
-
452
-
453
-    /**
454
-     * Gets all the prices that combine to form the final price of this ticket
455
-     *
456
-     * @param array $query_params @see
457
-     *                            https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
458
-     * @return EE_Price[]|EE_Base_Class[]
459
-     * @throws EE_Error
460
-     * @throws ReflectionException
461
-     */
462
-    public function prices($query_params = [])
463
-    {
464
-        return $this->get_many_related('Price', $query_params);
465
-    }
466
-
467
-
468
-    /**
469
-     * Gets all the ticket datetimes (ie, relations between datetimes and tickets)
470
-     *
471
-     * @param array $query_params @see
472
-     *                            https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
473
-     * @return EE_Datetime_Ticket|EE_Base_Class[]
474
-     * @throws EE_Error
475
-     * @throws ReflectionException
476
-     */
477
-    public function datetime_tickets($query_params = [])
478
-    {
479
-        return $this->get_many_related('Datetime_Ticket', $query_params);
480
-    }
481
-
482
-
483
-    /**
484
-     * Gets all the datetimes from the db ordered by DTT_order
485
-     *
486
-     * @param boolean $show_expired
487
-     * @param boolean $show_deleted
488
-     * @return EE_Datetime[]
489
-     * @throws EE_Error
490
-     * @throws ReflectionException
491
-     */
492
-    public function datetimes_ordered($show_expired = true, $show_deleted = false)
493
-    {
494
-        return EEM_Datetime::instance($this->_timezone)->get_datetimes_for_ticket_ordered_by_DTT_order(
495
-            $this->ID(),
496
-            $show_expired,
497
-            $show_deleted
498
-        );
499
-    }
500
-
501
-
502
-    /**
503
-     * Gets ID
504
-     *
505
-     * @return string
506
-     * @throws EE_Error
507
-     * @throws ReflectionException
508
-     */
509
-    public function ID()
510
-    {
511
-        return $this->get('TKT_ID');
512
-    }
513
-
514
-
515
-    /**
516
-     * get the author of the ticket.
517
-     *
518
-     * @return int
519
-     * @throws EE_Error
520
-     * @throws ReflectionException
521
-     * @since 4.5.0
522
-     */
523
-    public function wp_user()
524
-    {
525
-        return $this->get('TKT_wp_user');
526
-    }
527
-
528
-
529
-    /**
530
-     * Gets the template for the ticket
531
-     *
532
-     * @return EE_Ticket_Template|EE_Base_Class
533
-     * @throws EE_Error
534
-     * @throws ReflectionException
535
-     */
536
-    public function template()
537
-    {
538
-        return $this->get_first_related('Ticket_Template');
539
-    }
540
-
541
-
542
-    /**
543
-     * Simply returns an array of EE_Price objects that are taxes.
544
-     *
545
-     * @return EE_Price[]
546
-     * @throws EE_Error
547
-     */
548
-    public function get_ticket_taxes_for_admin()
549
-    {
550
-        return EE_Taxes::get_taxes_for_admin();
551
-    }
552
-
553
-
554
-    /**
555
-     * @return float
556
-     * @throws EE_Error
557
-     * @throws ReflectionException
558
-     */
559
-    public function ticket_price()
560
-    {
561
-        return $this->get('TKT_price');
562
-    }
563
-
564
-
565
-    /**
566
-     * @return mixed
567
-     * @throws EE_Error
568
-     * @throws ReflectionException
569
-     */
570
-    public function pretty_price()
571
-    {
572
-        return $this->get_pretty('TKT_price');
573
-    }
574
-
575
-
576
-    /**
577
-     * @return bool
578
-     * @throws EE_Error
579
-     * @throws ReflectionException
580
-     */
581
-    public function is_free()
582
-    {
583
-        return $this->get_ticket_total_with_taxes() === (float) 0;
584
-    }
585
-
586
-
587
-    /**
588
-     * get_ticket_total_with_taxes
589
-     *
590
-     * @param bool $no_cache
591
-     * @return float
592
-     * @throws EE_Error
593
-     * @throws ReflectionException
594
-     */
595
-    public function get_ticket_total_with_taxes($no_cache = false)
596
-    {
597
-        if ($this->_ticket_total_with_taxes === null || $no_cache) {
598
-            $this->_ticket_total_with_taxes = $this->get_ticket_subtotal() + $this->get_ticket_taxes_total_for_admin();
599
-        }
600
-        return (float) $this->_ticket_total_with_taxes;
601
-    }
602
-
603
-
604
-    /**
605
-     * @throws EE_Error
606
-     * @throws ReflectionException
607
-     */
608
-    public function ensure_TKT_Price_correct()
609
-    {
610
-        $this->set('TKT_price', EE_Taxes::get_subtotal_for_admin($this));
611
-        $this->save();
612
-    }
613
-
614
-
615
-    /**
616
-     * @return float
617
-     * @throws EE_Error
618
-     * @throws ReflectionException
619
-     */
620
-    public function get_ticket_subtotal()
621
-    {
622
-        return EE_Taxes::get_subtotal_for_admin($this);
623
-    }
624
-
625
-
626
-    /**
627
-     * Returns the total taxes applied to this ticket
628
-     *
629
-     * @return float
630
-     * @throws EE_Error
631
-     * @throws ReflectionException
632
-     */
633
-    public function get_ticket_taxes_total_for_admin()
634
-    {
635
-        return EE_Taxes::get_total_taxes_for_admin($this);
636
-    }
637
-
638
-
639
-    /**
640
-     * Sets name
641
-     *
642
-     * @param string $name
643
-     * @throws EE_Error
644
-     * @throws ReflectionException
645
-     */
646
-    public function set_name($name)
647
-    {
648
-        $this->set('TKT_name', $name);
649
-    }
650
-
651
-
652
-    /**
653
-     * Gets description
654
-     *
655
-     * @return string
656
-     * @throws EE_Error
657
-     * @throws ReflectionException
658
-     */
659
-    public function description()
660
-    {
661
-        return $this->get('TKT_description');
662
-    }
663
-
664
-
665
-    /**
666
-     * Sets description
667
-     *
668
-     * @param string $description
669
-     * @throws EE_Error
670
-     * @throws ReflectionException
671
-     */
672
-    public function set_description($description)
673
-    {
674
-        $this->set('TKT_description', $description);
675
-    }
676
-
677
-
678
-    /**
679
-     * Gets start_date
680
-     *
681
-     * @param string $date_format
682
-     * @param string $time_format
683
-     * @return string
684
-     * @throws EE_Error
685
-     * @throws ReflectionException
686
-     */
687
-    public function start_date($date_format = '', $time_format = '')
688
-    {
689
-        return $this->_get_datetime('TKT_start_date', $date_format, $time_format);
690
-    }
691
-
692
-
693
-    /**
694
-     * Sets start_date
695
-     *
696
-     * @param string $start_date
697
-     * @return void
698
-     * @throws EE_Error
699
-     * @throws ReflectionException
700
-     */
701
-    public function set_start_date($start_date)
702
-    {
703
-        $this->_set_date_time('B', $start_date, 'TKT_start_date');
704
-    }
705
-
706
-
707
-    /**
708
-     * Gets end_date
709
-     *
710
-     * @param string $date_format
711
-     * @param string $time_format
712
-     * @return string
713
-     * @throws EE_Error
714
-     * @throws ReflectionException
715
-     */
716
-    public function end_date($date_format = '', $time_format = '')
717
-    {
718
-        return $this->_get_datetime('TKT_end_date', $date_format, $time_format);
719
-    }
720
-
721
-
722
-    /**
723
-     * Sets end_date
724
-     *
725
-     * @param string $end_date
726
-     * @return void
727
-     * @throws EE_Error
728
-     * @throws ReflectionException
729
-     */
730
-    public function set_end_date($end_date)
731
-    {
732
-        $this->_set_date_time('B', $end_date, 'TKT_end_date');
733
-    }
734
-
735
-
736
-    /**
737
-     * Sets sell until time
738
-     *
739
-     * @param string $time a string representation of the sell until time (ex 9am or 7:30pm)
740
-     * @throws EE_Error
741
-     * @throws ReflectionException
742
-     * @since 4.5.0
743
-     */
744
-    public function set_end_time($time)
745
-    {
746
-        $this->_set_time_for($time, 'TKT_end_date');
747
-    }
748
-
749
-
750
-    /**
751
-     * Sets min
752
-     *
753
-     * @param int $min
754
-     * @return void
755
-     * @throws EE_Error
756
-     * @throws ReflectionException
757
-     */
758
-    public function set_min($min)
759
-    {
760
-        $this->set('TKT_min', $min);
761
-    }
762
-
763
-
764
-    /**
765
-     * Gets max
766
-     *
767
-     * @return int
768
-     * @throws EE_Error
769
-     * @throws ReflectionException
770
-     */
771
-    public function max()
772
-    {
773
-        return $this->get('TKT_max');
774
-    }
775
-
776
-
777
-    /**
778
-     * Sets max
779
-     *
780
-     * @param int $max
781
-     * @return void
782
-     * @throws EE_Error
783
-     * @throws ReflectionException
784
-     */
785
-    public function set_max($max)
786
-    {
787
-        $this->set('TKT_max', $max);
788
-    }
789
-
790
-
791
-    /**
792
-     * Sets price
793
-     *
794
-     * @param float $price
795
-     * @return void
796
-     * @throws EE_Error
797
-     * @throws ReflectionException
798
-     */
799
-    public function set_price($price)
800
-    {
801
-        $this->set('TKT_price', $price);
802
-    }
803
-
804
-
805
-    /**
806
-     * Gets sold
807
-     *
808
-     * @return int
809
-     * @throws EE_Error
810
-     * @throws ReflectionException
811
-     */
812
-    public function sold()
813
-    {
814
-        return $this->get_raw('TKT_sold');
815
-    }
816
-
817
-
818
-    /**
819
-     * Sets sold
820
-     *
821
-     * @param int $sold
822
-     * @return void
823
-     * @throws EE_Error
824
-     * @throws ReflectionException
825
-     */
826
-    public function set_sold($sold)
827
-    {
828
-        // sold can not go below zero
829
-        $sold = max(0, $sold);
830
-        $this->set('TKT_sold', $sold);
831
-    }
832
-
833
-
834
-    /**
835
-     * Increments sold by amount passed by $qty AND decrements the reserved count on both this ticket and its
836
-     * associated datetimes.
837
-     *
838
-     * @param int $qty
839
-     * @return boolean
840
-     * @throws EE_Error
841
-     * @throws InvalidArgumentException
842
-     * @throws InvalidDataTypeException
843
-     * @throws InvalidInterfaceException
844
-     * @throws ReflectionException
845
-     * @since 4.9.80.p
846
-     */
847
-    public function increaseSold($qty = 1)
848
-    {
849
-        $qty = absint($qty);
850
-        // increment sold and decrement reserved datetime quantities simultaneously
851
-        // don't worry about failures, because they must have already had a spot reserved
852
-        $this->increaseSoldForDatetimes($qty);
853
-        // Increment and decrement ticket quantities simultaneously
854
-        $success = $this->adjustNumericFieldsInDb(
855
-            [
856
-                'TKT_reserved' => $qty * -1,
857
-                'TKT_sold'     => $qty,
858
-            ]
859
-        );
860
-        do_action(
861
-            'AHEE__EE_Ticket__increase_sold',
862
-            $this,
863
-            $qty,
864
-            $this->sold(),
865
-            $success
866
-        );
867
-        return $success;
868
-    }
869
-
870
-
871
-    /**
872
-     * On each datetime related to this ticket, increases its sold count and decreases its reserved count by $qty.
873
-     *
874
-     * @param int           $qty positive or negative. Positive means to increase sold counts (and decrease reserved
875
-     *                           counts), Negative means to decreases old counts (and increase reserved counts).
876
-     * @param EE_Datetime[] $datetimes
877
-     * @throws EE_Error
878
-     * @throws InvalidArgumentException
879
-     * @throws InvalidDataTypeException
880
-     * @throws InvalidInterfaceException
881
-     * @throws ReflectionException
882
-     * @since 4.9.80.p
883
-     */
884
-    protected function increaseSoldForDatetimes($qty, array $datetimes = [])
885
-    {
886
-        $datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
887
-        foreach ($datetimes as $datetime) {
888
-            $datetime->increaseSold($qty);
889
-        }
890
-    }
891
-
892
-
893
-    /**
894
-     * Decrements (subtracts) sold by amount passed by $qty on both the ticket and its related datetimes directly in the
895
-     * DB and then updates the model objects.
896
-     * Does not affect the reserved counts.
897
-     *
898
-     * @param int $qty
899
-     * @return boolean
900
-     * @throws EE_Error
901
-     * @throws InvalidArgumentException
902
-     * @throws InvalidDataTypeException
903
-     * @throws InvalidInterfaceException
904
-     * @throws ReflectionException
905
-     * @since 4.9.80.p
906
-     */
907
-    public function decreaseSold($qty = 1)
908
-    {
909
-        $qty = absint($qty);
910
-        $this->decreaseSoldForDatetimes($qty);
911
-        $success = $this->adjustNumericFieldsInDb(
912
-            [
913
-                'TKT_sold' => $qty * -1,
914
-            ]
915
-        );
916
-        do_action(
917
-            'AHEE__EE_Ticket__decrease_sold',
918
-            $this,
919
-            $qty,
920
-            $this->sold(),
921
-            $success
922
-        );
923
-        return $success;
924
-    }
925
-
926
-
927
-    /**
928
-     * Decreases sold on related datetimes
929
-     *
930
-     * @param int           $qty
931
-     * @param EE_Datetime[] $datetimes
932
-     * @return void
933
-     * @throws EE_Error
934
-     * @throws InvalidArgumentException
935
-     * @throws InvalidDataTypeException
936
-     * @throws InvalidInterfaceException
937
-     * @throws ReflectionException
938
-     * @since 4.9.80.p
939
-     */
940
-    protected function decreaseSoldForDatetimes($qty = 1, array $datetimes = [])
941
-    {
942
-        $datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
943
-        if (is_array($datetimes)) {
944
-            foreach ($datetimes as $datetime) {
945
-                if ($datetime instanceof EE_Datetime) {
946
-                    $datetime->decreaseSold($qty);
947
-                }
948
-            }
949
-        }
950
-    }
951
-
952
-
953
-    /**
954
-     * Gets qty of reserved tickets
955
-     *
956
-     * @return int
957
-     * @throws EE_Error
958
-     * @throws ReflectionException
959
-     */
960
-    public function reserved()
961
-    {
962
-        return $this->get_raw('TKT_reserved');
963
-    }
964
-
965
-
966
-    /**
967
-     * Sets reserved
968
-     *
969
-     * @param int $reserved
970
-     * @return void
971
-     * @throws EE_Error
972
-     * @throws ReflectionException
973
-     */
974
-    public function set_reserved($reserved)
975
-    {
976
-        // reserved can not go below zero
977
-        $reserved = max(0, (int) $reserved);
978
-        $this->set('TKT_reserved', $reserved);
979
-    }
980
-
981
-
982
-    /**
983
-     * Increments reserved by amount passed by $qty, and persists it immediately to the database.
984
-     *
985
-     * @param int    $qty
986
-     * @param string $source
987
-     * @return bool whether we successfully reserved the ticket or not.
988
-     * @throws EE_Error
989
-     * @throws InvalidArgumentException
990
-     * @throws ReflectionException
991
-     * @throws InvalidDataTypeException
992
-     * @throws InvalidInterfaceException
993
-     * @since 4.9.80.p
994
-     */
995
-    public function increaseReserved($qty = 1, $source = 'unknown')
996
-    {
997
-        $qty = absint($qty);
998
-        do_action(
999
-            'AHEE__EE_Ticket__increase_reserved__begin',
1000
-            $this,
1001
-            $qty,
1002
-            $source
1003
-        );
1004
-        $this->add_extra_meta(EE_Ticket::META_KEY_TICKET_RESERVATIONS, "{$qty} from {$source}");
1005
-        $success                         = false;
1006
-        $datetimes_adjusted_successfully = $this->increaseReservedForDatetimes($qty);
1007
-        if ($datetimes_adjusted_successfully) {
1008
-            $success = $this->incrementFieldConditionallyInDb(
1009
-                'TKT_reserved',
1010
-                'TKT_sold',
1011
-                'TKT_qty',
1012
-                $qty
1013
-            );
1014
-            if (! $success) {
1015
-                // The datetimes were successfully bumped, but not the
1016
-                // ticket. So we need to manually rollback the datetimes.
1017
-                $this->decreaseReservedForDatetimes($qty);
1018
-            }
1019
-        }
1020
-        do_action(
1021
-            'AHEE__EE_Ticket__increase_reserved',
1022
-            $this,
1023
-            $qty,
1024
-            $this->reserved(),
1025
-            $success
1026
-        );
1027
-        return $success;
1028
-    }
1029
-
1030
-
1031
-    /**
1032
-     * Increases reserved counts on related datetimes
1033
-     *
1034
-     * @param int           $qty
1035
-     * @param EE_Datetime[] $datetimes
1036
-     * @return boolean indicating success
1037
-     * @throws EE_Error
1038
-     * @throws InvalidArgumentException
1039
-     * @throws InvalidDataTypeException
1040
-     * @throws InvalidInterfaceException
1041
-     * @throws ReflectionException
1042
-     * @since 4.9.80.p
1043
-     */
1044
-    protected function increaseReservedForDatetimes($qty = 1, array $datetimes = [])
1045
-    {
1046
-        $datetimes         = ! empty($datetimes) ? $datetimes : $this->datetimes();
1047
-        $datetimes_updated = [];
1048
-        $limit_exceeded    = false;
1049
-        if (is_array($datetimes)) {
1050
-            foreach ($datetimes as $datetime) {
1051
-                if ($datetime instanceof EE_Datetime) {
1052
-                    if ($datetime->increaseReserved($qty)) {
1053
-                        $datetimes_updated[] = $datetime;
1054
-                    } else {
1055
-                        $limit_exceeded = true;
1056
-                        break;
1057
-                    }
1058
-                }
1059
-            }
1060
-            // If somewhere along the way we detected a datetime whose
1061
-            // limit was exceeded, do a manual rollback.
1062
-            if ($limit_exceeded) {
1063
-                $this->decreaseReservedForDatetimes($qty, $datetimes_updated);
1064
-                return false;
1065
-            }
1066
-        }
1067
-        return true;
1068
-    }
1069
-
1070
-
1071
-    /**
1072
-     * Decrements (subtracts) reserved by amount passed by $qty, and persists it immediately to the database.
1073
-     *
1074
-     * @param int    $qty
1075
-     * @param bool   $adjust_datetimes
1076
-     * @param string $source
1077
-     * @return boolean
1078
-     * @throws EE_Error
1079
-     * @throws InvalidArgumentException
1080
-     * @throws ReflectionException
1081
-     * @throws InvalidDataTypeException
1082
-     * @throws InvalidInterfaceException
1083
-     * @since 4.9.80.p
1084
-     */
1085
-    public function decreaseReserved($qty = 1, $adjust_datetimes = true, $source = 'unknown')
1086
-    {
1087
-        $qty = absint($qty);
1088
-        $this->add_extra_meta(EE_Ticket::META_KEY_TICKET_RESERVATIONS, "-{$qty} from {$source}");
1089
-        if ($adjust_datetimes) {
1090
-            $this->decreaseReservedForDatetimes($qty);
1091
-        }
1092
-        $success = $this->adjustNumericFieldsInDb(
1093
-            [
1094
-                'TKT_reserved' => $qty * -1,
1095
-            ]
1096
-        );
1097
-        do_action(
1098
-            'AHEE__EE_Ticket__decrease_reserved',
1099
-            $this,
1100
-            $qty,
1101
-            $this->reserved(),
1102
-            $success
1103
-        );
1104
-        return $success;
1105
-    }
1106
-
1107
-
1108
-    /**
1109
-     * Decreases the reserved count on the specified datetimes.
1110
-     *
1111
-     * @param int           $qty
1112
-     * @param EE_Datetime[] $datetimes
1113
-     * @throws EE_Error
1114
-     * @throws InvalidArgumentException
1115
-     * @throws ReflectionException
1116
-     * @throws InvalidDataTypeException
1117
-     * @throws InvalidInterfaceException
1118
-     * @since 4.9.80.p
1119
-     */
1120
-    protected function decreaseReservedForDatetimes($qty = 1, array $datetimes = [])
1121
-    {
1122
-        $datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
1123
-        foreach ($datetimes as $datetime) {
1124
-            if ($datetime instanceof EE_Datetime) {
1125
-                $datetime->decreaseReserved($qty);
1126
-            }
1127
-        }
1128
-    }
1129
-
1130
-
1131
-    /**
1132
-     * Gets ticket quantity
1133
-     *
1134
-     * @param string $context     ticket quantity is somewhat subjective depending on the exact information sought
1135
-     *                            therefore $context can be one of three values: '', 'reg_limit', or 'saleable'
1136
-     *                            '' (default) quantity is the actual db value for TKT_qty, unaffected by other objects
1137
-     *                            REG LIMIT: caps qty based on DTT_reg_limit for ALL related datetimes
1138
-     *                            SALEABLE: also considers datetime sold and returns zero if ANY DTT is sold out, and
1139
-     *                            is therefore the truest measure of tickets that can be purchased at the moment
1140
-     * @return int
1141
-     * @throws EE_Error
1142
-     * @throws ReflectionException
1143
-     */
1144
-    public function qty($context = '')
1145
-    {
1146
-        switch ($context) {
1147
-            case 'reg_limit':
1148
-                return $this->real_quantity_on_ticket();
1149
-            case 'saleable':
1150
-                return $this->real_quantity_on_ticket('saleable');
1151
-            default:
1152
-                return $this->get_raw('TKT_qty');
1153
-        }
1154
-    }
1155
-
1156
-
1157
-    /**
1158
-     * Gets ticket quantity
1159
-     *
1160
-     * @param string $context     ticket quantity is somewhat subjective depending on the exact information sought
1161
-     *                            therefore $context can be one of two values: 'reg_limit', or 'saleable'
1162
-     *                            REG LIMIT: caps qty based on DTT_reg_limit for ALL related datetimes
1163
-     *                            SALEABLE: also considers datetime sold and returns zero if ANY DTT is sold out, and
1164
-     *                            is therefore the truest measure of tickets that can be purchased at the moment
1165
-     * @param int    $DTT_ID      the primary key for a particular datetime.
1166
-     *                            set to 0 for all related datetimes
1167
-     * @return int
1168
-     * @throws EE_Error
1169
-     * @throws ReflectionException
1170
-     */
1171
-    public function real_quantity_on_ticket($context = 'reg_limit', $DTT_ID = 0)
1172
-    {
1173
-        $raw = $this->get_raw('TKT_qty');
1174
-        // return immediately if it's zero
1175
-        if ($raw === 0) {
1176
-            return $raw;
1177
-        }
1178
-        // echo "\n\n<br />Ticket: " . $this->name() . '<br />';
1179
-        // ensure qty doesn't exceed raw value for THIS ticket
1180
-        $qty = min(EE_INF, $raw);
1181
-        // echo "\n . qty: " . $qty . '<br />';
1182
-        // calculate this ticket's total sales and reservations
1183
-        $sold_and_reserved_for_this_ticket = $this->sold() + $this->reserved();
1184
-        // echo "\n . sold: " . $this->sold() . '<br />';
1185
-        // echo "\n . reserved: " . $this->reserved() . '<br />';
1186
-        // echo "\n . sold_and_reserved_for_this_ticket: " . $sold_and_reserved_for_this_ticket . '<br />';
1187
-        // first we need to calculate the maximum number of tickets available for the datetime
1188
-        // do we want data for one datetime or all of them ?
1189
-        $query_params = $DTT_ID ? [['DTT_ID' => $DTT_ID]] : [];
1190
-        $datetimes    = $this->datetimes($query_params);
1191
-        if (is_array($datetimes) && ! empty($datetimes)) {
1192
-            foreach ($datetimes as $datetime) {
1193
-                if ($datetime instanceof EE_Datetime) {
1194
-                    $datetime->refresh_from_db();
1195
-                    // echo "\n . . datetime name: " . $datetime->name() . '<br />';
1196
-                    // echo "\n . . datetime ID: " . $datetime->ID() . '<br />';
1197
-                    // initialize with no restrictions for each datetime
1198
-                    // but adjust datetime qty based on datetime reg limit
1199
-                    $datetime_qty = min(EE_INF, $datetime->reg_limit());
1200
-                    // echo "\n . . . datetime reg_limit: " . $datetime->reg_limit() . '<br />';
1201
-                    // echo "\n . . . datetime_qty: " . $datetime_qty . '<br />';
1202
-                    // if we want the actual saleable amount, then we need to consider OTHER ticket sales
1203
-                    // and reservations for this datetime, that do NOT include sales and reservations
1204
-                    // for this ticket (so we add $this->sold() and $this->reserved() back in)
1205
-                    if ($context === 'saleable') {
1206
-                        $datetime_qty = max(
1207
-                            $datetime_qty - $datetime->sold_and_reserved() + $sold_and_reserved_for_this_ticket,
1208
-                            0
1209
-                        );
1210
-                        // echo "\n . . . datetime sold: " . $datetime->sold() . '<br />';
1211
-                        // echo "\n . . . datetime reserved: " . $datetime->reserved() . '<br />';
1212
-                        // echo "\n . . . datetime sold_and_reserved: " . $datetime->sold_and_reserved() . '<br />';
1213
-                        // echo "\n . . . datetime_qty: " . $datetime_qty . '<br />';
1214
-                        $datetime_qty = ! $datetime->sold_out() ? $datetime_qty : 0;
1215
-                        // echo "\n . . . datetime_qty: " . $datetime_qty . '<br />';
1216
-                    }
1217
-                    $qty = min($datetime_qty, $qty);
1218
-                    // echo "\n . . qty: " . $qty . '<br />';
1219
-                }
1220
-            }
1221
-        }
1222
-        // NOW that we know the  maximum number of tickets available for the datetime
1223
-        // we can finally factor in the details for this specific ticket
1224
-        if ($qty > 0 && $context === 'saleable') {
1225
-            // and subtract the sales for THIS ticket
1226
-            $qty = max($qty - $sold_and_reserved_for_this_ticket, 0);
1227
-            // echo "\n . qty: " . $qty . '<br />';
1228
-        }
1229
-        // echo "\nFINAL QTY: " . $qty . "<br /><br />";
1230
-        return $qty;
1231
-    }
1232
-
1233
-
1234
-    /**
1235
-     * Sets qty - IMPORTANT!!! Does NOT allow QTY to be set higher than the lowest reg limit of any related datetimes
1236
-     *
1237
-     * @param int $qty
1238
-     * @return void
1239
-     * @throws EE_Error
1240
-     * @throws ReflectionException
1241
-     */
1242
-    public function set_qty($qty)
1243
-    {
1244
-        $datetimes = $this->datetimes();
1245
-        foreach ($datetimes as $datetime) {
1246
-            if ($datetime instanceof EE_Datetime) {
1247
-                $qty = min($qty, $datetime->reg_limit());
1248
-            }
1249
-        }
1250
-        $this->set('TKT_qty', $qty);
1251
-    }
1252
-
1253
-
1254
-    /**
1255
-     * Gets uses
1256
-     *
1257
-     * @return int
1258
-     * @throws EE_Error
1259
-     * @throws ReflectionException
1260
-     */
1261
-    public function uses()
1262
-    {
1263
-        return $this->get('TKT_uses');
1264
-    }
1265
-
1266
-
1267
-    /**
1268
-     * Sets uses
1269
-     *
1270
-     * @param int $uses
1271
-     * @return void
1272
-     * @throws EE_Error
1273
-     * @throws ReflectionException
1274
-     */
1275
-    public function set_uses($uses)
1276
-    {
1277
-        $this->set('TKT_uses', $uses);
1278
-    }
1279
-
1280
-
1281
-    /**
1282
-     * returns whether ticket is required or not.
1283
-     *
1284
-     * @return boolean
1285
-     * @throws EE_Error
1286
-     * @throws ReflectionException
1287
-     */
1288
-    public function required()
1289
-    {
1290
-        return $this->get('TKT_required');
1291
-    }
1292
-
1293
-
1294
-    /**
1295
-     * sets the TKT_required property
1296
-     *
1297
-     * @param boolean $required
1298
-     * @return void
1299
-     * @throws EE_Error
1300
-     * @throws ReflectionException
1301
-     */
1302
-    public function set_required($required)
1303
-    {
1304
-        $this->set('TKT_required', $required);
1305
-    }
1306
-
1307
-
1308
-    /**
1309
-     * Gets taxable
1310
-     *
1311
-     * @return boolean
1312
-     * @throws EE_Error
1313
-     * @throws ReflectionException
1314
-     */
1315
-    public function taxable()
1316
-    {
1317
-        return $this->get('TKT_taxable');
1318
-    }
1319
-
1320
-
1321
-    /**
1322
-     * Sets taxable
1323
-     *
1324
-     * @param boolean $taxable
1325
-     * @return void
1326
-     * @throws EE_Error
1327
-     * @throws ReflectionException
1328
-     */
1329
-    public function set_taxable($taxable)
1330
-    {
1331
-        $this->set('TKT_taxable', $taxable);
1332
-    }
1333
-
1334
-
1335
-    /**
1336
-     * Gets is_default
1337
-     *
1338
-     * @return boolean
1339
-     * @throws EE_Error
1340
-     * @throws ReflectionException
1341
-     */
1342
-    public function is_default()
1343
-    {
1344
-        return $this->get('TKT_is_default');
1345
-    }
1346
-
1347
-
1348
-    /**
1349
-     * Sets is_default
1350
-     *
1351
-     * @param boolean $is_default
1352
-     * @return void
1353
-     * @throws EE_Error
1354
-     * @throws ReflectionException
1355
-     */
1356
-    public function set_is_default($is_default)
1357
-    {
1358
-        $this->set('TKT_is_default', $is_default);
1359
-    }
1360
-
1361
-
1362
-    /**
1363
-     * Gets order
1364
-     *
1365
-     * @return int
1366
-     * @throws EE_Error
1367
-     * @throws ReflectionException
1368
-     */
1369
-    public function order()
1370
-    {
1371
-        return $this->get('TKT_order');
1372
-    }
1373
-
1374
-
1375
-    /**
1376
-     * Sets order
1377
-     *
1378
-     * @param int $order
1379
-     * @return void
1380
-     * @throws EE_Error
1381
-     * @throws ReflectionException
1382
-     */
1383
-    public function set_order($order)
1384
-    {
1385
-        $this->set('TKT_order', $order);
1386
-    }
1387
-
1388
-
1389
-    /**
1390
-     * Gets row
1391
-     *
1392
-     * @return int
1393
-     * @throws EE_Error
1394
-     * @throws ReflectionException
1395
-     */
1396
-    public function row()
1397
-    {
1398
-        return $this->get('TKT_row');
1399
-    }
1400
-
1401
-
1402
-    /**
1403
-     * Sets row
1404
-     *
1405
-     * @param int $row
1406
-     * @return void
1407
-     * @throws EE_Error
1408
-     * @throws ReflectionException
1409
-     */
1410
-    public function set_row($row)
1411
-    {
1412
-        $this->set('TKT_row', $row);
1413
-    }
1414
-
1415
-
1416
-    /**
1417
-     * Gets deleted
1418
-     *
1419
-     * @return boolean
1420
-     * @throws EE_Error
1421
-     * @throws ReflectionException
1422
-     */
1423
-    public function deleted()
1424
-    {
1425
-        return $this->get('TKT_deleted');
1426
-    }
1427
-
1428
-
1429
-    /**
1430
-     * Sets deleted
1431
-     *
1432
-     * @param boolean $deleted
1433
-     * @return void
1434
-     * @throws EE_Error
1435
-     * @throws ReflectionException
1436
-     */
1437
-    public function set_deleted($deleted)
1438
-    {
1439
-        $this->set('TKT_deleted', $deleted);
1440
-    }
1441
-
1442
-
1443
-    /**
1444
-     * Gets parent
1445
-     *
1446
-     * @return int
1447
-     * @throws EE_Error
1448
-     * @throws ReflectionException
1449
-     */
1450
-    public function parent_ID()
1451
-    {
1452
-        return $this->get('TKT_parent');
1453
-    }
1454
-
1455
-
1456
-    /**
1457
-     * Sets parent
1458
-     *
1459
-     * @param int $parent
1460
-     * @return void
1461
-     * @throws EE_Error
1462
-     * @throws ReflectionException
1463
-     */
1464
-    public function set_parent_ID($parent)
1465
-    {
1466
-        $this->set('TKT_parent', $parent);
1467
-    }
1468
-
1469
-
1470
-    /**
1471
-     * @return boolean
1472
-     * @throws EE_Error
1473
-     * @throws InvalidArgumentException
1474
-     * @throws InvalidDataTypeException
1475
-     * @throws InvalidInterfaceException
1476
-     * @throws ReflectionException
1477
-     */
1478
-    public function reverse_calculate()
1479
-    {
1480
-        return $this->get('TKT_reverse_calculate');
1481
-    }
1482
-
1483
-
1484
-    /**
1485
-     * @param boolean $reverse_calculate
1486
-     * @throws EE_Error
1487
-     * @throws InvalidArgumentException
1488
-     * @throws InvalidDataTypeException
1489
-     * @throws InvalidInterfaceException
1490
-     * @throws ReflectionException
1491
-     */
1492
-    public function set_reverse_calculate($reverse_calculate)
1493
-    {
1494
-        $this->set('TKT_reverse_calculate', $reverse_calculate);
1495
-    }
1496
-
1497
-
1498
-    /**
1499
-     * Gets a string which is handy for showing in gateways etc that describes the ticket.
1500
-     *
1501
-     * @return string
1502
-     * @throws EE_Error
1503
-     * @throws ReflectionException
1504
-     */
1505
-    public function name_and_info()
1506
-    {
1507
-        $times = [];
1508
-        foreach ($this->datetimes() as $datetime) {
1509
-            $times[] = $datetime->start_date_and_time();
1510
-        }
1511
-        return $this->name() . ' @ ' . implode(', ', $times) . ' for ' . $this->pretty_price();
1512
-    }
1513
-
1514
-
1515
-    /**
1516
-     * Gets name
1517
-     *
1518
-     * @return string
1519
-     * @throws EE_Error
1520
-     * @throws ReflectionException
1521
-     */
1522
-    public function name()
1523
-    {
1524
-        return $this->get('TKT_name');
1525
-    }
1526
-
1527
-
1528
-    /**
1529
-     * Gets price
1530
-     *
1531
-     * @return float
1532
-     * @throws EE_Error
1533
-     * @throws ReflectionException
1534
-     */
1535
-    public function price()
1536
-    {
1537
-        return $this->get('TKT_price');
1538
-    }
1539
-
1540
-
1541
-    /**
1542
-     * Gets all the registrations for this ticket
1543
-     *
1544
-     * @param array $query_params @see
1545
-     *                            https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1546
-     * @return EE_Registration[]|EE_Base_Class[]
1547
-     * @throws EE_Error
1548
-     * @throws ReflectionException
1549
-     */
1550
-    public function registrations($query_params = [])
1551
-    {
1552
-        return $this->get_many_related('Registration', $query_params);
1553
-    }
1554
-
1555
-
1556
-    /**
1557
-     * Updates the TKT_sold attribute (and saves) based on the number of APPROVED registrations for this ticket.
1558
-     *
1559
-     * @return int
1560
-     * @throws EE_Error
1561
-     * @throws ReflectionException
1562
-     */
1563
-    public function update_tickets_sold()
1564
-    {
1565
-        $count_regs_for_this_ticket = $this->count_registrations(
1566
-            [
1567
-                [
1568
-                    'STS_ID'      => EEM_Registration::status_id_approved,
1569
-                    'REG_deleted' => 0,
1570
-                ],
1571
-            ]
1572
-        );
1573
-        $this->set_sold($count_regs_for_this_ticket);
1574
-        $this->save();
1575
-        return $count_regs_for_this_ticket;
1576
-    }
1577
-
1578
-
1579
-    /**
1580
-     * Counts the registrations for this ticket
1581
-     *
1582
-     * @param array $query_params @see
1583
-     *                            https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1584
-     * @return int
1585
-     * @throws EE_Error
1586
-     * @throws ReflectionException
1587
-     */
1588
-    public function count_registrations($query_params = [])
1589
-    {
1590
-        return $this->count_related('Registration', $query_params);
1591
-    }
1592
-
1593
-
1594
-    /**
1595
-     * Implementation for EEI_Has_Icon interface method.
1596
-     *
1597
-     * @return string
1598
-     * @see EEI_Visual_Representation for comments
1599
-     */
1600
-    public function get_icon()
1601
-    {
1602
-        return '<span class="dashicons dashicons-tickets-alt"/>';
1603
-    }
1604
-
1605
-
1606
-    /**
1607
-     * Implementation of the EEI_Event_Relation interface method
1608
-     *
1609
-     * @return EE_Event
1610
-     * @throws EE_Error
1611
-     * @throws UnexpectedEntityException
1612
-     * @throws ReflectionException
1613
-     * @see EEI_Event_Relation for comments
1614
-     */
1615
-    public function get_related_event()
1616
-    {
1617
-        // get one datetime to use for getting the event
1618
-        $datetime = $this->first_datetime();
1619
-        if (! $datetime instanceof EE_Datetime) {
1620
-            throw new UnexpectedEntityException(
1621
-                $datetime,
1622
-                'EE_Datetime',
1623
-                sprintf(
1624
-                    __('The ticket (%s) is not associated with any valid datetimes.', 'event_espresso'),
1625
-                    $this->name()
1626
-                )
1627
-            );
1628
-        }
1629
-        $event = $datetime->event();
1630
-        if (! $event instanceof EE_Event) {
1631
-            throw new UnexpectedEntityException(
1632
-                $event,
1633
-                'EE_Event',
1634
-                sprintf(
1635
-                    __('The ticket (%s) is not associated with a valid event.', 'event_espresso'),
1636
-                    $this->name()
1637
-                )
1638
-            );
1639
-        }
1640
-        return $event;
1641
-    }
1642
-
1643
-
1644
-    /**
1645
-     * Implementation of the EEI_Event_Relation interface method
1646
-     *
1647
-     * @return string
1648
-     * @throws UnexpectedEntityException
1649
-     * @throws EE_Error
1650
-     * @throws ReflectionException
1651
-     * @see EEI_Event_Relation for comments
1652
-     */
1653
-    public function get_event_name()
1654
-    {
1655
-        $event = $this->get_related_event();
1656
-        return $event instanceof EE_Event ? $event->name() : '';
1657
-    }
1658
-
1659
-
1660
-    /**
1661
-     * Implementation of the EEI_Event_Relation interface method
1662
-     *
1663
-     * @return int
1664
-     * @throws UnexpectedEntityException
1665
-     * @throws EE_Error
1666
-     * @throws ReflectionException
1667
-     * @see EEI_Event_Relation for comments
1668
-     */
1669
-    public function get_event_ID()
1670
-    {
1671
-        $event = $this->get_related_event();
1672
-        return $event instanceof EE_Event ? $event->ID() : 0;
1673
-    }
1674
-
1675
-
1676
-    /**
1677
-     * This simply returns whether a ticket can be permanently deleted or not.
1678
-     * The criteria for determining this is whether the ticket has any related registrations.
1679
-     * If there are none then it can be permanently deleted.
1680
-     *
1681
-     * @return bool
1682
-     * @throws EE_Error
1683
-     * @throws ReflectionException
1684
-     */
1685
-    public function is_permanently_deleteable()
1686
-    {
1687
-        return $this->count_registrations() === 0;
1688
-    }
1689
-
1690
-
1691
-    /*******************************************************************
17
+	/**
18
+	 * TicKet Sold out:
19
+	 * constant used by ticket_status() to indicate that a ticket is sold out
20
+	 * and no longer available for purchases
21
+	 */
22
+	const sold_out = 'TKS';
23
+
24
+	/**
25
+	 * TicKet Expired:
26
+	 * constant used by ticket_status() to indicate that a ticket is expired
27
+	 * and no longer available for purchase
28
+	 */
29
+	const expired = 'TKE';
30
+
31
+	/**
32
+	 * TicKet Archived:
33
+	 * constant used by ticket_status() to indicate that a ticket is archived
34
+	 * and no longer available for purchase
35
+	 */
36
+	const archived = 'TKA';
37
+
38
+	/**
39
+	 * TicKet Pending:
40
+	 * constant used by ticket_status() to indicate that a ticket is pending
41
+	 * and is NOT YET available for purchase
42
+	 */
43
+	const pending = 'TKP';
44
+
45
+	/**
46
+	 * TicKet On sale:
47
+	 * constant used by ticket_status() to indicate that a ticket is On Sale
48
+	 * and IS available for purchase
49
+	 */
50
+	const onsale = 'TKO';
51
+
52
+	/**
53
+	 * extra meta key for tracking ticket reservations
54
+	 *
55
+	 * @type string
56
+	 */
57
+	const META_KEY_TICKET_RESERVATIONS = 'ticket_reservations';
58
+
59
+	/**
60
+	 * cached result from method of the same name
61
+	 *
62
+	 * @var float $_ticket_total_with_taxes
63
+	 */
64
+	private $_ticket_total_with_taxes;
65
+
66
+
67
+	/**
68
+	 * @param array  $props_n_values          incoming values
69
+	 * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
70
+	 *                                        used.)
71
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
72
+	 *                                        date_format and the second value is the time format
73
+	 * @return EE_Ticket
74
+	 * @throws EE_Error
75
+	 * @throws ReflectionException
76
+	 */
77
+	public static function new_instance($props_n_values = [], $timezone = '', $date_formats = [])
78
+	{
79
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
80
+		return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
81
+	}
82
+
83
+
84
+	/**
85
+	 * @param array  $props_n_values  incoming values from the database
86
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
87
+	 *                                the website will be used.
88
+	 * @return EE_Ticket
89
+	 * @throws EE_Error
90
+	 * @throws ReflectionException
91
+	 */
92
+	public static function new_instance_from_db($props_n_values = [], $timezone = '')
93
+	{
94
+		return new self($props_n_values, true, $timezone);
95
+	}
96
+
97
+
98
+	/**
99
+	 * @return bool
100
+	 * @throws EE_Error
101
+	 * @throws ReflectionException
102
+	 */
103
+	public function parent()
104
+	{
105
+		return $this->get('TKT_parent');
106
+	}
107
+
108
+
109
+	/**
110
+	 * return if a ticket has quantities available for purchase
111
+	 *
112
+	 * @param int $DTT_ID the primary key for a particular datetime
113
+	 * @return boolean
114
+	 * @throws EE_Error
115
+	 * @throws ReflectionException
116
+	 */
117
+	public function available($DTT_ID = 0)
118
+	{
119
+		// are we checking availability for a particular datetime ?
120
+		if ($DTT_ID) {
121
+			// get that datetime object
122
+			$datetime = $this->get_first_related('Datetime', [['DTT_ID' => $DTT_ID]]);
123
+			// if  ticket sales for this datetime have exceeded the reg limit...
124
+			if ($datetime instanceof EE_Datetime && $datetime->sold_out()) {
125
+				return false;
126
+			}
127
+		}
128
+		// datetime is still open for registration, but is this ticket sold out ?
129
+		return $this->qty() < 1 || $this->qty() > $this->sold();
130
+	}
131
+
132
+
133
+	/**
134
+	 * Using the start date and end date this method calculates whether the ticket is On Sale, Pending, or Expired
135
+	 *
136
+	 * @param bool        $display   true = we'll return a localized string, otherwise we just return the value of the
137
+	 *                               relevant status const
138
+	 * @param bool | null $remaining if it is already known that tickets are available, then simply pass a bool to save
139
+	 *                               further processing
140
+	 * @return mixed status int if the display string isn't requested
141
+	 * @throws EE_Error
142
+	 * @throws ReflectionException
143
+	 */
144
+	public function ticket_status($display = false, $remaining = null)
145
+	{
146
+		$remaining = is_bool($remaining) ? $remaining : $this->is_remaining();
147
+		if (! $remaining) {
148
+			return $display ? EEH_Template::pretty_status(EE_Ticket::sold_out, false, 'sentence') : EE_Ticket::sold_out;
149
+		}
150
+		if ($this->get('TKT_deleted')) {
151
+			return $display ? EEH_Template::pretty_status(EE_Ticket::archived, false, 'sentence') : EE_Ticket::archived;
152
+		}
153
+		if ($this->is_expired()) {
154
+			return $display ? EEH_Template::pretty_status(EE_Ticket::expired, false, 'sentence') : EE_Ticket::expired;
155
+		}
156
+		if ($this->is_pending()) {
157
+			return $display ? EEH_Template::pretty_status(EE_Ticket::pending, false, 'sentence') : EE_Ticket::pending;
158
+		}
159
+		if ($this->is_on_sale()) {
160
+			return $display ? EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence') : EE_Ticket::onsale;
161
+		}
162
+		return '';
163
+	}
164
+
165
+
166
+	/**
167
+	 * The purpose of this method is to simply return a boolean for whether there are any tickets remaining for sale
168
+	 * considering ALL the factors used for figuring that out.
169
+	 *
170
+	 * @access public
171
+	 * @param int $DTT_ID if an int above 0 is included here then we get a specific dtt.
172
+	 * @return boolean         true = tickets remaining, false not.
173
+	 * @throws EE_Error
174
+	 * @throws ReflectionException
175
+	 */
176
+	public function is_remaining($DTT_ID = 0)
177
+	{
178
+		$num_remaining = $this->remaining($DTT_ID);
179
+		if ($num_remaining === 0) {
180
+			return false;
181
+		}
182
+		if ($num_remaining > 0 && $num_remaining < $this->min()) {
183
+			return false;
184
+		}
185
+		return true;
186
+	}
187
+
188
+
189
+	/**
190
+	 * return the total number of tickets available for purchase
191
+	 *
192
+	 * @param int $DTT_ID  the primary key for a particular datetime.
193
+	 *                     set to 0 for all related datetimes
194
+	 * @return int
195
+	 * @throws EE_Error
196
+	 * @throws ReflectionException
197
+	 */
198
+	public function remaining($DTT_ID = 0)
199
+	{
200
+		return $this->real_quantity_on_ticket('saleable', $DTT_ID);
201
+	}
202
+
203
+
204
+	/**
205
+	 * Gets min
206
+	 *
207
+	 * @return int
208
+	 * @throws EE_Error
209
+	 * @throws ReflectionException
210
+	 */
211
+	public function min()
212
+	{
213
+		return $this->get('TKT_min');
214
+	}
215
+
216
+
217
+	/**
218
+	 * return if a ticket is no longer available cause its available dates have expired.
219
+	 *
220
+	 * @return boolean
221
+	 * @throws EE_Error
222
+	 * @throws ReflectionException
223
+	 */
224
+	public function is_expired()
225
+	{
226
+		return ($this->get_raw('TKT_end_date') < time());
227
+	}
228
+
229
+
230
+	/**
231
+	 * Return if a ticket is yet to go on sale or not
232
+	 *
233
+	 * @return boolean
234
+	 * @throws EE_Error
235
+	 * @throws ReflectionException
236
+	 */
237
+	public function is_pending()
238
+	{
239
+		return ($this->get_raw('TKT_start_date') >= time());
240
+	}
241
+
242
+
243
+	/**
244
+	 * Return if a ticket is on sale or not
245
+	 *
246
+	 * @return boolean
247
+	 * @throws EE_Error
248
+	 * @throws ReflectionException
249
+	 */
250
+	public function is_on_sale()
251
+	{
252
+		return ($this->get_raw('TKT_start_date') <= time() && $this->get_raw('TKT_end_date') >= time());
253
+	}
254
+
255
+
256
+	/**
257
+	 * This returns the chronologically last datetime that this ticket is associated with
258
+	 *
259
+	 * @param string $date_format
260
+	 * @param string $conjunction - conjunction junction what's your function ? this string joins the start date with
261
+	 *                            the end date ie: Jan 01 "to" Dec 31
262
+	 * @return string
263
+	 * @throws EE_Error
264
+	 * @throws ReflectionException
265
+	 */
266
+	public function date_range($date_format = '', $conjunction = ' - ')
267
+	{
268
+		$date_format = ! empty($date_format) ? $date_format : $this->_dt_frmt;
269
+		$first_date  = $this->first_datetime() instanceof EE_Datetime
270
+			? $this->first_datetime()->get_i18n_datetime('DTT_EVT_start', $date_format)
271
+			: '';
272
+		$last_date   = $this->last_datetime() instanceof EE_Datetime
273
+			? $this->last_datetime()->get_i18n_datetime('DTT_EVT_end', $date_format)
274
+			: '';
275
+
276
+		return $first_date && $last_date ? $first_date . $conjunction . $last_date : '';
277
+	}
278
+
279
+
280
+	/**
281
+	 * This returns the chronologically first datetime that this ticket is associated with
282
+	 *
283
+	 * @return EE_Datetime
284
+	 * @throws EE_Error
285
+	 * @throws ReflectionException
286
+	 */
287
+	public function first_datetime()
288
+	{
289
+		$datetimes = $this->datetimes(['limit' => 1]);
290
+		return reset($datetimes);
291
+	}
292
+
293
+
294
+	/**
295
+	 * Gets all the datetimes this ticket can be used for attending.
296
+	 * Unless otherwise specified, orders datetimes by start date.
297
+	 *
298
+	 * @param array $query_params @see
299
+	 *                            https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
300
+	 * @return EE_Datetime[]|EE_Base_Class[]
301
+	 * @throws EE_Error
302
+	 * @throws ReflectionException
303
+	 */
304
+	public function datetimes($query_params = [])
305
+	{
306
+		if (! isset($query_params['order_by'])) {
307
+			$query_params['order_by']['DTT_order'] = 'ASC';
308
+		}
309
+		return $this->get_many_related('Datetime', $query_params);
310
+	}
311
+
312
+
313
+	/**
314
+	 * This returns the chronologically last datetime that this ticket is associated with
315
+	 *
316
+	 * @return EE_Datetime
317
+	 * @throws EE_Error
318
+	 * @throws ReflectionException
319
+	 */
320
+	public function last_datetime()
321
+	{
322
+		$datetimes = $this->datetimes(['limit' => 1, 'order_by' => ['DTT_EVT_start' => 'DESC']]);
323
+		return end($datetimes);
324
+	}
325
+
326
+
327
+	/**
328
+	 * This returns the total tickets sold depending on the given parameters.
329
+	 *
330
+	 * @param string $what    Can be one of two options: 'ticket', 'datetime'.
331
+	 *                        'ticket' = total ticket sales for all datetimes this ticket is related to
332
+	 *                        'datetime' = total ticket sales for a specified datetime (required $dtt_id)
333
+	 *                        'datetime' = total ticket sales in the datetime_ticket table.
334
+	 *                        If $dtt_id is not given then we return an array of sales indexed by datetime.
335
+	 *                        If $dtt_id IS given then we return the tickets sold for that given datetime.
336
+	 * @param int    $dtt_id  [optional] include the dtt_id with $what = 'datetime'.
337
+	 * @return mixed (array|int)          how many tickets have sold
338
+	 * @throws EE_Error
339
+	 * @throws ReflectionException
340
+	 */
341
+	public function tickets_sold($what = 'ticket', $dtt_id = null)
342
+	{
343
+		$total        = 0;
344
+		$tickets_sold = $this->_all_tickets_sold();
345
+		switch ($what) {
346
+			case 'ticket':
347
+				return $tickets_sold['ticket'];
348
+				break;
349
+			case 'datetime':
350
+				if (empty($tickets_sold['datetime'])) {
351
+					return $total;
352
+				}
353
+				if (! empty($dtt_id) && ! isset($tickets_sold['datetime'][ $dtt_id ])) {
354
+					EE_Error::add_error(
355
+						__(
356
+							'You\'ve requested the amount of tickets sold for a given ticket and datetime, however there are no records for the datetime id you included.  Are you SURE that is a datetime related to this ticket?',
357
+							'event_espresso'
358
+						),
359
+						__FILE__,
360
+						__FUNCTION__,
361
+						__LINE__
362
+					);
363
+					return $total;
364
+				}
365
+				return empty($dtt_id) ? $tickets_sold['datetime'] : $tickets_sold['datetime'][ $dtt_id ];
366
+				break;
367
+			default:
368
+				return $total;
369
+		}
370
+	}
371
+
372
+
373
+	/**
374
+	 * This returns an array indexed by datetime_id for tickets sold with this ticket.
375
+	 *
376
+	 * @return EE_Ticket[]
377
+	 * @throws EE_Error
378
+	 * @throws ReflectionException
379
+	 */
380
+	protected function _all_tickets_sold()
381
+	{
382
+		$datetimes    = $this->get_many_related('Datetime');
383
+		$tickets_sold = [];
384
+		if (! empty($datetimes)) {
385
+			foreach ($datetimes as $datetime) {
386
+				$tickets_sold['datetime'][ $datetime->ID() ] = $datetime->get('DTT_sold');
387
+			}
388
+		}
389
+		// Tickets sold
390
+		$tickets_sold['ticket'] = $this->sold();
391
+		return $tickets_sold;
392
+	}
393
+
394
+
395
+	/**
396
+	 * This returns the base price object for the ticket.
397
+	 *
398
+	 * @param bool $return_array whether to return as an array indexed by price id or just the object.
399
+	 * @return EE_Price|EE_Base_Class|EE_Price[]|EE_Base_Class[]
400
+	 * @throws EE_Error
401
+	 * @throws ReflectionException
402
+	 */
403
+	public function base_price($return_array = false)
404
+	{
405
+		$_where = ['Price_Type.PBT_ID' => EEM_Price_Type::base_type_base_price];
406
+		return $return_array
407
+			? $this->get_many_related('Price', [$_where])
408
+			: $this->get_first_related('Price', [$_where]);
409
+	}
410
+
411
+
412
+	/**
413
+	 * This returns ONLY the price modifiers for the ticket (i.e. no taxes or base price)
414
+	 *
415
+	 * @access public
416
+	 * @return EE_Price[]
417
+	 * @throws EE_Error
418
+	 * @throws ReflectionException
419
+	 */
420
+	public function price_modifiers()
421
+	{
422
+		$query_params = [
423
+			0 => [
424
+				'Price_Type.PBT_ID' => [
425
+					'NOT IN',
426
+					[EEM_Price_Type::base_type_base_price, EEM_Price_Type::base_type_tax],
427
+				],
428
+			],
429
+		];
430
+		return $this->prices($query_params);
431
+	}
432
+
433
+
434
+	/**
435
+	 * This returns ONLY the price modifiers for the ticket (i.e. no taxes or base price)
436
+	 *
437
+	 * @access public
438
+	 * @return EE_Price[]
439
+	 * @throws EE_Error
440
+	 * @throws ReflectionException
441
+	 */
442
+	public function tax_price_modifiers()
443
+	{
444
+		$query_params = [
445
+			0 => [
446
+				'Price_Type.PBT_ID' => EEM_Price_Type::base_type_tax,
447
+			],
448
+		];
449
+		return $this->prices($query_params);
450
+	}
451
+
452
+
453
+	/**
454
+	 * Gets all the prices that combine to form the final price of this ticket
455
+	 *
456
+	 * @param array $query_params @see
457
+	 *                            https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
458
+	 * @return EE_Price[]|EE_Base_Class[]
459
+	 * @throws EE_Error
460
+	 * @throws ReflectionException
461
+	 */
462
+	public function prices($query_params = [])
463
+	{
464
+		return $this->get_many_related('Price', $query_params);
465
+	}
466
+
467
+
468
+	/**
469
+	 * Gets all the ticket datetimes (ie, relations between datetimes and tickets)
470
+	 *
471
+	 * @param array $query_params @see
472
+	 *                            https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
473
+	 * @return EE_Datetime_Ticket|EE_Base_Class[]
474
+	 * @throws EE_Error
475
+	 * @throws ReflectionException
476
+	 */
477
+	public function datetime_tickets($query_params = [])
478
+	{
479
+		return $this->get_many_related('Datetime_Ticket', $query_params);
480
+	}
481
+
482
+
483
+	/**
484
+	 * Gets all the datetimes from the db ordered by DTT_order
485
+	 *
486
+	 * @param boolean $show_expired
487
+	 * @param boolean $show_deleted
488
+	 * @return EE_Datetime[]
489
+	 * @throws EE_Error
490
+	 * @throws ReflectionException
491
+	 */
492
+	public function datetimes_ordered($show_expired = true, $show_deleted = false)
493
+	{
494
+		return EEM_Datetime::instance($this->_timezone)->get_datetimes_for_ticket_ordered_by_DTT_order(
495
+			$this->ID(),
496
+			$show_expired,
497
+			$show_deleted
498
+		);
499
+	}
500
+
501
+
502
+	/**
503
+	 * Gets ID
504
+	 *
505
+	 * @return string
506
+	 * @throws EE_Error
507
+	 * @throws ReflectionException
508
+	 */
509
+	public function ID()
510
+	{
511
+		return $this->get('TKT_ID');
512
+	}
513
+
514
+
515
+	/**
516
+	 * get the author of the ticket.
517
+	 *
518
+	 * @return int
519
+	 * @throws EE_Error
520
+	 * @throws ReflectionException
521
+	 * @since 4.5.0
522
+	 */
523
+	public function wp_user()
524
+	{
525
+		return $this->get('TKT_wp_user');
526
+	}
527
+
528
+
529
+	/**
530
+	 * Gets the template for the ticket
531
+	 *
532
+	 * @return EE_Ticket_Template|EE_Base_Class
533
+	 * @throws EE_Error
534
+	 * @throws ReflectionException
535
+	 */
536
+	public function template()
537
+	{
538
+		return $this->get_first_related('Ticket_Template');
539
+	}
540
+
541
+
542
+	/**
543
+	 * Simply returns an array of EE_Price objects that are taxes.
544
+	 *
545
+	 * @return EE_Price[]
546
+	 * @throws EE_Error
547
+	 */
548
+	public function get_ticket_taxes_for_admin()
549
+	{
550
+		return EE_Taxes::get_taxes_for_admin();
551
+	}
552
+
553
+
554
+	/**
555
+	 * @return float
556
+	 * @throws EE_Error
557
+	 * @throws ReflectionException
558
+	 */
559
+	public function ticket_price()
560
+	{
561
+		return $this->get('TKT_price');
562
+	}
563
+
564
+
565
+	/**
566
+	 * @return mixed
567
+	 * @throws EE_Error
568
+	 * @throws ReflectionException
569
+	 */
570
+	public function pretty_price()
571
+	{
572
+		return $this->get_pretty('TKT_price');
573
+	}
574
+
575
+
576
+	/**
577
+	 * @return bool
578
+	 * @throws EE_Error
579
+	 * @throws ReflectionException
580
+	 */
581
+	public function is_free()
582
+	{
583
+		return $this->get_ticket_total_with_taxes() === (float) 0;
584
+	}
585
+
586
+
587
+	/**
588
+	 * get_ticket_total_with_taxes
589
+	 *
590
+	 * @param bool $no_cache
591
+	 * @return float
592
+	 * @throws EE_Error
593
+	 * @throws ReflectionException
594
+	 */
595
+	public function get_ticket_total_with_taxes($no_cache = false)
596
+	{
597
+		if ($this->_ticket_total_with_taxes === null || $no_cache) {
598
+			$this->_ticket_total_with_taxes = $this->get_ticket_subtotal() + $this->get_ticket_taxes_total_for_admin();
599
+		}
600
+		return (float) $this->_ticket_total_with_taxes;
601
+	}
602
+
603
+
604
+	/**
605
+	 * @throws EE_Error
606
+	 * @throws ReflectionException
607
+	 */
608
+	public function ensure_TKT_Price_correct()
609
+	{
610
+		$this->set('TKT_price', EE_Taxes::get_subtotal_for_admin($this));
611
+		$this->save();
612
+	}
613
+
614
+
615
+	/**
616
+	 * @return float
617
+	 * @throws EE_Error
618
+	 * @throws ReflectionException
619
+	 */
620
+	public function get_ticket_subtotal()
621
+	{
622
+		return EE_Taxes::get_subtotal_for_admin($this);
623
+	}
624
+
625
+
626
+	/**
627
+	 * Returns the total taxes applied to this ticket
628
+	 *
629
+	 * @return float
630
+	 * @throws EE_Error
631
+	 * @throws ReflectionException
632
+	 */
633
+	public function get_ticket_taxes_total_for_admin()
634
+	{
635
+		return EE_Taxes::get_total_taxes_for_admin($this);
636
+	}
637
+
638
+
639
+	/**
640
+	 * Sets name
641
+	 *
642
+	 * @param string $name
643
+	 * @throws EE_Error
644
+	 * @throws ReflectionException
645
+	 */
646
+	public function set_name($name)
647
+	{
648
+		$this->set('TKT_name', $name);
649
+	}
650
+
651
+
652
+	/**
653
+	 * Gets description
654
+	 *
655
+	 * @return string
656
+	 * @throws EE_Error
657
+	 * @throws ReflectionException
658
+	 */
659
+	public function description()
660
+	{
661
+		return $this->get('TKT_description');
662
+	}
663
+
664
+
665
+	/**
666
+	 * Sets description
667
+	 *
668
+	 * @param string $description
669
+	 * @throws EE_Error
670
+	 * @throws ReflectionException
671
+	 */
672
+	public function set_description($description)
673
+	{
674
+		$this->set('TKT_description', $description);
675
+	}
676
+
677
+
678
+	/**
679
+	 * Gets start_date
680
+	 *
681
+	 * @param string $date_format
682
+	 * @param string $time_format
683
+	 * @return string
684
+	 * @throws EE_Error
685
+	 * @throws ReflectionException
686
+	 */
687
+	public function start_date($date_format = '', $time_format = '')
688
+	{
689
+		return $this->_get_datetime('TKT_start_date', $date_format, $time_format);
690
+	}
691
+
692
+
693
+	/**
694
+	 * Sets start_date
695
+	 *
696
+	 * @param string $start_date
697
+	 * @return void
698
+	 * @throws EE_Error
699
+	 * @throws ReflectionException
700
+	 */
701
+	public function set_start_date($start_date)
702
+	{
703
+		$this->_set_date_time('B', $start_date, 'TKT_start_date');
704
+	}
705
+
706
+
707
+	/**
708
+	 * Gets end_date
709
+	 *
710
+	 * @param string $date_format
711
+	 * @param string $time_format
712
+	 * @return string
713
+	 * @throws EE_Error
714
+	 * @throws ReflectionException
715
+	 */
716
+	public function end_date($date_format = '', $time_format = '')
717
+	{
718
+		return $this->_get_datetime('TKT_end_date', $date_format, $time_format);
719
+	}
720
+
721
+
722
+	/**
723
+	 * Sets end_date
724
+	 *
725
+	 * @param string $end_date
726
+	 * @return void
727
+	 * @throws EE_Error
728
+	 * @throws ReflectionException
729
+	 */
730
+	public function set_end_date($end_date)
731
+	{
732
+		$this->_set_date_time('B', $end_date, 'TKT_end_date');
733
+	}
734
+
735
+
736
+	/**
737
+	 * Sets sell until time
738
+	 *
739
+	 * @param string $time a string representation of the sell until time (ex 9am or 7:30pm)
740
+	 * @throws EE_Error
741
+	 * @throws ReflectionException
742
+	 * @since 4.5.0
743
+	 */
744
+	public function set_end_time($time)
745
+	{
746
+		$this->_set_time_for($time, 'TKT_end_date');
747
+	}
748
+
749
+
750
+	/**
751
+	 * Sets min
752
+	 *
753
+	 * @param int $min
754
+	 * @return void
755
+	 * @throws EE_Error
756
+	 * @throws ReflectionException
757
+	 */
758
+	public function set_min($min)
759
+	{
760
+		$this->set('TKT_min', $min);
761
+	}
762
+
763
+
764
+	/**
765
+	 * Gets max
766
+	 *
767
+	 * @return int
768
+	 * @throws EE_Error
769
+	 * @throws ReflectionException
770
+	 */
771
+	public function max()
772
+	{
773
+		return $this->get('TKT_max');
774
+	}
775
+
776
+
777
+	/**
778
+	 * Sets max
779
+	 *
780
+	 * @param int $max
781
+	 * @return void
782
+	 * @throws EE_Error
783
+	 * @throws ReflectionException
784
+	 */
785
+	public function set_max($max)
786
+	{
787
+		$this->set('TKT_max', $max);
788
+	}
789
+
790
+
791
+	/**
792
+	 * Sets price
793
+	 *
794
+	 * @param float $price
795
+	 * @return void
796
+	 * @throws EE_Error
797
+	 * @throws ReflectionException
798
+	 */
799
+	public function set_price($price)
800
+	{
801
+		$this->set('TKT_price', $price);
802
+	}
803
+
804
+
805
+	/**
806
+	 * Gets sold
807
+	 *
808
+	 * @return int
809
+	 * @throws EE_Error
810
+	 * @throws ReflectionException
811
+	 */
812
+	public function sold()
813
+	{
814
+		return $this->get_raw('TKT_sold');
815
+	}
816
+
817
+
818
+	/**
819
+	 * Sets sold
820
+	 *
821
+	 * @param int $sold
822
+	 * @return void
823
+	 * @throws EE_Error
824
+	 * @throws ReflectionException
825
+	 */
826
+	public function set_sold($sold)
827
+	{
828
+		// sold can not go below zero
829
+		$sold = max(0, $sold);
830
+		$this->set('TKT_sold', $sold);
831
+	}
832
+
833
+
834
+	/**
835
+	 * Increments sold by amount passed by $qty AND decrements the reserved count on both this ticket and its
836
+	 * associated datetimes.
837
+	 *
838
+	 * @param int $qty
839
+	 * @return boolean
840
+	 * @throws EE_Error
841
+	 * @throws InvalidArgumentException
842
+	 * @throws InvalidDataTypeException
843
+	 * @throws InvalidInterfaceException
844
+	 * @throws ReflectionException
845
+	 * @since 4.9.80.p
846
+	 */
847
+	public function increaseSold($qty = 1)
848
+	{
849
+		$qty = absint($qty);
850
+		// increment sold and decrement reserved datetime quantities simultaneously
851
+		// don't worry about failures, because they must have already had a spot reserved
852
+		$this->increaseSoldForDatetimes($qty);
853
+		// Increment and decrement ticket quantities simultaneously
854
+		$success = $this->adjustNumericFieldsInDb(
855
+			[
856
+				'TKT_reserved' => $qty * -1,
857
+				'TKT_sold'     => $qty,
858
+			]
859
+		);
860
+		do_action(
861
+			'AHEE__EE_Ticket__increase_sold',
862
+			$this,
863
+			$qty,
864
+			$this->sold(),
865
+			$success
866
+		);
867
+		return $success;
868
+	}
869
+
870
+
871
+	/**
872
+	 * On each datetime related to this ticket, increases its sold count and decreases its reserved count by $qty.
873
+	 *
874
+	 * @param int           $qty positive or negative. Positive means to increase sold counts (and decrease reserved
875
+	 *                           counts), Negative means to decreases old counts (and increase reserved counts).
876
+	 * @param EE_Datetime[] $datetimes
877
+	 * @throws EE_Error
878
+	 * @throws InvalidArgumentException
879
+	 * @throws InvalidDataTypeException
880
+	 * @throws InvalidInterfaceException
881
+	 * @throws ReflectionException
882
+	 * @since 4.9.80.p
883
+	 */
884
+	protected function increaseSoldForDatetimes($qty, array $datetimes = [])
885
+	{
886
+		$datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
887
+		foreach ($datetimes as $datetime) {
888
+			$datetime->increaseSold($qty);
889
+		}
890
+	}
891
+
892
+
893
+	/**
894
+	 * Decrements (subtracts) sold by amount passed by $qty on both the ticket and its related datetimes directly in the
895
+	 * DB and then updates the model objects.
896
+	 * Does not affect the reserved counts.
897
+	 *
898
+	 * @param int $qty
899
+	 * @return boolean
900
+	 * @throws EE_Error
901
+	 * @throws InvalidArgumentException
902
+	 * @throws InvalidDataTypeException
903
+	 * @throws InvalidInterfaceException
904
+	 * @throws ReflectionException
905
+	 * @since 4.9.80.p
906
+	 */
907
+	public function decreaseSold($qty = 1)
908
+	{
909
+		$qty = absint($qty);
910
+		$this->decreaseSoldForDatetimes($qty);
911
+		$success = $this->adjustNumericFieldsInDb(
912
+			[
913
+				'TKT_sold' => $qty * -1,
914
+			]
915
+		);
916
+		do_action(
917
+			'AHEE__EE_Ticket__decrease_sold',
918
+			$this,
919
+			$qty,
920
+			$this->sold(),
921
+			$success
922
+		);
923
+		return $success;
924
+	}
925
+
926
+
927
+	/**
928
+	 * Decreases sold on related datetimes
929
+	 *
930
+	 * @param int           $qty
931
+	 * @param EE_Datetime[] $datetimes
932
+	 * @return void
933
+	 * @throws EE_Error
934
+	 * @throws InvalidArgumentException
935
+	 * @throws InvalidDataTypeException
936
+	 * @throws InvalidInterfaceException
937
+	 * @throws ReflectionException
938
+	 * @since 4.9.80.p
939
+	 */
940
+	protected function decreaseSoldForDatetimes($qty = 1, array $datetimes = [])
941
+	{
942
+		$datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
943
+		if (is_array($datetimes)) {
944
+			foreach ($datetimes as $datetime) {
945
+				if ($datetime instanceof EE_Datetime) {
946
+					$datetime->decreaseSold($qty);
947
+				}
948
+			}
949
+		}
950
+	}
951
+
952
+
953
+	/**
954
+	 * Gets qty of reserved tickets
955
+	 *
956
+	 * @return int
957
+	 * @throws EE_Error
958
+	 * @throws ReflectionException
959
+	 */
960
+	public function reserved()
961
+	{
962
+		return $this->get_raw('TKT_reserved');
963
+	}
964
+
965
+
966
+	/**
967
+	 * Sets reserved
968
+	 *
969
+	 * @param int $reserved
970
+	 * @return void
971
+	 * @throws EE_Error
972
+	 * @throws ReflectionException
973
+	 */
974
+	public function set_reserved($reserved)
975
+	{
976
+		// reserved can not go below zero
977
+		$reserved = max(0, (int) $reserved);
978
+		$this->set('TKT_reserved', $reserved);
979
+	}
980
+
981
+
982
+	/**
983
+	 * Increments reserved by amount passed by $qty, and persists it immediately to the database.
984
+	 *
985
+	 * @param int    $qty
986
+	 * @param string $source
987
+	 * @return bool whether we successfully reserved the ticket or not.
988
+	 * @throws EE_Error
989
+	 * @throws InvalidArgumentException
990
+	 * @throws ReflectionException
991
+	 * @throws InvalidDataTypeException
992
+	 * @throws InvalidInterfaceException
993
+	 * @since 4.9.80.p
994
+	 */
995
+	public function increaseReserved($qty = 1, $source = 'unknown')
996
+	{
997
+		$qty = absint($qty);
998
+		do_action(
999
+			'AHEE__EE_Ticket__increase_reserved__begin',
1000
+			$this,
1001
+			$qty,
1002
+			$source
1003
+		);
1004
+		$this->add_extra_meta(EE_Ticket::META_KEY_TICKET_RESERVATIONS, "{$qty} from {$source}");
1005
+		$success                         = false;
1006
+		$datetimes_adjusted_successfully = $this->increaseReservedForDatetimes($qty);
1007
+		if ($datetimes_adjusted_successfully) {
1008
+			$success = $this->incrementFieldConditionallyInDb(
1009
+				'TKT_reserved',
1010
+				'TKT_sold',
1011
+				'TKT_qty',
1012
+				$qty
1013
+			);
1014
+			if (! $success) {
1015
+				// The datetimes were successfully bumped, but not the
1016
+				// ticket. So we need to manually rollback the datetimes.
1017
+				$this->decreaseReservedForDatetimes($qty);
1018
+			}
1019
+		}
1020
+		do_action(
1021
+			'AHEE__EE_Ticket__increase_reserved',
1022
+			$this,
1023
+			$qty,
1024
+			$this->reserved(),
1025
+			$success
1026
+		);
1027
+		return $success;
1028
+	}
1029
+
1030
+
1031
+	/**
1032
+	 * Increases reserved counts on related datetimes
1033
+	 *
1034
+	 * @param int           $qty
1035
+	 * @param EE_Datetime[] $datetimes
1036
+	 * @return boolean indicating success
1037
+	 * @throws EE_Error
1038
+	 * @throws InvalidArgumentException
1039
+	 * @throws InvalidDataTypeException
1040
+	 * @throws InvalidInterfaceException
1041
+	 * @throws ReflectionException
1042
+	 * @since 4.9.80.p
1043
+	 */
1044
+	protected function increaseReservedForDatetimes($qty = 1, array $datetimes = [])
1045
+	{
1046
+		$datetimes         = ! empty($datetimes) ? $datetimes : $this->datetimes();
1047
+		$datetimes_updated = [];
1048
+		$limit_exceeded    = false;
1049
+		if (is_array($datetimes)) {
1050
+			foreach ($datetimes as $datetime) {
1051
+				if ($datetime instanceof EE_Datetime) {
1052
+					if ($datetime->increaseReserved($qty)) {
1053
+						$datetimes_updated[] = $datetime;
1054
+					} else {
1055
+						$limit_exceeded = true;
1056
+						break;
1057
+					}
1058
+				}
1059
+			}
1060
+			// If somewhere along the way we detected a datetime whose
1061
+			// limit was exceeded, do a manual rollback.
1062
+			if ($limit_exceeded) {
1063
+				$this->decreaseReservedForDatetimes($qty, $datetimes_updated);
1064
+				return false;
1065
+			}
1066
+		}
1067
+		return true;
1068
+	}
1069
+
1070
+
1071
+	/**
1072
+	 * Decrements (subtracts) reserved by amount passed by $qty, and persists it immediately to the database.
1073
+	 *
1074
+	 * @param int    $qty
1075
+	 * @param bool   $adjust_datetimes
1076
+	 * @param string $source
1077
+	 * @return boolean
1078
+	 * @throws EE_Error
1079
+	 * @throws InvalidArgumentException
1080
+	 * @throws ReflectionException
1081
+	 * @throws InvalidDataTypeException
1082
+	 * @throws InvalidInterfaceException
1083
+	 * @since 4.9.80.p
1084
+	 */
1085
+	public function decreaseReserved($qty = 1, $adjust_datetimes = true, $source = 'unknown')
1086
+	{
1087
+		$qty = absint($qty);
1088
+		$this->add_extra_meta(EE_Ticket::META_KEY_TICKET_RESERVATIONS, "-{$qty} from {$source}");
1089
+		if ($adjust_datetimes) {
1090
+			$this->decreaseReservedForDatetimes($qty);
1091
+		}
1092
+		$success = $this->adjustNumericFieldsInDb(
1093
+			[
1094
+				'TKT_reserved' => $qty * -1,
1095
+			]
1096
+		);
1097
+		do_action(
1098
+			'AHEE__EE_Ticket__decrease_reserved',
1099
+			$this,
1100
+			$qty,
1101
+			$this->reserved(),
1102
+			$success
1103
+		);
1104
+		return $success;
1105
+	}
1106
+
1107
+
1108
+	/**
1109
+	 * Decreases the reserved count on the specified datetimes.
1110
+	 *
1111
+	 * @param int           $qty
1112
+	 * @param EE_Datetime[] $datetimes
1113
+	 * @throws EE_Error
1114
+	 * @throws InvalidArgumentException
1115
+	 * @throws ReflectionException
1116
+	 * @throws InvalidDataTypeException
1117
+	 * @throws InvalidInterfaceException
1118
+	 * @since 4.9.80.p
1119
+	 */
1120
+	protected function decreaseReservedForDatetimes($qty = 1, array $datetimes = [])
1121
+	{
1122
+		$datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
1123
+		foreach ($datetimes as $datetime) {
1124
+			if ($datetime instanceof EE_Datetime) {
1125
+				$datetime->decreaseReserved($qty);
1126
+			}
1127
+		}
1128
+	}
1129
+
1130
+
1131
+	/**
1132
+	 * Gets ticket quantity
1133
+	 *
1134
+	 * @param string $context     ticket quantity is somewhat subjective depending on the exact information sought
1135
+	 *                            therefore $context can be one of three values: '', 'reg_limit', or 'saleable'
1136
+	 *                            '' (default) quantity is the actual db value for TKT_qty, unaffected by other objects
1137
+	 *                            REG LIMIT: caps qty based on DTT_reg_limit for ALL related datetimes
1138
+	 *                            SALEABLE: also considers datetime sold and returns zero if ANY DTT is sold out, and
1139
+	 *                            is therefore the truest measure of tickets that can be purchased at the moment
1140
+	 * @return int
1141
+	 * @throws EE_Error
1142
+	 * @throws ReflectionException
1143
+	 */
1144
+	public function qty($context = '')
1145
+	{
1146
+		switch ($context) {
1147
+			case 'reg_limit':
1148
+				return $this->real_quantity_on_ticket();
1149
+			case 'saleable':
1150
+				return $this->real_quantity_on_ticket('saleable');
1151
+			default:
1152
+				return $this->get_raw('TKT_qty');
1153
+		}
1154
+	}
1155
+
1156
+
1157
+	/**
1158
+	 * Gets ticket quantity
1159
+	 *
1160
+	 * @param string $context     ticket quantity is somewhat subjective depending on the exact information sought
1161
+	 *                            therefore $context can be one of two values: 'reg_limit', or 'saleable'
1162
+	 *                            REG LIMIT: caps qty based on DTT_reg_limit for ALL related datetimes
1163
+	 *                            SALEABLE: also considers datetime sold and returns zero if ANY DTT is sold out, and
1164
+	 *                            is therefore the truest measure of tickets that can be purchased at the moment
1165
+	 * @param int    $DTT_ID      the primary key for a particular datetime.
1166
+	 *                            set to 0 for all related datetimes
1167
+	 * @return int
1168
+	 * @throws EE_Error
1169
+	 * @throws ReflectionException
1170
+	 */
1171
+	public function real_quantity_on_ticket($context = 'reg_limit', $DTT_ID = 0)
1172
+	{
1173
+		$raw = $this->get_raw('TKT_qty');
1174
+		// return immediately if it's zero
1175
+		if ($raw === 0) {
1176
+			return $raw;
1177
+		}
1178
+		// echo "\n\n<br />Ticket: " . $this->name() . '<br />';
1179
+		// ensure qty doesn't exceed raw value for THIS ticket
1180
+		$qty = min(EE_INF, $raw);
1181
+		// echo "\n . qty: " . $qty . '<br />';
1182
+		// calculate this ticket's total sales and reservations
1183
+		$sold_and_reserved_for_this_ticket = $this->sold() + $this->reserved();
1184
+		// echo "\n . sold: " . $this->sold() . '<br />';
1185
+		// echo "\n . reserved: " . $this->reserved() . '<br />';
1186
+		// echo "\n . sold_and_reserved_for_this_ticket: " . $sold_and_reserved_for_this_ticket . '<br />';
1187
+		// first we need to calculate the maximum number of tickets available for the datetime
1188
+		// do we want data for one datetime or all of them ?
1189
+		$query_params = $DTT_ID ? [['DTT_ID' => $DTT_ID]] : [];
1190
+		$datetimes    = $this->datetimes($query_params);
1191
+		if (is_array($datetimes) && ! empty($datetimes)) {
1192
+			foreach ($datetimes as $datetime) {
1193
+				if ($datetime instanceof EE_Datetime) {
1194
+					$datetime->refresh_from_db();
1195
+					// echo "\n . . datetime name: " . $datetime->name() . '<br />';
1196
+					// echo "\n . . datetime ID: " . $datetime->ID() . '<br />';
1197
+					// initialize with no restrictions for each datetime
1198
+					// but adjust datetime qty based on datetime reg limit
1199
+					$datetime_qty = min(EE_INF, $datetime->reg_limit());
1200
+					// echo "\n . . . datetime reg_limit: " . $datetime->reg_limit() . '<br />';
1201
+					// echo "\n . . . datetime_qty: " . $datetime_qty . '<br />';
1202
+					// if we want the actual saleable amount, then we need to consider OTHER ticket sales
1203
+					// and reservations for this datetime, that do NOT include sales and reservations
1204
+					// for this ticket (so we add $this->sold() and $this->reserved() back in)
1205
+					if ($context === 'saleable') {
1206
+						$datetime_qty = max(
1207
+							$datetime_qty - $datetime->sold_and_reserved() + $sold_and_reserved_for_this_ticket,
1208
+							0
1209
+						);
1210
+						// echo "\n . . . datetime sold: " . $datetime->sold() . '<br />';
1211
+						// echo "\n . . . datetime reserved: " . $datetime->reserved() . '<br />';
1212
+						// echo "\n . . . datetime sold_and_reserved: " . $datetime->sold_and_reserved() . '<br />';
1213
+						// echo "\n . . . datetime_qty: " . $datetime_qty . '<br />';
1214
+						$datetime_qty = ! $datetime->sold_out() ? $datetime_qty : 0;
1215
+						// echo "\n . . . datetime_qty: " . $datetime_qty . '<br />';
1216
+					}
1217
+					$qty = min($datetime_qty, $qty);
1218
+					// echo "\n . . qty: " . $qty . '<br />';
1219
+				}
1220
+			}
1221
+		}
1222
+		// NOW that we know the  maximum number of tickets available for the datetime
1223
+		// we can finally factor in the details for this specific ticket
1224
+		if ($qty > 0 && $context === 'saleable') {
1225
+			// and subtract the sales for THIS ticket
1226
+			$qty = max($qty - $sold_and_reserved_for_this_ticket, 0);
1227
+			// echo "\n . qty: " . $qty . '<br />';
1228
+		}
1229
+		// echo "\nFINAL QTY: " . $qty . "<br /><br />";
1230
+		return $qty;
1231
+	}
1232
+
1233
+
1234
+	/**
1235
+	 * Sets qty - IMPORTANT!!! Does NOT allow QTY to be set higher than the lowest reg limit of any related datetimes
1236
+	 *
1237
+	 * @param int $qty
1238
+	 * @return void
1239
+	 * @throws EE_Error
1240
+	 * @throws ReflectionException
1241
+	 */
1242
+	public function set_qty($qty)
1243
+	{
1244
+		$datetimes = $this->datetimes();
1245
+		foreach ($datetimes as $datetime) {
1246
+			if ($datetime instanceof EE_Datetime) {
1247
+				$qty = min($qty, $datetime->reg_limit());
1248
+			}
1249
+		}
1250
+		$this->set('TKT_qty', $qty);
1251
+	}
1252
+
1253
+
1254
+	/**
1255
+	 * Gets uses
1256
+	 *
1257
+	 * @return int
1258
+	 * @throws EE_Error
1259
+	 * @throws ReflectionException
1260
+	 */
1261
+	public function uses()
1262
+	{
1263
+		return $this->get('TKT_uses');
1264
+	}
1265
+
1266
+
1267
+	/**
1268
+	 * Sets uses
1269
+	 *
1270
+	 * @param int $uses
1271
+	 * @return void
1272
+	 * @throws EE_Error
1273
+	 * @throws ReflectionException
1274
+	 */
1275
+	public function set_uses($uses)
1276
+	{
1277
+		$this->set('TKT_uses', $uses);
1278
+	}
1279
+
1280
+
1281
+	/**
1282
+	 * returns whether ticket is required or not.
1283
+	 *
1284
+	 * @return boolean
1285
+	 * @throws EE_Error
1286
+	 * @throws ReflectionException
1287
+	 */
1288
+	public function required()
1289
+	{
1290
+		return $this->get('TKT_required');
1291
+	}
1292
+
1293
+
1294
+	/**
1295
+	 * sets the TKT_required property
1296
+	 *
1297
+	 * @param boolean $required
1298
+	 * @return void
1299
+	 * @throws EE_Error
1300
+	 * @throws ReflectionException
1301
+	 */
1302
+	public function set_required($required)
1303
+	{
1304
+		$this->set('TKT_required', $required);
1305
+	}
1306
+
1307
+
1308
+	/**
1309
+	 * Gets taxable
1310
+	 *
1311
+	 * @return boolean
1312
+	 * @throws EE_Error
1313
+	 * @throws ReflectionException
1314
+	 */
1315
+	public function taxable()
1316
+	{
1317
+		return $this->get('TKT_taxable');
1318
+	}
1319
+
1320
+
1321
+	/**
1322
+	 * Sets taxable
1323
+	 *
1324
+	 * @param boolean $taxable
1325
+	 * @return void
1326
+	 * @throws EE_Error
1327
+	 * @throws ReflectionException
1328
+	 */
1329
+	public function set_taxable($taxable)
1330
+	{
1331
+		$this->set('TKT_taxable', $taxable);
1332
+	}
1333
+
1334
+
1335
+	/**
1336
+	 * Gets is_default
1337
+	 *
1338
+	 * @return boolean
1339
+	 * @throws EE_Error
1340
+	 * @throws ReflectionException
1341
+	 */
1342
+	public function is_default()
1343
+	{
1344
+		return $this->get('TKT_is_default');
1345
+	}
1346
+
1347
+
1348
+	/**
1349
+	 * Sets is_default
1350
+	 *
1351
+	 * @param boolean $is_default
1352
+	 * @return void
1353
+	 * @throws EE_Error
1354
+	 * @throws ReflectionException
1355
+	 */
1356
+	public function set_is_default($is_default)
1357
+	{
1358
+		$this->set('TKT_is_default', $is_default);
1359
+	}
1360
+
1361
+
1362
+	/**
1363
+	 * Gets order
1364
+	 *
1365
+	 * @return int
1366
+	 * @throws EE_Error
1367
+	 * @throws ReflectionException
1368
+	 */
1369
+	public function order()
1370
+	{
1371
+		return $this->get('TKT_order');
1372
+	}
1373
+
1374
+
1375
+	/**
1376
+	 * Sets order
1377
+	 *
1378
+	 * @param int $order
1379
+	 * @return void
1380
+	 * @throws EE_Error
1381
+	 * @throws ReflectionException
1382
+	 */
1383
+	public function set_order($order)
1384
+	{
1385
+		$this->set('TKT_order', $order);
1386
+	}
1387
+
1388
+
1389
+	/**
1390
+	 * Gets row
1391
+	 *
1392
+	 * @return int
1393
+	 * @throws EE_Error
1394
+	 * @throws ReflectionException
1395
+	 */
1396
+	public function row()
1397
+	{
1398
+		return $this->get('TKT_row');
1399
+	}
1400
+
1401
+
1402
+	/**
1403
+	 * Sets row
1404
+	 *
1405
+	 * @param int $row
1406
+	 * @return void
1407
+	 * @throws EE_Error
1408
+	 * @throws ReflectionException
1409
+	 */
1410
+	public function set_row($row)
1411
+	{
1412
+		$this->set('TKT_row', $row);
1413
+	}
1414
+
1415
+
1416
+	/**
1417
+	 * Gets deleted
1418
+	 *
1419
+	 * @return boolean
1420
+	 * @throws EE_Error
1421
+	 * @throws ReflectionException
1422
+	 */
1423
+	public function deleted()
1424
+	{
1425
+		return $this->get('TKT_deleted');
1426
+	}
1427
+
1428
+
1429
+	/**
1430
+	 * Sets deleted
1431
+	 *
1432
+	 * @param boolean $deleted
1433
+	 * @return void
1434
+	 * @throws EE_Error
1435
+	 * @throws ReflectionException
1436
+	 */
1437
+	public function set_deleted($deleted)
1438
+	{
1439
+		$this->set('TKT_deleted', $deleted);
1440
+	}
1441
+
1442
+
1443
+	/**
1444
+	 * Gets parent
1445
+	 *
1446
+	 * @return int
1447
+	 * @throws EE_Error
1448
+	 * @throws ReflectionException
1449
+	 */
1450
+	public function parent_ID()
1451
+	{
1452
+		return $this->get('TKT_parent');
1453
+	}
1454
+
1455
+
1456
+	/**
1457
+	 * Sets parent
1458
+	 *
1459
+	 * @param int $parent
1460
+	 * @return void
1461
+	 * @throws EE_Error
1462
+	 * @throws ReflectionException
1463
+	 */
1464
+	public function set_parent_ID($parent)
1465
+	{
1466
+		$this->set('TKT_parent', $parent);
1467
+	}
1468
+
1469
+
1470
+	/**
1471
+	 * @return boolean
1472
+	 * @throws EE_Error
1473
+	 * @throws InvalidArgumentException
1474
+	 * @throws InvalidDataTypeException
1475
+	 * @throws InvalidInterfaceException
1476
+	 * @throws ReflectionException
1477
+	 */
1478
+	public function reverse_calculate()
1479
+	{
1480
+		return $this->get('TKT_reverse_calculate');
1481
+	}
1482
+
1483
+
1484
+	/**
1485
+	 * @param boolean $reverse_calculate
1486
+	 * @throws EE_Error
1487
+	 * @throws InvalidArgumentException
1488
+	 * @throws InvalidDataTypeException
1489
+	 * @throws InvalidInterfaceException
1490
+	 * @throws ReflectionException
1491
+	 */
1492
+	public function set_reverse_calculate($reverse_calculate)
1493
+	{
1494
+		$this->set('TKT_reverse_calculate', $reverse_calculate);
1495
+	}
1496
+
1497
+
1498
+	/**
1499
+	 * Gets a string which is handy for showing in gateways etc that describes the ticket.
1500
+	 *
1501
+	 * @return string
1502
+	 * @throws EE_Error
1503
+	 * @throws ReflectionException
1504
+	 */
1505
+	public function name_and_info()
1506
+	{
1507
+		$times = [];
1508
+		foreach ($this->datetimes() as $datetime) {
1509
+			$times[] = $datetime->start_date_and_time();
1510
+		}
1511
+		return $this->name() . ' @ ' . implode(', ', $times) . ' for ' . $this->pretty_price();
1512
+	}
1513
+
1514
+
1515
+	/**
1516
+	 * Gets name
1517
+	 *
1518
+	 * @return string
1519
+	 * @throws EE_Error
1520
+	 * @throws ReflectionException
1521
+	 */
1522
+	public function name()
1523
+	{
1524
+		return $this->get('TKT_name');
1525
+	}
1526
+
1527
+
1528
+	/**
1529
+	 * Gets price
1530
+	 *
1531
+	 * @return float
1532
+	 * @throws EE_Error
1533
+	 * @throws ReflectionException
1534
+	 */
1535
+	public function price()
1536
+	{
1537
+		return $this->get('TKT_price');
1538
+	}
1539
+
1540
+
1541
+	/**
1542
+	 * Gets all the registrations for this ticket
1543
+	 *
1544
+	 * @param array $query_params @see
1545
+	 *                            https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1546
+	 * @return EE_Registration[]|EE_Base_Class[]
1547
+	 * @throws EE_Error
1548
+	 * @throws ReflectionException
1549
+	 */
1550
+	public function registrations($query_params = [])
1551
+	{
1552
+		return $this->get_many_related('Registration', $query_params);
1553
+	}
1554
+
1555
+
1556
+	/**
1557
+	 * Updates the TKT_sold attribute (and saves) based on the number of APPROVED registrations for this ticket.
1558
+	 *
1559
+	 * @return int
1560
+	 * @throws EE_Error
1561
+	 * @throws ReflectionException
1562
+	 */
1563
+	public function update_tickets_sold()
1564
+	{
1565
+		$count_regs_for_this_ticket = $this->count_registrations(
1566
+			[
1567
+				[
1568
+					'STS_ID'      => EEM_Registration::status_id_approved,
1569
+					'REG_deleted' => 0,
1570
+				],
1571
+			]
1572
+		);
1573
+		$this->set_sold($count_regs_for_this_ticket);
1574
+		$this->save();
1575
+		return $count_regs_for_this_ticket;
1576
+	}
1577
+
1578
+
1579
+	/**
1580
+	 * Counts the registrations for this ticket
1581
+	 *
1582
+	 * @param array $query_params @see
1583
+	 *                            https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1584
+	 * @return int
1585
+	 * @throws EE_Error
1586
+	 * @throws ReflectionException
1587
+	 */
1588
+	public function count_registrations($query_params = [])
1589
+	{
1590
+		return $this->count_related('Registration', $query_params);
1591
+	}
1592
+
1593
+
1594
+	/**
1595
+	 * Implementation for EEI_Has_Icon interface method.
1596
+	 *
1597
+	 * @return string
1598
+	 * @see EEI_Visual_Representation for comments
1599
+	 */
1600
+	public function get_icon()
1601
+	{
1602
+		return '<span class="dashicons dashicons-tickets-alt"/>';
1603
+	}
1604
+
1605
+
1606
+	/**
1607
+	 * Implementation of the EEI_Event_Relation interface method
1608
+	 *
1609
+	 * @return EE_Event
1610
+	 * @throws EE_Error
1611
+	 * @throws UnexpectedEntityException
1612
+	 * @throws ReflectionException
1613
+	 * @see EEI_Event_Relation for comments
1614
+	 */
1615
+	public function get_related_event()
1616
+	{
1617
+		// get one datetime to use for getting the event
1618
+		$datetime = $this->first_datetime();
1619
+		if (! $datetime instanceof EE_Datetime) {
1620
+			throw new UnexpectedEntityException(
1621
+				$datetime,
1622
+				'EE_Datetime',
1623
+				sprintf(
1624
+					__('The ticket (%s) is not associated with any valid datetimes.', 'event_espresso'),
1625
+					$this->name()
1626
+				)
1627
+			);
1628
+		}
1629
+		$event = $datetime->event();
1630
+		if (! $event instanceof EE_Event) {
1631
+			throw new UnexpectedEntityException(
1632
+				$event,
1633
+				'EE_Event',
1634
+				sprintf(
1635
+					__('The ticket (%s) is not associated with a valid event.', 'event_espresso'),
1636
+					$this->name()
1637
+				)
1638
+			);
1639
+		}
1640
+		return $event;
1641
+	}
1642
+
1643
+
1644
+	/**
1645
+	 * Implementation of the EEI_Event_Relation interface method
1646
+	 *
1647
+	 * @return string
1648
+	 * @throws UnexpectedEntityException
1649
+	 * @throws EE_Error
1650
+	 * @throws ReflectionException
1651
+	 * @see EEI_Event_Relation for comments
1652
+	 */
1653
+	public function get_event_name()
1654
+	{
1655
+		$event = $this->get_related_event();
1656
+		return $event instanceof EE_Event ? $event->name() : '';
1657
+	}
1658
+
1659
+
1660
+	/**
1661
+	 * Implementation of the EEI_Event_Relation interface method
1662
+	 *
1663
+	 * @return int
1664
+	 * @throws UnexpectedEntityException
1665
+	 * @throws EE_Error
1666
+	 * @throws ReflectionException
1667
+	 * @see EEI_Event_Relation for comments
1668
+	 */
1669
+	public function get_event_ID()
1670
+	{
1671
+		$event = $this->get_related_event();
1672
+		return $event instanceof EE_Event ? $event->ID() : 0;
1673
+	}
1674
+
1675
+
1676
+	/**
1677
+	 * This simply returns whether a ticket can be permanently deleted or not.
1678
+	 * The criteria for determining this is whether the ticket has any related registrations.
1679
+	 * If there are none then it can be permanently deleted.
1680
+	 *
1681
+	 * @return bool
1682
+	 * @throws EE_Error
1683
+	 * @throws ReflectionException
1684
+	 */
1685
+	public function is_permanently_deleteable()
1686
+	{
1687
+		return $this->count_registrations() === 0;
1688
+	}
1689
+
1690
+
1691
+	/*******************************************************************
1692 1692
      ***********************  DEPRECATED METHODS  **********************
1693 1693
      *******************************************************************/
1694 1694
 
1695 1695
 
1696
-    /**
1697
-     * Increments sold by amount passed by $qty AND decrements the reserved count on both this ticket and its
1698
-     * associated datetimes.
1699
-     *
1700
-     * @param int $qty
1701
-     * @return void
1702
-     * @throws EE_Error
1703
-     * @throws InvalidArgumentException
1704
-     * @throws InvalidDataTypeException
1705
-     * @throws InvalidInterfaceException
1706
-     * @throws ReflectionException
1707
-     * @deprecated 4.9.80.p
1708
-     */
1709
-    public function increase_sold($qty = 1)
1710
-    {
1711
-        EE_Error::doing_it_wrong(
1712
-            __FUNCTION__,
1713
-            esc_html__('Please use EE_Ticket::increaseSold() instead', 'event_espresso'),
1714
-            '4.9.80.p',
1715
-            '5.0.0.p'
1716
-        );
1717
-        $this->increaseSold($qty);
1718
-    }
1719
-
1720
-
1721
-    /**
1722
-     * On each datetime related to this ticket, increases its sold count and decreases its reserved count by $qty.
1723
-     *
1724
-     * @param int $qty positive or negative. Positive means to increase sold counts (and decrease reserved counts),
1725
-     *                 Negative means to decreases old counts (and increase reserved counts).
1726
-     * @throws EE_Error
1727
-     * @throws InvalidArgumentException
1728
-     * @throws InvalidDataTypeException
1729
-     * @throws InvalidInterfaceException
1730
-     * @throws ReflectionException
1731
-     * @deprecated 4.9.80.p
1732
-     */
1733
-    protected function _increase_sold_for_datetimes($qty)
1734
-    {
1735
-        EE_Error::doing_it_wrong(
1736
-            __FUNCTION__,
1737
-            esc_html__('Please use EE_Ticket::increaseSoldForDatetimes() instead', 'event_espresso'),
1738
-            '4.9.80.p',
1739
-            '5.0.0.p'
1740
-        );
1741
-        $this->increaseSoldForDatetimes($qty);
1742
-    }
1743
-
1744
-
1745
-    /**
1746
-     * Decrements (subtracts) sold by amount passed by $qty on both the ticket and its related datetimes directly in the
1747
-     * DB and then updates the model objects.
1748
-     * Does not affect the reserved counts.
1749
-     *
1750
-     * @param int $qty
1751
-     * @return void
1752
-     * @throws EE_Error
1753
-     * @throws InvalidArgumentException
1754
-     * @throws InvalidDataTypeException
1755
-     * @throws InvalidInterfaceException
1756
-     * @throws ReflectionException
1757
-     * @deprecated 4.9.80.p
1758
-     */
1759
-    public function decrease_sold($qty = 1)
1760
-    {
1761
-        EE_Error::doing_it_wrong(
1762
-            __FUNCTION__,
1763
-            esc_html__('Please use EE_Ticket::decreaseSold() instead', 'event_espresso'),
1764
-            '4.9.80.p',
1765
-            '5.0.0.p'
1766
-        );
1767
-        $this->decreaseSold($qty);
1768
-    }
1769
-
1770
-
1771
-    /**
1772
-     * Decreases sold on related datetimes
1773
-     *
1774
-     * @param int $qty
1775
-     * @return void
1776
-     * @throws EE_Error
1777
-     * @throws InvalidArgumentException
1778
-     * @throws InvalidDataTypeException
1779
-     * @throws InvalidInterfaceException
1780
-     * @throws ReflectionException
1781
-     * @deprecated 4.9.80.p
1782
-     */
1783
-    protected function _decrease_sold_for_datetimes($qty = 1)
1784
-    {
1785
-        EE_Error::doing_it_wrong(
1786
-            __FUNCTION__,
1787
-            esc_html__('Please use EE_Ticket::decreaseSoldForDatetimes() instead', 'event_espresso'),
1788
-            '4.9.80.p',
1789
-            '5.0.0.p'
1790
-        );
1791
-        $this->decreaseSoldForDatetimes($qty);
1792
-    }
1793
-
1794
-
1795
-    /**
1796
-     * Increments reserved by amount passed by $qty, and persists it immediately to the database.
1797
-     *
1798
-     * @param int    $qty
1799
-     * @param string $source
1800
-     * @return bool whether we successfully reserved the ticket or not.
1801
-     * @throws EE_Error
1802
-     * @throws InvalidArgumentException
1803
-     * @throws ReflectionException
1804
-     * @throws InvalidDataTypeException
1805
-     * @throws InvalidInterfaceException
1806
-     * @deprecated 4.9.80.p
1807
-     */
1808
-    public function increase_reserved($qty = 1, $source = 'unknown')
1809
-    {
1810
-        EE_Error::doing_it_wrong(
1811
-            __FUNCTION__,
1812
-            esc_html__('Please use EE_Ticket::increaseReserved() instead', 'event_espresso'),
1813
-            '4.9.80.p',
1814
-            '5.0.0.p'
1815
-        );
1816
-        return $this->increaseReserved($qty);
1817
-    }
1818
-
1819
-
1820
-    /**
1821
-     * Increases sold on related datetimes
1822
-     *
1823
-     * @param int $qty
1824
-     * @return boolean indicating success
1825
-     * @throws EE_Error
1826
-     * @throws InvalidArgumentException
1827
-     * @throws InvalidDataTypeException
1828
-     * @throws InvalidInterfaceException
1829
-     * @throws ReflectionException
1830
-     * @deprecated 4.9.80.p
1831
-     */
1832
-    protected function _increase_reserved_for_datetimes($qty = 1)
1833
-    {
1834
-        EE_Error::doing_it_wrong(
1835
-            __FUNCTION__,
1836
-            esc_html__('Please use EE_Ticket::increaseReservedForDatetimes() instead', 'event_espresso'),
1837
-            '4.9.80.p',
1838
-            '5.0.0.p'
1839
-        );
1840
-        return $this->increaseReservedForDatetimes($qty);
1841
-    }
1842
-
1843
-
1844
-    /**
1845
-     * Decrements (subtracts) reserved by amount passed by $qty, and persists it immediately to the database.
1846
-     *
1847
-     * @param int    $qty
1848
-     * @param bool   $adjust_datetimes
1849
-     * @param string $source
1850
-     * @return void
1851
-     * @throws EE_Error
1852
-     * @throws InvalidArgumentException
1853
-     * @throws ReflectionException
1854
-     * @throws InvalidDataTypeException
1855
-     * @throws InvalidInterfaceException
1856
-     * @deprecated 4.9.80.p
1857
-     */
1858
-    public function decrease_reserved($qty = 1, $adjust_datetimes = true, $source = 'unknown')
1859
-    {
1860
-        EE_Error::doing_it_wrong(
1861
-            __FUNCTION__,
1862
-            esc_html__('Please use EE_Ticket::decreaseReserved() instead', 'event_espresso'),
1863
-            '4.9.80.p',
1864
-            '5.0.0.p'
1865
-        );
1866
-        $this->decreaseReserved($qty);
1867
-    }
1868
-
1869
-
1870
-    /**
1871
-     * Decreases reserved on related datetimes
1872
-     *
1873
-     * @param int $qty
1874
-     * @return void
1875
-     * @throws EE_Error
1876
-     * @throws InvalidArgumentException
1877
-     * @throws ReflectionException
1878
-     * @throws InvalidDataTypeException
1879
-     * @throws InvalidInterfaceException
1880
-     * @deprecated 4.9.80.p
1881
-     */
1882
-    protected function _decrease_reserved_for_datetimes($qty = 1)
1883
-    {
1884
-        EE_Error::doing_it_wrong(
1885
-            __FUNCTION__,
1886
-            esc_html__('Please use EE_Ticket::decreaseReservedForDatetimes() instead', 'event_espresso'),
1887
-            '4.9.80.p',
1888
-            '5.0.0.p'
1889
-        );
1890
-        $this->decreaseReservedForDatetimes($qty);
1891
-    }
1696
+	/**
1697
+	 * Increments sold by amount passed by $qty AND decrements the reserved count on both this ticket and its
1698
+	 * associated datetimes.
1699
+	 *
1700
+	 * @param int $qty
1701
+	 * @return void
1702
+	 * @throws EE_Error
1703
+	 * @throws InvalidArgumentException
1704
+	 * @throws InvalidDataTypeException
1705
+	 * @throws InvalidInterfaceException
1706
+	 * @throws ReflectionException
1707
+	 * @deprecated 4.9.80.p
1708
+	 */
1709
+	public function increase_sold($qty = 1)
1710
+	{
1711
+		EE_Error::doing_it_wrong(
1712
+			__FUNCTION__,
1713
+			esc_html__('Please use EE_Ticket::increaseSold() instead', 'event_espresso'),
1714
+			'4.9.80.p',
1715
+			'5.0.0.p'
1716
+		);
1717
+		$this->increaseSold($qty);
1718
+	}
1719
+
1720
+
1721
+	/**
1722
+	 * On each datetime related to this ticket, increases its sold count and decreases its reserved count by $qty.
1723
+	 *
1724
+	 * @param int $qty positive or negative. Positive means to increase sold counts (and decrease reserved counts),
1725
+	 *                 Negative means to decreases old counts (and increase reserved counts).
1726
+	 * @throws EE_Error
1727
+	 * @throws InvalidArgumentException
1728
+	 * @throws InvalidDataTypeException
1729
+	 * @throws InvalidInterfaceException
1730
+	 * @throws ReflectionException
1731
+	 * @deprecated 4.9.80.p
1732
+	 */
1733
+	protected function _increase_sold_for_datetimes($qty)
1734
+	{
1735
+		EE_Error::doing_it_wrong(
1736
+			__FUNCTION__,
1737
+			esc_html__('Please use EE_Ticket::increaseSoldForDatetimes() instead', 'event_espresso'),
1738
+			'4.9.80.p',
1739
+			'5.0.0.p'
1740
+		);
1741
+		$this->increaseSoldForDatetimes($qty);
1742
+	}
1743
+
1744
+
1745
+	/**
1746
+	 * Decrements (subtracts) sold by amount passed by $qty on both the ticket and its related datetimes directly in the
1747
+	 * DB and then updates the model objects.
1748
+	 * Does not affect the reserved counts.
1749
+	 *
1750
+	 * @param int $qty
1751
+	 * @return void
1752
+	 * @throws EE_Error
1753
+	 * @throws InvalidArgumentException
1754
+	 * @throws InvalidDataTypeException
1755
+	 * @throws InvalidInterfaceException
1756
+	 * @throws ReflectionException
1757
+	 * @deprecated 4.9.80.p
1758
+	 */
1759
+	public function decrease_sold($qty = 1)
1760
+	{
1761
+		EE_Error::doing_it_wrong(
1762
+			__FUNCTION__,
1763
+			esc_html__('Please use EE_Ticket::decreaseSold() instead', 'event_espresso'),
1764
+			'4.9.80.p',
1765
+			'5.0.0.p'
1766
+		);
1767
+		$this->decreaseSold($qty);
1768
+	}
1769
+
1770
+
1771
+	/**
1772
+	 * Decreases sold on related datetimes
1773
+	 *
1774
+	 * @param int $qty
1775
+	 * @return void
1776
+	 * @throws EE_Error
1777
+	 * @throws InvalidArgumentException
1778
+	 * @throws InvalidDataTypeException
1779
+	 * @throws InvalidInterfaceException
1780
+	 * @throws ReflectionException
1781
+	 * @deprecated 4.9.80.p
1782
+	 */
1783
+	protected function _decrease_sold_for_datetimes($qty = 1)
1784
+	{
1785
+		EE_Error::doing_it_wrong(
1786
+			__FUNCTION__,
1787
+			esc_html__('Please use EE_Ticket::decreaseSoldForDatetimes() instead', 'event_espresso'),
1788
+			'4.9.80.p',
1789
+			'5.0.0.p'
1790
+		);
1791
+		$this->decreaseSoldForDatetimes($qty);
1792
+	}
1793
+
1794
+
1795
+	/**
1796
+	 * Increments reserved by amount passed by $qty, and persists it immediately to the database.
1797
+	 *
1798
+	 * @param int    $qty
1799
+	 * @param string $source
1800
+	 * @return bool whether we successfully reserved the ticket or not.
1801
+	 * @throws EE_Error
1802
+	 * @throws InvalidArgumentException
1803
+	 * @throws ReflectionException
1804
+	 * @throws InvalidDataTypeException
1805
+	 * @throws InvalidInterfaceException
1806
+	 * @deprecated 4.9.80.p
1807
+	 */
1808
+	public function increase_reserved($qty = 1, $source = 'unknown')
1809
+	{
1810
+		EE_Error::doing_it_wrong(
1811
+			__FUNCTION__,
1812
+			esc_html__('Please use EE_Ticket::increaseReserved() instead', 'event_espresso'),
1813
+			'4.9.80.p',
1814
+			'5.0.0.p'
1815
+		);
1816
+		return $this->increaseReserved($qty);
1817
+	}
1818
+
1819
+
1820
+	/**
1821
+	 * Increases sold on related datetimes
1822
+	 *
1823
+	 * @param int $qty
1824
+	 * @return boolean indicating success
1825
+	 * @throws EE_Error
1826
+	 * @throws InvalidArgumentException
1827
+	 * @throws InvalidDataTypeException
1828
+	 * @throws InvalidInterfaceException
1829
+	 * @throws ReflectionException
1830
+	 * @deprecated 4.9.80.p
1831
+	 */
1832
+	protected function _increase_reserved_for_datetimes($qty = 1)
1833
+	{
1834
+		EE_Error::doing_it_wrong(
1835
+			__FUNCTION__,
1836
+			esc_html__('Please use EE_Ticket::increaseReservedForDatetimes() instead', 'event_espresso'),
1837
+			'4.9.80.p',
1838
+			'5.0.0.p'
1839
+		);
1840
+		return $this->increaseReservedForDatetimes($qty);
1841
+	}
1842
+
1843
+
1844
+	/**
1845
+	 * Decrements (subtracts) reserved by amount passed by $qty, and persists it immediately to the database.
1846
+	 *
1847
+	 * @param int    $qty
1848
+	 * @param bool   $adjust_datetimes
1849
+	 * @param string $source
1850
+	 * @return void
1851
+	 * @throws EE_Error
1852
+	 * @throws InvalidArgumentException
1853
+	 * @throws ReflectionException
1854
+	 * @throws InvalidDataTypeException
1855
+	 * @throws InvalidInterfaceException
1856
+	 * @deprecated 4.9.80.p
1857
+	 */
1858
+	public function decrease_reserved($qty = 1, $adjust_datetimes = true, $source = 'unknown')
1859
+	{
1860
+		EE_Error::doing_it_wrong(
1861
+			__FUNCTION__,
1862
+			esc_html__('Please use EE_Ticket::decreaseReserved() instead', 'event_espresso'),
1863
+			'4.9.80.p',
1864
+			'5.0.0.p'
1865
+		);
1866
+		$this->decreaseReserved($qty);
1867
+	}
1868
+
1869
+
1870
+	/**
1871
+	 * Decreases reserved on related datetimes
1872
+	 *
1873
+	 * @param int $qty
1874
+	 * @return void
1875
+	 * @throws EE_Error
1876
+	 * @throws InvalidArgumentException
1877
+	 * @throws ReflectionException
1878
+	 * @throws InvalidDataTypeException
1879
+	 * @throws InvalidInterfaceException
1880
+	 * @deprecated 4.9.80.p
1881
+	 */
1882
+	protected function _decrease_reserved_for_datetimes($qty = 1)
1883
+	{
1884
+		EE_Error::doing_it_wrong(
1885
+			__FUNCTION__,
1886
+			esc_html__('Please use EE_Ticket::decreaseReservedForDatetimes() instead', 'event_espresso'),
1887
+			'4.9.80.p',
1888
+			'5.0.0.p'
1889
+		);
1890
+		$this->decreaseReservedForDatetimes($qty);
1891
+	}
1892 1892
 }
Please login to merge, or discard this patch.
core/db_classes/EE_Event.class.php 1 patch
Indentation   +1389 added lines, -1389 removed lines patch added patch discarded remove patch
@@ -15,1393 +15,1393 @@
 block discarded – undo
15 15
 class EE_Event extends EE_CPT_Base implements EEI_Line_Item_Object, EEI_Admin_Links, EEI_Has_Icon, EEI_Event
16 16
 {
17 17
 
18
-    /**
19
-     * cached value for the the logical active status for the event
20
-     *
21
-     * @see get_active_status()
22
-     * @var string
23
-     */
24
-    protected $_active_status = '';
25
-
26
-    /**
27
-     * This is just used for caching the Primary Datetime for the Event on initial retrieval
28
-     *
29
-     * @var EE_Datetime
30
-     */
31
-    protected $_Primary_Datetime;
32
-
33
-    /**
34
-     * @var EventSpacesCalculator $available_spaces_calculator
35
-     */
36
-    protected $available_spaces_calculator;
37
-
38
-
39
-    /**
40
-     * @param array  $props_n_values          incoming values
41
-     * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
42
-     *                                        used.)
43
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
44
-     *                                        date_format and the second value is the time format
45
-     * @return EE_Event
46
-     * @throws EE_Error
47
-     */
48
-    public static function new_instance($props_n_values = array(), $timezone = '', $date_formats = array())
49
-    {
50
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
51
-        return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
52
-    }
53
-
54
-
55
-    /**
56
-     * @param array  $props_n_values  incoming values from the database
57
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
58
-     *                                the website will be used.
59
-     * @return EE_Event
60
-     * @throws EE_Error
61
-     */
62
-    public static function new_instance_from_db($props_n_values = array(), $timezone = '')
63
-    {
64
-        return new self($props_n_values, true, $timezone);
65
-    }
66
-
67
-
68
-    /**
69
-     * @return EventSpacesCalculator
70
-     * @throws \EE_Error
71
-     */
72
-    public function getAvailableSpacesCalculator()
73
-    {
74
-        if (! $this->available_spaces_calculator instanceof EventSpacesCalculator) {
75
-            $this->available_spaces_calculator = new EventSpacesCalculator($this);
76
-        }
77
-        return $this->available_spaces_calculator;
78
-    }
79
-
80
-
81
-    /**
82
-     * Overrides parent set() method so that all calls to set( 'status', $status ) can be routed to internal methods
83
-     *
84
-     * @param string $field_name
85
-     * @param mixed  $field_value
86
-     * @param bool   $use_default
87
-     * @throws EE_Error
88
-     */
89
-    public function set($field_name, $field_value, $use_default = false)
90
-    {
91
-        switch ($field_name) {
92
-            case 'status':
93
-                $this->set_status($field_value, $use_default);
94
-                break;
95
-            default:
96
-                parent::set($field_name, $field_value, $use_default);
97
-        }
98
-    }
99
-
100
-
101
-    /**
102
-     *    set_status
103
-     * Checks if event status is being changed to SOLD OUT
104
-     * and updates event meta data with previous event status
105
-     * so that we can revert things if/when the event is no longer sold out
106
-     *
107
-     * @access public
108
-     * @param string $new_status
109
-     * @param bool   $use_default
110
-     * @return void
111
-     * @throws EE_Error
112
-     */
113
-    public function set_status($new_status = null, $use_default = false)
114
-    {
115
-        // if nothing is set, and we aren't explicitly wanting to reset the status, then just leave
116
-        if (empty($new_status) && ! $use_default) {
117
-            return;
118
-        }
119
-        // get current Event status
120
-        $old_status = $this->status();
121
-        // if status has changed
122
-        if ($old_status !== $new_status) {
123
-            // TO sold_out
124
-            if ($new_status === EEM_Event::sold_out) {
125
-                // save the previous event status so that we can revert if the event is no longer sold out
126
-                $this->add_post_meta('_previous_event_status', $old_status);
127
-                do_action('AHEE__EE_Event__set_status__to_sold_out', $this, $old_status, $new_status);
128
-                // OR FROM  sold_out
129
-            } elseif ($old_status === EEM_Event::sold_out) {
130
-                $this->delete_post_meta('_previous_event_status');
131
-                do_action('AHEE__EE_Event__set_status__from_sold_out', $this, $old_status, $new_status);
132
-            }
133
-            // clear out the active status so that it gets reset the next time it is requested
134
-            $this->_active_status = null;
135
-            // update status
136
-            parent::set('status', $new_status, $use_default);
137
-            do_action('AHEE__EE_Event__set_status__after_update', $this);
138
-            return;
139
-        }
140
-        // even though the old value matches the new value, it's still good to
141
-        // allow the parent set method to have a say
142
-        parent::set('status', $new_status, $use_default);
143
-    }
144
-
145
-
146
-    /**
147
-     * Gets all the datetimes for this event
148
-     *
149
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
150
-     * @return EE_Base_Class[]|EE_Datetime[]
151
-     * @throws EE_Error
152
-     */
153
-    public function datetimes($query_params = array())
154
-    {
155
-        return $this->get_many_related('Datetime', $query_params);
156
-    }
157
-
158
-
159
-    /**
160
-     * Gets all the datetimes for this event, ordered by DTT_EVT_start in ascending order
161
-     *
162
-     * @return EE_Base_Class[]|EE_Datetime[]
163
-     * @throws EE_Error
164
-     */
165
-    public function datetimes_in_chronological_order()
166
-    {
167
-        return $this->get_many_related('Datetime', array('order_by' => array('DTT_EVT_start' => 'ASC')));
168
-    }
169
-
170
-
171
-    /**
172
-     * Gets all the datetimes for this event, ordered by the DTT_order on the datetime.
173
-     * @darren, we should probably UNSET timezone on the EEM_Datetime model
174
-     * after running our query, so that this timezone isn't set for EVERY query
175
-     * on EEM_Datetime for the rest of the request, no?
176
-     *
177
-     * @param boolean $show_expired whether or not to include expired events
178
-     * @param boolean $show_deleted whether or not to include deleted events
179
-     * @param null    $limit
180
-     * @return EE_Datetime[]
181
-     * @throws EE_Error
182
-     */
183
-    public function datetimes_ordered($show_expired = true, $show_deleted = false, $limit = null)
184
-    {
185
-        return EEM_Datetime::instance($this->_timezone)->get_datetimes_for_event_ordered_by_DTT_order(
186
-            $this->ID(),
187
-            $show_expired,
188
-            $show_deleted,
189
-            $limit
190
-        );
191
-    }
192
-
193
-
194
-    /**
195
-     * Returns one related datetime. Mostly only used by some legacy code.
196
-     *
197
-     * @return EE_Base_Class|EE_Datetime
198
-     * @throws EE_Error
199
-     */
200
-    public function first_datetime()
201
-    {
202
-        return $this->get_first_related('Datetime');
203
-    }
204
-
205
-
206
-    /**
207
-     * Returns the 'primary' datetime for the event
208
-     *
209
-     * @param bool $try_to_exclude_expired
210
-     * @param bool $try_to_exclude_deleted
211
-     * @return EE_Datetime
212
-     * @throws EE_Error
213
-     */
214
-    public function primary_datetime($try_to_exclude_expired = true, $try_to_exclude_deleted = true)
215
-    {
216
-        if (! empty($this->_Primary_Datetime)) {
217
-            return $this->_Primary_Datetime;
218
-        }
219
-        $this->_Primary_Datetime = EEM_Datetime::instance($this->_timezone)->get_primary_datetime_for_event(
220
-            $this->ID(),
221
-            $try_to_exclude_expired,
222
-            $try_to_exclude_deleted
223
-        );
224
-        return $this->_Primary_Datetime;
225
-    }
226
-
227
-
228
-    /**
229
-     * Gets all the tickets available for purchase of this event
230
-     *
231
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
232
-     * @return EE_Base_Class[]|EE_Ticket[]
233
-     * @throws EE_Error
234
-     */
235
-    public function tickets($query_params = array())
236
-    {
237
-        // first get all datetimes
238
-        $datetimes = $this->datetimes_ordered();
239
-        if (! $datetimes) {
240
-            return array();
241
-        }
242
-        $datetime_ids = array();
243
-        foreach ($datetimes as $datetime) {
244
-            $datetime_ids[] = $datetime->ID();
245
-        }
246
-        $where_params = array('Datetime.DTT_ID' => array('IN', $datetime_ids));
247
-        // if incoming $query_params has where conditions let's merge but not override existing.
248
-        if (is_array($query_params) && isset($query_params[0])) {
249
-            $where_params = array_merge($query_params[0], $where_params);
250
-            unset($query_params[0]);
251
-        }
252
-        // now add $where_params to $query_params
253
-        $query_params[0] = $where_params;
254
-        return EEM_Ticket::instance()->get_all($query_params);
255
-    }
256
-
257
-
258
-    /**
259
-     * get all unexpired untrashed tickets
260
-     *
261
-     * @return EE_Ticket[]
262
-     * @throws EE_Error
263
-     */
264
-    public function active_tickets()
265
-    {
266
-        return $this->tickets(
267
-            array(
268
-                array(
269
-                    'TKT_end_date' => array('>=', EEM_Ticket::instance()->current_time_for_query('TKT_end_date')),
270
-                    'TKT_deleted'  => false,
271
-                ),
272
-            )
273
-        );
274
-    }
275
-
276
-
277
-    /**
278
-     * @return bool
279
-     * @throws EE_Error
280
-     */
281
-    public function additional_limit()
282
-    {
283
-        return $this->get('EVT_additional_limit');
284
-    }
285
-
286
-
287
-    /**
288
-     * @return bool
289
-     * @throws EE_Error
290
-     */
291
-    public function allow_overflow()
292
-    {
293
-        return $this->get('EVT_allow_overflow');
294
-    }
295
-
296
-
297
-    /**
298
-     * @return bool
299
-     * @throws EE_Error
300
-     */
301
-    public function created()
302
-    {
303
-        return $this->get('EVT_created');
304
-    }
305
-
306
-
307
-    /**
308
-     * @return bool
309
-     * @throws EE_Error
310
-     */
311
-    public function description()
312
-    {
313
-        return $this->get('EVT_desc');
314
-    }
315
-
316
-
317
-    /**
318
-     * Runs do_shortcode and wpautop on the description
319
-     *
320
-     * @return string of html
321
-     * @throws EE_Error
322
-     */
323
-    public function description_filtered()
324
-    {
325
-        return $this->get_pretty('EVT_desc');
326
-    }
327
-
328
-
329
-    /**
330
-     * @return bool
331
-     * @throws EE_Error
332
-     */
333
-    public function display_description()
334
-    {
335
-        return $this->get('EVT_display_desc');
336
-    }
337
-
338
-
339
-    /**
340
-     * @return bool
341
-     * @throws EE_Error
342
-     */
343
-    public function display_ticket_selector()
344
-    {
345
-        return (bool) $this->get('EVT_display_ticket_selector');
346
-    }
347
-
348
-
349
-    /**
350
-     * @return bool
351
-     * @throws EE_Error
352
-     */
353
-    public function external_url()
354
-    {
355
-        return $this->get('EVT_external_URL');
356
-    }
357
-
358
-
359
-    /**
360
-     * @return bool
361
-     * @throws EE_Error
362
-     */
363
-    public function member_only()
364
-    {
365
-        return $this->get('EVT_member_only');
366
-    }
367
-
368
-
369
-    /**
370
-     * @return bool
371
-     * @throws EE_Error
372
-     */
373
-    public function phone()
374
-    {
375
-        return $this->get('EVT_phone');
376
-    }
377
-
378
-
379
-    /**
380
-     * @return bool
381
-     * @throws EE_Error
382
-     */
383
-    public function modified()
384
-    {
385
-        return $this->get('EVT_modified');
386
-    }
387
-
388
-
389
-    /**
390
-     * @return bool
391
-     * @throws EE_Error
392
-     */
393
-    public function name()
394
-    {
395
-        return $this->get('EVT_name');
396
-    }
397
-
398
-
399
-    /**
400
-     * @return bool
401
-     * @throws EE_Error
402
-     */
403
-    public function order()
404
-    {
405
-        return $this->get('EVT_order');
406
-    }
407
-
408
-
409
-    /**
410
-     * @return bool|string
411
-     * @throws EE_Error
412
-     */
413
-    public function default_registration_status()
414
-    {
415
-        $event_default_registration_status = $this->get('EVT_default_registration_status');
416
-        return ! empty($event_default_registration_status)
417
-            ? $event_default_registration_status
418
-            : EE_Registry::instance()->CFG->registration->default_STS_ID;
419
-    }
420
-
421
-
422
-    /**
423
-     * @param int  $num_words
424
-     * @param null $more
425
-     * @param bool $not_full_desc
426
-     * @return bool|string
427
-     * @throws EE_Error
428
-     */
429
-    public function short_description($num_words = 55, $more = null, $not_full_desc = false)
430
-    {
431
-        $short_desc = $this->get('EVT_short_desc');
432
-        if (! empty($short_desc) || $not_full_desc) {
433
-            return $short_desc;
434
-        }
435
-        $full_desc = $this->get('EVT_desc');
436
-        return wp_trim_words($full_desc, $num_words, $more);
437
-    }
438
-
439
-
440
-    /**
441
-     * @return bool
442
-     * @throws EE_Error
443
-     */
444
-    public function slug()
445
-    {
446
-        return $this->get('EVT_slug');
447
-    }
448
-
449
-
450
-    /**
451
-     * @return bool
452
-     * @throws EE_Error
453
-     */
454
-    public function timezone_string()
455
-    {
456
-        return $this->get('EVT_timezone_string');
457
-    }
458
-
459
-
460
-    /**
461
-     * @return bool
462
-     * @throws EE_Error
463
-     */
464
-    public function visible_on()
465
-    {
466
-        return $this->get('EVT_visible_on');
467
-    }
468
-
469
-
470
-    /**
471
-     * @return int
472
-     * @throws EE_Error
473
-     */
474
-    public function wp_user()
475
-    {
476
-        return $this->get('EVT_wp_user');
477
-    }
478
-
479
-
480
-    /**
481
-     * @return bool
482
-     * @throws EE_Error
483
-     */
484
-    public function donations()
485
-    {
486
-        return $this->get('EVT_donations');
487
-    }
488
-
489
-
490
-    /**
491
-     * @param $limit
492
-     * @throws EE_Error
493
-     */
494
-    public function set_additional_limit($limit)
495
-    {
496
-        $this->set('EVT_additional_limit', $limit);
497
-    }
498
-
499
-
500
-    /**
501
-     * @param $created
502
-     * @throws EE_Error
503
-     */
504
-    public function set_created($created)
505
-    {
506
-        $this->set('EVT_created', $created);
507
-    }
508
-
509
-
510
-    /**
511
-     * @param $desc
512
-     * @throws EE_Error
513
-     */
514
-    public function set_description($desc)
515
-    {
516
-        $this->set('EVT_desc', $desc);
517
-    }
518
-
519
-
520
-    /**
521
-     * @param $display_desc
522
-     * @throws EE_Error
523
-     */
524
-    public function set_display_description($display_desc)
525
-    {
526
-        $this->set('EVT_display_desc', $display_desc);
527
-    }
528
-
529
-
530
-    /**
531
-     * @param $display_ticket_selector
532
-     * @throws EE_Error
533
-     */
534
-    public function set_display_ticket_selector($display_ticket_selector)
535
-    {
536
-        $this->set('EVT_display_ticket_selector', $display_ticket_selector);
537
-    }
538
-
539
-
540
-    /**
541
-     * @param $external_url
542
-     * @throws EE_Error
543
-     */
544
-    public function set_external_url($external_url)
545
-    {
546
-        $this->set('EVT_external_URL', $external_url);
547
-    }
548
-
549
-
550
-    /**
551
-     * @param $member_only
552
-     * @throws EE_Error
553
-     */
554
-    public function set_member_only($member_only)
555
-    {
556
-        $this->set('EVT_member_only', $member_only);
557
-    }
558
-
559
-
560
-    /**
561
-     * @param $event_phone
562
-     * @throws EE_Error
563
-     */
564
-    public function set_event_phone($event_phone)
565
-    {
566
-        $this->set('EVT_phone', $event_phone);
567
-    }
568
-
569
-
570
-    /**
571
-     * @param $modified
572
-     * @throws EE_Error
573
-     */
574
-    public function set_modified($modified)
575
-    {
576
-        $this->set('EVT_modified', $modified);
577
-    }
578
-
579
-
580
-    /**
581
-     * @param $name
582
-     * @throws EE_Error
583
-     */
584
-    public function set_name($name)
585
-    {
586
-        $this->set('EVT_name', $name);
587
-    }
588
-
589
-
590
-    /**
591
-     * @param $order
592
-     * @throws EE_Error
593
-     */
594
-    public function set_order($order)
595
-    {
596
-        $this->set('EVT_order', $order);
597
-    }
598
-
599
-
600
-    /**
601
-     * @param $short_desc
602
-     * @throws EE_Error
603
-     */
604
-    public function set_short_description($short_desc)
605
-    {
606
-        $this->set('EVT_short_desc', $short_desc);
607
-    }
608
-
609
-
610
-    /**
611
-     * @param $slug
612
-     * @throws EE_Error
613
-     */
614
-    public function set_slug($slug)
615
-    {
616
-        $this->set('EVT_slug', $slug);
617
-    }
618
-
619
-
620
-    /**
621
-     * @param $timezone_string
622
-     * @throws EE_Error
623
-     */
624
-    public function set_timezone_string($timezone_string)
625
-    {
626
-        $this->set('EVT_timezone_string', $timezone_string);
627
-    }
628
-
629
-
630
-    /**
631
-     * @param $visible_on
632
-     * @throws EE_Error
633
-     */
634
-    public function set_visible_on($visible_on)
635
-    {
636
-        $this->set('EVT_visible_on', $visible_on);
637
-    }
638
-
639
-
640
-    /**
641
-     * @param $wp_user
642
-     * @throws EE_Error
643
-     */
644
-    public function set_wp_user($wp_user)
645
-    {
646
-        $this->set('EVT_wp_user', $wp_user);
647
-    }
648
-
649
-
650
-    /**
651
-     * @param $default_registration_status
652
-     * @throws EE_Error
653
-     */
654
-    public function set_default_registration_status($default_registration_status)
655
-    {
656
-        $this->set('EVT_default_registration_status', $default_registration_status);
657
-    }
658
-
659
-
660
-    /**
661
-     * @param $donations
662
-     * @throws EE_Error
663
-     */
664
-    public function set_donations($donations)
665
-    {
666
-        $this->set('EVT_donations', $donations);
667
-    }
668
-
669
-
670
-    /**
671
-     * Adds a venue to this event
672
-     *
673
-     * @param EE_Venue /int $venue_id_or_obj
674
-     * @return EE_Base_Class|EE_Venue
675
-     * @throws EE_Error
676
-     */
677
-    public function add_venue($venue_id_or_obj)
678
-    {
679
-        return $this->_add_relation_to($venue_id_or_obj, 'Venue');
680
-    }
681
-
682
-
683
-    /**
684
-     * Removes a venue from the event
685
-     *
686
-     * @param EE_Venue /int $venue_id_or_obj
687
-     * @return EE_Base_Class|EE_Venue
688
-     * @throws EE_Error
689
-     */
690
-    public function remove_venue($venue_id_or_obj)
691
-    {
692
-        return $this->_remove_relation_to($venue_id_or_obj, 'Venue');
693
-    }
694
-
695
-
696
-    /**
697
-     * Gets all the venues related ot the event. May provide additional $query_params if desired
698
-     *
699
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
700
-     * @return EE_Base_Class[]|EE_Venue[]
701
-     * @throws EE_Error
702
-     */
703
-    public function venues($query_params = array())
704
-    {
705
-        return $this->get_many_related('Venue', $query_params);
706
-    }
707
-
708
-
709
-    /**
710
-     * check if event id is present and if event is published
711
-     *
712
-     * @access public
713
-     * @return boolean true yes, false no
714
-     * @throws EE_Error
715
-     */
716
-    private function _has_ID_and_is_published()
717
-    {
718
-        // first check if event id is present and not NULL,
719
-        // then check if this event is published (or any of the equivalent "published" statuses)
720
-        return
721
-            $this->ID() && $this->ID() !== null
722
-            && (
723
-                $this->status() === 'publish'
724
-                || $this->status() === EEM_Event::sold_out
725
-                || $this->status() === EEM_Event::postponed
726
-                || $this->status() === EEM_Event::cancelled
727
-            );
728
-    }
729
-
730
-
731
-    /**
732
-     * This simply compares the internal dates with NOW and determines if the event is upcoming or not.
733
-     *
734
-     * @access public
735
-     * @return boolean true yes, false no
736
-     * @throws EE_Error
737
-     */
738
-    public function is_upcoming()
739
-    {
740
-        // check if event id is present and if this event is published
741
-        if ($this->is_inactive()) {
742
-            return false;
743
-        }
744
-        // set initial value
745
-        $upcoming = false;
746
-        // next let's get all datetimes and loop through them
747
-        $datetimes = $this->datetimes_in_chronological_order();
748
-        foreach ($datetimes as $datetime) {
749
-            if ($datetime instanceof EE_Datetime) {
750
-                // if this dtt is expired then we continue cause one of the other datetimes might be upcoming.
751
-                if ($datetime->is_expired()) {
752
-                    continue;
753
-                }
754
-                // if this dtt is active then we return false.
755
-                if ($datetime->is_active()) {
756
-                    return false;
757
-                }
758
-                // otherwise let's check upcoming status
759
-                $upcoming = $datetime->is_upcoming();
760
-            }
761
-        }
762
-        return $upcoming;
763
-    }
764
-
765
-
766
-    /**
767
-     * @return bool
768
-     * @throws EE_Error
769
-     */
770
-    public function is_active()
771
-    {
772
-        // check if event id is present and if this event is published
773
-        if ($this->is_inactive()) {
774
-            return false;
775
-        }
776
-        // set initial value
777
-        $active = false;
778
-        // next let's get all datetimes and loop through them
779
-        $datetimes = $this->datetimes_in_chronological_order();
780
-        foreach ($datetimes as $datetime) {
781
-            if ($datetime instanceof EE_Datetime) {
782
-                // if this dtt is expired then we continue cause one of the other datetimes might be active.
783
-                if ($datetime->is_expired()) {
784
-                    continue;
785
-                }
786
-                // if this dtt is upcoming then we return false.
787
-                if ($datetime->is_upcoming()) {
788
-                    return false;
789
-                }
790
-                // otherwise let's check active status
791
-                $active = $datetime->is_active();
792
-            }
793
-        }
794
-        return $active;
795
-    }
796
-
797
-
798
-    /**
799
-     * @return bool
800
-     * @throws EE_Error
801
-     */
802
-    public function is_expired()
803
-    {
804
-        // check if event id is present and if this event is published
805
-        if ($this->is_inactive()) {
806
-            return false;
807
-        }
808
-        // set initial value
809
-        $expired = false;
810
-        // first let's get all datetimes and loop through them
811
-        $datetimes = $this->datetimes_in_chronological_order();
812
-        foreach ($datetimes as $datetime) {
813
-            if ($datetime instanceof EE_Datetime) {
814
-                // if this dtt is upcoming or active then we return false.
815
-                if ($datetime->is_upcoming() || $datetime->is_active()) {
816
-                    return false;
817
-                }
818
-                // otherwise let's check active status
819
-                $expired = $datetime->is_expired();
820
-            }
821
-        }
822
-        return $expired;
823
-    }
824
-
825
-
826
-    /**
827
-     * @return bool
828
-     * @throws EE_Error
829
-     */
830
-    public function is_inactive()
831
-    {
832
-        // check if event id is present and if this event is published
833
-        if ($this->_has_ID_and_is_published()) {
834
-            return false;
835
-        }
836
-        return true;
837
-    }
838
-
839
-
840
-    /**
841
-     * calculate spaces remaining based on "saleable" tickets
842
-     *
843
-     * @param array $tickets
844
-     * @param bool  $filtered
845
-     * @return int|float
846
-     * @throws EE_Error
847
-     * @throws DomainException
848
-     * @throws UnexpectedEntityException
849
-     */
850
-    public function spaces_remaining($tickets = array(), $filtered = true)
851
-    {
852
-        $this->getAvailableSpacesCalculator()->setActiveTickets($tickets);
853
-        $spaces_remaining = $this->getAvailableSpacesCalculator()->spacesRemaining();
854
-        return $filtered
855
-            ? apply_filters(
856
-                'FHEE_EE_Event__spaces_remaining',
857
-                $spaces_remaining,
858
-                $this,
859
-                $tickets
860
-            )
861
-            : $spaces_remaining;
862
-    }
863
-
864
-
865
-    /**
866
-     *    perform_sold_out_status_check
867
-     *    checks all of this events's datetime  reg_limit - sold values to determine if ANY datetimes have spaces
868
-     *    available... if NOT, then the event status will get toggled to 'sold_out'
869
-     *
870
-     * @return bool    return the ACTUAL sold out state.
871
-     * @throws EE_Error
872
-     * @throws DomainException
873
-     * @throws UnexpectedEntityException
874
-     */
875
-    public function perform_sold_out_status_check()
876
-    {
877
-        // get all tickets
878
-        $tickets = $this->tickets(
879
-            array(
880
-                'default_where_conditions' => 'none',
881
-                'order_by' => array('TKT_qty' => 'ASC'),
882
-            )
883
-        );
884
-        $all_expired = true;
885
-        foreach ($tickets as $ticket) {
886
-            if (! $ticket->is_expired()) {
887
-                $all_expired = false;
888
-                break;
889
-            }
890
-        }
891
-        // if all the tickets are just expired, then don't update the event status to sold out
892
-        if ($all_expired) {
893
-            return true;
894
-        }
895
-        $spaces_remaining = $this->spaces_remaining($tickets);
896
-        if ($spaces_remaining < 1) {
897
-            if ($this->status() !== EEM_Event::post_status_private) {
898
-                $this->set_status(EEM_Event::sold_out);
899
-                $this->save();
900
-            }
901
-            $sold_out = true;
902
-        } else {
903
-            $sold_out = false;
904
-            // was event previously marked as sold out ?
905
-            if ($this->status() === EEM_Event::sold_out) {
906
-                // revert status to previous value, if it was set
907
-                $previous_event_status = $this->get_post_meta('_previous_event_status', true);
908
-                if ($previous_event_status) {
909
-                    $this->set_status($previous_event_status);
910
-                    $this->save();
911
-                }
912
-            }
913
-        }
914
-        do_action('AHEE__EE_Event__perform_sold_out_status_check__end', $this, $sold_out, $spaces_remaining, $tickets);
915
-        return $sold_out;
916
-    }
917
-
918
-
919
-    /**
920
-     * This returns the total remaining spaces for sale on this event.
921
-     *
922
-     * @uses EE_Event::total_available_spaces()
923
-     * @return float|int
924
-     * @throws EE_Error
925
-     * @throws DomainException
926
-     * @throws UnexpectedEntityException
927
-     */
928
-    public function spaces_remaining_for_sale()
929
-    {
930
-        return $this->total_available_spaces(true);
931
-    }
932
-
933
-
934
-    /**
935
-     * This returns the total spaces available for an event
936
-     * while considering all the qtys on the tickets and the reg limits
937
-     * on the datetimes attached to this event.
938
-     *
939
-     * @param   bool $consider_sold Whether to consider any tickets that have already sold in our calculation.
940
-     *                              If this is false, then we return the most tickets that could ever be sold
941
-     *                              for this event with the datetime and tickets setup on the event under optimal
942
-     *                              selling conditions.  Otherwise we return a live calculation of spaces available
943
-     *                              based on tickets sold.  Depending on setup and stage of sales, this
944
-     *                              may appear to equal remaining tickets.  However, the more tickets are
945
-     *                              sold out, the more accurate the "live" total is.
946
-     * @return float|int
947
-     * @throws EE_Error
948
-     * @throws DomainException
949
-     * @throws UnexpectedEntityException
950
-     */
951
-    public function total_available_spaces($consider_sold = false)
952
-    {
953
-        $spaces_available = $consider_sold
954
-            ? $this->getAvailableSpacesCalculator()->spacesRemaining()
955
-            : $this->getAvailableSpacesCalculator()->totalSpacesAvailable();
956
-        return apply_filters(
957
-            'FHEE_EE_Event__total_available_spaces__spaces_available',
958
-            $spaces_available,
959
-            $this,
960
-            $this->getAvailableSpacesCalculator()->getDatetimes(),
961
-            $this->getAvailableSpacesCalculator()->getActiveTickets()
962
-        );
963
-    }
964
-
965
-
966
-    /**
967
-     * Checks if the event is set to sold out
968
-     *
969
-     * @param  bool $actual whether or not to perform calculations to not only figure the
970
-     *                      actual status but also to flip the status if necessary to sold
971
-     *                      out If false, we just check the existing status of the event
972
-     * @return boolean
973
-     * @throws EE_Error
974
-     */
975
-    public function is_sold_out($actual = false)
976
-    {
977
-        if (! $actual) {
978
-            return $this->status() === EEM_Event::sold_out;
979
-        }
980
-        return $this->perform_sold_out_status_check();
981
-    }
982
-
983
-
984
-    /**
985
-     * Checks if the event is marked as postponed
986
-     *
987
-     * @return boolean
988
-     */
989
-    public function is_postponed()
990
-    {
991
-        return $this->status() === EEM_Event::postponed;
992
-    }
993
-
994
-
995
-    /**
996
-     * Checks if the event is marked as cancelled
997
-     *
998
-     * @return boolean
999
-     */
1000
-    public function is_cancelled()
1001
-    {
1002
-        return $this->status() === EEM_Event::cancelled;
1003
-    }
1004
-
1005
-
1006
-    /**
1007
-     * Get the logical active status in a hierarchical order for all the datetimes.  Note
1008
-     * Basically, we order the datetimes by EVT_start_date.  Then first test on whether the event is published.  If its
1009
-     * NOT published then we test for whether its expired or not.  IF it IS published then we test first on whether an
1010
-     * event has any active dates.  If no active dates then we check for any upcoming dates.  If no upcoming dates then
1011
-     * the event is considered expired.
1012
-     * NOTE: this method does NOT calculate whether the datetimes are sold out when event is published.  Sold Out is a
1013
-     * status set on the EVENT when it is not published and thus is done
1014
-     *
1015
-     * @param bool $reset
1016
-     * @return bool | string - based on EE_Datetime active constants or FALSE if error.
1017
-     * @throws EE_Error
1018
-     */
1019
-    public function get_active_status($reset = false)
1020
-    {
1021
-        // if the active status has already been set, then just use that value (unless we are resetting it)
1022
-        if (! empty($this->_active_status) && ! $reset) {
1023
-            return $this->_active_status;
1024
-        }
1025
-        // first check if event id is present on this object
1026
-        if (! $this->ID()) {
1027
-            return false;
1028
-        }
1029
-        $where_params_for_event = array(array('EVT_ID' => $this->ID()));
1030
-        // if event is published:
1031
-        if ($this->status() === EEM_Event::post_status_publish || $this->status() === EEM_Event::post_status_private) {
1032
-            // active?
1033
-            if (
1034
-                EEM_Datetime::instance()->get_datetime_count_for_status(
1035
-                    EE_Datetime::active,
1036
-                    $where_params_for_event
1037
-                ) > 0
1038
-            ) {
1039
-                $this->_active_status = EE_Datetime::active;
1040
-            } else {
1041
-                // upcoming?
1042
-                if (
1043
-                    EEM_Datetime::instance()->get_datetime_count_for_status(
1044
-                        EE_Datetime::upcoming,
1045
-                        $where_params_for_event
1046
-                    ) > 0
1047
-                ) {
1048
-                    $this->_active_status = EE_Datetime::upcoming;
1049
-                } else {
1050
-                    // expired?
1051
-                    if (
1052
-                        EEM_Datetime::instance()->get_datetime_count_for_status(
1053
-                            EE_Datetime::expired,
1054
-                            $where_params_for_event
1055
-                        ) > 0
1056
-                    ) {
1057
-                        $this->_active_status = EE_Datetime::expired;
1058
-                    } else {
1059
-                        // it would be odd if things make it this far because it basically means there are no datetime's
1060
-                        // attached to the event.  So in this case it will just be considered inactive.
1061
-                        $this->_active_status = EE_Datetime::inactive;
1062
-                    }
1063
-                }
1064
-            }
1065
-        } else {
1066
-            // the event is not published, so let's just set it's active status according to its' post status
1067
-            switch ($this->status()) {
1068
-                case EEM_Event::sold_out:
1069
-                    $this->_active_status = EE_Datetime::sold_out;
1070
-                    break;
1071
-                case EEM_Event::cancelled:
1072
-                    $this->_active_status = EE_Datetime::cancelled;
1073
-                    break;
1074
-                case EEM_Event::postponed:
1075
-                    $this->_active_status = EE_Datetime::postponed;
1076
-                    break;
1077
-                default:
1078
-                    $this->_active_status = EE_Datetime::inactive;
1079
-            }
1080
-        }
1081
-        return $this->_active_status;
1082
-    }
1083
-
1084
-
1085
-    /**
1086
-     *    pretty_active_status
1087
-     *
1088
-     * @access public
1089
-     * @param boolean $echo whether to return (FALSE), or echo out the result (TRUE)
1090
-     * @return mixed void|string
1091
-     * @throws EE_Error
1092
-     */
1093
-    public function pretty_active_status($echo = true)
1094
-    {
1095
-        $active_status = $this->get_active_status();
1096
-        $status = '<span class="ee-status event-active-status-'
1097
-                  . $active_status
1098
-                  . '">'
1099
-                  . EEH_Template::pretty_status($active_status, false, 'sentence')
1100
-                  . '</span>';
1101
-        if ($echo) {
1102
-            echo $status;
1103
-            return '';
1104
-        }
1105
-        return $status;
1106
-    }
1107
-
1108
-
1109
-    /**
1110
-     * @return bool|int
1111
-     * @throws EE_Error
1112
-     */
1113
-    public function get_number_of_tickets_sold()
1114
-    {
1115
-        $tkt_sold = 0;
1116
-        if (! $this->ID()) {
1117
-            return 0;
1118
-        }
1119
-        $datetimes = $this->datetimes();
1120
-        foreach ($datetimes as $datetime) {
1121
-            if ($datetime instanceof EE_Datetime) {
1122
-                $tkt_sold += $datetime->sold();
1123
-            }
1124
-        }
1125
-        return $tkt_sold;
1126
-    }
1127
-
1128
-
1129
-    /**
1130
-     * This just returns a count of all the registrations for this event
1131
-     *
1132
-     * @access  public
1133
-     * @return int
1134
-     * @throws EE_Error
1135
-     */
1136
-    public function get_count_of_all_registrations()
1137
-    {
1138
-        return EEM_Event::instance()->count_related($this, 'Registration');
1139
-    }
1140
-
1141
-
1142
-    /**
1143
-     * This returns the ticket with the earliest start time that is
1144
-     * available for this event (across all datetimes attached to the event)
1145
-     *
1146
-     * @return EE_Base_Class|EE_Ticket|null
1147
-     * @throws EE_Error
1148
-     */
1149
-    public function get_ticket_with_earliest_start_time()
1150
-    {
1151
-        $where['Datetime.EVT_ID'] = $this->ID();
1152
-        $query_params = array($where, 'order_by' => array('TKT_start_date' => 'ASC'));
1153
-        return EE_Registry::instance()->load_model('Ticket')->get_one($query_params);
1154
-    }
1155
-
1156
-
1157
-    /**
1158
-     * This returns the ticket with the latest end time that is available
1159
-     * for this event (across all datetimes attached to the event)
1160
-     *
1161
-     * @return EE_Base_Class|EE_Ticket|null
1162
-     * @throws EE_Error
1163
-     */
1164
-    public function get_ticket_with_latest_end_time()
1165
-    {
1166
-        $where['Datetime.EVT_ID'] = $this->ID();
1167
-        $query_params = array($where, 'order_by' => array('TKT_end_date' => 'DESC'));
1168
-        return EE_Registry::instance()->load_model('Ticket')->get_one($query_params);
1169
-    }
1170
-
1171
-
1172
-    /**
1173
-     * This returns the number of different ticket types currently on sale for this event.
1174
-     *
1175
-     * @return int
1176
-     * @throws EE_Error
1177
-     */
1178
-    public function countTicketsOnSale()
1179
-    {
1180
-        $where = array(
1181
-            'Datetime.EVT_ID' => $this->ID(),
1182
-            'TKT_start_date'  => array('<', time()),
1183
-            'TKT_end_date'    => array('>', time()),
1184
-        );
1185
-        return EEM_Ticket::instance()->count(array($where));
1186
-    }
1187
-
1188
-
1189
-    /**
1190
-     * This returns whether there are any tickets on sale for this event.
1191
-     *
1192
-     * @return bool true = YES tickets on sale.
1193
-     * @throws EE_Error
1194
-     */
1195
-    public function tickets_on_sale()
1196
-    {
1197
-        return $this->countTicketsOnSale() > 0;
1198
-    }
1199
-
1200
-
1201
-    /**
1202
-     * Gets the URL for viewing this event on the front-end. Overrides parent
1203
-     * to check for an external URL first
1204
-     *
1205
-     * @return string
1206
-     * @throws EE_Error
1207
-     */
1208
-    public function get_permalink()
1209
-    {
1210
-        if ($this->external_url()) {
1211
-            return $this->external_url();
1212
-        }
1213
-        return parent::get_permalink();
1214
-    }
1215
-
1216
-
1217
-    /**
1218
-     * Gets the first term for 'espresso_event_categories' we can find
1219
-     *
1220
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1221
-     * @return EE_Base_Class|EE_Term|null
1222
-     * @throws EE_Error
1223
-     */
1224
-    public function first_event_category($query_params = array())
1225
-    {
1226
-        $query_params[0]['Term_Taxonomy.taxonomy'] = 'espresso_event_categories';
1227
-        $query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $this->ID();
1228
-        return EEM_Term::instance()->get_one($query_params);
1229
-    }
1230
-
1231
-
1232
-    /**
1233
-     * Gets all terms for 'espresso_event_categories' we can find
1234
-     *
1235
-     * @param array $query_params
1236
-     * @return EE_Base_Class[]|EE_Term[]
1237
-     * @throws EE_Error
1238
-     */
1239
-    public function get_all_event_categories($query_params = array())
1240
-    {
1241
-        $query_params[0]['Term_Taxonomy.taxonomy'] = 'espresso_event_categories';
1242
-        $query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $this->ID();
1243
-        return EEM_Term::instance()->get_all($query_params);
1244
-    }
1245
-
1246
-
1247
-    /**
1248
-     * Adds a question group to this event
1249
-     *
1250
-     * @param EE_Question_Group|int $question_group_id_or_obj
1251
-     * @param bool $for_primary if true, the question group will be added for the primary
1252
-     *                                           registrant, if false will be added for others. default: false
1253
-     * @return EE_Base_Class|EE_Question_Group
1254
-     * @throws EE_Error
1255
-     * @throws InvalidArgumentException
1256
-     * @throws InvalidDataTypeException
1257
-     * @throws InvalidInterfaceException
1258
-     * @throws ReflectionException
1259
-     */
1260
-    public function add_question_group($question_group_id_or_obj, $for_primary = false)
1261
-    {
1262
-        // If the row already exists, it will be updated. If it doesn't, it will be inserted.
1263
-        // That's in EE_HABTM_Relation::add_relation_to().
1264
-        return $this->_add_relation_to(
1265
-            $question_group_id_or_obj,
1266
-            'Question_Group',
1267
-            [
1268
-                EEM_Event_Question_Group::instance()->fieldNameForContext($for_primary) => true
1269
-            ]
1270
-        );
1271
-    }
1272
-
1273
-
1274
-    /**
1275
-     * Removes a question group from the event
1276
-     *
1277
-     * @param EE_Question_Group|int $question_group_id_or_obj
1278
-     * @param bool $for_primary if true, the question group will be removed from the primary
1279
-     *                                           registrant, if false will be removed from others. default: false
1280
-     * @return EE_Base_Class|EE_Question_Group
1281
-     * @throws EE_Error
1282
-     * @throws InvalidArgumentException
1283
-     * @throws ReflectionException
1284
-     * @throws InvalidDataTypeException
1285
-     * @throws InvalidInterfaceException
1286
-     */
1287
-    public function remove_question_group($question_group_id_or_obj, $for_primary = false)
1288
-    {
1289
-        // If the question group is used for the other type (primary or additional)
1290
-        // then just update it. If not, delete it outright.
1291
-        $existing_relation = $this->get_first_related(
1292
-            'Event_Question_Group',
1293
-            [
1294
-                [
1295
-                    'QSG_ID' => EEM_Question_Group::instance()->ensure_is_ID($question_group_id_or_obj)
1296
-                ]
1297
-            ]
1298
-        );
1299
-        $field_to_update = EEM_Event_Question_Group::instance()->fieldNameForContext($for_primary);
1300
-        $other_field = EEM_Event_Question_Group::instance()->fieldNameForContext(! $for_primary);
1301
-        if ($existing_relation->get($other_field) === false) {
1302
-            // Delete it. It's now no longer for primary or additional question groups.
1303
-            return $this->_remove_relation_to($question_group_id_or_obj, 'Question_Group');
1304
-        }
1305
-        // Just update it. They'll still use this question group for the other category
1306
-        $existing_relation->save(
1307
-            [
1308
-                $field_to_update => false
1309
-            ]
1310
-        );
1311
-    }
1312
-
1313
-
1314
-    /**
1315
-     * Gets all the question groups, ordering them by QSG_order ascending
1316
-     *
1317
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1318
-     * @return EE_Base_Class[]|EE_Question_Group[]
1319
-     * @throws EE_Error
1320
-     */
1321
-    public function question_groups($query_params = array())
1322
-    {
1323
-        $query_params = ! empty($query_params) ? $query_params : array('order_by' => array('QSG_order' => 'ASC'));
1324
-        return $this->get_many_related('Question_Group', $query_params);
1325
-    }
1326
-
1327
-
1328
-    /**
1329
-     * Implementation for EEI_Has_Icon interface method.
1330
-     *
1331
-     * @see EEI_Visual_Representation for comments
1332
-     * @return string
1333
-     */
1334
-    public function get_icon()
1335
-    {
1336
-        return '<span class="dashicons dashicons-flag"></span>';
1337
-    }
1338
-
1339
-
1340
-    /**
1341
-     * Implementation for EEI_Admin_Links interface method.
1342
-     *
1343
-     * @see EEI_Admin_Links for comments
1344
-     * @return string
1345
-     * @throws EE_Error
1346
-     */
1347
-    public function get_admin_details_link()
1348
-    {
1349
-        return $this->get_admin_edit_link();
1350
-    }
1351
-
1352
-
1353
-    /**
1354
-     * Implementation for EEI_Admin_Links interface method.
1355
-     *
1356
-     * @see EEI_Admin_Links for comments
1357
-     * @return string
1358
-     * @throws EE_Error
1359
-     */
1360
-    public function get_admin_edit_link()
1361
-    {
1362
-        return EEH_URL::add_query_args_and_nonce(
1363
-            array(
1364
-                'page'   => 'espresso_events',
1365
-                'action' => 'edit',
1366
-                'post'   => $this->ID(),
1367
-            ),
1368
-            admin_url('admin.php')
1369
-        );
1370
-    }
1371
-
1372
-
1373
-    /**
1374
-     * Implementation for EEI_Admin_Links interface method.
1375
-     *
1376
-     * @see EEI_Admin_Links for comments
1377
-     * @return string
1378
-     */
1379
-    public function get_admin_settings_link()
1380
-    {
1381
-        return EEH_URL::add_query_args_and_nonce(
1382
-            array(
1383
-                'page'   => 'espresso_events',
1384
-                'action' => 'default_event_settings',
1385
-            ),
1386
-            admin_url('admin.php')
1387
-        );
1388
-    }
1389
-
1390
-
1391
-    /**
1392
-     * Implementation for EEI_Admin_Links interface method.
1393
-     *
1394
-     * @see EEI_Admin_Links for comments
1395
-     * @return string
1396
-     */
1397
-    public function get_admin_overview_link()
1398
-    {
1399
-        return EEH_URL::add_query_args_and_nonce(
1400
-            array(
1401
-                'page'   => 'espresso_events',
1402
-                'action' => 'default',
1403
-            ),
1404
-            admin_url('admin.php')
1405
-        );
1406
-    }
18
+	/**
19
+	 * cached value for the the logical active status for the event
20
+	 *
21
+	 * @see get_active_status()
22
+	 * @var string
23
+	 */
24
+	protected $_active_status = '';
25
+
26
+	/**
27
+	 * This is just used for caching the Primary Datetime for the Event on initial retrieval
28
+	 *
29
+	 * @var EE_Datetime
30
+	 */
31
+	protected $_Primary_Datetime;
32
+
33
+	/**
34
+	 * @var EventSpacesCalculator $available_spaces_calculator
35
+	 */
36
+	protected $available_spaces_calculator;
37
+
38
+
39
+	/**
40
+	 * @param array  $props_n_values          incoming values
41
+	 * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
42
+	 *                                        used.)
43
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
44
+	 *                                        date_format and the second value is the time format
45
+	 * @return EE_Event
46
+	 * @throws EE_Error
47
+	 */
48
+	public static function new_instance($props_n_values = array(), $timezone = '', $date_formats = array())
49
+	{
50
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
51
+		return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
52
+	}
53
+
54
+
55
+	/**
56
+	 * @param array  $props_n_values  incoming values from the database
57
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
58
+	 *                                the website will be used.
59
+	 * @return EE_Event
60
+	 * @throws EE_Error
61
+	 */
62
+	public static function new_instance_from_db($props_n_values = array(), $timezone = '')
63
+	{
64
+		return new self($props_n_values, true, $timezone);
65
+	}
66
+
67
+
68
+	/**
69
+	 * @return EventSpacesCalculator
70
+	 * @throws \EE_Error
71
+	 */
72
+	public function getAvailableSpacesCalculator()
73
+	{
74
+		if (! $this->available_spaces_calculator instanceof EventSpacesCalculator) {
75
+			$this->available_spaces_calculator = new EventSpacesCalculator($this);
76
+		}
77
+		return $this->available_spaces_calculator;
78
+	}
79
+
80
+
81
+	/**
82
+	 * Overrides parent set() method so that all calls to set( 'status', $status ) can be routed to internal methods
83
+	 *
84
+	 * @param string $field_name
85
+	 * @param mixed  $field_value
86
+	 * @param bool   $use_default
87
+	 * @throws EE_Error
88
+	 */
89
+	public function set($field_name, $field_value, $use_default = false)
90
+	{
91
+		switch ($field_name) {
92
+			case 'status':
93
+				$this->set_status($field_value, $use_default);
94
+				break;
95
+			default:
96
+				parent::set($field_name, $field_value, $use_default);
97
+		}
98
+	}
99
+
100
+
101
+	/**
102
+	 *    set_status
103
+	 * Checks if event status is being changed to SOLD OUT
104
+	 * and updates event meta data with previous event status
105
+	 * so that we can revert things if/when the event is no longer sold out
106
+	 *
107
+	 * @access public
108
+	 * @param string $new_status
109
+	 * @param bool   $use_default
110
+	 * @return void
111
+	 * @throws EE_Error
112
+	 */
113
+	public function set_status($new_status = null, $use_default = false)
114
+	{
115
+		// if nothing is set, and we aren't explicitly wanting to reset the status, then just leave
116
+		if (empty($new_status) && ! $use_default) {
117
+			return;
118
+		}
119
+		// get current Event status
120
+		$old_status = $this->status();
121
+		// if status has changed
122
+		if ($old_status !== $new_status) {
123
+			// TO sold_out
124
+			if ($new_status === EEM_Event::sold_out) {
125
+				// save the previous event status so that we can revert if the event is no longer sold out
126
+				$this->add_post_meta('_previous_event_status', $old_status);
127
+				do_action('AHEE__EE_Event__set_status__to_sold_out', $this, $old_status, $new_status);
128
+				// OR FROM  sold_out
129
+			} elseif ($old_status === EEM_Event::sold_out) {
130
+				$this->delete_post_meta('_previous_event_status');
131
+				do_action('AHEE__EE_Event__set_status__from_sold_out', $this, $old_status, $new_status);
132
+			}
133
+			// clear out the active status so that it gets reset the next time it is requested
134
+			$this->_active_status = null;
135
+			// update status
136
+			parent::set('status', $new_status, $use_default);
137
+			do_action('AHEE__EE_Event__set_status__after_update', $this);
138
+			return;
139
+		}
140
+		// even though the old value matches the new value, it's still good to
141
+		// allow the parent set method to have a say
142
+		parent::set('status', $new_status, $use_default);
143
+	}
144
+
145
+
146
+	/**
147
+	 * Gets all the datetimes for this event
148
+	 *
149
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
150
+	 * @return EE_Base_Class[]|EE_Datetime[]
151
+	 * @throws EE_Error
152
+	 */
153
+	public function datetimes($query_params = array())
154
+	{
155
+		return $this->get_many_related('Datetime', $query_params);
156
+	}
157
+
158
+
159
+	/**
160
+	 * Gets all the datetimes for this event, ordered by DTT_EVT_start in ascending order
161
+	 *
162
+	 * @return EE_Base_Class[]|EE_Datetime[]
163
+	 * @throws EE_Error
164
+	 */
165
+	public function datetimes_in_chronological_order()
166
+	{
167
+		return $this->get_many_related('Datetime', array('order_by' => array('DTT_EVT_start' => 'ASC')));
168
+	}
169
+
170
+
171
+	/**
172
+	 * Gets all the datetimes for this event, ordered by the DTT_order on the datetime.
173
+	 * @darren, we should probably UNSET timezone on the EEM_Datetime model
174
+	 * after running our query, so that this timezone isn't set for EVERY query
175
+	 * on EEM_Datetime for the rest of the request, no?
176
+	 *
177
+	 * @param boolean $show_expired whether or not to include expired events
178
+	 * @param boolean $show_deleted whether or not to include deleted events
179
+	 * @param null    $limit
180
+	 * @return EE_Datetime[]
181
+	 * @throws EE_Error
182
+	 */
183
+	public function datetimes_ordered($show_expired = true, $show_deleted = false, $limit = null)
184
+	{
185
+		return EEM_Datetime::instance($this->_timezone)->get_datetimes_for_event_ordered_by_DTT_order(
186
+			$this->ID(),
187
+			$show_expired,
188
+			$show_deleted,
189
+			$limit
190
+		);
191
+	}
192
+
193
+
194
+	/**
195
+	 * Returns one related datetime. Mostly only used by some legacy code.
196
+	 *
197
+	 * @return EE_Base_Class|EE_Datetime
198
+	 * @throws EE_Error
199
+	 */
200
+	public function first_datetime()
201
+	{
202
+		return $this->get_first_related('Datetime');
203
+	}
204
+
205
+
206
+	/**
207
+	 * Returns the 'primary' datetime for the event
208
+	 *
209
+	 * @param bool $try_to_exclude_expired
210
+	 * @param bool $try_to_exclude_deleted
211
+	 * @return EE_Datetime
212
+	 * @throws EE_Error
213
+	 */
214
+	public function primary_datetime($try_to_exclude_expired = true, $try_to_exclude_deleted = true)
215
+	{
216
+		if (! empty($this->_Primary_Datetime)) {
217
+			return $this->_Primary_Datetime;
218
+		}
219
+		$this->_Primary_Datetime = EEM_Datetime::instance($this->_timezone)->get_primary_datetime_for_event(
220
+			$this->ID(),
221
+			$try_to_exclude_expired,
222
+			$try_to_exclude_deleted
223
+		);
224
+		return $this->_Primary_Datetime;
225
+	}
226
+
227
+
228
+	/**
229
+	 * Gets all the tickets available for purchase of this event
230
+	 *
231
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
232
+	 * @return EE_Base_Class[]|EE_Ticket[]
233
+	 * @throws EE_Error
234
+	 */
235
+	public function tickets($query_params = array())
236
+	{
237
+		// first get all datetimes
238
+		$datetimes = $this->datetimes_ordered();
239
+		if (! $datetimes) {
240
+			return array();
241
+		}
242
+		$datetime_ids = array();
243
+		foreach ($datetimes as $datetime) {
244
+			$datetime_ids[] = $datetime->ID();
245
+		}
246
+		$where_params = array('Datetime.DTT_ID' => array('IN', $datetime_ids));
247
+		// if incoming $query_params has where conditions let's merge but not override existing.
248
+		if (is_array($query_params) && isset($query_params[0])) {
249
+			$where_params = array_merge($query_params[0], $where_params);
250
+			unset($query_params[0]);
251
+		}
252
+		// now add $where_params to $query_params
253
+		$query_params[0] = $where_params;
254
+		return EEM_Ticket::instance()->get_all($query_params);
255
+	}
256
+
257
+
258
+	/**
259
+	 * get all unexpired untrashed tickets
260
+	 *
261
+	 * @return EE_Ticket[]
262
+	 * @throws EE_Error
263
+	 */
264
+	public function active_tickets()
265
+	{
266
+		return $this->tickets(
267
+			array(
268
+				array(
269
+					'TKT_end_date' => array('>=', EEM_Ticket::instance()->current_time_for_query('TKT_end_date')),
270
+					'TKT_deleted'  => false,
271
+				),
272
+			)
273
+		);
274
+	}
275
+
276
+
277
+	/**
278
+	 * @return bool
279
+	 * @throws EE_Error
280
+	 */
281
+	public function additional_limit()
282
+	{
283
+		return $this->get('EVT_additional_limit');
284
+	}
285
+
286
+
287
+	/**
288
+	 * @return bool
289
+	 * @throws EE_Error
290
+	 */
291
+	public function allow_overflow()
292
+	{
293
+		return $this->get('EVT_allow_overflow');
294
+	}
295
+
296
+
297
+	/**
298
+	 * @return bool
299
+	 * @throws EE_Error
300
+	 */
301
+	public function created()
302
+	{
303
+		return $this->get('EVT_created');
304
+	}
305
+
306
+
307
+	/**
308
+	 * @return bool
309
+	 * @throws EE_Error
310
+	 */
311
+	public function description()
312
+	{
313
+		return $this->get('EVT_desc');
314
+	}
315
+
316
+
317
+	/**
318
+	 * Runs do_shortcode and wpautop on the description
319
+	 *
320
+	 * @return string of html
321
+	 * @throws EE_Error
322
+	 */
323
+	public function description_filtered()
324
+	{
325
+		return $this->get_pretty('EVT_desc');
326
+	}
327
+
328
+
329
+	/**
330
+	 * @return bool
331
+	 * @throws EE_Error
332
+	 */
333
+	public function display_description()
334
+	{
335
+		return $this->get('EVT_display_desc');
336
+	}
337
+
338
+
339
+	/**
340
+	 * @return bool
341
+	 * @throws EE_Error
342
+	 */
343
+	public function display_ticket_selector()
344
+	{
345
+		return (bool) $this->get('EVT_display_ticket_selector');
346
+	}
347
+
348
+
349
+	/**
350
+	 * @return bool
351
+	 * @throws EE_Error
352
+	 */
353
+	public function external_url()
354
+	{
355
+		return $this->get('EVT_external_URL');
356
+	}
357
+
358
+
359
+	/**
360
+	 * @return bool
361
+	 * @throws EE_Error
362
+	 */
363
+	public function member_only()
364
+	{
365
+		return $this->get('EVT_member_only');
366
+	}
367
+
368
+
369
+	/**
370
+	 * @return bool
371
+	 * @throws EE_Error
372
+	 */
373
+	public function phone()
374
+	{
375
+		return $this->get('EVT_phone');
376
+	}
377
+
378
+
379
+	/**
380
+	 * @return bool
381
+	 * @throws EE_Error
382
+	 */
383
+	public function modified()
384
+	{
385
+		return $this->get('EVT_modified');
386
+	}
387
+
388
+
389
+	/**
390
+	 * @return bool
391
+	 * @throws EE_Error
392
+	 */
393
+	public function name()
394
+	{
395
+		return $this->get('EVT_name');
396
+	}
397
+
398
+
399
+	/**
400
+	 * @return bool
401
+	 * @throws EE_Error
402
+	 */
403
+	public function order()
404
+	{
405
+		return $this->get('EVT_order');
406
+	}
407
+
408
+
409
+	/**
410
+	 * @return bool|string
411
+	 * @throws EE_Error
412
+	 */
413
+	public function default_registration_status()
414
+	{
415
+		$event_default_registration_status = $this->get('EVT_default_registration_status');
416
+		return ! empty($event_default_registration_status)
417
+			? $event_default_registration_status
418
+			: EE_Registry::instance()->CFG->registration->default_STS_ID;
419
+	}
420
+
421
+
422
+	/**
423
+	 * @param int  $num_words
424
+	 * @param null $more
425
+	 * @param bool $not_full_desc
426
+	 * @return bool|string
427
+	 * @throws EE_Error
428
+	 */
429
+	public function short_description($num_words = 55, $more = null, $not_full_desc = false)
430
+	{
431
+		$short_desc = $this->get('EVT_short_desc');
432
+		if (! empty($short_desc) || $not_full_desc) {
433
+			return $short_desc;
434
+		}
435
+		$full_desc = $this->get('EVT_desc');
436
+		return wp_trim_words($full_desc, $num_words, $more);
437
+	}
438
+
439
+
440
+	/**
441
+	 * @return bool
442
+	 * @throws EE_Error
443
+	 */
444
+	public function slug()
445
+	{
446
+		return $this->get('EVT_slug');
447
+	}
448
+
449
+
450
+	/**
451
+	 * @return bool
452
+	 * @throws EE_Error
453
+	 */
454
+	public function timezone_string()
455
+	{
456
+		return $this->get('EVT_timezone_string');
457
+	}
458
+
459
+
460
+	/**
461
+	 * @return bool
462
+	 * @throws EE_Error
463
+	 */
464
+	public function visible_on()
465
+	{
466
+		return $this->get('EVT_visible_on');
467
+	}
468
+
469
+
470
+	/**
471
+	 * @return int
472
+	 * @throws EE_Error
473
+	 */
474
+	public function wp_user()
475
+	{
476
+		return $this->get('EVT_wp_user');
477
+	}
478
+
479
+
480
+	/**
481
+	 * @return bool
482
+	 * @throws EE_Error
483
+	 */
484
+	public function donations()
485
+	{
486
+		return $this->get('EVT_donations');
487
+	}
488
+
489
+
490
+	/**
491
+	 * @param $limit
492
+	 * @throws EE_Error
493
+	 */
494
+	public function set_additional_limit($limit)
495
+	{
496
+		$this->set('EVT_additional_limit', $limit);
497
+	}
498
+
499
+
500
+	/**
501
+	 * @param $created
502
+	 * @throws EE_Error
503
+	 */
504
+	public function set_created($created)
505
+	{
506
+		$this->set('EVT_created', $created);
507
+	}
508
+
509
+
510
+	/**
511
+	 * @param $desc
512
+	 * @throws EE_Error
513
+	 */
514
+	public function set_description($desc)
515
+	{
516
+		$this->set('EVT_desc', $desc);
517
+	}
518
+
519
+
520
+	/**
521
+	 * @param $display_desc
522
+	 * @throws EE_Error
523
+	 */
524
+	public function set_display_description($display_desc)
525
+	{
526
+		$this->set('EVT_display_desc', $display_desc);
527
+	}
528
+
529
+
530
+	/**
531
+	 * @param $display_ticket_selector
532
+	 * @throws EE_Error
533
+	 */
534
+	public function set_display_ticket_selector($display_ticket_selector)
535
+	{
536
+		$this->set('EVT_display_ticket_selector', $display_ticket_selector);
537
+	}
538
+
539
+
540
+	/**
541
+	 * @param $external_url
542
+	 * @throws EE_Error
543
+	 */
544
+	public function set_external_url($external_url)
545
+	{
546
+		$this->set('EVT_external_URL', $external_url);
547
+	}
548
+
549
+
550
+	/**
551
+	 * @param $member_only
552
+	 * @throws EE_Error
553
+	 */
554
+	public function set_member_only($member_only)
555
+	{
556
+		$this->set('EVT_member_only', $member_only);
557
+	}
558
+
559
+
560
+	/**
561
+	 * @param $event_phone
562
+	 * @throws EE_Error
563
+	 */
564
+	public function set_event_phone($event_phone)
565
+	{
566
+		$this->set('EVT_phone', $event_phone);
567
+	}
568
+
569
+
570
+	/**
571
+	 * @param $modified
572
+	 * @throws EE_Error
573
+	 */
574
+	public function set_modified($modified)
575
+	{
576
+		$this->set('EVT_modified', $modified);
577
+	}
578
+
579
+
580
+	/**
581
+	 * @param $name
582
+	 * @throws EE_Error
583
+	 */
584
+	public function set_name($name)
585
+	{
586
+		$this->set('EVT_name', $name);
587
+	}
588
+
589
+
590
+	/**
591
+	 * @param $order
592
+	 * @throws EE_Error
593
+	 */
594
+	public function set_order($order)
595
+	{
596
+		$this->set('EVT_order', $order);
597
+	}
598
+
599
+
600
+	/**
601
+	 * @param $short_desc
602
+	 * @throws EE_Error
603
+	 */
604
+	public function set_short_description($short_desc)
605
+	{
606
+		$this->set('EVT_short_desc', $short_desc);
607
+	}
608
+
609
+
610
+	/**
611
+	 * @param $slug
612
+	 * @throws EE_Error
613
+	 */
614
+	public function set_slug($slug)
615
+	{
616
+		$this->set('EVT_slug', $slug);
617
+	}
618
+
619
+
620
+	/**
621
+	 * @param $timezone_string
622
+	 * @throws EE_Error
623
+	 */
624
+	public function set_timezone_string($timezone_string)
625
+	{
626
+		$this->set('EVT_timezone_string', $timezone_string);
627
+	}
628
+
629
+
630
+	/**
631
+	 * @param $visible_on
632
+	 * @throws EE_Error
633
+	 */
634
+	public function set_visible_on($visible_on)
635
+	{
636
+		$this->set('EVT_visible_on', $visible_on);
637
+	}
638
+
639
+
640
+	/**
641
+	 * @param $wp_user
642
+	 * @throws EE_Error
643
+	 */
644
+	public function set_wp_user($wp_user)
645
+	{
646
+		$this->set('EVT_wp_user', $wp_user);
647
+	}
648
+
649
+
650
+	/**
651
+	 * @param $default_registration_status
652
+	 * @throws EE_Error
653
+	 */
654
+	public function set_default_registration_status($default_registration_status)
655
+	{
656
+		$this->set('EVT_default_registration_status', $default_registration_status);
657
+	}
658
+
659
+
660
+	/**
661
+	 * @param $donations
662
+	 * @throws EE_Error
663
+	 */
664
+	public function set_donations($donations)
665
+	{
666
+		$this->set('EVT_donations', $donations);
667
+	}
668
+
669
+
670
+	/**
671
+	 * Adds a venue to this event
672
+	 *
673
+	 * @param EE_Venue /int $venue_id_or_obj
674
+	 * @return EE_Base_Class|EE_Venue
675
+	 * @throws EE_Error
676
+	 */
677
+	public function add_venue($venue_id_or_obj)
678
+	{
679
+		return $this->_add_relation_to($venue_id_or_obj, 'Venue');
680
+	}
681
+
682
+
683
+	/**
684
+	 * Removes a venue from the event
685
+	 *
686
+	 * @param EE_Venue /int $venue_id_or_obj
687
+	 * @return EE_Base_Class|EE_Venue
688
+	 * @throws EE_Error
689
+	 */
690
+	public function remove_venue($venue_id_or_obj)
691
+	{
692
+		return $this->_remove_relation_to($venue_id_or_obj, 'Venue');
693
+	}
694
+
695
+
696
+	/**
697
+	 * Gets all the venues related ot the event. May provide additional $query_params if desired
698
+	 *
699
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
700
+	 * @return EE_Base_Class[]|EE_Venue[]
701
+	 * @throws EE_Error
702
+	 */
703
+	public function venues($query_params = array())
704
+	{
705
+		return $this->get_many_related('Venue', $query_params);
706
+	}
707
+
708
+
709
+	/**
710
+	 * check if event id is present and if event is published
711
+	 *
712
+	 * @access public
713
+	 * @return boolean true yes, false no
714
+	 * @throws EE_Error
715
+	 */
716
+	private function _has_ID_and_is_published()
717
+	{
718
+		// first check if event id is present and not NULL,
719
+		// then check if this event is published (or any of the equivalent "published" statuses)
720
+		return
721
+			$this->ID() && $this->ID() !== null
722
+			&& (
723
+				$this->status() === 'publish'
724
+				|| $this->status() === EEM_Event::sold_out
725
+				|| $this->status() === EEM_Event::postponed
726
+				|| $this->status() === EEM_Event::cancelled
727
+			);
728
+	}
729
+
730
+
731
+	/**
732
+	 * This simply compares the internal dates with NOW and determines if the event is upcoming or not.
733
+	 *
734
+	 * @access public
735
+	 * @return boolean true yes, false no
736
+	 * @throws EE_Error
737
+	 */
738
+	public function is_upcoming()
739
+	{
740
+		// check if event id is present and if this event is published
741
+		if ($this->is_inactive()) {
742
+			return false;
743
+		}
744
+		// set initial value
745
+		$upcoming = false;
746
+		// next let's get all datetimes and loop through them
747
+		$datetimes = $this->datetimes_in_chronological_order();
748
+		foreach ($datetimes as $datetime) {
749
+			if ($datetime instanceof EE_Datetime) {
750
+				// if this dtt is expired then we continue cause one of the other datetimes might be upcoming.
751
+				if ($datetime->is_expired()) {
752
+					continue;
753
+				}
754
+				// if this dtt is active then we return false.
755
+				if ($datetime->is_active()) {
756
+					return false;
757
+				}
758
+				// otherwise let's check upcoming status
759
+				$upcoming = $datetime->is_upcoming();
760
+			}
761
+		}
762
+		return $upcoming;
763
+	}
764
+
765
+
766
+	/**
767
+	 * @return bool
768
+	 * @throws EE_Error
769
+	 */
770
+	public function is_active()
771
+	{
772
+		// check if event id is present and if this event is published
773
+		if ($this->is_inactive()) {
774
+			return false;
775
+		}
776
+		// set initial value
777
+		$active = false;
778
+		// next let's get all datetimes and loop through them
779
+		$datetimes = $this->datetimes_in_chronological_order();
780
+		foreach ($datetimes as $datetime) {
781
+			if ($datetime instanceof EE_Datetime) {
782
+				// if this dtt is expired then we continue cause one of the other datetimes might be active.
783
+				if ($datetime->is_expired()) {
784
+					continue;
785
+				}
786
+				// if this dtt is upcoming then we return false.
787
+				if ($datetime->is_upcoming()) {
788
+					return false;
789
+				}
790
+				// otherwise let's check active status
791
+				$active = $datetime->is_active();
792
+			}
793
+		}
794
+		return $active;
795
+	}
796
+
797
+
798
+	/**
799
+	 * @return bool
800
+	 * @throws EE_Error
801
+	 */
802
+	public function is_expired()
803
+	{
804
+		// check if event id is present and if this event is published
805
+		if ($this->is_inactive()) {
806
+			return false;
807
+		}
808
+		// set initial value
809
+		$expired = false;
810
+		// first let's get all datetimes and loop through them
811
+		$datetimes = $this->datetimes_in_chronological_order();
812
+		foreach ($datetimes as $datetime) {
813
+			if ($datetime instanceof EE_Datetime) {
814
+				// if this dtt is upcoming or active then we return false.
815
+				if ($datetime->is_upcoming() || $datetime->is_active()) {
816
+					return false;
817
+				}
818
+				// otherwise let's check active status
819
+				$expired = $datetime->is_expired();
820
+			}
821
+		}
822
+		return $expired;
823
+	}
824
+
825
+
826
+	/**
827
+	 * @return bool
828
+	 * @throws EE_Error
829
+	 */
830
+	public function is_inactive()
831
+	{
832
+		// check if event id is present and if this event is published
833
+		if ($this->_has_ID_and_is_published()) {
834
+			return false;
835
+		}
836
+		return true;
837
+	}
838
+
839
+
840
+	/**
841
+	 * calculate spaces remaining based on "saleable" tickets
842
+	 *
843
+	 * @param array $tickets
844
+	 * @param bool  $filtered
845
+	 * @return int|float
846
+	 * @throws EE_Error
847
+	 * @throws DomainException
848
+	 * @throws UnexpectedEntityException
849
+	 */
850
+	public function spaces_remaining($tickets = array(), $filtered = true)
851
+	{
852
+		$this->getAvailableSpacesCalculator()->setActiveTickets($tickets);
853
+		$spaces_remaining = $this->getAvailableSpacesCalculator()->spacesRemaining();
854
+		return $filtered
855
+			? apply_filters(
856
+				'FHEE_EE_Event__spaces_remaining',
857
+				$spaces_remaining,
858
+				$this,
859
+				$tickets
860
+			)
861
+			: $spaces_remaining;
862
+	}
863
+
864
+
865
+	/**
866
+	 *    perform_sold_out_status_check
867
+	 *    checks all of this events's datetime  reg_limit - sold values to determine if ANY datetimes have spaces
868
+	 *    available... if NOT, then the event status will get toggled to 'sold_out'
869
+	 *
870
+	 * @return bool    return the ACTUAL sold out state.
871
+	 * @throws EE_Error
872
+	 * @throws DomainException
873
+	 * @throws UnexpectedEntityException
874
+	 */
875
+	public function perform_sold_out_status_check()
876
+	{
877
+		// get all tickets
878
+		$tickets = $this->tickets(
879
+			array(
880
+				'default_where_conditions' => 'none',
881
+				'order_by' => array('TKT_qty' => 'ASC'),
882
+			)
883
+		);
884
+		$all_expired = true;
885
+		foreach ($tickets as $ticket) {
886
+			if (! $ticket->is_expired()) {
887
+				$all_expired = false;
888
+				break;
889
+			}
890
+		}
891
+		// if all the tickets are just expired, then don't update the event status to sold out
892
+		if ($all_expired) {
893
+			return true;
894
+		}
895
+		$spaces_remaining = $this->spaces_remaining($tickets);
896
+		if ($spaces_remaining < 1) {
897
+			if ($this->status() !== EEM_Event::post_status_private) {
898
+				$this->set_status(EEM_Event::sold_out);
899
+				$this->save();
900
+			}
901
+			$sold_out = true;
902
+		} else {
903
+			$sold_out = false;
904
+			// was event previously marked as sold out ?
905
+			if ($this->status() === EEM_Event::sold_out) {
906
+				// revert status to previous value, if it was set
907
+				$previous_event_status = $this->get_post_meta('_previous_event_status', true);
908
+				if ($previous_event_status) {
909
+					$this->set_status($previous_event_status);
910
+					$this->save();
911
+				}
912
+			}
913
+		}
914
+		do_action('AHEE__EE_Event__perform_sold_out_status_check__end', $this, $sold_out, $spaces_remaining, $tickets);
915
+		return $sold_out;
916
+	}
917
+
918
+
919
+	/**
920
+	 * This returns the total remaining spaces for sale on this event.
921
+	 *
922
+	 * @uses EE_Event::total_available_spaces()
923
+	 * @return float|int
924
+	 * @throws EE_Error
925
+	 * @throws DomainException
926
+	 * @throws UnexpectedEntityException
927
+	 */
928
+	public function spaces_remaining_for_sale()
929
+	{
930
+		return $this->total_available_spaces(true);
931
+	}
932
+
933
+
934
+	/**
935
+	 * This returns the total spaces available for an event
936
+	 * while considering all the qtys on the tickets and the reg limits
937
+	 * on the datetimes attached to this event.
938
+	 *
939
+	 * @param   bool $consider_sold Whether to consider any tickets that have already sold in our calculation.
940
+	 *                              If this is false, then we return the most tickets that could ever be sold
941
+	 *                              for this event with the datetime and tickets setup on the event under optimal
942
+	 *                              selling conditions.  Otherwise we return a live calculation of spaces available
943
+	 *                              based on tickets sold.  Depending on setup and stage of sales, this
944
+	 *                              may appear to equal remaining tickets.  However, the more tickets are
945
+	 *                              sold out, the more accurate the "live" total is.
946
+	 * @return float|int
947
+	 * @throws EE_Error
948
+	 * @throws DomainException
949
+	 * @throws UnexpectedEntityException
950
+	 */
951
+	public function total_available_spaces($consider_sold = false)
952
+	{
953
+		$spaces_available = $consider_sold
954
+			? $this->getAvailableSpacesCalculator()->spacesRemaining()
955
+			: $this->getAvailableSpacesCalculator()->totalSpacesAvailable();
956
+		return apply_filters(
957
+			'FHEE_EE_Event__total_available_spaces__spaces_available',
958
+			$spaces_available,
959
+			$this,
960
+			$this->getAvailableSpacesCalculator()->getDatetimes(),
961
+			$this->getAvailableSpacesCalculator()->getActiveTickets()
962
+		);
963
+	}
964
+
965
+
966
+	/**
967
+	 * Checks if the event is set to sold out
968
+	 *
969
+	 * @param  bool $actual whether or not to perform calculations to not only figure the
970
+	 *                      actual status but also to flip the status if necessary to sold
971
+	 *                      out If false, we just check the existing status of the event
972
+	 * @return boolean
973
+	 * @throws EE_Error
974
+	 */
975
+	public function is_sold_out($actual = false)
976
+	{
977
+		if (! $actual) {
978
+			return $this->status() === EEM_Event::sold_out;
979
+		}
980
+		return $this->perform_sold_out_status_check();
981
+	}
982
+
983
+
984
+	/**
985
+	 * Checks if the event is marked as postponed
986
+	 *
987
+	 * @return boolean
988
+	 */
989
+	public function is_postponed()
990
+	{
991
+		return $this->status() === EEM_Event::postponed;
992
+	}
993
+
994
+
995
+	/**
996
+	 * Checks if the event is marked as cancelled
997
+	 *
998
+	 * @return boolean
999
+	 */
1000
+	public function is_cancelled()
1001
+	{
1002
+		return $this->status() === EEM_Event::cancelled;
1003
+	}
1004
+
1005
+
1006
+	/**
1007
+	 * Get the logical active status in a hierarchical order for all the datetimes.  Note
1008
+	 * Basically, we order the datetimes by EVT_start_date.  Then first test on whether the event is published.  If its
1009
+	 * NOT published then we test for whether its expired or not.  IF it IS published then we test first on whether an
1010
+	 * event has any active dates.  If no active dates then we check for any upcoming dates.  If no upcoming dates then
1011
+	 * the event is considered expired.
1012
+	 * NOTE: this method does NOT calculate whether the datetimes are sold out when event is published.  Sold Out is a
1013
+	 * status set on the EVENT when it is not published and thus is done
1014
+	 *
1015
+	 * @param bool $reset
1016
+	 * @return bool | string - based on EE_Datetime active constants or FALSE if error.
1017
+	 * @throws EE_Error
1018
+	 */
1019
+	public function get_active_status($reset = false)
1020
+	{
1021
+		// if the active status has already been set, then just use that value (unless we are resetting it)
1022
+		if (! empty($this->_active_status) && ! $reset) {
1023
+			return $this->_active_status;
1024
+		}
1025
+		// first check if event id is present on this object
1026
+		if (! $this->ID()) {
1027
+			return false;
1028
+		}
1029
+		$where_params_for_event = array(array('EVT_ID' => $this->ID()));
1030
+		// if event is published:
1031
+		if ($this->status() === EEM_Event::post_status_publish || $this->status() === EEM_Event::post_status_private) {
1032
+			// active?
1033
+			if (
1034
+				EEM_Datetime::instance()->get_datetime_count_for_status(
1035
+					EE_Datetime::active,
1036
+					$where_params_for_event
1037
+				) > 0
1038
+			) {
1039
+				$this->_active_status = EE_Datetime::active;
1040
+			} else {
1041
+				// upcoming?
1042
+				if (
1043
+					EEM_Datetime::instance()->get_datetime_count_for_status(
1044
+						EE_Datetime::upcoming,
1045
+						$where_params_for_event
1046
+					) > 0
1047
+				) {
1048
+					$this->_active_status = EE_Datetime::upcoming;
1049
+				} else {
1050
+					// expired?
1051
+					if (
1052
+						EEM_Datetime::instance()->get_datetime_count_for_status(
1053
+							EE_Datetime::expired,
1054
+							$where_params_for_event
1055
+						) > 0
1056
+					) {
1057
+						$this->_active_status = EE_Datetime::expired;
1058
+					} else {
1059
+						// it would be odd if things make it this far because it basically means there are no datetime's
1060
+						// attached to the event.  So in this case it will just be considered inactive.
1061
+						$this->_active_status = EE_Datetime::inactive;
1062
+					}
1063
+				}
1064
+			}
1065
+		} else {
1066
+			// the event is not published, so let's just set it's active status according to its' post status
1067
+			switch ($this->status()) {
1068
+				case EEM_Event::sold_out:
1069
+					$this->_active_status = EE_Datetime::sold_out;
1070
+					break;
1071
+				case EEM_Event::cancelled:
1072
+					$this->_active_status = EE_Datetime::cancelled;
1073
+					break;
1074
+				case EEM_Event::postponed:
1075
+					$this->_active_status = EE_Datetime::postponed;
1076
+					break;
1077
+				default:
1078
+					$this->_active_status = EE_Datetime::inactive;
1079
+			}
1080
+		}
1081
+		return $this->_active_status;
1082
+	}
1083
+
1084
+
1085
+	/**
1086
+	 *    pretty_active_status
1087
+	 *
1088
+	 * @access public
1089
+	 * @param boolean $echo whether to return (FALSE), or echo out the result (TRUE)
1090
+	 * @return mixed void|string
1091
+	 * @throws EE_Error
1092
+	 */
1093
+	public function pretty_active_status($echo = true)
1094
+	{
1095
+		$active_status = $this->get_active_status();
1096
+		$status = '<span class="ee-status event-active-status-'
1097
+				  . $active_status
1098
+				  . '">'
1099
+				  . EEH_Template::pretty_status($active_status, false, 'sentence')
1100
+				  . '</span>';
1101
+		if ($echo) {
1102
+			echo $status;
1103
+			return '';
1104
+		}
1105
+		return $status;
1106
+	}
1107
+
1108
+
1109
+	/**
1110
+	 * @return bool|int
1111
+	 * @throws EE_Error
1112
+	 */
1113
+	public function get_number_of_tickets_sold()
1114
+	{
1115
+		$tkt_sold = 0;
1116
+		if (! $this->ID()) {
1117
+			return 0;
1118
+		}
1119
+		$datetimes = $this->datetimes();
1120
+		foreach ($datetimes as $datetime) {
1121
+			if ($datetime instanceof EE_Datetime) {
1122
+				$tkt_sold += $datetime->sold();
1123
+			}
1124
+		}
1125
+		return $tkt_sold;
1126
+	}
1127
+
1128
+
1129
+	/**
1130
+	 * This just returns a count of all the registrations for this event
1131
+	 *
1132
+	 * @access  public
1133
+	 * @return int
1134
+	 * @throws EE_Error
1135
+	 */
1136
+	public function get_count_of_all_registrations()
1137
+	{
1138
+		return EEM_Event::instance()->count_related($this, 'Registration');
1139
+	}
1140
+
1141
+
1142
+	/**
1143
+	 * This returns the ticket with the earliest start time that is
1144
+	 * available for this event (across all datetimes attached to the event)
1145
+	 *
1146
+	 * @return EE_Base_Class|EE_Ticket|null
1147
+	 * @throws EE_Error
1148
+	 */
1149
+	public function get_ticket_with_earliest_start_time()
1150
+	{
1151
+		$where['Datetime.EVT_ID'] = $this->ID();
1152
+		$query_params = array($where, 'order_by' => array('TKT_start_date' => 'ASC'));
1153
+		return EE_Registry::instance()->load_model('Ticket')->get_one($query_params);
1154
+	}
1155
+
1156
+
1157
+	/**
1158
+	 * This returns the ticket with the latest end time that is available
1159
+	 * for this event (across all datetimes attached to the event)
1160
+	 *
1161
+	 * @return EE_Base_Class|EE_Ticket|null
1162
+	 * @throws EE_Error
1163
+	 */
1164
+	public function get_ticket_with_latest_end_time()
1165
+	{
1166
+		$where['Datetime.EVT_ID'] = $this->ID();
1167
+		$query_params = array($where, 'order_by' => array('TKT_end_date' => 'DESC'));
1168
+		return EE_Registry::instance()->load_model('Ticket')->get_one($query_params);
1169
+	}
1170
+
1171
+
1172
+	/**
1173
+	 * This returns the number of different ticket types currently on sale for this event.
1174
+	 *
1175
+	 * @return int
1176
+	 * @throws EE_Error
1177
+	 */
1178
+	public function countTicketsOnSale()
1179
+	{
1180
+		$where = array(
1181
+			'Datetime.EVT_ID' => $this->ID(),
1182
+			'TKT_start_date'  => array('<', time()),
1183
+			'TKT_end_date'    => array('>', time()),
1184
+		);
1185
+		return EEM_Ticket::instance()->count(array($where));
1186
+	}
1187
+
1188
+
1189
+	/**
1190
+	 * This returns whether there are any tickets on sale for this event.
1191
+	 *
1192
+	 * @return bool true = YES tickets on sale.
1193
+	 * @throws EE_Error
1194
+	 */
1195
+	public function tickets_on_sale()
1196
+	{
1197
+		return $this->countTicketsOnSale() > 0;
1198
+	}
1199
+
1200
+
1201
+	/**
1202
+	 * Gets the URL for viewing this event on the front-end. Overrides parent
1203
+	 * to check for an external URL first
1204
+	 *
1205
+	 * @return string
1206
+	 * @throws EE_Error
1207
+	 */
1208
+	public function get_permalink()
1209
+	{
1210
+		if ($this->external_url()) {
1211
+			return $this->external_url();
1212
+		}
1213
+		return parent::get_permalink();
1214
+	}
1215
+
1216
+
1217
+	/**
1218
+	 * Gets the first term for 'espresso_event_categories' we can find
1219
+	 *
1220
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1221
+	 * @return EE_Base_Class|EE_Term|null
1222
+	 * @throws EE_Error
1223
+	 */
1224
+	public function first_event_category($query_params = array())
1225
+	{
1226
+		$query_params[0]['Term_Taxonomy.taxonomy'] = 'espresso_event_categories';
1227
+		$query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $this->ID();
1228
+		return EEM_Term::instance()->get_one($query_params);
1229
+	}
1230
+
1231
+
1232
+	/**
1233
+	 * Gets all terms for 'espresso_event_categories' we can find
1234
+	 *
1235
+	 * @param array $query_params
1236
+	 * @return EE_Base_Class[]|EE_Term[]
1237
+	 * @throws EE_Error
1238
+	 */
1239
+	public function get_all_event_categories($query_params = array())
1240
+	{
1241
+		$query_params[0]['Term_Taxonomy.taxonomy'] = 'espresso_event_categories';
1242
+		$query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $this->ID();
1243
+		return EEM_Term::instance()->get_all($query_params);
1244
+	}
1245
+
1246
+
1247
+	/**
1248
+	 * Adds a question group to this event
1249
+	 *
1250
+	 * @param EE_Question_Group|int $question_group_id_or_obj
1251
+	 * @param bool $for_primary if true, the question group will be added for the primary
1252
+	 *                                           registrant, if false will be added for others. default: false
1253
+	 * @return EE_Base_Class|EE_Question_Group
1254
+	 * @throws EE_Error
1255
+	 * @throws InvalidArgumentException
1256
+	 * @throws InvalidDataTypeException
1257
+	 * @throws InvalidInterfaceException
1258
+	 * @throws ReflectionException
1259
+	 */
1260
+	public function add_question_group($question_group_id_or_obj, $for_primary = false)
1261
+	{
1262
+		// If the row already exists, it will be updated. If it doesn't, it will be inserted.
1263
+		// That's in EE_HABTM_Relation::add_relation_to().
1264
+		return $this->_add_relation_to(
1265
+			$question_group_id_or_obj,
1266
+			'Question_Group',
1267
+			[
1268
+				EEM_Event_Question_Group::instance()->fieldNameForContext($for_primary) => true
1269
+			]
1270
+		);
1271
+	}
1272
+
1273
+
1274
+	/**
1275
+	 * Removes a question group from the event
1276
+	 *
1277
+	 * @param EE_Question_Group|int $question_group_id_or_obj
1278
+	 * @param bool $for_primary if true, the question group will be removed from the primary
1279
+	 *                                           registrant, if false will be removed from others. default: false
1280
+	 * @return EE_Base_Class|EE_Question_Group
1281
+	 * @throws EE_Error
1282
+	 * @throws InvalidArgumentException
1283
+	 * @throws ReflectionException
1284
+	 * @throws InvalidDataTypeException
1285
+	 * @throws InvalidInterfaceException
1286
+	 */
1287
+	public function remove_question_group($question_group_id_or_obj, $for_primary = false)
1288
+	{
1289
+		// If the question group is used for the other type (primary or additional)
1290
+		// then just update it. If not, delete it outright.
1291
+		$existing_relation = $this->get_first_related(
1292
+			'Event_Question_Group',
1293
+			[
1294
+				[
1295
+					'QSG_ID' => EEM_Question_Group::instance()->ensure_is_ID($question_group_id_or_obj)
1296
+				]
1297
+			]
1298
+		);
1299
+		$field_to_update = EEM_Event_Question_Group::instance()->fieldNameForContext($for_primary);
1300
+		$other_field = EEM_Event_Question_Group::instance()->fieldNameForContext(! $for_primary);
1301
+		if ($existing_relation->get($other_field) === false) {
1302
+			// Delete it. It's now no longer for primary or additional question groups.
1303
+			return $this->_remove_relation_to($question_group_id_or_obj, 'Question_Group');
1304
+		}
1305
+		// Just update it. They'll still use this question group for the other category
1306
+		$existing_relation->save(
1307
+			[
1308
+				$field_to_update => false
1309
+			]
1310
+		);
1311
+	}
1312
+
1313
+
1314
+	/**
1315
+	 * Gets all the question groups, ordering them by QSG_order ascending
1316
+	 *
1317
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1318
+	 * @return EE_Base_Class[]|EE_Question_Group[]
1319
+	 * @throws EE_Error
1320
+	 */
1321
+	public function question_groups($query_params = array())
1322
+	{
1323
+		$query_params = ! empty($query_params) ? $query_params : array('order_by' => array('QSG_order' => 'ASC'));
1324
+		return $this->get_many_related('Question_Group', $query_params);
1325
+	}
1326
+
1327
+
1328
+	/**
1329
+	 * Implementation for EEI_Has_Icon interface method.
1330
+	 *
1331
+	 * @see EEI_Visual_Representation for comments
1332
+	 * @return string
1333
+	 */
1334
+	public function get_icon()
1335
+	{
1336
+		return '<span class="dashicons dashicons-flag"></span>';
1337
+	}
1338
+
1339
+
1340
+	/**
1341
+	 * Implementation for EEI_Admin_Links interface method.
1342
+	 *
1343
+	 * @see EEI_Admin_Links for comments
1344
+	 * @return string
1345
+	 * @throws EE_Error
1346
+	 */
1347
+	public function get_admin_details_link()
1348
+	{
1349
+		return $this->get_admin_edit_link();
1350
+	}
1351
+
1352
+
1353
+	/**
1354
+	 * Implementation for EEI_Admin_Links interface method.
1355
+	 *
1356
+	 * @see EEI_Admin_Links for comments
1357
+	 * @return string
1358
+	 * @throws EE_Error
1359
+	 */
1360
+	public function get_admin_edit_link()
1361
+	{
1362
+		return EEH_URL::add_query_args_and_nonce(
1363
+			array(
1364
+				'page'   => 'espresso_events',
1365
+				'action' => 'edit',
1366
+				'post'   => $this->ID(),
1367
+			),
1368
+			admin_url('admin.php')
1369
+		);
1370
+	}
1371
+
1372
+
1373
+	/**
1374
+	 * Implementation for EEI_Admin_Links interface method.
1375
+	 *
1376
+	 * @see EEI_Admin_Links for comments
1377
+	 * @return string
1378
+	 */
1379
+	public function get_admin_settings_link()
1380
+	{
1381
+		return EEH_URL::add_query_args_and_nonce(
1382
+			array(
1383
+				'page'   => 'espresso_events',
1384
+				'action' => 'default_event_settings',
1385
+			),
1386
+			admin_url('admin.php')
1387
+		);
1388
+	}
1389
+
1390
+
1391
+	/**
1392
+	 * Implementation for EEI_Admin_Links interface method.
1393
+	 *
1394
+	 * @see EEI_Admin_Links for comments
1395
+	 * @return string
1396
+	 */
1397
+	public function get_admin_overview_link()
1398
+	{
1399
+		return EEH_URL::add_query_args_and_nonce(
1400
+			array(
1401
+				'page'   => 'espresso_events',
1402
+				'action' => 'default',
1403
+			),
1404
+			admin_url('admin.php')
1405
+		);
1406
+	}
1407 1407
 }
Please login to merge, or discard this patch.
core/db_classes/EE_Currency.class.php 1 patch
Indentation   +234 added lines, -234 removed lines patch added patch discarded remove patch
@@ -10,238 +10,238 @@
 block discarded – undo
10 10
 class EE_Currency extends EE_Base_Class
11 11
 {
12 12
 
13
-    /** Currency COde
14
-     *
15
-     * @var CUR_code
16
-     */
17
-    protected $_CUR_code = null;
18
-
19
-    /** Currency Name Singular
20
-     *
21
-     * @var CUR_single
22
-     */
23
-    protected $_CUR_single = null;
24
-
25
-    /** Currency Name Plural
26
-     *
27
-     * @var CUR_plural
28
-     */
29
-    protected $_CUR_plural = null;
30
-
31
-    /** Currency Sign
32
-     *
33
-     * @var CUR_sign
34
-     */
35
-    protected $_CUR_sign = null;
36
-
37
-    /** Currency Decimal Places
38
-     *
39
-     * @var CUR_dec_plc
40
-     */
41
-    protected $_CUR_dec_plc = null;
42
-
43
-    /** Active?
44
-     *
45
-     * @var CUR_active
46
-     */
47
-    protected $_CUR_active = null;
48
-
49
-    protected $_Payment_Method;
50
-
51
-
52
-    /**
53
-     * @param array  $props_n_values          incoming values
54
-     * @param string $timezone                incoming timezone
55
-     *                                        (if not set the timezone set for the website will be used.)
56
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
57
-     *                                        date_format and the second value is the time format
58
-     * @return EE_Currency
59
-     * @throws EE_Error
60
-     * @throws ReflectionException
61
-     */
62
-    public static function new_instance($props_n_values = [], $timezone = '', $date_formats = [])
63
-    {
64
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
65
-        return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
66
-    }
67
-
68
-
69
-    /**
70
-     * @param array  $props_n_values  incoming values from the database
71
-     * @param string $timezone        incoming timezone as set by the model.
72
-     *                                If not set the timezone for the website will be used.
73
-     * @return EE_Currency
74
-     * @throws EE_Error
75
-     * @throws ReflectionException
76
-     */
77
-    public static function new_instance_from_db($props_n_values = [], $timezone = '')
78
-    {
79
-        return new self($props_n_values, true, $timezone);
80
-    }
81
-
82
-
83
-    /**
84
-     * Sets code
85
-     *
86
-     * @param string $code
87
-     * @throws EE_Error
88
-     * @throws ReflectionException
89
-     */
90
-    public function set_code($code)
91
-    {
92
-        $this->set('CUR_code', $code);
93
-    }
94
-
95
-
96
-    /**
97
-     * Gets active
98
-     *
99
-     * @return boolean
100
-     * @throws EE_Error
101
-     */
102
-    public function active()
103
-    {
104
-        return $this->get('CUR_active');
105
-    }
106
-
107
-
108
-    /**
109
-     * Sets active
110
-     *
111
-     * @param boolean $active
112
-     * @throws EE_Error
113
-     * @throws ReflectionException
114
-     */
115
-    public function set_active($active)
116
-    {
117
-        $this->set('CUR_active', $active);
118
-    }
119
-
120
-
121
-    /**
122
-     * Gets dec_plc
123
-     *
124
-     * @return int
125
-     * @throws EE_Error
126
-     */
127
-    public function dec_plc()
128
-    {
129
-        return $this->get('CUR_dec_plc');
130
-    }
131
-
132
-
133
-    /**
134
-     * Sets dec_plc
135
-     *
136
-     * @param int $dec_plc
137
-     * @throws EE_Error
138
-     * @throws ReflectionException
139
-     */
140
-    public function set_dec_plc($dec_plc)
141
-    {
142
-        $this->set('CUR_dec_plc', $dec_plc);
143
-    }
144
-
145
-
146
-    /**
147
-     * Sets plural
148
-     *
149
-     * @param string $plural
150
-     * @throws EE_Error
151
-     * @throws ReflectionException
152
-     */
153
-    public function set_plural_name($plural)
154
-    {
155
-        $this->set('CUR_plural', $plural);
156
-    }
157
-
158
-
159
-    /**
160
-     * Gets sign
161
-     *
162
-     * @return string
163
-     * @throws EE_Error
164
-     */
165
-    public function sign()
166
-    {
167
-        return $this->get('CUR_sign');
168
-    }
169
-
170
-
171
-    /**
172
-     * Sets sign
173
-     *
174
-     * @param string $sign
175
-     * @throws EE_Error
176
-     * @throws ReflectionException
177
-     */
178
-    public function set_sign($sign)
179
-    {
180
-        $this->set('CUR_sign', $sign);
181
-    }
182
-
183
-
184
-    /**
185
-     * Gets single
186
-     *
187
-     * @return string
188
-     * @throws EE_Error
189
-     */
190
-    public function singular_name()
191
-    {
192
-        return $this->get('CUR_single');
193
-    }
194
-
195
-
196
-    /**
197
-     * Sets single
198
-     *
199
-     * @param string $single
200
-     * @throws EE_Error
201
-     * @throws ReflectionException
202
-     */
203
-    public function set_singular_name($single)
204
-    {
205
-        $this->set('CUR_single', $single);
206
-    }
207
-
208
-
209
-    /**
210
-     * Gets a prettier name
211
-     *
212
-     * @return string
213
-     * @throws EE_Error
214
-     */
215
-    public function name()
216
-    {
217
-        return sprintf(
218
-            esc_html__("%s (%s)", "event_espresso"),
219
-            $this->code(),
220
-            $this->plural_name()
221
-        );
222
-    }
223
-
224
-
225
-    /**
226
-     * Gets code
227
-     *
228
-     * @return string
229
-     * @throws EE_Error
230
-     */
231
-    public function code()
232
-    {
233
-        return $this->get('CUR_code');
234
-    }
235
-
236
-
237
-    /**
238
-     * Gets plural
239
-     *
240
-     * @return string
241
-     * @throws EE_Error
242
-     */
243
-    public function plural_name()
244
-    {
245
-        return $this->get('CUR_plural');
246
-    }
13
+	/** Currency COde
14
+	 *
15
+	 * @var CUR_code
16
+	 */
17
+	protected $_CUR_code = null;
18
+
19
+	/** Currency Name Singular
20
+	 *
21
+	 * @var CUR_single
22
+	 */
23
+	protected $_CUR_single = null;
24
+
25
+	/** Currency Name Plural
26
+	 *
27
+	 * @var CUR_plural
28
+	 */
29
+	protected $_CUR_plural = null;
30
+
31
+	/** Currency Sign
32
+	 *
33
+	 * @var CUR_sign
34
+	 */
35
+	protected $_CUR_sign = null;
36
+
37
+	/** Currency Decimal Places
38
+	 *
39
+	 * @var CUR_dec_plc
40
+	 */
41
+	protected $_CUR_dec_plc = null;
42
+
43
+	/** Active?
44
+	 *
45
+	 * @var CUR_active
46
+	 */
47
+	protected $_CUR_active = null;
48
+
49
+	protected $_Payment_Method;
50
+
51
+
52
+	/**
53
+	 * @param array  $props_n_values          incoming values
54
+	 * @param string $timezone                incoming timezone
55
+	 *                                        (if not set the timezone set for the website will be used.)
56
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
57
+	 *                                        date_format and the second value is the time format
58
+	 * @return EE_Currency
59
+	 * @throws EE_Error
60
+	 * @throws ReflectionException
61
+	 */
62
+	public static function new_instance($props_n_values = [], $timezone = '', $date_formats = [])
63
+	{
64
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
65
+		return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
66
+	}
67
+
68
+
69
+	/**
70
+	 * @param array  $props_n_values  incoming values from the database
71
+	 * @param string $timezone        incoming timezone as set by the model.
72
+	 *                                If not set the timezone for the website will be used.
73
+	 * @return EE_Currency
74
+	 * @throws EE_Error
75
+	 * @throws ReflectionException
76
+	 */
77
+	public static function new_instance_from_db($props_n_values = [], $timezone = '')
78
+	{
79
+		return new self($props_n_values, true, $timezone);
80
+	}
81
+
82
+
83
+	/**
84
+	 * Sets code
85
+	 *
86
+	 * @param string $code
87
+	 * @throws EE_Error
88
+	 * @throws ReflectionException
89
+	 */
90
+	public function set_code($code)
91
+	{
92
+		$this->set('CUR_code', $code);
93
+	}
94
+
95
+
96
+	/**
97
+	 * Gets active
98
+	 *
99
+	 * @return boolean
100
+	 * @throws EE_Error
101
+	 */
102
+	public function active()
103
+	{
104
+		return $this->get('CUR_active');
105
+	}
106
+
107
+
108
+	/**
109
+	 * Sets active
110
+	 *
111
+	 * @param boolean $active
112
+	 * @throws EE_Error
113
+	 * @throws ReflectionException
114
+	 */
115
+	public function set_active($active)
116
+	{
117
+		$this->set('CUR_active', $active);
118
+	}
119
+
120
+
121
+	/**
122
+	 * Gets dec_plc
123
+	 *
124
+	 * @return int
125
+	 * @throws EE_Error
126
+	 */
127
+	public function dec_plc()
128
+	{
129
+		return $this->get('CUR_dec_plc');
130
+	}
131
+
132
+
133
+	/**
134
+	 * Sets dec_plc
135
+	 *
136
+	 * @param int $dec_plc
137
+	 * @throws EE_Error
138
+	 * @throws ReflectionException
139
+	 */
140
+	public function set_dec_plc($dec_plc)
141
+	{
142
+		$this->set('CUR_dec_plc', $dec_plc);
143
+	}
144
+
145
+
146
+	/**
147
+	 * Sets plural
148
+	 *
149
+	 * @param string $plural
150
+	 * @throws EE_Error
151
+	 * @throws ReflectionException
152
+	 */
153
+	public function set_plural_name($plural)
154
+	{
155
+		$this->set('CUR_plural', $plural);
156
+	}
157
+
158
+
159
+	/**
160
+	 * Gets sign
161
+	 *
162
+	 * @return string
163
+	 * @throws EE_Error
164
+	 */
165
+	public function sign()
166
+	{
167
+		return $this->get('CUR_sign');
168
+	}
169
+
170
+
171
+	/**
172
+	 * Sets sign
173
+	 *
174
+	 * @param string $sign
175
+	 * @throws EE_Error
176
+	 * @throws ReflectionException
177
+	 */
178
+	public function set_sign($sign)
179
+	{
180
+		$this->set('CUR_sign', $sign);
181
+	}
182
+
183
+
184
+	/**
185
+	 * Gets single
186
+	 *
187
+	 * @return string
188
+	 * @throws EE_Error
189
+	 */
190
+	public function singular_name()
191
+	{
192
+		return $this->get('CUR_single');
193
+	}
194
+
195
+
196
+	/**
197
+	 * Sets single
198
+	 *
199
+	 * @param string $single
200
+	 * @throws EE_Error
201
+	 * @throws ReflectionException
202
+	 */
203
+	public function set_singular_name($single)
204
+	{
205
+		$this->set('CUR_single', $single);
206
+	}
207
+
208
+
209
+	/**
210
+	 * Gets a prettier name
211
+	 *
212
+	 * @return string
213
+	 * @throws EE_Error
214
+	 */
215
+	public function name()
216
+	{
217
+		return sprintf(
218
+			esc_html__("%s (%s)", "event_espresso"),
219
+			$this->code(),
220
+			$this->plural_name()
221
+		);
222
+	}
223
+
224
+
225
+	/**
226
+	 * Gets code
227
+	 *
228
+	 * @return string
229
+	 * @throws EE_Error
230
+	 */
231
+	public function code()
232
+	{
233
+		return $this->get('CUR_code');
234
+	}
235
+
236
+
237
+	/**
238
+	 * Gets plural
239
+	 *
240
+	 * @return string
241
+	 * @throws EE_Error
242
+	 */
243
+	public function plural_name()
244
+	{
245
+		return $this->get('CUR_plural');
246
+	}
247 247
 }
Please login to merge, or discard this patch.