Completed
Branch EDTR/reverse-calculate-ticket (cc17d2)
by
unknown
08:35 queued 37s
created
core/db_classes/EE_Ticket.class.php 1 patch
Indentation   +1762 added lines, -1762 removed lines patch added patch discarded remove patch
@@ -14,1770 +14,1770 @@
 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 purchase
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
-     */
76
-    public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
77
-    {
78
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
79
-        return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
80
-    }
81
-
82
-
83
-    /**
84
-     * @param array  $props_n_values  incoming values from the database
85
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
86
-     *                                the website will be used.
87
-     * @return EE_Ticket
88
-     * @throws EE_Error
89
-     */
90
-    public static function new_instance_from_db($props_n_values = array(), $timezone = null)
91
-    {
92
-        return new self($props_n_values, true, $timezone);
93
-    }
94
-
95
-
96
-    /**
97
-     * @return bool
98
-     * @throws EE_Error
99
-     */
100
-    public function parent()
101
-    {
102
-        return $this->get('TKT_parent');
103
-    }
104
-
105
-
106
-    /**
107
-     * return if a ticket has quantities available for purchase
108
-     *
109
-     * @param  int $DTT_ID the primary key for a particular datetime
110
-     * @return boolean
111
-     * @throws EE_Error
112
-     */
113
-    public function available($DTT_ID = 0)
114
-    {
115
-        // are we checking availability for a particular datetime ?
116
-        if ($DTT_ID) {
117
-            // get that datetime object
118
-            $datetime = $this->get_first_related('Datetime', array(array('DTT_ID' => $DTT_ID)));
119
-            // if  ticket sales for this datetime have exceeded the reg limit...
120
-            if ($datetime instanceof EE_Datetime && $datetime->sold_out()) {
121
-                return false;
122
-            }
123
-        }
124
-        // datetime is still open for registration, but is this ticket sold out ?
125
-        return $this->qty() < 1 || $this->qty() > $this->sold() ? true : false;
126
-    }
127
-
128
-
129
-    /**
130
-     * Using the start date and end date this method calculates whether the ticket is On Sale, Pending, or Expired
131
-     *
132
-     * @param bool        $display   true = we'll return a localized string, otherwise we just return the value of the
133
-     *                               relevant status const
134
-     * @param bool | null $remaining if it is already known that tickets are available, then simply pass a bool to save
135
-     *               further processing
136
-     * @return mixed status int if the display string isn't requested
137
-     * @throws EE_Error
138
-     */
139
-    public function ticket_status($display = false, $remaining = null)
140
-    {
141
-        $remaining = is_bool($remaining) ? $remaining : $this->is_remaining();
142
-        if (! $remaining) {
143
-            return $display ? EEH_Template::pretty_status(EE_Ticket::sold_out, false, 'sentence') : EE_Ticket::sold_out;
144
-        }
145
-        if ($this->get('TKT_deleted')) {
146
-            return $display ? EEH_Template::pretty_status(EE_Ticket::archived, false, 'sentence') : EE_Ticket::archived;
147
-        }
148
-        if ($this->is_expired()) {
149
-            return $display ? EEH_Template::pretty_status(EE_Ticket::expired, false, 'sentence') : EE_Ticket::expired;
150
-        }
151
-        if ($this->is_pending()) {
152
-            return $display ? EEH_Template::pretty_status(EE_Ticket::pending, false, 'sentence') : EE_Ticket::pending;
153
-        }
154
-        if ($this->is_on_sale()) {
155
-            return $display ? EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence') : EE_Ticket::onsale;
156
-        }
157
-        return '';
158
-    }
159
-
160
-
161
-    /**
162
-     * The purpose of this method is to simply return a boolean for whether there are any tickets remaining for sale
163
-     * considering ALL the factors used for figuring that out.
164
-     *
165
-     * @access public
166
-     * @param  int $DTT_ID if an int above 0 is included here then we get a specific dtt.
167
-     * @return boolean         true = tickets remaining, false not.
168
-     * @throws EE_Error
169
-     */
170
-    public function is_remaining($DTT_ID = 0)
171
-    {
172
-        $num_remaining = $this->remaining($DTT_ID);
173
-        if ($num_remaining === 0) {
174
-            return false;
175
-        }
176
-        if ($num_remaining > 0 && $num_remaining < $this->min()) {
177
-            return false;
178
-        }
179
-        return true;
180
-    }
181
-
182
-
183
-    /**
184
-     * return the total number of tickets available for purchase
185
-     *
186
-     * @param  int $DTT_ID the primary key for a particular datetime.
187
-     *                     set to 0 for all related datetimes
188
-     * @return int
189
-     * @throws EE_Error
190
-     */
191
-    public function remaining($DTT_ID = 0)
192
-    {
193
-        return $this->real_quantity_on_ticket('saleable', $DTT_ID);
194
-    }
195
-
196
-
197
-    /**
198
-     * Gets min
199
-     *
200
-     * @return int
201
-     * @throws EE_Error
202
-     */
203
-    public function min()
204
-    {
205
-        return $this->get('TKT_min');
206
-    }
207
-
208
-
209
-    /**
210
-     * return if a ticket is no longer available cause its available dates have expired.
211
-     *
212
-     * @return boolean
213
-     * @throws EE_Error
214
-     */
215
-    public function is_expired()
216
-    {
217
-        return ($this->get_raw('TKT_end_date') < time());
218
-    }
219
-
220
-
221
-    /**
222
-     * Return if a ticket is yet to go on sale or not
223
-     *
224
-     * @return boolean
225
-     * @throws EE_Error
226
-     */
227
-    public function is_pending()
228
-    {
229
-        return ($this->get_raw('TKT_start_date') > time());
230
-    }
231
-
232
-
233
-    /**
234
-     * Return if a ticket is on sale or not
235
-     *
236
-     * @return boolean
237
-     * @throws EE_Error
238
-     */
239
-    public function is_on_sale()
240
-    {
241
-        return ($this->get_raw('TKT_start_date') < time() && $this->get_raw('TKT_end_date') > time());
242
-    }
243
-
244
-
245
-    /**
246
-     * This returns the chronologically last datetime that this ticket is associated with
247
-     *
248
-     * @param string $dt_frmt
249
-     * @param string $conjunction - conjunction junction what's your function ? this string joins the start date with
250
-     *                            the end date ie: Jan 01 "to" Dec 31
251
-     * @return string
252
-     * @throws EE_Error
253
-     */
254
-    public function date_range($dt_frmt = '', $conjunction = ' - ')
255
-    {
256
-        $dt_frmt = ! empty($dt_frmt) ? $dt_frmt : $this->_dt_frmt;
257
-        $first_date = $this->first_datetime() instanceof EE_Datetime ? $this->first_datetime()->get_i18n_datetime('DTT_EVT_start', $dt_frmt)
258
-            : '';
259
-        $last_date = $this->last_datetime() instanceof EE_Datetime ? $this->last_datetime()->get_i18n_datetime('DTT_EVT_end', $dt_frmt) : '';
260
-
261
-        return $first_date && $last_date ? $first_date . $conjunction . $last_date : '';
262
-    }
263
-
264
-
265
-    /**
266
-     * This returns the chronologically first datetime that this ticket is associated with
267
-     *
268
-     * @return EE_Datetime
269
-     * @throws EE_Error
270
-     */
271
-    public function first_datetime()
272
-    {
273
-        $datetimes = $this->datetimes(array('limit' => 1));
274
-        return reset($datetimes);
275
-    }
276
-
277
-
278
-    /**
279
-     * Gets all the datetimes this ticket can be used for attending.
280
-     * Unless otherwise specified, orders datetimes by start date.
281
-     *
282
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
283
-     * @return EE_Datetime[]|EE_Base_Class[]
284
-     * @throws EE_Error
285
-     */
286
-    public function datetimes($query_params = array())
287
-    {
288
-        if (! isset($query_params['order_by'])) {
289
-            $query_params['order_by']['DTT_order'] = 'ASC';
290
-        }
291
-        return $this->get_many_related('Datetime', $query_params);
292
-    }
293
-
294
-
295
-    /**
296
-     * This returns the chronologically last datetime that this ticket is associated with
297
-     *
298
-     * @return EE_Datetime
299
-     * @throws EE_Error
300
-     */
301
-    public function last_datetime()
302
-    {
303
-        $datetimes = $this->datetimes(array('limit' => 1, 'order_by' => array('DTT_EVT_start' => 'DESC')));
304
-        return end($datetimes);
305
-    }
306
-
307
-
308
-    /**
309
-     * This returns the total tickets sold depending on the given parameters.
310
-     *
311
-     * @param  string $what   Can be one of two options: 'ticket', 'datetime'.
312
-     *                        'ticket' = total ticket sales for all datetimes this ticket is related to
313
-     *                        'datetime' = total ticket sales for a specified datetime (required $dtt_id)
314
-     *                        'datetime' = total ticket sales in the datetime_ticket table.
315
-     *                        If $dtt_id is not given then we return an array of sales indexed by datetime.
316
-     *                        If $dtt_id IS given then we return the tickets sold for that given datetime.
317
-     * @param  int    $dtt_id [optional] include the dtt_id with $what = 'datetime'.
318
-     * @return mixed (array|int)          how many tickets have sold
319
-     * @throws EE_Error
320
-     */
321
-    public function tickets_sold($what = 'ticket', $dtt_id = null)
322
-    {
323
-        $total = 0;
324
-        $tickets_sold = $this->_all_tickets_sold();
325
-        switch ($what) {
326
-            case 'ticket':
327
-                return $tickets_sold['ticket'];
328
-                break;
329
-            case 'datetime':
330
-                if (empty($tickets_sold['datetime'])) {
331
-                    return $total;
332
-                }
333
-                if (! empty($dtt_id) && ! isset($tickets_sold['datetime'][ $dtt_id ])) {
334
-                    EE_Error::add_error(
335
-                        __(
336
-                            '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?',
337
-                            'event_espresso'
338
-                        ),
339
-                        __FILE__,
340
-                        __FUNCTION__,
341
-                        __LINE__
342
-                    );
343
-                    return $total;
344
-                }
345
-                return empty($dtt_id) ? $tickets_sold['datetime'] : $tickets_sold['datetime'][ $dtt_id ];
346
-                break;
347
-            default:
348
-                return $total;
349
-        }
350
-    }
351
-
352
-
353
-    /**
354
-     * This returns an array indexed by datetime_id for tickets sold with this ticket.
355
-     *
356
-     * @return EE_Ticket[]
357
-     * @throws EE_Error
358
-     */
359
-    protected function _all_tickets_sold()
360
-    {
361
-        $datetimes = $this->get_many_related('Datetime');
362
-        $tickets_sold = array();
363
-        if (! empty($datetimes)) {
364
-            foreach ($datetimes as $datetime) {
365
-                $tickets_sold['datetime'][ $datetime->ID() ] = $datetime->get('DTT_sold');
366
-            }
367
-        }
368
-        // Tickets sold
369
-        $tickets_sold['ticket'] = $this->sold();
370
-        return $tickets_sold;
371
-    }
372
-
373
-
374
-    /**
375
-     * This returns the base price object for the ticket.
376
-     *
377
-     * @param  bool $return_array whether to return as an array indexed by price id or just the object.
378
-     * @return EE_Price|EE_Base_Class|EE_Price[]|EE_Base_Class[]
379
-     * @throws EE_Error
380
-     */
381
-    public function base_price($return_array = false)
382
-    {
383
-        $_where = array('Price_Type.PBT_ID' => EEM_Price_Type::base_type_base_price);
384
-        return $return_array
385
-            ? $this->get_many_related('Price', array($_where))
386
-            : $this->get_first_related('Price', array($_where));
387
-    }
388
-
389
-
390
-    /**
391
-     * This returns ONLY the price modifiers for the ticket (i.e. no taxes or base price)
392
-     *
393
-     * @access public
394
-     * @return EE_Price[]
395
-     * @throws EE_Error
396
-     */
397
-    public function price_modifiers()
398
-    {
399
-        $query_params = array(
400
-            0 => array(
401
-                'Price_Type.PBT_ID' => array(
402
-                    'NOT IN',
403
-                    array(EEM_Price_Type::base_type_base_price, EEM_Price_Type::base_type_tax),
404
-                ),
405
-            ),
406
-        );
407
-        return $this->prices($query_params);
408
-    }
409
-
410
-
411
-    /**
412
-     * Gets all the prices that combine to form the final price of this ticket
413
-     *
414
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
415
-     * @return EE_Price[]|EE_Base_Class[]
416
-     * @throws EE_Error
417
-     */
418
-    public function prices($query_params = array())
419
-    {
420
-        return $this->get_many_related('Price', $query_params);
421
-    }
422
-
423
-
424
-    /**
425
-     * Gets all the ticket applicabilities (ie, relations between datetimes and tickets)
426
-     *
427
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
428
-     * @return EE_Datetime_Ticket|EE_Base_Class[]
429
-     * @throws EE_Error
430
-     */
431
-    public function datetime_tickets($query_params = array())
432
-    {
433
-        return $this->get_many_related('Datetime_Ticket', $query_params);
434
-    }
435
-
436
-
437
-    /**
438
-     * Gets all the datetimes from the db ordered by DTT_order
439
-     *
440
-     * @param boolean $show_expired
441
-     * @param boolean $show_deleted
442
-     * @return EE_Datetime[]
443
-     * @throws EE_Error
444
-     */
445
-    public function datetimes_ordered($show_expired = true, $show_deleted = false)
446
-    {
447
-        return EEM_Datetime::instance($this->_timezone)->get_datetimes_for_ticket_ordered_by_DTT_order(
448
-            $this->ID(),
449
-            $show_expired,
450
-            $show_deleted
451
-        );
452
-    }
453
-
454
-
455
-    /**
456
-     * Gets ID
457
-     *
458
-     * @return string
459
-     * @throws EE_Error
460
-     */
461
-    public function ID()
462
-    {
463
-        return $this->get('TKT_ID');
464
-    }
465
-
466
-
467
-    /**
468
-     * get the author of the ticket.
469
-     *
470
-     * @since 4.5.0
471
-     * @return int
472
-     * @throws EE_Error
473
-     */
474
-    public function wp_user()
475
-    {
476
-        return $this->get('TKT_wp_user');
477
-    }
478
-
479
-
480
-    /**
481
-     * Gets the template for the ticket
482
-     *
483
-     * @return EE_Ticket_Template|EE_Base_Class
484
-     * @throws EE_Error
485
-     */
486
-    public function template()
487
-    {
488
-        return $this->get_first_related('Ticket_Template');
489
-    }
490
-
491
-
492
-    /**
493
-     * Simply returns an array of EE_Price objects that are taxes.
494
-     *
495
-     * @return EE_Price[]
496
-     * @throws EE_Error
497
-     */
498
-    public function get_ticket_taxes_for_admin()
499
-    {
500
-        return EE_Taxes::get_taxes_for_admin();
501
-    }
502
-
503
-
504
-    /**
505
-     * @return float
506
-     * @throws EE_Error
507
-     */
508
-    public function ticket_price()
509
-    {
510
-        return $this->get('TKT_price');
511
-    }
512
-
513
-
514
-    /**
515
-     * @return mixed
516
-     * @throws EE_Error
517
-     */
518
-    public function pretty_price()
519
-    {
520
-        return $this->get_pretty('TKT_price');
521
-    }
522
-
523
-
524
-    /**
525
-     * @return bool
526
-     * @throws EE_Error
527
-     */
528
-    public function is_free()
529
-    {
530
-        return $this->get_ticket_total_with_taxes() === (float) 0;
531
-    }
532
-
533
-
534
-    /**
535
-     * get_ticket_total_with_taxes
536
-     *
537
-     * @param bool $no_cache
538
-     * @return float
539
-     * @throws EE_Error
540
-     */
541
-    public function get_ticket_total_with_taxes($no_cache = false)
542
-    {
543
-        if ($this->_ticket_total_with_taxes === null || $no_cache) {
544
-            $this->_ticket_total_with_taxes = $this->get_ticket_subtotal() + $this->get_ticket_taxes_total_for_admin();
545
-        }
546
-        return (float) $this->_ticket_total_with_taxes;
547
-    }
548
-
549
-
550
-    public function ensure_TKT_Price_correct()
551
-    {
552
-        $this->set('TKT_price', EE_Taxes::get_subtotal_for_admin($this));
553
-        $this->save();
554
-    }
555
-
556
-
557
-    /**
558
-     * @return float
559
-     * @throws EE_Error
560
-     */
561
-    public function get_ticket_subtotal()
562
-    {
563
-        return EE_Taxes::get_subtotal_for_admin($this);
564
-    }
565
-
566
-
567
-    /**
568
-     * Returns the total taxes applied to this ticket
569
-     *
570
-     * @return float
571
-     * @throws EE_Error
572
-     */
573
-    public function get_ticket_taxes_total_for_admin()
574
-    {
575
-        return EE_Taxes::get_total_taxes_for_admin($this);
576
-    }
577
-
578
-
579
-    /**
580
-     * Sets name
581
-     *
582
-     * @param string $name
583
-     * @throws EE_Error
584
-     */
585
-    public function set_name($name)
586
-    {
587
-        $this->set('TKT_name', $name);
588
-    }
589
-
590
-
591
-    /**
592
-     * Gets description
593
-     *
594
-     * @return string
595
-     * @throws EE_Error
596
-     */
597
-    public function description()
598
-    {
599
-        return $this->get('TKT_description');
600
-    }
601
-
602
-
603
-    /**
604
-     * Sets description
605
-     *
606
-     * @param string $description
607
-     * @throws EE_Error
608
-     */
609
-    public function set_description($description)
610
-    {
611
-        $this->set('TKT_description', $description);
612
-    }
613
-
614
-
615
-    /**
616
-     * Gets start_date
617
-     *
618
-     * @param string $dt_frmt
619
-     * @param string $tm_frmt
620
-     * @return string
621
-     * @throws EE_Error
622
-     */
623
-    public function start_date($dt_frmt = '', $tm_frmt = '')
624
-    {
625
-        return $this->_get_datetime('TKT_start_date', $dt_frmt, $tm_frmt);
626
-    }
627
-
628
-
629
-    /**
630
-     * Sets start_date
631
-     *
632
-     * @param string $start_date
633
-     * @return void
634
-     * @throws EE_Error
635
-     */
636
-    public function set_start_date($start_date)
637
-    {
638
-        $this->_set_date_time('B', $start_date, 'TKT_start_date');
639
-    }
640
-
641
-
642
-    /**
643
-     * Gets end_date
644
-     *
645
-     * @param string $dt_frmt
646
-     * @param string $tm_frmt
647
-     * @return string
648
-     * @throws EE_Error
649
-     */
650
-    public function end_date($dt_frmt = '', $tm_frmt = '')
651
-    {
652
-        return $this->_get_datetime('TKT_end_date', $dt_frmt, $tm_frmt);
653
-    }
654
-
655
-
656
-    /**
657
-     * Sets end_date
658
-     *
659
-     * @param string $end_date
660
-     * @return void
661
-     * @throws EE_Error
662
-     */
663
-    public function set_end_date($end_date)
664
-    {
665
-        $this->_set_date_time('B', $end_date, 'TKT_end_date');
666
-    }
667
-
668
-
669
-    /**
670
-     * Sets sell until time
671
-     *
672
-     * @since 4.5.0
673
-     * @param string $time a string representation of the sell until time (ex 9am or 7:30pm)
674
-     * @throws EE_Error
675
-     */
676
-    public function set_end_time($time)
677
-    {
678
-        $this->_set_time_for($time, 'TKT_end_date');
679
-    }
680
-
681
-
682
-    /**
683
-     * Sets min
684
-     *
685
-     * @param int $min
686
-     * @return void
687
-     * @throws EE_Error
688
-     */
689
-    public function set_min($min)
690
-    {
691
-        $this->set('TKT_min', $min);
692
-    }
693
-
694
-
695
-    /**
696
-     * Gets max
697
-     *
698
-     * @return int
699
-     * @throws EE_Error
700
-     */
701
-    public function max()
702
-    {
703
-        return $this->get('TKT_max');
704
-    }
705
-
706
-
707
-    /**
708
-     * Sets max
709
-     *
710
-     * @param int $max
711
-     * @return void
712
-     * @throws EE_Error
713
-     */
714
-    public function set_max($max)
715
-    {
716
-        $this->set('TKT_max', $max);
717
-    }
718
-
719
-
720
-    /**
721
-     * Sets price
722
-     *
723
-     * @param float $price
724
-     * @return void
725
-     * @throws EE_Error
726
-     */
727
-    public function set_price($price)
728
-    {
729
-        $this->set('TKT_price', $price);
730
-    }
731
-
732
-
733
-    /**
734
-     * Gets sold
735
-     *
736
-     * @return int
737
-     * @throws EE_Error
738
-     */
739
-    public function sold()
740
-    {
741
-        return $this->get_raw('TKT_sold');
742
-    }
743
-
744
-
745
-    /**
746
-     * Sets sold
747
-     *
748
-     * @param int $sold
749
-     * @return void
750
-     * @throws EE_Error
751
-     */
752
-    public function set_sold($sold)
753
-    {
754
-        // sold can not go below zero
755
-        $sold = max(0, $sold);
756
-        $this->set('TKT_sold', $sold);
757
-    }
758
-
759
-
760
-    /**
761
-     * Increments sold by amount passed by $qty AND decrements the reserved count on both this ticket and its
762
-     * associated datetimes.
763
-     *
764
-     * @since 4.9.80.p
765
-     * @param int $qty
766
-     * @return boolean
767
-     * @throws EE_Error
768
-     * @throws InvalidArgumentException
769
-     * @throws InvalidDataTypeException
770
-     * @throws InvalidInterfaceException
771
-     * @throws ReflectionException
772
-     */
773
-    public function increaseSold($qty = 1)
774
-    {
775
-        $qty = absint($qty);
776
-        // increment sold and decrement reserved datetime quantities simultaneously
777
-        // don't worry about failures, because they must have already had a spot reserved
778
-        $this->increaseSoldForDatetimes($qty);
779
-        // Increment and decrement ticket quantities simultaneously
780
-        $success = $this->adjustNumericFieldsInDb(
781
-            [
782
-                'TKT_reserved' => $qty * -1,
783
-                'TKT_sold' => $qty
784
-            ]
785
-        );
786
-        do_action(
787
-            'AHEE__EE_Ticket__increase_sold',
788
-            $this,
789
-            $qty,
790
-            $this->sold(),
791
-            $success
792
-        );
793
-        return $success;
794
-    }
795
-
796
-    /**
797
-     * On each datetime related to this ticket, increases its sold count and decreases its reserved count by $qty.
798
-     *
799
-     * @since 4.9.80.p
800
-     * @param int $qty positive or negative. Positive means to increase sold counts (and decrease reserved counts),
801
-     *             Negative means to decreases old counts (and increase reserved counts).
802
-     * @param EE_Datetime[] $datetimes
803
-     * @throws EE_Error
804
-     * @throws InvalidArgumentException
805
-     * @throws InvalidDataTypeException
806
-     * @throws InvalidInterfaceException
807
-     * @throws ReflectionException
808
-     */
809
-    protected function increaseSoldForDatetimes($qty, array $datetimes = [])
810
-    {
811
-        $datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
812
-        foreach ($datetimes as $datetime) {
813
-            $datetime->increaseSold($qty);
814
-        }
815
-    }
816
-
817
-
818
-
819
-    /**
820
-     * Decrements (subtracts) sold by amount passed by $qty on both the ticket and its related datetimes directly in the
821
-     * DB and then updates the model objects.
822
-     * Does not affect the reserved counts.
823
-     *
824
-     * @since 4.9.80.p
825
-     * @param int $qty
826
-     * @return boolean
827
-     * @throws EE_Error
828
-     * @throws InvalidArgumentException
829
-     * @throws InvalidDataTypeException
830
-     * @throws InvalidInterfaceException
831
-     * @throws ReflectionException
832
-     */
833
-    public function decreaseSold($qty = 1)
834
-    {
835
-        $qty = absint($qty);
836
-        $this->decreaseSoldForDatetimes($qty);
837
-        $success = $this->adjustNumericFieldsInDb(
838
-            [
839
-                'TKT_sold' => $qty * -1
840
-            ]
841
-        );
842
-        do_action(
843
-            'AHEE__EE_Ticket__decrease_sold',
844
-            $this,
845
-            $qty,
846
-            $this->sold(),
847
-            $success
848
-        );
849
-        return $success;
850
-    }
851
-
852
-
853
-    /**
854
-     * Decreases sold on related datetimes
855
-     *
856
-     * @since 4.9.80.p
857
-     * @param int $qty
858
-     * @param EE_Datetime[] $datetimes
859
-     * @return void
860
-     * @throws EE_Error
861
-     * @throws InvalidArgumentException
862
-     * @throws InvalidDataTypeException
863
-     * @throws InvalidInterfaceException
864
-     * @throws ReflectionException
865
-     */
866
-    protected function decreaseSoldForDatetimes($qty = 1, array $datetimes = [])
867
-    {
868
-        $datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
869
-        if (is_array($datetimes)) {
870
-            foreach ($datetimes as $datetime) {
871
-                if ($datetime instanceof EE_Datetime) {
872
-                    $datetime->decreaseSold($qty);
873
-                }
874
-            }
875
-        }
876
-    }
877
-
878
-
879
-    /**
880
-     * Gets qty of reserved tickets
881
-     *
882
-     * @return int
883
-     * @throws EE_Error
884
-     */
885
-    public function reserved()
886
-    {
887
-        return $this->get_raw('TKT_reserved');
888
-    }
889
-
890
-
891
-    /**
892
-     * Sets reserved
893
-     *
894
-     * @param int $reserved
895
-     * @return void
896
-     * @throws EE_Error
897
-     */
898
-    public function set_reserved($reserved)
899
-    {
900
-        // reserved can not go below zero
901
-        $reserved = max(0, (int) $reserved);
902
-        $this->set('TKT_reserved', $reserved);
903
-    }
904
-
905
-
906
-    /**
907
-     * Increments reserved by amount passed by $qty, and persists it immediately to the database.
908
-     *
909
-     * @since 4.9.80.p
910
-     * @param int    $qty
911
-     * @param string $source
912
-     * @return bool whether we successfully reserved the ticket or not.
913
-     * @throws EE_Error
914
-     * @throws InvalidArgumentException
915
-     * @throws ReflectionException
916
-     * @throws InvalidDataTypeException
917
-     * @throws InvalidInterfaceException
918
-     */
919
-    public function increaseReserved($qty = 1, $source = 'unknown')
920
-    {
921
-        $qty = absint($qty);
922
-        do_action(
923
-            'AHEE__EE_Ticket__increase_reserved__begin',
924
-            $this,
925
-            $qty,
926
-            $source
927
-        );
928
-        $this->add_extra_meta(EE_Ticket::META_KEY_TICKET_RESERVATIONS, "{$qty} from {$source}");
929
-        $success = false;
930
-        $datetimes_adjusted_successfully = $this->increaseReservedForDatetimes($qty);
931
-        if ($datetimes_adjusted_successfully) {
932
-            $success = $this->incrementFieldConditionallyInDb(
933
-                'TKT_reserved',
934
-                'TKT_sold',
935
-                'TKT_qty',
936
-                $qty
937
-            );
938
-            if (! $success) {
939
-                // The datetimes were successfully bumped, but not the
940
-                // ticket. So we need to manually rollback the datetimes.
941
-                $this->decreaseReservedForDatetimes($qty);
942
-            }
943
-        }
944
-        do_action(
945
-            'AHEE__EE_Ticket__increase_reserved',
946
-            $this,
947
-            $qty,
948
-            $this->reserved(),
949
-            $success
950
-        );
951
-        return $success;
952
-    }
953
-
954
-
955
-    /**
956
-     * Increases reserved counts on related datetimes
957
-     *
958
-     * @since 4.9.80.p
959
-     * @param int $qty
960
-     * @param EE_Datetime[] $datetimes
961
-     * @return boolean indicating success
962
-     * @throws EE_Error
963
-     * @throws InvalidArgumentException
964
-     * @throws InvalidDataTypeException
965
-     * @throws InvalidInterfaceException
966
-     * @throws ReflectionException
967
-     */
968
-    protected function increaseReservedForDatetimes($qty = 1, array $datetimes = [])
969
-    {
970
-        $datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
971
-        $datetimes_updated = [];
972
-        $limit_exceeded = false;
973
-        if (is_array($datetimes)) {
974
-            foreach ($datetimes as $datetime) {
975
-                if ($datetime instanceof EE_Datetime) {
976
-                    if ($datetime->increaseReserved($qty)) {
977
-                        $datetimes_updated[] = $datetime;
978
-                    } else {
979
-                        $limit_exceeded = true;
980
-                        break;
981
-                    }
982
-                }
983
-            }
984
-            // If somewhere along the way we detected a datetime whose
985
-            // limit was exceeded, do a manual rollback.
986
-            if ($limit_exceeded) {
987
-                $this->decreaseReservedForDatetimes($qty, $datetimes_updated);
988
-                return false;
989
-            }
990
-        }
991
-        return true;
992
-    }
993
-
994
-
995
-    /**
996
-     * Decrements (subtracts) reserved by amount passed by $qty, and persists it immediately to the database.
997
-     *
998
-     * @since 4.9.80.p
999
-     * @param int    $qty
1000
-     * @param bool   $adjust_datetimes
1001
-     * @param string $source
1002
-     * @return boolean
1003
-     * @throws EE_Error
1004
-     * @throws InvalidArgumentException
1005
-     * @throws ReflectionException
1006
-     * @throws InvalidDataTypeException
1007
-     * @throws InvalidInterfaceException
1008
-     */
1009
-    public function decreaseReserved($qty = 1, $adjust_datetimes = true, $source = 'unknown')
1010
-    {
1011
-        $qty = absint($qty);
1012
-        $this->add_extra_meta(EE_Ticket::META_KEY_TICKET_RESERVATIONS, "-{$qty} from {$source}");
1013
-        if ($adjust_datetimes) {
1014
-            $this->decreaseReservedForDatetimes($qty);
1015
-        }
1016
-        $success = $this->adjustNumericFieldsInDb(
1017
-            [
1018
-                'TKT_reserved' => $qty * -1
1019
-            ]
1020
-        );
1021
-        do_action(
1022
-            'AHEE__EE_Ticket__decrease_reserved',
1023
-            $this,
1024
-            $qty,
1025
-            $this->reserved(),
1026
-            $success
1027
-        );
1028
-        return $success;
1029
-    }
1030
-
1031
-
1032
-    /**
1033
-     * Decreases the reserved count on the specified datetimes.
1034
-     *
1035
-     * @since 4.9.80.p
1036
-     * @param int           $qty
1037
-     * @param EE_Datetime[] $datetimes
1038
-     * @throws EE_Error
1039
-     * @throws InvalidArgumentException
1040
-     * @throws ReflectionException
1041
-     * @throws InvalidDataTypeException
1042
-     * @throws InvalidInterfaceException
1043
-     */
1044
-    protected function decreaseReservedForDatetimes($qty = 1, array $datetimes = [])
1045
-    {
1046
-        $datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
1047
-        foreach ($datetimes as $datetime) {
1048
-            if ($datetime instanceof EE_Datetime) {
1049
-                $datetime->decreaseReserved($qty);
1050
-            }
1051
-        }
1052
-    }
1053
-
1054
-
1055
-    /**
1056
-     * Gets ticket quantity
1057
-     *
1058
-     * @param string $context     ticket quantity is somewhat subjective depending on the exact information sought
1059
-     *                            therefore $context can be one of three values: '', 'reg_limit', or 'saleable'
1060
-     *                            '' (default) quantity is the actual db value for TKT_qty, unaffected by other objects
1061
-     *                            REG LIMIT: caps qty based on DTT_reg_limit for ALL related datetimes
1062
-     *                            SALEABLE: also considers datetime sold and returns zero if ANY DTT is sold out, and
1063
-     *                            is therefore the truest measure of tickets that can be purchased at the moment
1064
-     * @return int
1065
-     * @throws EE_Error
1066
-     */
1067
-    public function qty($context = '')
1068
-    {
1069
-        switch ($context) {
1070
-            case 'reg_limit':
1071
-                return $this->real_quantity_on_ticket();
1072
-            case 'saleable':
1073
-                return $this->real_quantity_on_ticket('saleable');
1074
-            default:
1075
-                return $this->get_raw('TKT_qty');
1076
-        }
1077
-    }
1078
-
1079
-
1080
-    /**
1081
-     * Gets ticket quantity
1082
-     *
1083
-     * @param string $context     ticket quantity is somewhat subjective depending on the exact information sought
1084
-     *                            therefore $context can be one of two values: 'reg_limit', or 'saleable'
1085
-     *                            REG LIMIT: caps qty based on DTT_reg_limit for ALL related datetimes
1086
-     *                            SALEABLE: also considers datetime sold and returns zero if ANY DTT is sold out, and
1087
-     *                            is therefore the truest measure of tickets that can be purchased at the moment
1088
-     * @param  int   $DTT_ID      the primary key for a particular datetime.
1089
-     *                            set to 0 for all related datetimes
1090
-     * @return int
1091
-     * @throws EE_Error
1092
-     */
1093
-    public function real_quantity_on_ticket($context = 'reg_limit', $DTT_ID = 0)
1094
-    {
1095
-        $raw = $this->get_raw('TKT_qty');
1096
-        // return immediately if it's zero
1097
-        if ($raw === 0) {
1098
-            return $raw;
1099
-        }
1100
-        // echo "\n\n<br />Ticket: " . $this->name() . '<br />';
1101
-        // ensure qty doesn't exceed raw value for THIS ticket
1102
-        $qty = min(EE_INF, $raw);
1103
-        // echo "\n . qty: " . $qty . '<br />';
1104
-        // calculate this ticket's total sales and reservations
1105
-        $sold_and_reserved_for_this_ticket = $this->sold() + $this->reserved();
1106
-        // echo "\n . sold: " . $this->sold() . '<br />';
1107
-        // echo "\n . reserved: " . $this->reserved() . '<br />';
1108
-        // echo "\n . sold_and_reserved_for_this_ticket: " . $sold_and_reserved_for_this_ticket . '<br />';
1109
-        // first we need to calculate the maximum number of tickets available for the datetime
1110
-        // do we want data for one datetime or all of them ?
1111
-        $query_params = $DTT_ID ? array(array('DTT_ID' => $DTT_ID)) : array();
1112
-        $datetimes = $this->datetimes($query_params);
1113
-        if (is_array($datetimes) && ! empty($datetimes)) {
1114
-            foreach ($datetimes as $datetime) {
1115
-                if ($datetime instanceof EE_Datetime) {
1116
-                    $datetime->refresh_from_db();
1117
-                    // echo "\n . . datetime name: " . $datetime->name() . '<br />';
1118
-                    // echo "\n . . datetime ID: " . $datetime->ID() . '<br />';
1119
-                    // initialize with no restrictions for each datetime
1120
-                    // but adjust datetime qty based on datetime reg limit
1121
-                    $datetime_qty = min(EE_INF, $datetime->reg_limit());
1122
-                    // echo "\n . . . datetime reg_limit: " . $datetime->reg_limit() . '<br />';
1123
-                    // echo "\n . . . datetime_qty: " . $datetime_qty . '<br />';
1124
-                    // if we want the actual saleable amount, then we need to consider OTHER ticket sales
1125
-                    // and reservations for this datetime, that do NOT include sales and reservations
1126
-                    // for this ticket (so we add $this->sold() and $this->reserved() back in)
1127
-                    if ($context === 'saleable') {
1128
-                        $datetime_qty = max(
1129
-                            $datetime_qty - $datetime->sold_and_reserved() + $sold_and_reserved_for_this_ticket,
1130
-                            0
1131
-                        );
1132
-                        // echo "\n . . . datetime sold: " . $datetime->sold() . '<br />';
1133
-                        // echo "\n . . . datetime reserved: " . $datetime->reserved() . '<br />';
1134
-                        // echo "\n . . . datetime sold_and_reserved: " . $datetime->sold_and_reserved() . '<br />';
1135
-                        // echo "\n . . . datetime_qty: " . $datetime_qty . '<br />';
1136
-                        $datetime_qty = ! $datetime->sold_out() ? $datetime_qty : 0;
1137
-                        // echo "\n . . . datetime_qty: " . $datetime_qty . '<br />';
1138
-                    }
1139
-                    $qty = min($datetime_qty, $qty);
1140
-                    // echo "\n . . qty: " . $qty . '<br />';
1141
-                }
1142
-            }
1143
-        }
1144
-        // NOW that we know the  maximum number of tickets available for the datetime
1145
-        // we can finally factor in the details for this specific ticket
1146
-        if ($qty > 0 && $context === 'saleable') {
1147
-            // and subtract the sales for THIS ticket
1148
-            $qty = max($qty - $sold_and_reserved_for_this_ticket, 0);
1149
-            // echo "\n . qty: " . $qty . '<br />';
1150
-        }
1151
-        // echo "\nFINAL QTY: " . $qty . "<br /><br />";
1152
-        return $qty;
1153
-    }
1154
-
1155
-
1156
-    /**
1157
-     * Sets qty - IMPORTANT!!! Does NOT allow QTY to be set higher than the lowest reg limit of any related datetimes
1158
-     *
1159
-     * @param int $qty
1160
-     * @return void
1161
-     * @throws EE_Error
1162
-     */
1163
-    public function set_qty($qty)
1164
-    {
1165
-        $datetimes = $this->datetimes();
1166
-        foreach ($datetimes as $datetime) {
1167
-            if ($datetime instanceof EE_Datetime) {
1168
-                $qty = min($qty, $datetime->reg_limit());
1169
-            }
1170
-        }
1171
-        $this->set('TKT_qty', $qty);
1172
-    }
1173
-
1174
-
1175
-    /**
1176
-     * Gets uses
1177
-     *
1178
-     * @return int
1179
-     * @throws EE_Error
1180
-     */
1181
-    public function uses()
1182
-    {
1183
-        return $this->get('TKT_uses');
1184
-    }
1185
-
1186
-
1187
-    /**
1188
-     * Sets uses
1189
-     *
1190
-     * @param int $uses
1191
-     * @return void
1192
-     * @throws EE_Error
1193
-     */
1194
-    public function set_uses($uses)
1195
-    {
1196
-        $this->set('TKT_uses', $uses);
1197
-    }
1198
-
1199
-
1200
-    /**
1201
-     * returns whether ticket is required or not.
1202
-     *
1203
-     * @return boolean
1204
-     * @throws EE_Error
1205
-     */
1206
-    public function required()
1207
-    {
1208
-        return $this->get('TKT_required');
1209
-    }
1210
-
1211
-
1212
-    /**
1213
-     * sets the TKT_required property
1214
-     *
1215
-     * @param boolean $required
1216
-     * @return void
1217
-     * @throws EE_Error
1218
-     */
1219
-    public function set_required($required)
1220
-    {
1221
-        $this->set('TKT_required', $required);
1222
-    }
1223
-
1224
-
1225
-    /**
1226
-     * Gets taxable
1227
-     *
1228
-     * @return boolean
1229
-     * @throws EE_Error
1230
-     */
1231
-    public function taxable()
1232
-    {
1233
-        return $this->get('TKT_taxable');
1234
-    }
1235
-
1236
-
1237
-    /**
1238
-     * Sets taxable
1239
-     *
1240
-     * @param boolean $taxable
1241
-     * @return void
1242
-     * @throws EE_Error
1243
-     */
1244
-    public function set_taxable($taxable)
1245
-    {
1246
-        $this->set('TKT_taxable', $taxable);
1247
-    }
1248
-
1249
-
1250
-    /**
1251
-     * Gets is_default
1252
-     *
1253
-     * @return boolean
1254
-     * @throws EE_Error
1255
-     */
1256
-    public function is_default()
1257
-    {
1258
-        return $this->get('TKT_is_default');
1259
-    }
1260
-
1261
-
1262
-    /**
1263
-     * Sets is_default
1264
-     *
1265
-     * @param boolean $is_default
1266
-     * @return void
1267
-     * @throws EE_Error
1268
-     */
1269
-    public function set_is_default($is_default)
1270
-    {
1271
-        $this->set('TKT_is_default', $is_default);
1272
-    }
1273
-
1274
-
1275
-    /**
1276
-     * Gets order
1277
-     *
1278
-     * @return int
1279
-     * @throws EE_Error
1280
-     */
1281
-    public function order()
1282
-    {
1283
-        return $this->get('TKT_order');
1284
-    }
1285
-
1286
-
1287
-    /**
1288
-     * Sets order
1289
-     *
1290
-     * @param int $order
1291
-     * @return void
1292
-     * @throws EE_Error
1293
-     */
1294
-    public function set_order($order)
1295
-    {
1296
-        $this->set('TKT_order', $order);
1297
-    }
1298
-
1299
-
1300
-    /**
1301
-     * Gets row
1302
-     *
1303
-     * @return int
1304
-     * @throws EE_Error
1305
-     */
1306
-    public function row()
1307
-    {
1308
-        return $this->get('TKT_row');
1309
-    }
1310
-
1311
-
1312
-    /**
1313
-     * Sets row
1314
-     *
1315
-     * @param int $row
1316
-     * @return void
1317
-     * @throws EE_Error
1318
-     */
1319
-    public function set_row($row)
1320
-    {
1321
-        $this->set('TKT_row', $row);
1322
-    }
1323
-
1324
-
1325
-    /**
1326
-     * Gets deleted
1327
-     *
1328
-     * @return boolean
1329
-     * @throws EE_Error
1330
-     */
1331
-    public function deleted()
1332
-    {
1333
-        return $this->get('TKT_deleted');
1334
-    }
1335
-
1336
-
1337
-    /**
1338
-     * Sets deleted
1339
-     *
1340
-     * @param boolean $deleted
1341
-     * @return void
1342
-     * @throws EE_Error
1343
-     */
1344
-    public function set_deleted($deleted)
1345
-    {
1346
-        $this->set('TKT_deleted', $deleted);
1347
-    }
1348
-
1349
-
1350
-    /**
1351
-     * Gets parent
1352
-     *
1353
-     * @return int
1354
-     * @throws EE_Error
1355
-     */
1356
-    public function parent_ID()
1357
-    {
1358
-        return $this->get('TKT_parent');
1359
-    }
1360
-
1361
-
1362
-    /**
1363
-     * Sets parent
1364
-     *
1365
-     * @param int $parent
1366
-     * @return void
1367
-     * @throws EE_Error
1368
-     */
1369
-    public function set_parent_ID($parent)
1370
-    {
1371
-        $this->set('TKT_parent', $parent);
1372
-    }
1373
-
1374
-
1375
-    /**
1376
-     * @return boolean
1377
-     * @throws EE_Error
1378
-     * @throws InvalidArgumentException
1379
-     * @throws InvalidDataTypeException
1380
-     * @throws InvalidInterfaceException
1381
-     * @throws ReflectionException
1382
-     */
1383
-    public function reverse_calculate()
1384
-    {
1385
-        return $this->get('TKT_reverse_calculate');
1386
-    }
1387
-
1388
-
1389
-    /**
1390
-     * @param boolean $reverse_calculate
1391
-     * @throws EE_Error
1392
-     * @throws InvalidArgumentException
1393
-     * @throws InvalidDataTypeException
1394
-     * @throws InvalidInterfaceException
1395
-     * @throws ReflectionException
1396
-     */
1397
-    public function set_reverse_calculate($reverse_calculate)
1398
-    {
1399
-        $this->set('TKT_reverse_calculate', $reverse_calculate);
1400
-    }
1401
-
1402
-
1403
-    /**
1404
-     * Gets a string which is handy for showing in gateways etc that describes the ticket.
1405
-     *
1406
-     * @return string
1407
-     * @throws EE_Error
1408
-     */
1409
-    public function name_and_info()
1410
-    {
1411
-        $times = array();
1412
-        foreach ($this->datetimes() as $datetime) {
1413
-            $times[] = $datetime->start_date_and_time();
1414
-        }
1415
-        return $this->name() . ' @ ' . implode(', ', $times) . ' for ' . $this->pretty_price();
1416
-    }
1417
-
1418
-
1419
-    /**
1420
-     * Gets name
1421
-     *
1422
-     * @return string
1423
-     * @throws EE_Error
1424
-     */
1425
-    public function name()
1426
-    {
1427
-        return $this->get('TKT_name');
1428
-    }
1429
-
1430
-
1431
-    /**
1432
-     * Gets price
1433
-     *
1434
-     * @return float
1435
-     * @throws EE_Error
1436
-     */
1437
-    public function price()
1438
-    {
1439
-        return $this->get('TKT_price');
1440
-    }
1441
-
1442
-
1443
-    /**
1444
-     * Gets all the registrations for this ticket
1445
-     *
1446
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1447
-     * @return EE_Registration[]|EE_Base_Class[]
1448
-     * @throws EE_Error
1449
-     */
1450
-    public function registrations($query_params = array())
1451
-    {
1452
-        return $this->get_many_related('Registration', $query_params);
1453
-    }
1454
-
1455
-
1456
-    /**
1457
-     * Updates the TKT_sold attribute (and saves) based on the number of APPROVED registrations for this ticket.
1458
-     *
1459
-     * @return int
1460
-     * @throws EE_Error
1461
-     */
1462
-    public function update_tickets_sold()
1463
-    {
1464
-        $count_regs_for_this_ticket = $this->count_registrations(
1465
-            array(
1466
-                array(
1467
-                    'STS_ID'      => EEM_Registration::status_id_approved,
1468
-                    'REG_deleted' => 0,
1469
-                ),
1470
-            )
1471
-        );
1472
-        $this->set_sold($count_regs_for_this_ticket);
1473
-        $this->save();
1474
-        return $count_regs_for_this_ticket;
1475
-    }
1476
-
1477
-
1478
-    /**
1479
-     * Counts the registrations for this ticket
1480
-     *
1481
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1482
-     * @return int
1483
-     */
1484
-    public function count_registrations($query_params = array())
1485
-    {
1486
-        return $this->count_related('Registration', $query_params);
1487
-    }
1488
-
1489
-
1490
-    /**
1491
-     * Implementation for EEI_Has_Icon interface method.
1492
-     *
1493
-     * @see EEI_Visual_Representation for comments
1494
-     * @return string
1495
-     */
1496
-    public function get_icon()
1497
-    {
1498
-        return '<span class="dashicons dashicons-tickets-alt"></span>';
1499
-    }
1500
-
1501
-
1502
-    /**
1503
-     * Implementation of the EEI_Event_Relation interface method
1504
-     *
1505
-     * @see EEI_Event_Relation for comments
1506
-     * @return EE_Event
1507
-     * @throws EE_Error
1508
-     * @throws UnexpectedEntityException
1509
-     */
1510
-    public function get_related_event()
1511
-    {
1512
-        // get one datetime to use for getting the event
1513
-        $datetime = $this->first_datetime();
1514
-        if (! $datetime instanceof \EE_Datetime) {
1515
-            throw new UnexpectedEntityException(
1516
-                $datetime,
1517
-                'EE_Datetime',
1518
-                sprintf(
1519
-                    __('The ticket (%s) is not associated with any valid datetimes.', 'event_espresso'),
1520
-                    $this->name()
1521
-                )
1522
-            );
1523
-        }
1524
-        $event = $datetime->event();
1525
-        if (! $event instanceof \EE_Event) {
1526
-            throw new UnexpectedEntityException(
1527
-                $event,
1528
-                'EE_Event',
1529
-                sprintf(
1530
-                    __('The ticket (%s) is not associated with a valid event.', 'event_espresso'),
1531
-                    $this->name()
1532
-                )
1533
-            );
1534
-        }
1535
-        return $event;
1536
-    }
1537
-
1538
-
1539
-    /**
1540
-     * Implementation of the EEI_Event_Relation interface method
1541
-     *
1542
-     * @see EEI_Event_Relation for comments
1543
-     * @return string
1544
-     * @throws UnexpectedEntityException
1545
-     * @throws EE_Error
1546
-     */
1547
-    public function get_event_name()
1548
-    {
1549
-        $event = $this->get_related_event();
1550
-        return $event instanceof EE_Event ? $event->name() : '';
1551
-    }
1552
-
1553
-
1554
-    /**
1555
-     * Implementation of the EEI_Event_Relation interface method
1556
-     *
1557
-     * @see EEI_Event_Relation for comments
1558
-     * @return int
1559
-     * @throws UnexpectedEntityException
1560
-     * @throws EE_Error
1561
-     */
1562
-    public function get_event_ID()
1563
-    {
1564
-        $event = $this->get_related_event();
1565
-        return $event instanceof EE_Event ? $event->ID() : 0;
1566
-    }
1567
-
1568
-
1569
-    /**
1570
-     * This simply returns whether a ticket can be permanently deleted or not.
1571
-     * The criteria for determining this is whether the ticket has any related registrations.
1572
-     * If there are none then it can be permanently deleted.
1573
-     *
1574
-     * @return bool
1575
-     */
1576
-    public function is_permanently_deleteable()
1577
-    {
1578
-        return $this->count_registrations() === 0;
1579
-    }
1580
-
1581
-
1582
-    /*******************************************************************
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 purchase
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
+	 */
76
+	public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
77
+	{
78
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
79
+		return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
80
+	}
81
+
82
+
83
+	/**
84
+	 * @param array  $props_n_values  incoming values from the database
85
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
86
+	 *                                the website will be used.
87
+	 * @return EE_Ticket
88
+	 * @throws EE_Error
89
+	 */
90
+	public static function new_instance_from_db($props_n_values = array(), $timezone = null)
91
+	{
92
+		return new self($props_n_values, true, $timezone);
93
+	}
94
+
95
+
96
+	/**
97
+	 * @return bool
98
+	 * @throws EE_Error
99
+	 */
100
+	public function parent()
101
+	{
102
+		return $this->get('TKT_parent');
103
+	}
104
+
105
+
106
+	/**
107
+	 * return if a ticket has quantities available for purchase
108
+	 *
109
+	 * @param  int $DTT_ID the primary key for a particular datetime
110
+	 * @return boolean
111
+	 * @throws EE_Error
112
+	 */
113
+	public function available($DTT_ID = 0)
114
+	{
115
+		// are we checking availability for a particular datetime ?
116
+		if ($DTT_ID) {
117
+			// get that datetime object
118
+			$datetime = $this->get_first_related('Datetime', array(array('DTT_ID' => $DTT_ID)));
119
+			// if  ticket sales for this datetime have exceeded the reg limit...
120
+			if ($datetime instanceof EE_Datetime && $datetime->sold_out()) {
121
+				return false;
122
+			}
123
+		}
124
+		// datetime is still open for registration, but is this ticket sold out ?
125
+		return $this->qty() < 1 || $this->qty() > $this->sold() ? true : false;
126
+	}
127
+
128
+
129
+	/**
130
+	 * Using the start date and end date this method calculates whether the ticket is On Sale, Pending, or Expired
131
+	 *
132
+	 * @param bool        $display   true = we'll return a localized string, otherwise we just return the value of the
133
+	 *                               relevant status const
134
+	 * @param bool | null $remaining if it is already known that tickets are available, then simply pass a bool to save
135
+	 *               further processing
136
+	 * @return mixed status int if the display string isn't requested
137
+	 * @throws EE_Error
138
+	 */
139
+	public function ticket_status($display = false, $remaining = null)
140
+	{
141
+		$remaining = is_bool($remaining) ? $remaining : $this->is_remaining();
142
+		if (! $remaining) {
143
+			return $display ? EEH_Template::pretty_status(EE_Ticket::sold_out, false, 'sentence') : EE_Ticket::sold_out;
144
+		}
145
+		if ($this->get('TKT_deleted')) {
146
+			return $display ? EEH_Template::pretty_status(EE_Ticket::archived, false, 'sentence') : EE_Ticket::archived;
147
+		}
148
+		if ($this->is_expired()) {
149
+			return $display ? EEH_Template::pretty_status(EE_Ticket::expired, false, 'sentence') : EE_Ticket::expired;
150
+		}
151
+		if ($this->is_pending()) {
152
+			return $display ? EEH_Template::pretty_status(EE_Ticket::pending, false, 'sentence') : EE_Ticket::pending;
153
+		}
154
+		if ($this->is_on_sale()) {
155
+			return $display ? EEH_Template::pretty_status(EE_Ticket::onsale, false, 'sentence') : EE_Ticket::onsale;
156
+		}
157
+		return '';
158
+	}
159
+
160
+
161
+	/**
162
+	 * The purpose of this method is to simply return a boolean for whether there are any tickets remaining for sale
163
+	 * considering ALL the factors used for figuring that out.
164
+	 *
165
+	 * @access public
166
+	 * @param  int $DTT_ID if an int above 0 is included here then we get a specific dtt.
167
+	 * @return boolean         true = tickets remaining, false not.
168
+	 * @throws EE_Error
169
+	 */
170
+	public function is_remaining($DTT_ID = 0)
171
+	{
172
+		$num_remaining = $this->remaining($DTT_ID);
173
+		if ($num_remaining === 0) {
174
+			return false;
175
+		}
176
+		if ($num_remaining > 0 && $num_remaining < $this->min()) {
177
+			return false;
178
+		}
179
+		return true;
180
+	}
181
+
182
+
183
+	/**
184
+	 * return the total number of tickets available for purchase
185
+	 *
186
+	 * @param  int $DTT_ID the primary key for a particular datetime.
187
+	 *                     set to 0 for all related datetimes
188
+	 * @return int
189
+	 * @throws EE_Error
190
+	 */
191
+	public function remaining($DTT_ID = 0)
192
+	{
193
+		return $this->real_quantity_on_ticket('saleable', $DTT_ID);
194
+	}
195
+
196
+
197
+	/**
198
+	 * Gets min
199
+	 *
200
+	 * @return int
201
+	 * @throws EE_Error
202
+	 */
203
+	public function min()
204
+	{
205
+		return $this->get('TKT_min');
206
+	}
207
+
208
+
209
+	/**
210
+	 * return if a ticket is no longer available cause its available dates have expired.
211
+	 *
212
+	 * @return boolean
213
+	 * @throws EE_Error
214
+	 */
215
+	public function is_expired()
216
+	{
217
+		return ($this->get_raw('TKT_end_date') < time());
218
+	}
219
+
220
+
221
+	/**
222
+	 * Return if a ticket is yet to go on sale or not
223
+	 *
224
+	 * @return boolean
225
+	 * @throws EE_Error
226
+	 */
227
+	public function is_pending()
228
+	{
229
+		return ($this->get_raw('TKT_start_date') > time());
230
+	}
231
+
232
+
233
+	/**
234
+	 * Return if a ticket is on sale or not
235
+	 *
236
+	 * @return boolean
237
+	 * @throws EE_Error
238
+	 */
239
+	public function is_on_sale()
240
+	{
241
+		return ($this->get_raw('TKT_start_date') < time() && $this->get_raw('TKT_end_date') > time());
242
+	}
243
+
244
+
245
+	/**
246
+	 * This returns the chronologically last datetime that this ticket is associated with
247
+	 *
248
+	 * @param string $dt_frmt
249
+	 * @param string $conjunction - conjunction junction what's your function ? this string joins the start date with
250
+	 *                            the end date ie: Jan 01 "to" Dec 31
251
+	 * @return string
252
+	 * @throws EE_Error
253
+	 */
254
+	public function date_range($dt_frmt = '', $conjunction = ' - ')
255
+	{
256
+		$dt_frmt = ! empty($dt_frmt) ? $dt_frmt : $this->_dt_frmt;
257
+		$first_date = $this->first_datetime() instanceof EE_Datetime ? $this->first_datetime()->get_i18n_datetime('DTT_EVT_start', $dt_frmt)
258
+			: '';
259
+		$last_date = $this->last_datetime() instanceof EE_Datetime ? $this->last_datetime()->get_i18n_datetime('DTT_EVT_end', $dt_frmt) : '';
260
+
261
+		return $first_date && $last_date ? $first_date . $conjunction . $last_date : '';
262
+	}
263
+
264
+
265
+	/**
266
+	 * This returns the chronologically first datetime that this ticket is associated with
267
+	 *
268
+	 * @return EE_Datetime
269
+	 * @throws EE_Error
270
+	 */
271
+	public function first_datetime()
272
+	{
273
+		$datetimes = $this->datetimes(array('limit' => 1));
274
+		return reset($datetimes);
275
+	}
276
+
277
+
278
+	/**
279
+	 * Gets all the datetimes this ticket can be used for attending.
280
+	 * Unless otherwise specified, orders datetimes by start date.
281
+	 *
282
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
283
+	 * @return EE_Datetime[]|EE_Base_Class[]
284
+	 * @throws EE_Error
285
+	 */
286
+	public function datetimes($query_params = array())
287
+	{
288
+		if (! isset($query_params['order_by'])) {
289
+			$query_params['order_by']['DTT_order'] = 'ASC';
290
+		}
291
+		return $this->get_many_related('Datetime', $query_params);
292
+	}
293
+
294
+
295
+	/**
296
+	 * This returns the chronologically last datetime that this ticket is associated with
297
+	 *
298
+	 * @return EE_Datetime
299
+	 * @throws EE_Error
300
+	 */
301
+	public function last_datetime()
302
+	{
303
+		$datetimes = $this->datetimes(array('limit' => 1, 'order_by' => array('DTT_EVT_start' => 'DESC')));
304
+		return end($datetimes);
305
+	}
306
+
307
+
308
+	/**
309
+	 * This returns the total tickets sold depending on the given parameters.
310
+	 *
311
+	 * @param  string $what   Can be one of two options: 'ticket', 'datetime'.
312
+	 *                        'ticket' = total ticket sales for all datetimes this ticket is related to
313
+	 *                        'datetime' = total ticket sales for a specified datetime (required $dtt_id)
314
+	 *                        'datetime' = total ticket sales in the datetime_ticket table.
315
+	 *                        If $dtt_id is not given then we return an array of sales indexed by datetime.
316
+	 *                        If $dtt_id IS given then we return the tickets sold for that given datetime.
317
+	 * @param  int    $dtt_id [optional] include the dtt_id with $what = 'datetime'.
318
+	 * @return mixed (array|int)          how many tickets have sold
319
+	 * @throws EE_Error
320
+	 */
321
+	public function tickets_sold($what = 'ticket', $dtt_id = null)
322
+	{
323
+		$total = 0;
324
+		$tickets_sold = $this->_all_tickets_sold();
325
+		switch ($what) {
326
+			case 'ticket':
327
+				return $tickets_sold['ticket'];
328
+				break;
329
+			case 'datetime':
330
+				if (empty($tickets_sold['datetime'])) {
331
+					return $total;
332
+				}
333
+				if (! empty($dtt_id) && ! isset($tickets_sold['datetime'][ $dtt_id ])) {
334
+					EE_Error::add_error(
335
+						__(
336
+							'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?',
337
+							'event_espresso'
338
+						),
339
+						__FILE__,
340
+						__FUNCTION__,
341
+						__LINE__
342
+					);
343
+					return $total;
344
+				}
345
+				return empty($dtt_id) ? $tickets_sold['datetime'] : $tickets_sold['datetime'][ $dtt_id ];
346
+				break;
347
+			default:
348
+				return $total;
349
+		}
350
+	}
351
+
352
+
353
+	/**
354
+	 * This returns an array indexed by datetime_id for tickets sold with this ticket.
355
+	 *
356
+	 * @return EE_Ticket[]
357
+	 * @throws EE_Error
358
+	 */
359
+	protected function _all_tickets_sold()
360
+	{
361
+		$datetimes = $this->get_many_related('Datetime');
362
+		$tickets_sold = array();
363
+		if (! empty($datetimes)) {
364
+			foreach ($datetimes as $datetime) {
365
+				$tickets_sold['datetime'][ $datetime->ID() ] = $datetime->get('DTT_sold');
366
+			}
367
+		}
368
+		// Tickets sold
369
+		$tickets_sold['ticket'] = $this->sold();
370
+		return $tickets_sold;
371
+	}
372
+
373
+
374
+	/**
375
+	 * This returns the base price object for the ticket.
376
+	 *
377
+	 * @param  bool $return_array whether to return as an array indexed by price id or just the object.
378
+	 * @return EE_Price|EE_Base_Class|EE_Price[]|EE_Base_Class[]
379
+	 * @throws EE_Error
380
+	 */
381
+	public function base_price($return_array = false)
382
+	{
383
+		$_where = array('Price_Type.PBT_ID' => EEM_Price_Type::base_type_base_price);
384
+		return $return_array
385
+			? $this->get_many_related('Price', array($_where))
386
+			: $this->get_first_related('Price', array($_where));
387
+	}
388
+
389
+
390
+	/**
391
+	 * This returns ONLY the price modifiers for the ticket (i.e. no taxes or base price)
392
+	 *
393
+	 * @access public
394
+	 * @return EE_Price[]
395
+	 * @throws EE_Error
396
+	 */
397
+	public function price_modifiers()
398
+	{
399
+		$query_params = array(
400
+			0 => array(
401
+				'Price_Type.PBT_ID' => array(
402
+					'NOT IN',
403
+					array(EEM_Price_Type::base_type_base_price, EEM_Price_Type::base_type_tax),
404
+				),
405
+			),
406
+		);
407
+		return $this->prices($query_params);
408
+	}
409
+
410
+
411
+	/**
412
+	 * Gets all the prices that combine to form the final price of this ticket
413
+	 *
414
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
415
+	 * @return EE_Price[]|EE_Base_Class[]
416
+	 * @throws EE_Error
417
+	 */
418
+	public function prices($query_params = array())
419
+	{
420
+		return $this->get_many_related('Price', $query_params);
421
+	}
422
+
423
+
424
+	/**
425
+	 * Gets all the ticket applicabilities (ie, relations between datetimes and tickets)
426
+	 *
427
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
428
+	 * @return EE_Datetime_Ticket|EE_Base_Class[]
429
+	 * @throws EE_Error
430
+	 */
431
+	public function datetime_tickets($query_params = array())
432
+	{
433
+		return $this->get_many_related('Datetime_Ticket', $query_params);
434
+	}
435
+
436
+
437
+	/**
438
+	 * Gets all the datetimes from the db ordered by DTT_order
439
+	 *
440
+	 * @param boolean $show_expired
441
+	 * @param boolean $show_deleted
442
+	 * @return EE_Datetime[]
443
+	 * @throws EE_Error
444
+	 */
445
+	public function datetimes_ordered($show_expired = true, $show_deleted = false)
446
+	{
447
+		return EEM_Datetime::instance($this->_timezone)->get_datetimes_for_ticket_ordered_by_DTT_order(
448
+			$this->ID(),
449
+			$show_expired,
450
+			$show_deleted
451
+		);
452
+	}
453
+
454
+
455
+	/**
456
+	 * Gets ID
457
+	 *
458
+	 * @return string
459
+	 * @throws EE_Error
460
+	 */
461
+	public function ID()
462
+	{
463
+		return $this->get('TKT_ID');
464
+	}
465
+
466
+
467
+	/**
468
+	 * get the author of the ticket.
469
+	 *
470
+	 * @since 4.5.0
471
+	 * @return int
472
+	 * @throws EE_Error
473
+	 */
474
+	public function wp_user()
475
+	{
476
+		return $this->get('TKT_wp_user');
477
+	}
478
+
479
+
480
+	/**
481
+	 * Gets the template for the ticket
482
+	 *
483
+	 * @return EE_Ticket_Template|EE_Base_Class
484
+	 * @throws EE_Error
485
+	 */
486
+	public function template()
487
+	{
488
+		return $this->get_first_related('Ticket_Template');
489
+	}
490
+
491
+
492
+	/**
493
+	 * Simply returns an array of EE_Price objects that are taxes.
494
+	 *
495
+	 * @return EE_Price[]
496
+	 * @throws EE_Error
497
+	 */
498
+	public function get_ticket_taxes_for_admin()
499
+	{
500
+		return EE_Taxes::get_taxes_for_admin();
501
+	}
502
+
503
+
504
+	/**
505
+	 * @return float
506
+	 * @throws EE_Error
507
+	 */
508
+	public function ticket_price()
509
+	{
510
+		return $this->get('TKT_price');
511
+	}
512
+
513
+
514
+	/**
515
+	 * @return mixed
516
+	 * @throws EE_Error
517
+	 */
518
+	public function pretty_price()
519
+	{
520
+		return $this->get_pretty('TKT_price');
521
+	}
522
+
523
+
524
+	/**
525
+	 * @return bool
526
+	 * @throws EE_Error
527
+	 */
528
+	public function is_free()
529
+	{
530
+		return $this->get_ticket_total_with_taxes() === (float) 0;
531
+	}
532
+
533
+
534
+	/**
535
+	 * get_ticket_total_with_taxes
536
+	 *
537
+	 * @param bool $no_cache
538
+	 * @return float
539
+	 * @throws EE_Error
540
+	 */
541
+	public function get_ticket_total_with_taxes($no_cache = false)
542
+	{
543
+		if ($this->_ticket_total_with_taxes === null || $no_cache) {
544
+			$this->_ticket_total_with_taxes = $this->get_ticket_subtotal() + $this->get_ticket_taxes_total_for_admin();
545
+		}
546
+		return (float) $this->_ticket_total_with_taxes;
547
+	}
548
+
549
+
550
+	public function ensure_TKT_Price_correct()
551
+	{
552
+		$this->set('TKT_price', EE_Taxes::get_subtotal_for_admin($this));
553
+		$this->save();
554
+	}
555
+
556
+
557
+	/**
558
+	 * @return float
559
+	 * @throws EE_Error
560
+	 */
561
+	public function get_ticket_subtotal()
562
+	{
563
+		return EE_Taxes::get_subtotal_for_admin($this);
564
+	}
565
+
566
+
567
+	/**
568
+	 * Returns the total taxes applied to this ticket
569
+	 *
570
+	 * @return float
571
+	 * @throws EE_Error
572
+	 */
573
+	public function get_ticket_taxes_total_for_admin()
574
+	{
575
+		return EE_Taxes::get_total_taxes_for_admin($this);
576
+	}
577
+
578
+
579
+	/**
580
+	 * Sets name
581
+	 *
582
+	 * @param string $name
583
+	 * @throws EE_Error
584
+	 */
585
+	public function set_name($name)
586
+	{
587
+		$this->set('TKT_name', $name);
588
+	}
589
+
590
+
591
+	/**
592
+	 * Gets description
593
+	 *
594
+	 * @return string
595
+	 * @throws EE_Error
596
+	 */
597
+	public function description()
598
+	{
599
+		return $this->get('TKT_description');
600
+	}
601
+
602
+
603
+	/**
604
+	 * Sets description
605
+	 *
606
+	 * @param string $description
607
+	 * @throws EE_Error
608
+	 */
609
+	public function set_description($description)
610
+	{
611
+		$this->set('TKT_description', $description);
612
+	}
613
+
614
+
615
+	/**
616
+	 * Gets start_date
617
+	 *
618
+	 * @param string $dt_frmt
619
+	 * @param string $tm_frmt
620
+	 * @return string
621
+	 * @throws EE_Error
622
+	 */
623
+	public function start_date($dt_frmt = '', $tm_frmt = '')
624
+	{
625
+		return $this->_get_datetime('TKT_start_date', $dt_frmt, $tm_frmt);
626
+	}
627
+
628
+
629
+	/**
630
+	 * Sets start_date
631
+	 *
632
+	 * @param string $start_date
633
+	 * @return void
634
+	 * @throws EE_Error
635
+	 */
636
+	public function set_start_date($start_date)
637
+	{
638
+		$this->_set_date_time('B', $start_date, 'TKT_start_date');
639
+	}
640
+
641
+
642
+	/**
643
+	 * Gets end_date
644
+	 *
645
+	 * @param string $dt_frmt
646
+	 * @param string $tm_frmt
647
+	 * @return string
648
+	 * @throws EE_Error
649
+	 */
650
+	public function end_date($dt_frmt = '', $tm_frmt = '')
651
+	{
652
+		return $this->_get_datetime('TKT_end_date', $dt_frmt, $tm_frmt);
653
+	}
654
+
655
+
656
+	/**
657
+	 * Sets end_date
658
+	 *
659
+	 * @param string $end_date
660
+	 * @return void
661
+	 * @throws EE_Error
662
+	 */
663
+	public function set_end_date($end_date)
664
+	{
665
+		$this->_set_date_time('B', $end_date, 'TKT_end_date');
666
+	}
667
+
668
+
669
+	/**
670
+	 * Sets sell until time
671
+	 *
672
+	 * @since 4.5.0
673
+	 * @param string $time a string representation of the sell until time (ex 9am or 7:30pm)
674
+	 * @throws EE_Error
675
+	 */
676
+	public function set_end_time($time)
677
+	{
678
+		$this->_set_time_for($time, 'TKT_end_date');
679
+	}
680
+
681
+
682
+	/**
683
+	 * Sets min
684
+	 *
685
+	 * @param int $min
686
+	 * @return void
687
+	 * @throws EE_Error
688
+	 */
689
+	public function set_min($min)
690
+	{
691
+		$this->set('TKT_min', $min);
692
+	}
693
+
694
+
695
+	/**
696
+	 * Gets max
697
+	 *
698
+	 * @return int
699
+	 * @throws EE_Error
700
+	 */
701
+	public function max()
702
+	{
703
+		return $this->get('TKT_max');
704
+	}
705
+
706
+
707
+	/**
708
+	 * Sets max
709
+	 *
710
+	 * @param int $max
711
+	 * @return void
712
+	 * @throws EE_Error
713
+	 */
714
+	public function set_max($max)
715
+	{
716
+		$this->set('TKT_max', $max);
717
+	}
718
+
719
+
720
+	/**
721
+	 * Sets price
722
+	 *
723
+	 * @param float $price
724
+	 * @return void
725
+	 * @throws EE_Error
726
+	 */
727
+	public function set_price($price)
728
+	{
729
+		$this->set('TKT_price', $price);
730
+	}
731
+
732
+
733
+	/**
734
+	 * Gets sold
735
+	 *
736
+	 * @return int
737
+	 * @throws EE_Error
738
+	 */
739
+	public function sold()
740
+	{
741
+		return $this->get_raw('TKT_sold');
742
+	}
743
+
744
+
745
+	/**
746
+	 * Sets sold
747
+	 *
748
+	 * @param int $sold
749
+	 * @return void
750
+	 * @throws EE_Error
751
+	 */
752
+	public function set_sold($sold)
753
+	{
754
+		// sold can not go below zero
755
+		$sold = max(0, $sold);
756
+		$this->set('TKT_sold', $sold);
757
+	}
758
+
759
+
760
+	/**
761
+	 * Increments sold by amount passed by $qty AND decrements the reserved count on both this ticket and its
762
+	 * associated datetimes.
763
+	 *
764
+	 * @since 4.9.80.p
765
+	 * @param int $qty
766
+	 * @return boolean
767
+	 * @throws EE_Error
768
+	 * @throws InvalidArgumentException
769
+	 * @throws InvalidDataTypeException
770
+	 * @throws InvalidInterfaceException
771
+	 * @throws ReflectionException
772
+	 */
773
+	public function increaseSold($qty = 1)
774
+	{
775
+		$qty = absint($qty);
776
+		// increment sold and decrement reserved datetime quantities simultaneously
777
+		// don't worry about failures, because they must have already had a spot reserved
778
+		$this->increaseSoldForDatetimes($qty);
779
+		// Increment and decrement ticket quantities simultaneously
780
+		$success = $this->adjustNumericFieldsInDb(
781
+			[
782
+				'TKT_reserved' => $qty * -1,
783
+				'TKT_sold' => $qty
784
+			]
785
+		);
786
+		do_action(
787
+			'AHEE__EE_Ticket__increase_sold',
788
+			$this,
789
+			$qty,
790
+			$this->sold(),
791
+			$success
792
+		);
793
+		return $success;
794
+	}
795
+
796
+	/**
797
+	 * On each datetime related to this ticket, increases its sold count and decreases its reserved count by $qty.
798
+	 *
799
+	 * @since 4.9.80.p
800
+	 * @param int $qty positive or negative. Positive means to increase sold counts (and decrease reserved counts),
801
+	 *             Negative means to decreases old counts (and increase reserved counts).
802
+	 * @param EE_Datetime[] $datetimes
803
+	 * @throws EE_Error
804
+	 * @throws InvalidArgumentException
805
+	 * @throws InvalidDataTypeException
806
+	 * @throws InvalidInterfaceException
807
+	 * @throws ReflectionException
808
+	 */
809
+	protected function increaseSoldForDatetimes($qty, array $datetimes = [])
810
+	{
811
+		$datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
812
+		foreach ($datetimes as $datetime) {
813
+			$datetime->increaseSold($qty);
814
+		}
815
+	}
816
+
817
+
818
+
819
+	/**
820
+	 * Decrements (subtracts) sold by amount passed by $qty on both the ticket and its related datetimes directly in the
821
+	 * DB and then updates the model objects.
822
+	 * Does not affect the reserved counts.
823
+	 *
824
+	 * @since 4.9.80.p
825
+	 * @param int $qty
826
+	 * @return boolean
827
+	 * @throws EE_Error
828
+	 * @throws InvalidArgumentException
829
+	 * @throws InvalidDataTypeException
830
+	 * @throws InvalidInterfaceException
831
+	 * @throws ReflectionException
832
+	 */
833
+	public function decreaseSold($qty = 1)
834
+	{
835
+		$qty = absint($qty);
836
+		$this->decreaseSoldForDatetimes($qty);
837
+		$success = $this->adjustNumericFieldsInDb(
838
+			[
839
+				'TKT_sold' => $qty * -1
840
+			]
841
+		);
842
+		do_action(
843
+			'AHEE__EE_Ticket__decrease_sold',
844
+			$this,
845
+			$qty,
846
+			$this->sold(),
847
+			$success
848
+		);
849
+		return $success;
850
+	}
851
+
852
+
853
+	/**
854
+	 * Decreases sold on related datetimes
855
+	 *
856
+	 * @since 4.9.80.p
857
+	 * @param int $qty
858
+	 * @param EE_Datetime[] $datetimes
859
+	 * @return void
860
+	 * @throws EE_Error
861
+	 * @throws InvalidArgumentException
862
+	 * @throws InvalidDataTypeException
863
+	 * @throws InvalidInterfaceException
864
+	 * @throws ReflectionException
865
+	 */
866
+	protected function decreaseSoldForDatetimes($qty = 1, array $datetimes = [])
867
+	{
868
+		$datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
869
+		if (is_array($datetimes)) {
870
+			foreach ($datetimes as $datetime) {
871
+				if ($datetime instanceof EE_Datetime) {
872
+					$datetime->decreaseSold($qty);
873
+				}
874
+			}
875
+		}
876
+	}
877
+
878
+
879
+	/**
880
+	 * Gets qty of reserved tickets
881
+	 *
882
+	 * @return int
883
+	 * @throws EE_Error
884
+	 */
885
+	public function reserved()
886
+	{
887
+		return $this->get_raw('TKT_reserved');
888
+	}
889
+
890
+
891
+	/**
892
+	 * Sets reserved
893
+	 *
894
+	 * @param int $reserved
895
+	 * @return void
896
+	 * @throws EE_Error
897
+	 */
898
+	public function set_reserved($reserved)
899
+	{
900
+		// reserved can not go below zero
901
+		$reserved = max(0, (int) $reserved);
902
+		$this->set('TKT_reserved', $reserved);
903
+	}
904
+
905
+
906
+	/**
907
+	 * Increments reserved by amount passed by $qty, and persists it immediately to the database.
908
+	 *
909
+	 * @since 4.9.80.p
910
+	 * @param int    $qty
911
+	 * @param string $source
912
+	 * @return bool whether we successfully reserved the ticket or not.
913
+	 * @throws EE_Error
914
+	 * @throws InvalidArgumentException
915
+	 * @throws ReflectionException
916
+	 * @throws InvalidDataTypeException
917
+	 * @throws InvalidInterfaceException
918
+	 */
919
+	public function increaseReserved($qty = 1, $source = 'unknown')
920
+	{
921
+		$qty = absint($qty);
922
+		do_action(
923
+			'AHEE__EE_Ticket__increase_reserved__begin',
924
+			$this,
925
+			$qty,
926
+			$source
927
+		);
928
+		$this->add_extra_meta(EE_Ticket::META_KEY_TICKET_RESERVATIONS, "{$qty} from {$source}");
929
+		$success = false;
930
+		$datetimes_adjusted_successfully = $this->increaseReservedForDatetimes($qty);
931
+		if ($datetimes_adjusted_successfully) {
932
+			$success = $this->incrementFieldConditionallyInDb(
933
+				'TKT_reserved',
934
+				'TKT_sold',
935
+				'TKT_qty',
936
+				$qty
937
+			);
938
+			if (! $success) {
939
+				// The datetimes were successfully bumped, but not the
940
+				// ticket. So we need to manually rollback the datetimes.
941
+				$this->decreaseReservedForDatetimes($qty);
942
+			}
943
+		}
944
+		do_action(
945
+			'AHEE__EE_Ticket__increase_reserved',
946
+			$this,
947
+			$qty,
948
+			$this->reserved(),
949
+			$success
950
+		);
951
+		return $success;
952
+	}
953
+
954
+
955
+	/**
956
+	 * Increases reserved counts on related datetimes
957
+	 *
958
+	 * @since 4.9.80.p
959
+	 * @param int $qty
960
+	 * @param EE_Datetime[] $datetimes
961
+	 * @return boolean indicating success
962
+	 * @throws EE_Error
963
+	 * @throws InvalidArgumentException
964
+	 * @throws InvalidDataTypeException
965
+	 * @throws InvalidInterfaceException
966
+	 * @throws ReflectionException
967
+	 */
968
+	protected function increaseReservedForDatetimes($qty = 1, array $datetimes = [])
969
+	{
970
+		$datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
971
+		$datetimes_updated = [];
972
+		$limit_exceeded = false;
973
+		if (is_array($datetimes)) {
974
+			foreach ($datetimes as $datetime) {
975
+				if ($datetime instanceof EE_Datetime) {
976
+					if ($datetime->increaseReserved($qty)) {
977
+						$datetimes_updated[] = $datetime;
978
+					} else {
979
+						$limit_exceeded = true;
980
+						break;
981
+					}
982
+				}
983
+			}
984
+			// If somewhere along the way we detected a datetime whose
985
+			// limit was exceeded, do a manual rollback.
986
+			if ($limit_exceeded) {
987
+				$this->decreaseReservedForDatetimes($qty, $datetimes_updated);
988
+				return false;
989
+			}
990
+		}
991
+		return true;
992
+	}
993
+
994
+
995
+	/**
996
+	 * Decrements (subtracts) reserved by amount passed by $qty, and persists it immediately to the database.
997
+	 *
998
+	 * @since 4.9.80.p
999
+	 * @param int    $qty
1000
+	 * @param bool   $adjust_datetimes
1001
+	 * @param string $source
1002
+	 * @return boolean
1003
+	 * @throws EE_Error
1004
+	 * @throws InvalidArgumentException
1005
+	 * @throws ReflectionException
1006
+	 * @throws InvalidDataTypeException
1007
+	 * @throws InvalidInterfaceException
1008
+	 */
1009
+	public function decreaseReserved($qty = 1, $adjust_datetimes = true, $source = 'unknown')
1010
+	{
1011
+		$qty = absint($qty);
1012
+		$this->add_extra_meta(EE_Ticket::META_KEY_TICKET_RESERVATIONS, "-{$qty} from {$source}");
1013
+		if ($adjust_datetimes) {
1014
+			$this->decreaseReservedForDatetimes($qty);
1015
+		}
1016
+		$success = $this->adjustNumericFieldsInDb(
1017
+			[
1018
+				'TKT_reserved' => $qty * -1
1019
+			]
1020
+		);
1021
+		do_action(
1022
+			'AHEE__EE_Ticket__decrease_reserved',
1023
+			$this,
1024
+			$qty,
1025
+			$this->reserved(),
1026
+			$success
1027
+		);
1028
+		return $success;
1029
+	}
1030
+
1031
+
1032
+	/**
1033
+	 * Decreases the reserved count on the specified datetimes.
1034
+	 *
1035
+	 * @since 4.9.80.p
1036
+	 * @param int           $qty
1037
+	 * @param EE_Datetime[] $datetimes
1038
+	 * @throws EE_Error
1039
+	 * @throws InvalidArgumentException
1040
+	 * @throws ReflectionException
1041
+	 * @throws InvalidDataTypeException
1042
+	 * @throws InvalidInterfaceException
1043
+	 */
1044
+	protected function decreaseReservedForDatetimes($qty = 1, array $datetimes = [])
1045
+	{
1046
+		$datetimes = ! empty($datetimes) ? $datetimes : $this->datetimes();
1047
+		foreach ($datetimes as $datetime) {
1048
+			if ($datetime instanceof EE_Datetime) {
1049
+				$datetime->decreaseReserved($qty);
1050
+			}
1051
+		}
1052
+	}
1053
+
1054
+
1055
+	/**
1056
+	 * Gets ticket quantity
1057
+	 *
1058
+	 * @param string $context     ticket quantity is somewhat subjective depending on the exact information sought
1059
+	 *                            therefore $context can be one of three values: '', 'reg_limit', or 'saleable'
1060
+	 *                            '' (default) quantity is the actual db value for TKT_qty, unaffected by other objects
1061
+	 *                            REG LIMIT: caps qty based on DTT_reg_limit for ALL related datetimes
1062
+	 *                            SALEABLE: also considers datetime sold and returns zero if ANY DTT is sold out, and
1063
+	 *                            is therefore the truest measure of tickets that can be purchased at the moment
1064
+	 * @return int
1065
+	 * @throws EE_Error
1066
+	 */
1067
+	public function qty($context = '')
1068
+	{
1069
+		switch ($context) {
1070
+			case 'reg_limit':
1071
+				return $this->real_quantity_on_ticket();
1072
+			case 'saleable':
1073
+				return $this->real_quantity_on_ticket('saleable');
1074
+			default:
1075
+				return $this->get_raw('TKT_qty');
1076
+		}
1077
+	}
1078
+
1079
+
1080
+	/**
1081
+	 * Gets ticket quantity
1082
+	 *
1083
+	 * @param string $context     ticket quantity is somewhat subjective depending on the exact information sought
1084
+	 *                            therefore $context can be one of two values: 'reg_limit', or 'saleable'
1085
+	 *                            REG LIMIT: caps qty based on DTT_reg_limit for ALL related datetimes
1086
+	 *                            SALEABLE: also considers datetime sold and returns zero if ANY DTT is sold out, and
1087
+	 *                            is therefore the truest measure of tickets that can be purchased at the moment
1088
+	 * @param  int   $DTT_ID      the primary key for a particular datetime.
1089
+	 *                            set to 0 for all related datetimes
1090
+	 * @return int
1091
+	 * @throws EE_Error
1092
+	 */
1093
+	public function real_quantity_on_ticket($context = 'reg_limit', $DTT_ID = 0)
1094
+	{
1095
+		$raw = $this->get_raw('TKT_qty');
1096
+		// return immediately if it's zero
1097
+		if ($raw === 0) {
1098
+			return $raw;
1099
+		}
1100
+		// echo "\n\n<br />Ticket: " . $this->name() . '<br />';
1101
+		// ensure qty doesn't exceed raw value for THIS ticket
1102
+		$qty = min(EE_INF, $raw);
1103
+		// echo "\n . qty: " . $qty . '<br />';
1104
+		// calculate this ticket's total sales and reservations
1105
+		$sold_and_reserved_for_this_ticket = $this->sold() + $this->reserved();
1106
+		// echo "\n . sold: " . $this->sold() . '<br />';
1107
+		// echo "\n . reserved: " . $this->reserved() . '<br />';
1108
+		// echo "\n . sold_and_reserved_for_this_ticket: " . $sold_and_reserved_for_this_ticket . '<br />';
1109
+		// first we need to calculate the maximum number of tickets available for the datetime
1110
+		// do we want data for one datetime or all of them ?
1111
+		$query_params = $DTT_ID ? array(array('DTT_ID' => $DTT_ID)) : array();
1112
+		$datetimes = $this->datetimes($query_params);
1113
+		if (is_array($datetimes) && ! empty($datetimes)) {
1114
+			foreach ($datetimes as $datetime) {
1115
+				if ($datetime instanceof EE_Datetime) {
1116
+					$datetime->refresh_from_db();
1117
+					// echo "\n . . datetime name: " . $datetime->name() . '<br />';
1118
+					// echo "\n . . datetime ID: " . $datetime->ID() . '<br />';
1119
+					// initialize with no restrictions for each datetime
1120
+					// but adjust datetime qty based on datetime reg limit
1121
+					$datetime_qty = min(EE_INF, $datetime->reg_limit());
1122
+					// echo "\n . . . datetime reg_limit: " . $datetime->reg_limit() . '<br />';
1123
+					// echo "\n . . . datetime_qty: " . $datetime_qty . '<br />';
1124
+					// if we want the actual saleable amount, then we need to consider OTHER ticket sales
1125
+					// and reservations for this datetime, that do NOT include sales and reservations
1126
+					// for this ticket (so we add $this->sold() and $this->reserved() back in)
1127
+					if ($context === 'saleable') {
1128
+						$datetime_qty = max(
1129
+							$datetime_qty - $datetime->sold_and_reserved() + $sold_and_reserved_for_this_ticket,
1130
+							0
1131
+						);
1132
+						// echo "\n . . . datetime sold: " . $datetime->sold() . '<br />';
1133
+						// echo "\n . . . datetime reserved: " . $datetime->reserved() . '<br />';
1134
+						// echo "\n . . . datetime sold_and_reserved: " . $datetime->sold_and_reserved() . '<br />';
1135
+						// echo "\n . . . datetime_qty: " . $datetime_qty . '<br />';
1136
+						$datetime_qty = ! $datetime->sold_out() ? $datetime_qty : 0;
1137
+						// echo "\n . . . datetime_qty: " . $datetime_qty . '<br />';
1138
+					}
1139
+					$qty = min($datetime_qty, $qty);
1140
+					// echo "\n . . qty: " . $qty . '<br />';
1141
+				}
1142
+			}
1143
+		}
1144
+		// NOW that we know the  maximum number of tickets available for the datetime
1145
+		// we can finally factor in the details for this specific ticket
1146
+		if ($qty > 0 && $context === 'saleable') {
1147
+			// and subtract the sales for THIS ticket
1148
+			$qty = max($qty - $sold_and_reserved_for_this_ticket, 0);
1149
+			// echo "\n . qty: " . $qty . '<br />';
1150
+		}
1151
+		// echo "\nFINAL QTY: " . $qty . "<br /><br />";
1152
+		return $qty;
1153
+	}
1154
+
1155
+
1156
+	/**
1157
+	 * Sets qty - IMPORTANT!!! Does NOT allow QTY to be set higher than the lowest reg limit of any related datetimes
1158
+	 *
1159
+	 * @param int $qty
1160
+	 * @return void
1161
+	 * @throws EE_Error
1162
+	 */
1163
+	public function set_qty($qty)
1164
+	{
1165
+		$datetimes = $this->datetimes();
1166
+		foreach ($datetimes as $datetime) {
1167
+			if ($datetime instanceof EE_Datetime) {
1168
+				$qty = min($qty, $datetime->reg_limit());
1169
+			}
1170
+		}
1171
+		$this->set('TKT_qty', $qty);
1172
+	}
1173
+
1174
+
1175
+	/**
1176
+	 * Gets uses
1177
+	 *
1178
+	 * @return int
1179
+	 * @throws EE_Error
1180
+	 */
1181
+	public function uses()
1182
+	{
1183
+		return $this->get('TKT_uses');
1184
+	}
1185
+
1186
+
1187
+	/**
1188
+	 * Sets uses
1189
+	 *
1190
+	 * @param int $uses
1191
+	 * @return void
1192
+	 * @throws EE_Error
1193
+	 */
1194
+	public function set_uses($uses)
1195
+	{
1196
+		$this->set('TKT_uses', $uses);
1197
+	}
1198
+
1199
+
1200
+	/**
1201
+	 * returns whether ticket is required or not.
1202
+	 *
1203
+	 * @return boolean
1204
+	 * @throws EE_Error
1205
+	 */
1206
+	public function required()
1207
+	{
1208
+		return $this->get('TKT_required');
1209
+	}
1210
+
1211
+
1212
+	/**
1213
+	 * sets the TKT_required property
1214
+	 *
1215
+	 * @param boolean $required
1216
+	 * @return void
1217
+	 * @throws EE_Error
1218
+	 */
1219
+	public function set_required($required)
1220
+	{
1221
+		$this->set('TKT_required', $required);
1222
+	}
1223
+
1224
+
1225
+	/**
1226
+	 * Gets taxable
1227
+	 *
1228
+	 * @return boolean
1229
+	 * @throws EE_Error
1230
+	 */
1231
+	public function taxable()
1232
+	{
1233
+		return $this->get('TKT_taxable');
1234
+	}
1235
+
1236
+
1237
+	/**
1238
+	 * Sets taxable
1239
+	 *
1240
+	 * @param boolean $taxable
1241
+	 * @return void
1242
+	 * @throws EE_Error
1243
+	 */
1244
+	public function set_taxable($taxable)
1245
+	{
1246
+		$this->set('TKT_taxable', $taxable);
1247
+	}
1248
+
1249
+
1250
+	/**
1251
+	 * Gets is_default
1252
+	 *
1253
+	 * @return boolean
1254
+	 * @throws EE_Error
1255
+	 */
1256
+	public function is_default()
1257
+	{
1258
+		return $this->get('TKT_is_default');
1259
+	}
1260
+
1261
+
1262
+	/**
1263
+	 * Sets is_default
1264
+	 *
1265
+	 * @param boolean $is_default
1266
+	 * @return void
1267
+	 * @throws EE_Error
1268
+	 */
1269
+	public function set_is_default($is_default)
1270
+	{
1271
+		$this->set('TKT_is_default', $is_default);
1272
+	}
1273
+
1274
+
1275
+	/**
1276
+	 * Gets order
1277
+	 *
1278
+	 * @return int
1279
+	 * @throws EE_Error
1280
+	 */
1281
+	public function order()
1282
+	{
1283
+		return $this->get('TKT_order');
1284
+	}
1285
+
1286
+
1287
+	/**
1288
+	 * Sets order
1289
+	 *
1290
+	 * @param int $order
1291
+	 * @return void
1292
+	 * @throws EE_Error
1293
+	 */
1294
+	public function set_order($order)
1295
+	{
1296
+		$this->set('TKT_order', $order);
1297
+	}
1298
+
1299
+
1300
+	/**
1301
+	 * Gets row
1302
+	 *
1303
+	 * @return int
1304
+	 * @throws EE_Error
1305
+	 */
1306
+	public function row()
1307
+	{
1308
+		return $this->get('TKT_row');
1309
+	}
1310
+
1311
+
1312
+	/**
1313
+	 * Sets row
1314
+	 *
1315
+	 * @param int $row
1316
+	 * @return void
1317
+	 * @throws EE_Error
1318
+	 */
1319
+	public function set_row($row)
1320
+	{
1321
+		$this->set('TKT_row', $row);
1322
+	}
1323
+
1324
+
1325
+	/**
1326
+	 * Gets deleted
1327
+	 *
1328
+	 * @return boolean
1329
+	 * @throws EE_Error
1330
+	 */
1331
+	public function deleted()
1332
+	{
1333
+		return $this->get('TKT_deleted');
1334
+	}
1335
+
1336
+
1337
+	/**
1338
+	 * Sets deleted
1339
+	 *
1340
+	 * @param boolean $deleted
1341
+	 * @return void
1342
+	 * @throws EE_Error
1343
+	 */
1344
+	public function set_deleted($deleted)
1345
+	{
1346
+		$this->set('TKT_deleted', $deleted);
1347
+	}
1348
+
1349
+
1350
+	/**
1351
+	 * Gets parent
1352
+	 *
1353
+	 * @return int
1354
+	 * @throws EE_Error
1355
+	 */
1356
+	public function parent_ID()
1357
+	{
1358
+		return $this->get('TKT_parent');
1359
+	}
1360
+
1361
+
1362
+	/**
1363
+	 * Sets parent
1364
+	 *
1365
+	 * @param int $parent
1366
+	 * @return void
1367
+	 * @throws EE_Error
1368
+	 */
1369
+	public function set_parent_ID($parent)
1370
+	{
1371
+		$this->set('TKT_parent', $parent);
1372
+	}
1373
+
1374
+
1375
+	/**
1376
+	 * @return boolean
1377
+	 * @throws EE_Error
1378
+	 * @throws InvalidArgumentException
1379
+	 * @throws InvalidDataTypeException
1380
+	 * @throws InvalidInterfaceException
1381
+	 * @throws ReflectionException
1382
+	 */
1383
+	public function reverse_calculate()
1384
+	{
1385
+		return $this->get('TKT_reverse_calculate');
1386
+	}
1387
+
1388
+
1389
+	/**
1390
+	 * @param boolean $reverse_calculate
1391
+	 * @throws EE_Error
1392
+	 * @throws InvalidArgumentException
1393
+	 * @throws InvalidDataTypeException
1394
+	 * @throws InvalidInterfaceException
1395
+	 * @throws ReflectionException
1396
+	 */
1397
+	public function set_reverse_calculate($reverse_calculate)
1398
+	{
1399
+		$this->set('TKT_reverse_calculate', $reverse_calculate);
1400
+	}
1401
+
1402
+
1403
+	/**
1404
+	 * Gets a string which is handy for showing in gateways etc that describes the ticket.
1405
+	 *
1406
+	 * @return string
1407
+	 * @throws EE_Error
1408
+	 */
1409
+	public function name_and_info()
1410
+	{
1411
+		$times = array();
1412
+		foreach ($this->datetimes() as $datetime) {
1413
+			$times[] = $datetime->start_date_and_time();
1414
+		}
1415
+		return $this->name() . ' @ ' . implode(', ', $times) . ' for ' . $this->pretty_price();
1416
+	}
1417
+
1418
+
1419
+	/**
1420
+	 * Gets name
1421
+	 *
1422
+	 * @return string
1423
+	 * @throws EE_Error
1424
+	 */
1425
+	public function name()
1426
+	{
1427
+		return $this->get('TKT_name');
1428
+	}
1429
+
1430
+
1431
+	/**
1432
+	 * Gets price
1433
+	 *
1434
+	 * @return float
1435
+	 * @throws EE_Error
1436
+	 */
1437
+	public function price()
1438
+	{
1439
+		return $this->get('TKT_price');
1440
+	}
1441
+
1442
+
1443
+	/**
1444
+	 * Gets all the registrations for this ticket
1445
+	 *
1446
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1447
+	 * @return EE_Registration[]|EE_Base_Class[]
1448
+	 * @throws EE_Error
1449
+	 */
1450
+	public function registrations($query_params = array())
1451
+	{
1452
+		return $this->get_many_related('Registration', $query_params);
1453
+	}
1454
+
1455
+
1456
+	/**
1457
+	 * Updates the TKT_sold attribute (and saves) based on the number of APPROVED registrations for this ticket.
1458
+	 *
1459
+	 * @return int
1460
+	 * @throws EE_Error
1461
+	 */
1462
+	public function update_tickets_sold()
1463
+	{
1464
+		$count_regs_for_this_ticket = $this->count_registrations(
1465
+			array(
1466
+				array(
1467
+					'STS_ID'      => EEM_Registration::status_id_approved,
1468
+					'REG_deleted' => 0,
1469
+				),
1470
+			)
1471
+		);
1472
+		$this->set_sold($count_regs_for_this_ticket);
1473
+		$this->save();
1474
+		return $count_regs_for_this_ticket;
1475
+	}
1476
+
1477
+
1478
+	/**
1479
+	 * Counts the registrations for this ticket
1480
+	 *
1481
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1482
+	 * @return int
1483
+	 */
1484
+	public function count_registrations($query_params = array())
1485
+	{
1486
+		return $this->count_related('Registration', $query_params);
1487
+	}
1488
+
1489
+
1490
+	/**
1491
+	 * Implementation for EEI_Has_Icon interface method.
1492
+	 *
1493
+	 * @see EEI_Visual_Representation for comments
1494
+	 * @return string
1495
+	 */
1496
+	public function get_icon()
1497
+	{
1498
+		return '<span class="dashicons dashicons-tickets-alt"></span>';
1499
+	}
1500
+
1501
+
1502
+	/**
1503
+	 * Implementation of the EEI_Event_Relation interface method
1504
+	 *
1505
+	 * @see EEI_Event_Relation for comments
1506
+	 * @return EE_Event
1507
+	 * @throws EE_Error
1508
+	 * @throws UnexpectedEntityException
1509
+	 */
1510
+	public function get_related_event()
1511
+	{
1512
+		// get one datetime to use for getting the event
1513
+		$datetime = $this->first_datetime();
1514
+		if (! $datetime instanceof \EE_Datetime) {
1515
+			throw new UnexpectedEntityException(
1516
+				$datetime,
1517
+				'EE_Datetime',
1518
+				sprintf(
1519
+					__('The ticket (%s) is not associated with any valid datetimes.', 'event_espresso'),
1520
+					$this->name()
1521
+				)
1522
+			);
1523
+		}
1524
+		$event = $datetime->event();
1525
+		if (! $event instanceof \EE_Event) {
1526
+			throw new UnexpectedEntityException(
1527
+				$event,
1528
+				'EE_Event',
1529
+				sprintf(
1530
+					__('The ticket (%s) is not associated with a valid event.', 'event_espresso'),
1531
+					$this->name()
1532
+				)
1533
+			);
1534
+		}
1535
+		return $event;
1536
+	}
1537
+
1538
+
1539
+	/**
1540
+	 * Implementation of the EEI_Event_Relation interface method
1541
+	 *
1542
+	 * @see EEI_Event_Relation for comments
1543
+	 * @return string
1544
+	 * @throws UnexpectedEntityException
1545
+	 * @throws EE_Error
1546
+	 */
1547
+	public function get_event_name()
1548
+	{
1549
+		$event = $this->get_related_event();
1550
+		return $event instanceof EE_Event ? $event->name() : '';
1551
+	}
1552
+
1553
+
1554
+	/**
1555
+	 * Implementation of the EEI_Event_Relation interface method
1556
+	 *
1557
+	 * @see EEI_Event_Relation for comments
1558
+	 * @return int
1559
+	 * @throws UnexpectedEntityException
1560
+	 * @throws EE_Error
1561
+	 */
1562
+	public function get_event_ID()
1563
+	{
1564
+		$event = $this->get_related_event();
1565
+		return $event instanceof EE_Event ? $event->ID() : 0;
1566
+	}
1567
+
1568
+
1569
+	/**
1570
+	 * This simply returns whether a ticket can be permanently deleted or not.
1571
+	 * The criteria for determining this is whether the ticket has any related registrations.
1572
+	 * If there are none then it can be permanently deleted.
1573
+	 *
1574
+	 * @return bool
1575
+	 */
1576
+	public function is_permanently_deleteable()
1577
+	{
1578
+		return $this->count_registrations() === 0;
1579
+	}
1580
+
1581
+
1582
+	/*******************************************************************
1583 1583
      ***********************  DEPRECATED METHODS  **********************
1584 1584
      *******************************************************************/
1585 1585
 
1586 1586
 
1587
-    /**
1588
-     * Increments sold by amount passed by $qty AND decrements the reserved count on both this ticket and its
1589
-     * associated datetimes.
1590
-     *
1591
-     * @deprecated 4.9.80.p
1592
-     * @param int $qty
1593
-     * @return void
1594
-     * @throws EE_Error
1595
-     * @throws InvalidArgumentException
1596
-     * @throws InvalidDataTypeException
1597
-     * @throws InvalidInterfaceException
1598
-     * @throws ReflectionException
1599
-     */
1600
-    public function increase_sold($qty = 1)
1601
-    {
1602
-        EE_Error::doing_it_wrong(
1603
-            __FUNCTION__,
1604
-            esc_html__('Please use EE_Ticket::increaseSold() instead', 'event_espresso'),
1605
-            '4.9.80.p',
1606
-            '5.0.0.p'
1607
-        );
1608
-        $this->increaseSold($qty);
1609
-    }
1610
-
1611
-
1612
-    /**
1613
-     * On each datetime related to this ticket, increases its sold count and decreases its reserved count by $qty.
1614
-     *
1615
-     * @deprecated 4.9.80.p
1616
-     * @param int $qty positive or negative. Positive means to increase sold counts (and decrease reserved counts),
1617
-     *                 Negative means to decreases old counts (and increase reserved counts).
1618
-     * @throws EE_Error
1619
-     * @throws InvalidArgumentException
1620
-     * @throws InvalidDataTypeException
1621
-     * @throws InvalidInterfaceException
1622
-     * @throws ReflectionException
1623
-     */
1624
-    protected function _increase_sold_for_datetimes($qty)
1625
-    {
1626
-        EE_Error::doing_it_wrong(
1627
-            __FUNCTION__,
1628
-            esc_html__('Please use EE_Ticket::increaseSoldForDatetimes() instead', 'event_espresso'),
1629
-            '4.9.80.p',
1630
-            '5.0.0.p'
1631
-        );
1632
-        $this->increaseSoldForDatetimes($qty);
1633
-    }
1634
-
1635
-
1636
-    /**
1637
-     * Decrements (subtracts) sold by amount passed by $qty on both the ticket and its related datetimes directly in the
1638
-     * DB and then updates the model objects.
1639
-     * Does not affect the reserved counts.
1640
-     *
1641
-     * @deprecated 4.9.80.p
1642
-     * @param int $qty
1643
-     * @return void
1644
-     * @throws EE_Error
1645
-     * @throws InvalidArgumentException
1646
-     * @throws InvalidDataTypeException
1647
-     * @throws InvalidInterfaceException
1648
-     * @throws ReflectionException
1649
-     */
1650
-    public function decrease_sold($qty = 1)
1651
-    {
1652
-        EE_Error::doing_it_wrong(
1653
-            __FUNCTION__,
1654
-            esc_html__('Please use EE_Ticket::decreaseSold() instead', 'event_espresso'),
1655
-            '4.9.80.p',
1656
-            '5.0.0.p'
1657
-        );
1658
-        $this->decreaseSold($qty);
1659
-    }
1660
-
1661
-
1662
-    /**
1663
-     * Decreases sold on related datetimes
1664
-     *
1665
-     * @deprecated 4.9.80.p
1666
-     * @param int $qty
1667
-     * @return void
1668
-     * @throws EE_Error
1669
-     * @throws InvalidArgumentException
1670
-     * @throws InvalidDataTypeException
1671
-     * @throws InvalidInterfaceException
1672
-     * @throws ReflectionException
1673
-     */
1674
-    protected function _decrease_sold_for_datetimes($qty = 1)
1675
-    {
1676
-        EE_Error::doing_it_wrong(
1677
-            __FUNCTION__,
1678
-            esc_html__('Please use EE_Ticket::decreaseSoldForDatetimes() instead', 'event_espresso'),
1679
-            '4.9.80.p',
1680
-            '5.0.0.p'
1681
-        );
1682
-        $this->decreaseSoldForDatetimes($qty);
1683
-    }
1684
-
1685
-
1686
-    /**
1687
-     * Increments reserved by amount passed by $qty, and persists it immediately to the database.
1688
-     *
1689
-     * @deprecated 4.9.80.p
1690
-     * @param int    $qty
1691
-     * @param string $source
1692
-     * @return bool whether we successfully reserved the ticket or not.
1693
-     * @throws EE_Error
1694
-     * @throws InvalidArgumentException
1695
-     * @throws ReflectionException
1696
-     * @throws InvalidDataTypeException
1697
-     * @throws InvalidInterfaceException
1698
-     */
1699
-    public function increase_reserved($qty = 1, $source = 'unknown')
1700
-    {
1701
-        EE_Error::doing_it_wrong(
1702
-            __FUNCTION__,
1703
-            esc_html__('Please use EE_Ticket::increaseReserved() instead', 'event_espresso'),
1704
-            '4.9.80.p',
1705
-            '5.0.0.p'
1706
-        );
1707
-        return $this->increaseReserved($qty);
1708
-    }
1709
-
1710
-
1711
-    /**
1712
-     * Increases sold on related datetimes
1713
-     *
1714
-     * @deprecated 4.9.80.p
1715
-     * @param int $qty
1716
-     * @return boolean indicating success
1717
-     * @throws EE_Error
1718
-     * @throws InvalidArgumentException
1719
-     * @throws InvalidDataTypeException
1720
-     * @throws InvalidInterfaceException
1721
-     * @throws ReflectionException
1722
-     */
1723
-    protected function _increase_reserved_for_datetimes($qty = 1)
1724
-    {
1725
-        EE_Error::doing_it_wrong(
1726
-            __FUNCTION__,
1727
-            esc_html__('Please use EE_Ticket::increaseReservedForDatetimes() instead', 'event_espresso'),
1728
-            '4.9.80.p',
1729
-            '5.0.0.p'
1730
-        );
1731
-        return $this->increaseReservedForDatetimes($qty);
1732
-    }
1733
-
1734
-
1735
-    /**
1736
-     * Decrements (subtracts) reserved by amount passed by $qty, and persists it immediately to the database.
1737
-     *
1738
-     * @deprecated 4.9.80.p
1739
-     * @param int    $qty
1740
-     * @param bool   $adjust_datetimes
1741
-     * @param string $source
1742
-     * @return void
1743
-     * @throws EE_Error
1744
-     * @throws InvalidArgumentException
1745
-     * @throws ReflectionException
1746
-     * @throws InvalidDataTypeException
1747
-     * @throws InvalidInterfaceException
1748
-     */
1749
-    public function decrease_reserved($qty = 1, $adjust_datetimes = true, $source = 'unknown')
1750
-    {
1751
-        EE_Error::doing_it_wrong(
1752
-            __FUNCTION__,
1753
-            esc_html__('Please use EE_Ticket::decreaseReserved() instead', 'event_espresso'),
1754
-            '4.9.80.p',
1755
-            '5.0.0.p'
1756
-        );
1757
-        $this->decreaseReserved($qty);
1758
-    }
1759
-
1760
-
1761
-    /**
1762
-     * Decreases reserved on related datetimes
1763
-     *
1764
-     * @deprecated 4.9.80.p
1765
-     * @param int $qty
1766
-     * @return void
1767
-     * @throws EE_Error
1768
-     * @throws InvalidArgumentException
1769
-     * @throws ReflectionException
1770
-     * @throws InvalidDataTypeException
1771
-     * @throws InvalidInterfaceException
1772
-     */
1773
-    protected function _decrease_reserved_for_datetimes($qty = 1)
1774
-    {
1775
-        EE_Error::doing_it_wrong(
1776
-            __FUNCTION__,
1777
-            esc_html__('Please use EE_Ticket::decreaseReservedForDatetimes() instead', 'event_espresso'),
1778
-            '4.9.80.p',
1779
-            '5.0.0.p'
1780
-        );
1781
-        $this->decreaseReservedForDatetimes($qty);
1782
-    }
1587
+	/**
1588
+	 * Increments sold by amount passed by $qty AND decrements the reserved count on both this ticket and its
1589
+	 * associated datetimes.
1590
+	 *
1591
+	 * @deprecated 4.9.80.p
1592
+	 * @param int $qty
1593
+	 * @return void
1594
+	 * @throws EE_Error
1595
+	 * @throws InvalidArgumentException
1596
+	 * @throws InvalidDataTypeException
1597
+	 * @throws InvalidInterfaceException
1598
+	 * @throws ReflectionException
1599
+	 */
1600
+	public function increase_sold($qty = 1)
1601
+	{
1602
+		EE_Error::doing_it_wrong(
1603
+			__FUNCTION__,
1604
+			esc_html__('Please use EE_Ticket::increaseSold() instead', 'event_espresso'),
1605
+			'4.9.80.p',
1606
+			'5.0.0.p'
1607
+		);
1608
+		$this->increaseSold($qty);
1609
+	}
1610
+
1611
+
1612
+	/**
1613
+	 * On each datetime related to this ticket, increases its sold count and decreases its reserved count by $qty.
1614
+	 *
1615
+	 * @deprecated 4.9.80.p
1616
+	 * @param int $qty positive or negative. Positive means to increase sold counts (and decrease reserved counts),
1617
+	 *                 Negative means to decreases old counts (and increase reserved counts).
1618
+	 * @throws EE_Error
1619
+	 * @throws InvalidArgumentException
1620
+	 * @throws InvalidDataTypeException
1621
+	 * @throws InvalidInterfaceException
1622
+	 * @throws ReflectionException
1623
+	 */
1624
+	protected function _increase_sold_for_datetimes($qty)
1625
+	{
1626
+		EE_Error::doing_it_wrong(
1627
+			__FUNCTION__,
1628
+			esc_html__('Please use EE_Ticket::increaseSoldForDatetimes() instead', 'event_espresso'),
1629
+			'4.9.80.p',
1630
+			'5.0.0.p'
1631
+		);
1632
+		$this->increaseSoldForDatetimes($qty);
1633
+	}
1634
+
1635
+
1636
+	/**
1637
+	 * Decrements (subtracts) sold by amount passed by $qty on both the ticket and its related datetimes directly in the
1638
+	 * DB and then updates the model objects.
1639
+	 * Does not affect the reserved counts.
1640
+	 *
1641
+	 * @deprecated 4.9.80.p
1642
+	 * @param int $qty
1643
+	 * @return void
1644
+	 * @throws EE_Error
1645
+	 * @throws InvalidArgumentException
1646
+	 * @throws InvalidDataTypeException
1647
+	 * @throws InvalidInterfaceException
1648
+	 * @throws ReflectionException
1649
+	 */
1650
+	public function decrease_sold($qty = 1)
1651
+	{
1652
+		EE_Error::doing_it_wrong(
1653
+			__FUNCTION__,
1654
+			esc_html__('Please use EE_Ticket::decreaseSold() instead', 'event_espresso'),
1655
+			'4.9.80.p',
1656
+			'5.0.0.p'
1657
+		);
1658
+		$this->decreaseSold($qty);
1659
+	}
1660
+
1661
+
1662
+	/**
1663
+	 * Decreases sold on related datetimes
1664
+	 *
1665
+	 * @deprecated 4.9.80.p
1666
+	 * @param int $qty
1667
+	 * @return void
1668
+	 * @throws EE_Error
1669
+	 * @throws InvalidArgumentException
1670
+	 * @throws InvalidDataTypeException
1671
+	 * @throws InvalidInterfaceException
1672
+	 * @throws ReflectionException
1673
+	 */
1674
+	protected function _decrease_sold_for_datetimes($qty = 1)
1675
+	{
1676
+		EE_Error::doing_it_wrong(
1677
+			__FUNCTION__,
1678
+			esc_html__('Please use EE_Ticket::decreaseSoldForDatetimes() instead', 'event_espresso'),
1679
+			'4.9.80.p',
1680
+			'5.0.0.p'
1681
+		);
1682
+		$this->decreaseSoldForDatetimes($qty);
1683
+	}
1684
+
1685
+
1686
+	/**
1687
+	 * Increments reserved by amount passed by $qty, and persists it immediately to the database.
1688
+	 *
1689
+	 * @deprecated 4.9.80.p
1690
+	 * @param int    $qty
1691
+	 * @param string $source
1692
+	 * @return bool whether we successfully reserved the ticket or not.
1693
+	 * @throws EE_Error
1694
+	 * @throws InvalidArgumentException
1695
+	 * @throws ReflectionException
1696
+	 * @throws InvalidDataTypeException
1697
+	 * @throws InvalidInterfaceException
1698
+	 */
1699
+	public function increase_reserved($qty = 1, $source = 'unknown')
1700
+	{
1701
+		EE_Error::doing_it_wrong(
1702
+			__FUNCTION__,
1703
+			esc_html__('Please use EE_Ticket::increaseReserved() instead', 'event_espresso'),
1704
+			'4.9.80.p',
1705
+			'5.0.0.p'
1706
+		);
1707
+		return $this->increaseReserved($qty);
1708
+	}
1709
+
1710
+
1711
+	/**
1712
+	 * Increases sold on related datetimes
1713
+	 *
1714
+	 * @deprecated 4.9.80.p
1715
+	 * @param int $qty
1716
+	 * @return boolean indicating success
1717
+	 * @throws EE_Error
1718
+	 * @throws InvalidArgumentException
1719
+	 * @throws InvalidDataTypeException
1720
+	 * @throws InvalidInterfaceException
1721
+	 * @throws ReflectionException
1722
+	 */
1723
+	protected function _increase_reserved_for_datetimes($qty = 1)
1724
+	{
1725
+		EE_Error::doing_it_wrong(
1726
+			__FUNCTION__,
1727
+			esc_html__('Please use EE_Ticket::increaseReservedForDatetimes() instead', 'event_espresso'),
1728
+			'4.9.80.p',
1729
+			'5.0.0.p'
1730
+		);
1731
+		return $this->increaseReservedForDatetimes($qty);
1732
+	}
1733
+
1734
+
1735
+	/**
1736
+	 * Decrements (subtracts) reserved by amount passed by $qty, and persists it immediately to the database.
1737
+	 *
1738
+	 * @deprecated 4.9.80.p
1739
+	 * @param int    $qty
1740
+	 * @param bool   $adjust_datetimes
1741
+	 * @param string $source
1742
+	 * @return void
1743
+	 * @throws EE_Error
1744
+	 * @throws InvalidArgumentException
1745
+	 * @throws ReflectionException
1746
+	 * @throws InvalidDataTypeException
1747
+	 * @throws InvalidInterfaceException
1748
+	 */
1749
+	public function decrease_reserved($qty = 1, $adjust_datetimes = true, $source = 'unknown')
1750
+	{
1751
+		EE_Error::doing_it_wrong(
1752
+			__FUNCTION__,
1753
+			esc_html__('Please use EE_Ticket::decreaseReserved() instead', 'event_espresso'),
1754
+			'4.9.80.p',
1755
+			'5.0.0.p'
1756
+		);
1757
+		$this->decreaseReserved($qty);
1758
+	}
1759
+
1760
+
1761
+	/**
1762
+	 * Decreases reserved on related datetimes
1763
+	 *
1764
+	 * @deprecated 4.9.80.p
1765
+	 * @param int $qty
1766
+	 * @return void
1767
+	 * @throws EE_Error
1768
+	 * @throws InvalidArgumentException
1769
+	 * @throws ReflectionException
1770
+	 * @throws InvalidDataTypeException
1771
+	 * @throws InvalidInterfaceException
1772
+	 */
1773
+	protected function _decrease_reserved_for_datetimes($qty = 1)
1774
+	{
1775
+		EE_Error::doing_it_wrong(
1776
+			__FUNCTION__,
1777
+			esc_html__('Please use EE_Ticket::decreaseReservedForDatetimes() instead', 'event_espresso'),
1778
+			'4.9.80.p',
1779
+			'5.0.0.p'
1780
+		);
1781
+		$this->decreaseReservedForDatetimes($qty);
1782
+	}
1783 1783
 }
Please login to merge, or discard this patch.
core/db_models/EEM_Ticket.model.php 1 patch
Indentation   +313 added lines, -313 removed lines patch added patch discarded remove patch
@@ -10,331 +10,331 @@
 block discarded – undo
10 10
 class EEM_Ticket extends EEM_Soft_Delete_Base
11 11
 {
12 12
 
13
-    /**
14
-     * private instance of the EEM_Ticket object
15
-     *
16
-     * @var EEM_Ticket $_instance
17
-     */
18
-    protected static $_instance;
13
+	/**
14
+	 * private instance of the EEM_Ticket object
15
+	 *
16
+	 * @var EEM_Ticket $_instance
17
+	 */
18
+	protected static $_instance;
19 19
 
20 20
 
21
-    /**
22
-     * private constructor to prevent direct creation
23
-     *
24
-     * @Constructor
25
-     * @access private
26
-     * @param string $timezone string representing the timezone we want to set for returned Date Time Strings
27
-     *                         (and any incoming timezone data that gets saved).
28
-     *                         Note this just sends the timezone info to the date time model field objects.
29
-     *                         Default is NULL
30
-     *                         (and will be assumed using the set timezone in the 'timezone_string' wp option)
31
-     * @throws EE_Error
32
-     */
33
-    protected function __construct($timezone)
34
-    {
35
-        $this->singular_item = esc_html__('Ticket', 'event_espresso');
36
-        $this->plural_item = esc_html__('Tickets', 'event_espresso');
37
-        $this->_tables = array(
38
-            'Ticket' => new EE_Primary_Table('esp_ticket', 'TKT_ID'),
39
-        );
40
-        $this->_fields = array(
41
-            'Ticket' => array(
42
-                'TKT_ID'          => new EE_Primary_Key_Int_Field(
43
-                    'TKT_ID',
44
-                    esc_html__('Ticket ID', 'event_espresso')
45
-                ),
46
-                'TTM_ID'          => new EE_Foreign_Key_Int_Field(
47
-                    'TTM_ID',
48
-                    esc_html__('Ticket Template ID', 'event_espresso'),
49
-                    false,
50
-                    0,
51
-                    'Ticket_Template'
52
-                ),
53
-                'TKT_name'        => new EE_Plain_Text_Field(
54
-                    'TKT_name',
55
-                    esc_html__('Ticket Name', 'event_espresso'),
56
-                    false,
57
-                    ''
58
-                ),
59
-                'TKT_description' => new EE_Post_Content_Field(
60
-                    'TKT_description',
61
-                    esc_html__('Description of Ticket', 'event_espresso'),
62
-                    false,
63
-                    ''
64
-                ),
65
-                'TKT_start_date'  => new EE_Datetime_Field(
66
-                    'TKT_start_date',
67
-                    esc_html__('Start time/date of Ticket', 'event_espresso'),
68
-                    false,
69
-                    EE_Datetime_Field::now,
70
-                    $timezone
71
-                ),
72
-                'TKT_end_date'    => new EE_Datetime_Field(
73
-                    'TKT_end_date',
74
-                    esc_html__('End time/date of Ticket', 'event_espresso'),
75
-                    false,
76
-                    EE_Datetime_Field::now,
77
-                    $timezone
78
-                ),
79
-                'TKT_min'         => new EE_Integer_Field(
80
-                    'TKT_min',
81
-                    esc_html__('Minimum quantity of this ticket that must be purchased', 'event_espresso'),
82
-                    false,
83
-                    0
84
-                ),
85
-                'TKT_max'         => new EE_Infinite_Integer_Field(
86
-                    'TKT_max',
87
-                    esc_html__(
88
-                        'Maximum quantity of this ticket that can be purchased in one transaction',
89
-                        'event_espresso'
90
-                    ),
91
-                    false,
92
-                    EE_INF
93
-                ),
94
-                'TKT_price'       => new EE_Money_Field(
95
-                    'TKT_price',
96
-                    esc_html__('Final calculated price for ticket', 'event_espresso'),
97
-                    false,
98
-                    0
99
-                ),
100
-                'TKT_sold'        => new EE_Integer_Field(
101
-                    'TKT_sold',
102
-                    esc_html__('Number of this ticket sold', 'event_espresso'),
103
-                    false,
104
-                    0
105
-                ),
106
-                'TKT_qty'         => new EE_Infinite_Integer_Field(
107
-                    'TKT_qty',
108
-                    esc_html__('Quantity of this ticket that is available', 'event_espresso'),
109
-                    false,
110
-                    EE_INF
111
-                ),
112
-                'TKT_reserved'    => new EE_Integer_Field(
113
-                    'TKT_reserved',
114
-                    esc_html__(
115
-                        'Quantity of this ticket that is reserved, but not yet fully purchased',
116
-                        'event_espresso'
117
-                    ),
118
-                    false,
119
-                    0
120
-                ),
121
-                'TKT_uses'        => new EE_Infinite_Integer_Field(
122
-                    'TKT_uses',
123
-                    esc_html__('Number of datetimes this ticket can be used at', 'event_espresso'),
124
-                    false,
125
-                    EE_INF
126
-                ),
127
-                'TKT_required'    => new EE_Boolean_Field(
128
-                    'TKT_required',
129
-                    esc_html__(
130
-                        'Flag indicating whether this ticket must be purchased with a transaction',
131
-                        'event_espresso'
132
-                    ),
133
-                    false,
134
-                    false
135
-                ),
136
-                'TKT_taxable'     => new EE_Boolean_Field(
137
-                    'TKT_taxable',
138
-                    esc_html__(
139
-                        'Flag indicating whether there is tax applied on this ticket',
140
-                        'event_espresso'
141
-                    ),
142
-                    false,
143
-                    false
144
-                ),
145
-                'TKT_is_default'  => new EE_Boolean_Field(
146
-                    'TKT_is_default',
147
-                    esc_html__('Flag indicating that this ticket is a default ticket', 'event_espresso'),
148
-                    false,
149
-                    false
150
-                ),
151
-                'TKT_order'       => new EE_Integer_Field(
152
-                    'TKT_order',
153
-                    esc_html__(
154
-                        'The order in which the Ticket is displayed in the editor (used for autosaves when the form doesn\'t have the ticket ID yet)',
155
-                        'event_espresso'
156
-                    ),
157
-                    false,
158
-                    0
159
-                ),
160
-                'TKT_row'         => new EE_Integer_Field(
161
-                    'TKT_row',
162
-                    esc_html__('How tickets are displayed in the ui', 'event_espresso'),
163
-                    false,
164
-                    0
165
-                ),
166
-                'TKT_deleted'     => new EE_Trashed_Flag_Field(
167
-                    'TKT_deleted',
168
-                    esc_html__('Flag indicating if this has been archived or not', 'event_espresso'),
169
-                    false,
170
-                    false
171
-                ),
172
-                'TKT_wp_user'     => new EE_WP_User_Field(
173
-                    'TKT_wp_user',
174
-                    esc_html__('Ticket Creator ID', 'event_espresso'),
175
-                    false
176
-                ),
177
-                'TKT_parent'      => new EE_Integer_Field(
178
-                    'TKT_parent',
179
-                    esc_html__(
180
-                        'Indicates what TKT_ID is the parent of this TKT_ID (used in autosaves/revisions)',
181
-                        'event_espresso'
182
-                    ),
183
-                    true,
184
-                    0
185
-                ),
186
-                'TKT_reverse_calculate' => new EE_Boolean_Field(
187
-                    'TKT_reverse_calculate',
188
-                    esc_html__(
189
-                        'Flag indicating whether ticket calculations should run in reverse and calculate the base ticket price from the provided ticket total.',
190
-                        'event_espresso'
191
-                    ),
192
-                    false,
193
-                    false
194
-                ),
195
-            ),
196
-        );
197
-        $this->_model_relations = array(
198
-            'Datetime'        => new EE_HABTM_Relation('Datetime_Ticket'),
199
-            'Datetime_Ticket' => new EE_Has_Many_Relation(),
200
-            'Price'           => new EE_HABTM_Relation('Ticket_Price'),
201
-            'Ticket_Template' => new EE_Belongs_To_Relation(),
202
-            'Registration'    => new EE_Has_Many_Relation(),
203
-            'WP_User'         => new EE_Belongs_To_Relation(),
204
-        );
205
-        // this model is generally available for reading
206
-        $path_to_event = 'Datetime.Event';
207
-        $this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Default_Public(
208
-            'TKT_is_default',
209
-            $path_to_event
210
-        );
211
-        // account for default tickets in the caps
212
-        $this->_cap_restriction_generators[ EEM_Base::caps_read_admin ] = new EE_Restriction_Generator_Default_Protected(
213
-            'TKT_is_default',
214
-            $path_to_event
215
-        );
216
-        $this->_cap_restriction_generators[ EEM_Base::caps_edit ] = new EE_Restriction_Generator_Default_Protected(
217
-            'TKT_is_default',
218
-            $path_to_event
219
-        );
220
-        $this->_cap_restriction_generators[ EEM_Base::caps_delete ] = new EE_Restriction_Generator_Default_Protected(
221
-            'TKT_is_default',
222
-            $path_to_event
223
-        );
224
-        $this->model_chain_to_password = $path_to_event;
225
-        parent::__construct($timezone);
226
-    }
21
+	/**
22
+	 * private constructor to prevent direct creation
23
+	 *
24
+	 * @Constructor
25
+	 * @access private
26
+	 * @param string $timezone string representing the timezone we want to set for returned Date Time Strings
27
+	 *                         (and any incoming timezone data that gets saved).
28
+	 *                         Note this just sends the timezone info to the date time model field objects.
29
+	 *                         Default is NULL
30
+	 *                         (and will be assumed using the set timezone in the 'timezone_string' wp option)
31
+	 * @throws EE_Error
32
+	 */
33
+	protected function __construct($timezone)
34
+	{
35
+		$this->singular_item = esc_html__('Ticket', 'event_espresso');
36
+		$this->plural_item = esc_html__('Tickets', 'event_espresso');
37
+		$this->_tables = array(
38
+			'Ticket' => new EE_Primary_Table('esp_ticket', 'TKT_ID'),
39
+		);
40
+		$this->_fields = array(
41
+			'Ticket' => array(
42
+				'TKT_ID'          => new EE_Primary_Key_Int_Field(
43
+					'TKT_ID',
44
+					esc_html__('Ticket ID', 'event_espresso')
45
+				),
46
+				'TTM_ID'          => new EE_Foreign_Key_Int_Field(
47
+					'TTM_ID',
48
+					esc_html__('Ticket Template ID', 'event_espresso'),
49
+					false,
50
+					0,
51
+					'Ticket_Template'
52
+				),
53
+				'TKT_name'        => new EE_Plain_Text_Field(
54
+					'TKT_name',
55
+					esc_html__('Ticket Name', 'event_espresso'),
56
+					false,
57
+					''
58
+				),
59
+				'TKT_description' => new EE_Post_Content_Field(
60
+					'TKT_description',
61
+					esc_html__('Description of Ticket', 'event_espresso'),
62
+					false,
63
+					''
64
+				),
65
+				'TKT_start_date'  => new EE_Datetime_Field(
66
+					'TKT_start_date',
67
+					esc_html__('Start time/date of Ticket', 'event_espresso'),
68
+					false,
69
+					EE_Datetime_Field::now,
70
+					$timezone
71
+				),
72
+				'TKT_end_date'    => new EE_Datetime_Field(
73
+					'TKT_end_date',
74
+					esc_html__('End time/date of Ticket', 'event_espresso'),
75
+					false,
76
+					EE_Datetime_Field::now,
77
+					$timezone
78
+				),
79
+				'TKT_min'         => new EE_Integer_Field(
80
+					'TKT_min',
81
+					esc_html__('Minimum quantity of this ticket that must be purchased', 'event_espresso'),
82
+					false,
83
+					0
84
+				),
85
+				'TKT_max'         => new EE_Infinite_Integer_Field(
86
+					'TKT_max',
87
+					esc_html__(
88
+						'Maximum quantity of this ticket that can be purchased in one transaction',
89
+						'event_espresso'
90
+					),
91
+					false,
92
+					EE_INF
93
+				),
94
+				'TKT_price'       => new EE_Money_Field(
95
+					'TKT_price',
96
+					esc_html__('Final calculated price for ticket', 'event_espresso'),
97
+					false,
98
+					0
99
+				),
100
+				'TKT_sold'        => new EE_Integer_Field(
101
+					'TKT_sold',
102
+					esc_html__('Number of this ticket sold', 'event_espresso'),
103
+					false,
104
+					0
105
+				),
106
+				'TKT_qty'         => new EE_Infinite_Integer_Field(
107
+					'TKT_qty',
108
+					esc_html__('Quantity of this ticket that is available', 'event_espresso'),
109
+					false,
110
+					EE_INF
111
+				),
112
+				'TKT_reserved'    => new EE_Integer_Field(
113
+					'TKT_reserved',
114
+					esc_html__(
115
+						'Quantity of this ticket that is reserved, but not yet fully purchased',
116
+						'event_espresso'
117
+					),
118
+					false,
119
+					0
120
+				),
121
+				'TKT_uses'        => new EE_Infinite_Integer_Field(
122
+					'TKT_uses',
123
+					esc_html__('Number of datetimes this ticket can be used at', 'event_espresso'),
124
+					false,
125
+					EE_INF
126
+				),
127
+				'TKT_required'    => new EE_Boolean_Field(
128
+					'TKT_required',
129
+					esc_html__(
130
+						'Flag indicating whether this ticket must be purchased with a transaction',
131
+						'event_espresso'
132
+					),
133
+					false,
134
+					false
135
+				),
136
+				'TKT_taxable'     => new EE_Boolean_Field(
137
+					'TKT_taxable',
138
+					esc_html__(
139
+						'Flag indicating whether there is tax applied on this ticket',
140
+						'event_espresso'
141
+					),
142
+					false,
143
+					false
144
+				),
145
+				'TKT_is_default'  => new EE_Boolean_Field(
146
+					'TKT_is_default',
147
+					esc_html__('Flag indicating that this ticket is a default ticket', 'event_espresso'),
148
+					false,
149
+					false
150
+				),
151
+				'TKT_order'       => new EE_Integer_Field(
152
+					'TKT_order',
153
+					esc_html__(
154
+						'The order in which the Ticket is displayed in the editor (used for autosaves when the form doesn\'t have the ticket ID yet)',
155
+						'event_espresso'
156
+					),
157
+					false,
158
+					0
159
+				),
160
+				'TKT_row'         => new EE_Integer_Field(
161
+					'TKT_row',
162
+					esc_html__('How tickets are displayed in the ui', 'event_espresso'),
163
+					false,
164
+					0
165
+				),
166
+				'TKT_deleted'     => new EE_Trashed_Flag_Field(
167
+					'TKT_deleted',
168
+					esc_html__('Flag indicating if this has been archived or not', 'event_espresso'),
169
+					false,
170
+					false
171
+				),
172
+				'TKT_wp_user'     => new EE_WP_User_Field(
173
+					'TKT_wp_user',
174
+					esc_html__('Ticket Creator ID', 'event_espresso'),
175
+					false
176
+				),
177
+				'TKT_parent'      => new EE_Integer_Field(
178
+					'TKT_parent',
179
+					esc_html__(
180
+						'Indicates what TKT_ID is the parent of this TKT_ID (used in autosaves/revisions)',
181
+						'event_espresso'
182
+					),
183
+					true,
184
+					0
185
+				),
186
+				'TKT_reverse_calculate' => new EE_Boolean_Field(
187
+					'TKT_reverse_calculate',
188
+					esc_html__(
189
+						'Flag indicating whether ticket calculations should run in reverse and calculate the base ticket price from the provided ticket total.',
190
+						'event_espresso'
191
+					),
192
+					false,
193
+					false
194
+				),
195
+			),
196
+		);
197
+		$this->_model_relations = array(
198
+			'Datetime'        => new EE_HABTM_Relation('Datetime_Ticket'),
199
+			'Datetime_Ticket' => new EE_Has_Many_Relation(),
200
+			'Price'           => new EE_HABTM_Relation('Ticket_Price'),
201
+			'Ticket_Template' => new EE_Belongs_To_Relation(),
202
+			'Registration'    => new EE_Has_Many_Relation(),
203
+			'WP_User'         => new EE_Belongs_To_Relation(),
204
+		);
205
+		// this model is generally available for reading
206
+		$path_to_event = 'Datetime.Event';
207
+		$this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Default_Public(
208
+			'TKT_is_default',
209
+			$path_to_event
210
+		);
211
+		// account for default tickets in the caps
212
+		$this->_cap_restriction_generators[ EEM_Base::caps_read_admin ] = new EE_Restriction_Generator_Default_Protected(
213
+			'TKT_is_default',
214
+			$path_to_event
215
+		);
216
+		$this->_cap_restriction_generators[ EEM_Base::caps_edit ] = new EE_Restriction_Generator_Default_Protected(
217
+			'TKT_is_default',
218
+			$path_to_event
219
+		);
220
+		$this->_cap_restriction_generators[ EEM_Base::caps_delete ] = new EE_Restriction_Generator_Default_Protected(
221
+			'TKT_is_default',
222
+			$path_to_event
223
+		);
224
+		$this->model_chain_to_password = $path_to_event;
225
+		parent::__construct($timezone);
226
+	}
227 227
 
228 228
 
229
-    /**
230
-     * This returns all tickets that are defaults from the db
231
-     *
232
-     * @return EE_Ticket[]
233
-     * @throws EE_Error
234
-     */
235
-    public function get_all_default_tickets()
236
-    {
237
-        /** @type EE_Ticket[] $tickets */
238
-        $tickets = $this->get_all(array(array('TKT_is_default' => 1), 'order_by' => array('TKT_ID' => 'ASC')));
239
-        // we need to set the start date and end date to today's date and the start of the default dtt
240
-        return $this->_set_default_dates($tickets);
241
-    }
229
+	/**
230
+	 * This returns all tickets that are defaults from the db
231
+	 *
232
+	 * @return EE_Ticket[]
233
+	 * @throws EE_Error
234
+	 */
235
+	public function get_all_default_tickets()
236
+	{
237
+		/** @type EE_Ticket[] $tickets */
238
+		$tickets = $this->get_all(array(array('TKT_is_default' => 1), 'order_by' => array('TKT_ID' => 'ASC')));
239
+		// we need to set the start date and end date to today's date and the start of the default dtt
240
+		return $this->_set_default_dates($tickets);
241
+	}
242 242
 
243 243
 
244
-    /**
245
-     * sets up relevant start and end date for EE_Ticket (s)
246
-     *
247
-     * @param EE_Ticket[] $tickets
248
-     * @return EE_Ticket[]
249
-     * @throws EE_Error
250
-     */
251
-    private function _set_default_dates($tickets)
252
-    {
253
-        foreach ($tickets as $ticket) {
254
-            $ticket->set(
255
-                'TKT_start_date',
256
-                (int) $this->current_time_for_query('TKT_start_date', true)
257
-            );
258
-            $ticket->set(
259
-                'TKT_end_date',
260
-                (int) $this->current_time_for_query('TKT_end_date', true) + MONTH_IN_SECONDS
261
-            );
262
-            $ticket->set_end_time(
263
-                $this->convert_datetime_for_query(
264
-                    'TKT_end_date',
265
-                    '11:59 pm',
266
-                    'g:i a',
267
-                    $this->_timezone
268
-                )
269
-            );
270
-        }
271
-        return $tickets;
272
-    }
244
+	/**
245
+	 * sets up relevant start and end date for EE_Ticket (s)
246
+	 *
247
+	 * @param EE_Ticket[] $tickets
248
+	 * @return EE_Ticket[]
249
+	 * @throws EE_Error
250
+	 */
251
+	private function _set_default_dates($tickets)
252
+	{
253
+		foreach ($tickets as $ticket) {
254
+			$ticket->set(
255
+				'TKT_start_date',
256
+				(int) $this->current_time_for_query('TKT_start_date', true)
257
+			);
258
+			$ticket->set(
259
+				'TKT_end_date',
260
+				(int) $this->current_time_for_query('TKT_end_date', true) + MONTH_IN_SECONDS
261
+			);
262
+			$ticket->set_end_time(
263
+				$this->convert_datetime_for_query(
264
+					'TKT_end_date',
265
+					'11:59 pm',
266
+					'g:i a',
267
+					$this->_timezone
268
+				)
269
+			);
270
+		}
271
+		return $tickets;
272
+	}
273 273
 
274 274
 
275
-    /**
276
-     * Gets the total number of tickets available at a particular datetime (does
277
-     * NOT take int account the datetime's spaces available)
278
-     *
279
-     * @param int   $DTT_ID
280
-     * @param array $query_params
281
-     * @return int
282
-     */
283
-    public function sum_tickets_currently_available_at_datetime($DTT_ID, $query_params = array())
284
-    {
285
-        return EEM_Datetime::instance()->sum_tickets_currently_available_at_datetime($DTT_ID, $query_params);
286
-    }
275
+	/**
276
+	 * Gets the total number of tickets available at a particular datetime (does
277
+	 * NOT take int account the datetime's spaces available)
278
+	 *
279
+	 * @param int   $DTT_ID
280
+	 * @param array $query_params
281
+	 * @return int
282
+	 */
283
+	public function sum_tickets_currently_available_at_datetime($DTT_ID, $query_params = array())
284
+	{
285
+		return EEM_Datetime::instance()->sum_tickets_currently_available_at_datetime($DTT_ID, $query_params);
286
+	}
287 287
 
288 288
 
289
-    /**
290
-     * Updates the TKT_sold quantity on all the tickets matching $query_params
291
-     *
292
-     * @param EE_Ticket[] $tickets
293
-     * @return void
294
-     * @throws EE_Error
295
-     */
296
-    public function update_tickets_sold($tickets)
297
-    {
298
-        foreach ($tickets as $ticket) {
299
-            /* @var  $ticket EE_Ticket */
300
-            $ticket->update_tickets_sold();
301
-        }
302
-    }
289
+	/**
290
+	 * Updates the TKT_sold quantity on all the tickets matching $query_params
291
+	 *
292
+	 * @param EE_Ticket[] $tickets
293
+	 * @return void
294
+	 * @throws EE_Error
295
+	 */
296
+	public function update_tickets_sold($tickets)
297
+	{
298
+		foreach ($tickets as $ticket) {
299
+			/* @var  $ticket EE_Ticket */
300
+			$ticket->update_tickets_sold();
301
+		}
302
+	}
303 303
 
304 304
 
305
-    /**
306
-     * returns an array of EE_Ticket objects with a non-zero value for TKT_reserved
307
-     *
308
-     * @return EE_Base_Class[]|EE_Ticket[]
309
-     * @throws EE_Error
310
-     */
311
-    public function get_tickets_with_reservations()
312
-    {
313
-        return $this->get_all(
314
-            array(
315
-                array(
316
-                    'TKT_reserved' => array('>', 0),
317
-                ),
318
-            )
319
-        );
320
-    }
305
+	/**
306
+	 * returns an array of EE_Ticket objects with a non-zero value for TKT_reserved
307
+	 *
308
+	 * @return EE_Base_Class[]|EE_Ticket[]
309
+	 * @throws EE_Error
310
+	 */
311
+	public function get_tickets_with_reservations()
312
+	{
313
+		return $this->get_all(
314
+			array(
315
+				array(
316
+					'TKT_reserved' => array('>', 0),
317
+				),
318
+			)
319
+		);
320
+	}
321 321
 
322 322
 
323
-    /**
324
-     * returns an array of EE_Ticket objects matching the supplied list of IDs
325
-     *
326
-     * @param array $ticket_IDs
327
-     * @return EE_Base_Class[]|EE_Ticket[]
328
-     * @throws EE_Error
329
-     */
330
-    public function get_tickets_with_IDs(array $ticket_IDs)
331
-    {
332
-        return $this->get_all(
333
-            array(
334
-                array(
335
-                    'TKT_ID' => array('IN', $ticket_IDs),
336
-                ),
337
-            )
338
-        );
339
-    }
323
+	/**
324
+	 * returns an array of EE_Ticket objects matching the supplied list of IDs
325
+	 *
326
+	 * @param array $ticket_IDs
327
+	 * @return EE_Base_Class[]|EE_Ticket[]
328
+	 * @throws EE_Error
329
+	 */
330
+	public function get_tickets_with_IDs(array $ticket_IDs)
331
+	{
332
+		return $this->get_all(
333
+			array(
334
+				array(
335
+					'TKT_ID' => array('IN', $ticket_IDs),
336
+				),
337
+			)
338
+		);
339
+	}
340 340
 }
Please login to merge, or discard this patch.