Completed
Branch FET/editor-dates-tickets-refac... (89c3e0)
by
unknown
40:17 queued 32:20
created

EE_Ticket::reverse_calculate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
use EventEspresso\core\exceptions\InvalidDataTypeException;
4
use EventEspresso\core\exceptions\InvalidInterfaceException;
5
use EventEspresso\core\exceptions\UnexpectedEntityException;
6
7
/**
8
 * EE_Ticket class
9
 *
10
 * @package            Event Espresso
11
 * @subpackage         includes/classes/EE_Ticket.class.php
12
 * @author             Darren Ethier
13
 */
14
class EE_Ticket extends EE_Soft_Delete_Base_Class implements EEI_Line_Item_Object, EEI_Event_Relation, EEI_Has_Icon
15
{
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);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The expression reset($datetimes); of type EE_Base_Class|false adds false to the return on line 274 which is incompatible with the return type documented by EE_Ticket::first_datetime of type EE_Datetime. It seems like you forgot to handle an error condition.
Loading history...
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);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The expression end($datetimes); of type EE_Base_Class|false adds false to the return on line 304 which is incompatible with the return type documented by EE_Ticket::last_datetime of type EE_Datetime. It seems like you forgot to handle an error condition.
Loading history...
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;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
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;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
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 View Code Duplication
    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 View Code Duplication
    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 View Code Duplication
    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 View Code Duplication
    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 View Code Duplication
    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
     ***********************  DEPRECATED METHODS  **********************
1584
     *******************************************************************/
1585
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
    }
1783
}
1784