Completed
Branch BUG-11108-ticket-reserved-coun... (3a118f)
by
unknown
42:53 queued 32:32
created
core/EE_Cron_Tasks.core.php 2 patches
Indentation   +601 added lines, -601 removed lines patch added patch discarded remove patch
@@ -17,607 +17,607 @@
 block discarded – undo
17 17
 class EE_Cron_Tasks extends EE_Base
18 18
 {
19 19
 
20
-    /**
21
-     * WordPress doesn't allow duplicate crons within 10 minutes of the original,
22
-     * so we'll set our retry time for just over 10 minutes to avoid that
23
-     */
24
-    const reschedule_timeout = 605;
25
-
26
-
27
-    /**
28
-     * @var EE_Cron_Tasks
29
-     */
30
-    private static $_instance;
31
-
32
-
33
-    /**
34
-     * @return EE_Cron_Tasks
35
-     * @throws ReflectionException
36
-     * @throws EE_Error
37
-     * @throws InvalidArgumentException
38
-     * @throws InvalidInterfaceException
39
-     * @throws InvalidDataTypeException
40
-     */
41
-    public static function instance()
42
-    {
43
-        if (! self::$_instance instanceof EE_Cron_Tasks) {
44
-            self::$_instance = new self();
45
-        }
46
-        return self::$_instance;
47
-    }
48
-
49
-
50
-    /**
51
-     * @access private
52
-     * @throws InvalidDataTypeException
53
-     * @throws InvalidInterfaceException
54
-     * @throws InvalidArgumentException
55
-     * @throws EE_Error
56
-     * @throws ReflectionException
57
-     */
58
-    private function __construct()
59
-    {
60
-        do_action('AHEE_log', __CLASS__, __FUNCTION__);
61
-        // verify that WP Cron is enabled
62
-        if (
63
-            defined('DISABLE_WP_CRON')
64
-            && DISABLE_WP_CRON
65
-            && is_admin()
66
-            && ! get_option('ee_disabled_wp_cron_check')
67
-        ) {
68
-            /**
69
-             * This needs to be delayed until after the config is loaded because EE_Cron_Tasks is constructed before
70
-             * config is loaded.
71
-             * This is intentionally using a anonymous function so that its not easily de-registered.  Client code
72
-             * wanting to not have this functionality can just register its own action at a priority after this one to
73
-             * reverse any changes.
74
-             */
75
-            add_action(
76
-                'AHEE__EE_System__load_core_configuration__complete',
77
-                function ()
78
-                {
79
-                    EE_Registry::instance()->NET_CFG->core->do_messages_on_same_request = true;
80
-                    EE_Registry::instance()->NET_CFG->update_config(true, false);
81
-                    add_option('ee_disabled_wp_cron_check', 1, '', false);
82
-                }
83
-            );
84
-        }
85
-        // UPDATE TRANSACTION WITH PAYMENT
86
-        add_action(
87
-            'AHEE__EE_Cron_Tasks__update_transaction_with_payment_2',
88
-            array('EE_Cron_Tasks', 'setup_update_for_transaction_with_payment'),
89
-            10,
90
-            2
91
-        );
92
-        // ABANDONED / EXPIRED TRANSACTION CHECK
93
-        add_action(
94
-            'AHEE__EE_Cron_Tasks__expired_transaction_check',
95
-            array('EE_Cron_Tasks', 'expired_transaction_check'),
96
-            10,
97
-            1
98
-        );
99
-        // CLEAN OUT JUNK TRANSACTIONS AND RELATED DATA
100
-        add_action(
101
-            'AHEE__EE_Cron_Tasks__clean_up_junk_transactions',
102
-            array('EE_Cron_Tasks', 'clean_out_junk_transactions')
103
-        );
104
-        // logging
105
-        add_action(
106
-            'AHEE__EE_System__load_core_configuration__complete',
107
-            array('EE_Cron_Tasks', 'log_scheduled_ee_crons')
108
-        );
109
-        EE_Registry::instance()->load_lib('Messages_Scheduler');
110
-        //clean out old gateway logs
111
-        add_action(
112
-            'AHEE_EE_Cron_Tasks__clean_out_old_gateway_logs',
113
-            array('EE_Cron_Tasks', 'clean_out_old_gateway_logs')
114
-        );
115
-    }
116
-
117
-
118
-    /**
119
-     * @access protected
120
-     * @return void
121
-     */
122
-    public static function log_scheduled_ee_crons()
123
-    {
124
-        $ee_crons = array(
125
-            'AHEE__EE_Cron_Tasks__update_transaction_with_payment',
126
-            'AHEE__EE_Cron_Tasks__finalize_abandoned_transactions',
127
-            'AHEE__EE_Cron_Tasks__clean_up_junk_transactions',
128
-        );
129
-        $crons    = (array) get_option('cron');
130
-        if (! is_array($crons)) {
131
-            return;
132
-        }
133
-        foreach ($crons as $timestamp => $cron) {
134
-            /** @var array[] $cron */
135
-            foreach ($ee_crons as $ee_cron) {
136
-                if (isset($cron[ $ee_cron ]) && is_array($cron[ $ee_cron ])) {
137
-                    do_action('AHEE_log', __CLASS__, __FUNCTION__, $ee_cron, 'scheduled EE cron');
138
-                    foreach ($cron[ $ee_cron ] as $ee_cron_details) {
139
-                        if (! empty($ee_cron_details['args'])) {
140
-                            do_action(
141
-                                'AHEE_log',
142
-                                __CLASS__,
143
-                                __FUNCTION__,
144
-                                print_r($ee_cron_details['args'], true),
145
-                                "{$ee_cron} args"
146
-                            );
147
-                        }
148
-                    }
149
-                }
150
-            }
151
-        }
152
-    }
153
-
154
-
155
-
156
-    /**
157
-     * reschedule_cron_for_transactions_if_maintenance_mode
158
-     * if Maintenance Mode is active, this will reschedule a cron to run again in 10 minutes
159
-     *
160
-     * @param string $cron_task
161
-     * @param array  $TXN_IDs
162
-     * @return bool
163
-     * @throws DomainException
164
-     */
165
-    public static function reschedule_cron_for_transactions_if_maintenance_mode($cron_task, array $TXN_IDs)
166
-    {
167
-        if (! method_exists('EE_Cron_Tasks', $cron_task)) {
168
-            throw new DomainException(
169
-                sprintf(
170
-                    __('"%1$s" is not valid method on EE_Cron_Tasks.', 'event_espresso'),
171
-                    $cron_task
172
-                )
173
-            );
174
-        }
175
-        // reschedule the cron if we can't hit the db right now
176
-        if (! EE_Maintenance_Mode::instance()->models_can_query()) {
177
-            foreach ($TXN_IDs as $TXN_ID => $additional_vars) {
178
-                // ensure $additional_vars is an array
179
-                $additional_vars = is_array($additional_vars) ? $additional_vars : array($additional_vars);
180
-                // reset cron job for the TXN
181
-                call_user_func_array(
182
-                    array('EE_Cron_Tasks', $cron_task),
183
-                    array_merge(
184
-                        array(
185
-                            time() + (10 * MINUTE_IN_SECONDS),
186
-                            $TXN_ID,
187
-                        ),
188
-                        $additional_vars
189
-                    )
190
-                );
191
-            }
192
-            return true;
193
-        }
194
-        return false;
195
-    }
196
-
197
-
198
-
199
-
200
-    /****************  UPDATE TRANSACTION WITH PAYMENT ****************/
201
-
202
-
203
-
204
-    /**
205
-     * array of TXN IDs and the payment
206
-     *
207
-     * @var array
208
-     */
209
-    protected static $_update_transactions_with_payment = array();
210
-
211
-
212
-    /**
213
-     * schedule_update_transaction_with_payment
214
-     * sets a wp_schedule_single_event() for updating any TXNs that may
215
-     * require updating due to recently received payments
216
-     *
217
-     * @param int $timestamp
218
-     * @param int $TXN_ID
219
-     * @param int $PAY_ID
220
-     */
221
-    public static function schedule_update_transaction_with_payment(
222
-        $timestamp,
223
-        $TXN_ID,
224
-        $PAY_ID
225
-    ) {
226
-        do_action('AHEE_log', __CLASS__, __FUNCTION__);
227
-        // validate $TXN_ID and $timestamp
228
-        $TXN_ID    = absint($TXN_ID);
229
-        $timestamp = absint($timestamp);
230
-        if ($TXN_ID && $timestamp) {
231
-            wp_schedule_single_event(
232
-                $timestamp,
233
-                'AHEE__EE_Cron_Tasks__update_transaction_with_payment_2',
234
-                array($TXN_ID, $PAY_ID)
235
-            );
236
-        }
237
-    }
238
-
239
-
240
-    /**
241
-     * setup_update_for_transaction_with_payment
242
-     * this is the callback for the action hook:
243
-     * 'AHEE__EE_Cron_Tasks__update_transaction_with_payment'
244
-     * which is setup by EE_Cron_Tasks::schedule_update_transaction_with_payment().
245
-     * The passed TXN_ID and associated payment gets added to an array, and then
246
-     * the EE_Cron_Tasks::update_transaction_with_payment() function is hooked into
247
-     * 'shutdown' which will actually handle the processing of any
248
-     * transactions requiring updating, because doing so now would be too early
249
-     * and the required resources may not be available
250
-     *
251
-     * @param int $TXN_ID
252
-     * @param int $PAY_ID
253
-     */
254
-    public static function setup_update_for_transaction_with_payment($TXN_ID = 0, $PAY_ID = 0)
255
-    {
256
-        do_action('AHEE_log', __CLASS__, __FUNCTION__, $TXN_ID, '$TXN_ID');
257
-        if (absint($TXN_ID)) {
258
-            self::$_update_transactions_with_payment[ $TXN_ID ] = $PAY_ID;
259
-            add_action(
260
-                'shutdown',
261
-                array('EE_Cron_Tasks', 'update_transaction_with_payment'),
262
-                5
263
-            );
264
-        }
265
-    }
266
-
267
-
268
-    /**
269
-     * update_transaction_with_payment
270
-     * loops through the self::$_abandoned_transactions array
271
-     * and attempts to finalize any TXNs that have not been completed
272
-     * but have had their sessions expired, most likely due to a user not
273
-     * returning from an off-site payment gateway
274
-     *
275
-     * @throws EE_Error
276
-     * @throws DomainException
277
-     * @throws InvalidDataTypeException
278
-     * @throws InvalidInterfaceException
279
-     * @throws InvalidArgumentException
280
-     * @throws ReflectionException
281
-     * @throws RuntimeException
282
-     */
283
-    public static function update_transaction_with_payment()
284
-    {
285
-        do_action('AHEE_log', __CLASS__, __FUNCTION__);
286
-        if (
287
-            // are there any TXNs that need cleaning up ?
288
-            empty(self::$_update_transactions_with_payment)
289
-            // reschedule the cron if we can't hit the db right now
290
-            || EE_Cron_Tasks::reschedule_cron_for_transactions_if_maintenance_mode(
291
-                'schedule_update_transaction_with_payment',
292
-                self::$_update_transactions_with_payment
293
-            )
294
-        ) {
295
-            return;
296
-        }
297
-        /** @type EE_Payment_Processor $payment_processor */
298
-        $payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
299
-        // set revisit flag for payment processor
300
-        $payment_processor->set_revisit();
301
-        // load EEM_Transaction
302
-        EE_Registry::instance()->load_model('Transaction');
303
-        foreach (self::$_update_transactions_with_payment as $TXN_ID => $PAY_ID) {
304
-            // reschedule the cron if we can't hit the db right now
305
-            if (! EE_Maintenance_Mode::instance()->models_can_query()) {
306
-                // reset cron job for updating the TXN
307
-                EE_Cron_Tasks::schedule_update_transaction_with_payment(
308
-                    time() + EE_Cron_Tasks::reschedule_timeout,
309
-                    $TXN_ID,
310
-                    $PAY_ID
311
-                );
312
-                continue;
313
-            }
314
-            $transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
315
-            $payment     = EEM_Payment::instance()->get_one_by_ID($PAY_ID);
316
-            // verify transaction
317
-            if ($transaction instanceof EE_Transaction && $payment instanceof EE_Payment) {
318
-                // now try to update the TXN with any payments
319
-                $payment_processor->update_txn_based_on_payment($transaction, $payment, true, true);
320
-            }
321
-            unset(self::$_update_transactions_with_payment[ $TXN_ID ]);
322
-        }
323
-    }
324
-
325
-
326
-
327
-    /************  END OF UPDATE TRANSACTION WITH PAYMENT  ************/
328
-
329
-
330
-
331
-    /*****************  EXPIRED TRANSACTION CHECK *****************/
332
-
333
-
334
-
335
-    /**
336
-     * array of TXN IDs
337
-     *
338
-     * @var array
339
-     */
340
-    protected static $_expired_transactions = array();
341
-
342
-
343
-
344
-    /**
345
-     * schedule_expired_transaction_check
346
-     * sets a wp_schedule_single_event() for following up on TXNs after their session has expired
347
-     *
348
-     * @param int $timestamp
349
-     * @param int $TXN_ID
350
-     */
351
-    public static function schedule_expired_transaction_check(
352
-        $timestamp,
353
-        $TXN_ID
354
-    ) {
355
-        // validate $TXN_ID and $timestamp
356
-        $TXN_ID    = absint($TXN_ID);
357
-        $timestamp = absint($timestamp);
358
-        if ($TXN_ID && $timestamp) {
359
-            wp_schedule_single_event(
360
-                $timestamp,
361
-                'AHEE__EE_Cron_Tasks__expired_transaction_check',
362
-                array($TXN_ID)
363
-            );
364
-        }
365
-    }
366
-
367
-
368
-
369
-    /**
370
-     * expired_transaction_check
371
-     * this is the callback for the action hook:
372
-     * 'AHEE__EE_Cron_Tasks__transaction_session_expiration_check'
373
-     * which is utilized by wp_schedule_single_event()
374
-     * in \EED_Single_Page_Checkout::_initialize_transaction().
375
-     * The passed TXN_ID gets added to an array, and then the
376
-     * process_expired_transactions() function is hooked into
377
-     * 'AHEE__EE_System__core_loaded_and_ready' which will actually handle the
378
-     * processing of any failed transactions, because doing so now would be
379
-     * too early and the required resources may not be available
380
-     *
381
-     * @param int $TXN_ID
382
-     */
383
-    public static function expired_transaction_check($TXN_ID = 0)
384
-    {
385
-        if (absint($TXN_ID)) {
386
-            self::$_expired_transactions[ $TXN_ID ] = $TXN_ID;
387
-            add_action(
388
-                'shutdown',
389
-                array('EE_Cron_Tasks', 'process_expired_transactions'),
390
-                5
391
-            );
392
-        }
393
-    }
394
-
395
-
396
-
397
-    /**
398
-     * process_expired_transactions
399
-     * loops through the self::$_expired_transactions array and processes any failed TXNs
400
-     *
401
-     * @throws EE_Error
402
-     * @throws InvalidDataTypeException
403
-     * @throws InvalidInterfaceException
404
-     * @throws InvalidArgumentException
405
-     * @throws ReflectionException
406
-     * @throws DomainException
407
-     * @throws RuntimeException
408
-     */
409
-    public static function process_expired_transactions()
410
-    {
411
-        if (
412
-            // are there any TXNs that need cleaning up ?
413
-            empty(self::$_expired_transactions)
414
-            // reschedule the cron if we can't hit the db right now
415
-            || EE_Cron_Tasks::reschedule_cron_for_transactions_if_maintenance_mode(
416
-                'schedule_expired_transaction_check',
417
-                self::$_expired_transactions
418
-            )
419
-        ) {
420
-            return;
421
-        }
422
-        /** @type EE_Transaction_Processor $transaction_processor */
423
-        $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
424
-        // set revisit flag for txn processor
425
-        $transaction_processor->set_revisit();
426
-        // load EEM_Transaction
427
-        EE_Registry::instance()->load_model('Transaction');
428
-        foreach (self::$_expired_transactions as $TXN_ID) {
429
-            $transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
430
-            // verify transaction and whether it is failed or not
431
-            if ($transaction instanceof EE_Transaction) {
432
-                switch ($transaction->status_ID()) {
433
-                    // Completed TXNs
434
-                    case EEM_Transaction::complete_status_code :
435
-                        do_action(
436
-                            'AHEE__EE_Cron_Tasks__process_expired_transactions__completed_transaction',
437
-                            $transaction
438
-                        );
439
-                        break;
440
-                    // Overpaid TXNs
441
-                    case EEM_Transaction::overpaid_status_code :
442
-                        do_action(
443
-                            'AHEE__EE_Cron_Tasks__process_expired_transactions__overpaid_transaction',
444
-                            $transaction
445
-                        );
446
-                        break;
447
-                    // Incomplete TXNs
448
-                    case EEM_Transaction::incomplete_status_code :
449
-                        do_action(
450
-                            'AHEE__EE_Cron_Tasks__process_expired_transactions__incomplete_transaction',
451
-                            $transaction
452
-                        );
453
-                        // todo : move business logic into EE_Transaction_Processor for finalizing abandoned transactions
454
-                        break;
455
-                    // Abandoned TXNs
456
-                    case EEM_Transaction::abandoned_status_code :
457
-                        // run hook before updating transaction, primarily so
458
-                        // EED_Ticket_Sales_Monitor::process_abandoned_transactions() can release reserved tickets
459
-                        do_action(
460
-                            'AHEE__EE_Cron_Tasks__process_expired_transactions__abandoned_transaction',
461
-                            $transaction
462
-                        );
463
-                        // don't finalize the TXN if it has already been completed
464
-                        if ($transaction->all_reg_steps_completed() !== true) {
465
-                            /** @type EE_Payment_Processor $payment_processor */
466
-                            $payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
467
-                            // let's simulate an IPN here which will trigger any notifications that need to go out
468
-                            $payment_processor->update_txn_based_on_payment(
469
-                                $transaction,
470
-                                $transaction->last_payment(),
471
-                                true,
472
-                                true
473
-                            );
474
-                        }
475
-                        break;
476
-                    // Failed TXNs
477
-                    case EEM_Transaction::failed_status_code :
478
-                        do_action(
479
-                            'AHEE__EE_Cron_Tasks__process_expired_transactions__failed_transaction',
480
-                            $transaction
481
-                        );
482
-                        // todo : perform garbage collection here and remove clean_out_junk_transactions()
483
-                        //$registrations = $transaction->registrations();
484
-                        //if ( ! empty( $registrations ) ) {
485
-                        //	foreach ( $registrations as $registration ) {
486
-                        //		if ( $registration instanceof EE_Registration ) {
487
-                        //$delete_registration = true;
488
-                        //if ( $registration->attendee() instanceof EE_Attendee ) {
489
-                        //	$delete_registration = false;
490
-                        //}
491
-                        //if ( $delete_registration ) {
492
-                        //	$registration->delete_permanently();
493
-                        //	$registration->delete_related_permanently();
494
-                        //}
495
-                        //		}
496
-                        //	}
497
-                        //}
498
-                        break;
499
-                }
500
-            }
501
-            unset(self::$_expired_transactions[ $TXN_ID ]);
502
-        }
503
-    }
504
-
505
-
506
-
507
-    /*************  END OF EXPIRED TRANSACTION CHECK  *************/
508
-
509
-
510
-
511
-    /************* START CLEAN UP BOT TRANSACTIONS **********************/
512
-
513
-
514
-
515
-    /**
516
-     * callback for 'AHEE__EE_Cron_Tasks__clean_up_junk_transactions'
517
-     * which is setup during activation to run on an hourly cron
518
-     *
519
-     * @throws EE_Error
520
-     * @throws InvalidArgumentException
521
-     * @throws InvalidDataTypeException
522
-     * @throws InvalidInterfaceException
523
-     * @throws DomainException
524
-     */
525
-    public static function clean_out_junk_transactions()
526
-    {
527
-        if (EE_Maintenance_Mode::instance()->models_can_query()) {
528
-            EED_Ticket_Sales_Monitor::reset_reservation_counts();
529
-            EEM_Transaction::instance('')->delete_junk_transactions();
530
-            EEM_Registration::instance('')->delete_registrations_with_no_transaction();
531
-            EEM_Line_Item::instance('')->delete_line_items_with_no_transaction();
532
-        }
533
-    }
534
-
535
-
536
-
537
-    /**
538
-     * Deletes old gateway logs. After about a week we usually don't need them for debugging. But folks can filter that.
539
-     *
540
-     * @throws EE_Error
541
-     * @throws InvalidDataTypeException
542
-     * @throws InvalidInterfaceException
543
-     * @throws InvalidArgumentException
544
-     */
545
-    public static function clean_out_old_gateway_logs()
546
-    {
547
-        if (EE_Maintenance_Mode::instance()->models_can_query()) {
548
-            $time_diff_for_comparison = apply_filters(
549
-                'FHEE__EE_Cron_Tasks__clean_out_old_gateway_logs__time_diff_for_comparison',
550
-                '-1 week'
551
-            );
552
-            EEM_Change_Log::instance()->delete_gateway_logs_older_than(new DateTime($time_diff_for_comparison));
553
-        }
554
-    }
555
-
556
-
557
-    /*****************  FINALIZE ABANDONED TRANSACTIONS *****************/
558
-
559
-
560
-
561
-    /**
562
-     * @var array
563
-     */
564
-    protected static $_abandoned_transactions = array();
565
-
566
-
567
-    /**
568
-     * @deprecated
569
-     * @param int $timestamp
570
-     * @param int $TXN_ID
571
-     */
572
-    public static function schedule_finalize_abandoned_transactions_check($timestamp, $TXN_ID)
573
-    {
574
-        EE_Cron_Tasks::schedule_expired_transaction_check($timestamp, $TXN_ID);
575
-    }
576
-
577
-
578
-    /**
579
-     * @deprecated
580
-     * @param int $TXN_ID
581
-     */
582
-    public static function check_for_abandoned_transactions($TXN_ID = 0)
583
-    {
584
-        EE_Cron_Tasks::expired_transaction_check($TXN_ID);
585
-    }
586
-
587
-
588
-    /**
589
-     * @deprecated
590
-     * @throws EE_Error
591
-     * @throws DomainException
592
-     * @throws InvalidDataTypeException
593
-     * @throws InvalidInterfaceException
594
-     * @throws InvalidArgumentException
595
-     * @throws ReflectionException
596
-     * @throws RuntimeException
597
-     */
598
-    public static function finalize_abandoned_transactions()
599
-    {
600
-        do_action('AHEE_log', __CLASS__, __FUNCTION__);
601
-        if (
602
-            // are there any TXNs that need cleaning up ?
603
-            empty(self::$_abandoned_transactions)
604
-            // reschedule the cron if we can't hit the db right now
605
-            || EE_Cron_Tasks::reschedule_cron_for_transactions_if_maintenance_mode(
606
-                'schedule_expired_transaction_check',
607
-                self::$_abandoned_transactions
608
-            )
609
-        ) {
610
-            return;
611
-        }
612
-        // combine our arrays of transaction IDs
613
-        self::$_expired_transactions = self::$_abandoned_transactions + self::$_expired_transactions;
614
-        // and deal with abandoned transactions here now...
615
-        EE_Cron_Tasks::process_expired_transactions();
616
-    }
617
-
618
-
619
-
620
-    /*************  END OF FINALIZE ABANDONED TRANSACTIONS  *************/
20
+	/**
21
+	 * WordPress doesn't allow duplicate crons within 10 minutes of the original,
22
+	 * so we'll set our retry time for just over 10 minutes to avoid that
23
+	 */
24
+	const reschedule_timeout = 605;
25
+
26
+
27
+	/**
28
+	 * @var EE_Cron_Tasks
29
+	 */
30
+	private static $_instance;
31
+
32
+
33
+	/**
34
+	 * @return EE_Cron_Tasks
35
+	 * @throws ReflectionException
36
+	 * @throws EE_Error
37
+	 * @throws InvalidArgumentException
38
+	 * @throws InvalidInterfaceException
39
+	 * @throws InvalidDataTypeException
40
+	 */
41
+	public static function instance()
42
+	{
43
+		if (! self::$_instance instanceof EE_Cron_Tasks) {
44
+			self::$_instance = new self();
45
+		}
46
+		return self::$_instance;
47
+	}
48
+
49
+
50
+	/**
51
+	 * @access private
52
+	 * @throws InvalidDataTypeException
53
+	 * @throws InvalidInterfaceException
54
+	 * @throws InvalidArgumentException
55
+	 * @throws EE_Error
56
+	 * @throws ReflectionException
57
+	 */
58
+	private function __construct()
59
+	{
60
+		do_action('AHEE_log', __CLASS__, __FUNCTION__);
61
+		// verify that WP Cron is enabled
62
+		if (
63
+			defined('DISABLE_WP_CRON')
64
+			&& DISABLE_WP_CRON
65
+			&& is_admin()
66
+			&& ! get_option('ee_disabled_wp_cron_check')
67
+		) {
68
+			/**
69
+			 * This needs to be delayed until after the config is loaded because EE_Cron_Tasks is constructed before
70
+			 * config is loaded.
71
+			 * This is intentionally using a anonymous function so that its not easily de-registered.  Client code
72
+			 * wanting to not have this functionality can just register its own action at a priority after this one to
73
+			 * reverse any changes.
74
+			 */
75
+			add_action(
76
+				'AHEE__EE_System__load_core_configuration__complete',
77
+				function ()
78
+				{
79
+					EE_Registry::instance()->NET_CFG->core->do_messages_on_same_request = true;
80
+					EE_Registry::instance()->NET_CFG->update_config(true, false);
81
+					add_option('ee_disabled_wp_cron_check', 1, '', false);
82
+				}
83
+			);
84
+		}
85
+		// UPDATE TRANSACTION WITH PAYMENT
86
+		add_action(
87
+			'AHEE__EE_Cron_Tasks__update_transaction_with_payment_2',
88
+			array('EE_Cron_Tasks', 'setup_update_for_transaction_with_payment'),
89
+			10,
90
+			2
91
+		);
92
+		// ABANDONED / EXPIRED TRANSACTION CHECK
93
+		add_action(
94
+			'AHEE__EE_Cron_Tasks__expired_transaction_check',
95
+			array('EE_Cron_Tasks', 'expired_transaction_check'),
96
+			10,
97
+			1
98
+		);
99
+		// CLEAN OUT JUNK TRANSACTIONS AND RELATED DATA
100
+		add_action(
101
+			'AHEE__EE_Cron_Tasks__clean_up_junk_transactions',
102
+			array('EE_Cron_Tasks', 'clean_out_junk_transactions')
103
+		);
104
+		// logging
105
+		add_action(
106
+			'AHEE__EE_System__load_core_configuration__complete',
107
+			array('EE_Cron_Tasks', 'log_scheduled_ee_crons')
108
+		);
109
+		EE_Registry::instance()->load_lib('Messages_Scheduler');
110
+		//clean out old gateway logs
111
+		add_action(
112
+			'AHEE_EE_Cron_Tasks__clean_out_old_gateway_logs',
113
+			array('EE_Cron_Tasks', 'clean_out_old_gateway_logs')
114
+		);
115
+	}
116
+
117
+
118
+	/**
119
+	 * @access protected
120
+	 * @return void
121
+	 */
122
+	public static function log_scheduled_ee_crons()
123
+	{
124
+		$ee_crons = array(
125
+			'AHEE__EE_Cron_Tasks__update_transaction_with_payment',
126
+			'AHEE__EE_Cron_Tasks__finalize_abandoned_transactions',
127
+			'AHEE__EE_Cron_Tasks__clean_up_junk_transactions',
128
+		);
129
+		$crons    = (array) get_option('cron');
130
+		if (! is_array($crons)) {
131
+			return;
132
+		}
133
+		foreach ($crons as $timestamp => $cron) {
134
+			/** @var array[] $cron */
135
+			foreach ($ee_crons as $ee_cron) {
136
+				if (isset($cron[ $ee_cron ]) && is_array($cron[ $ee_cron ])) {
137
+					do_action('AHEE_log', __CLASS__, __FUNCTION__, $ee_cron, 'scheduled EE cron');
138
+					foreach ($cron[ $ee_cron ] as $ee_cron_details) {
139
+						if (! empty($ee_cron_details['args'])) {
140
+							do_action(
141
+								'AHEE_log',
142
+								__CLASS__,
143
+								__FUNCTION__,
144
+								print_r($ee_cron_details['args'], true),
145
+								"{$ee_cron} args"
146
+							);
147
+						}
148
+					}
149
+				}
150
+			}
151
+		}
152
+	}
153
+
154
+
155
+
156
+	/**
157
+	 * reschedule_cron_for_transactions_if_maintenance_mode
158
+	 * if Maintenance Mode is active, this will reschedule a cron to run again in 10 minutes
159
+	 *
160
+	 * @param string $cron_task
161
+	 * @param array  $TXN_IDs
162
+	 * @return bool
163
+	 * @throws DomainException
164
+	 */
165
+	public static function reschedule_cron_for_transactions_if_maintenance_mode($cron_task, array $TXN_IDs)
166
+	{
167
+		if (! method_exists('EE_Cron_Tasks', $cron_task)) {
168
+			throw new DomainException(
169
+				sprintf(
170
+					__('"%1$s" is not valid method on EE_Cron_Tasks.', 'event_espresso'),
171
+					$cron_task
172
+				)
173
+			);
174
+		}
175
+		// reschedule the cron if we can't hit the db right now
176
+		if (! EE_Maintenance_Mode::instance()->models_can_query()) {
177
+			foreach ($TXN_IDs as $TXN_ID => $additional_vars) {
178
+				// ensure $additional_vars is an array
179
+				$additional_vars = is_array($additional_vars) ? $additional_vars : array($additional_vars);
180
+				// reset cron job for the TXN
181
+				call_user_func_array(
182
+					array('EE_Cron_Tasks', $cron_task),
183
+					array_merge(
184
+						array(
185
+							time() + (10 * MINUTE_IN_SECONDS),
186
+							$TXN_ID,
187
+						),
188
+						$additional_vars
189
+					)
190
+				);
191
+			}
192
+			return true;
193
+		}
194
+		return false;
195
+	}
196
+
197
+
198
+
199
+
200
+	/****************  UPDATE TRANSACTION WITH PAYMENT ****************/
201
+
202
+
203
+
204
+	/**
205
+	 * array of TXN IDs and the payment
206
+	 *
207
+	 * @var array
208
+	 */
209
+	protected static $_update_transactions_with_payment = array();
210
+
211
+
212
+	/**
213
+	 * schedule_update_transaction_with_payment
214
+	 * sets a wp_schedule_single_event() for updating any TXNs that may
215
+	 * require updating due to recently received payments
216
+	 *
217
+	 * @param int $timestamp
218
+	 * @param int $TXN_ID
219
+	 * @param int $PAY_ID
220
+	 */
221
+	public static function schedule_update_transaction_with_payment(
222
+		$timestamp,
223
+		$TXN_ID,
224
+		$PAY_ID
225
+	) {
226
+		do_action('AHEE_log', __CLASS__, __FUNCTION__);
227
+		// validate $TXN_ID and $timestamp
228
+		$TXN_ID    = absint($TXN_ID);
229
+		$timestamp = absint($timestamp);
230
+		if ($TXN_ID && $timestamp) {
231
+			wp_schedule_single_event(
232
+				$timestamp,
233
+				'AHEE__EE_Cron_Tasks__update_transaction_with_payment_2',
234
+				array($TXN_ID, $PAY_ID)
235
+			);
236
+		}
237
+	}
238
+
239
+
240
+	/**
241
+	 * setup_update_for_transaction_with_payment
242
+	 * this is the callback for the action hook:
243
+	 * 'AHEE__EE_Cron_Tasks__update_transaction_with_payment'
244
+	 * which is setup by EE_Cron_Tasks::schedule_update_transaction_with_payment().
245
+	 * The passed TXN_ID and associated payment gets added to an array, and then
246
+	 * the EE_Cron_Tasks::update_transaction_with_payment() function is hooked into
247
+	 * 'shutdown' which will actually handle the processing of any
248
+	 * transactions requiring updating, because doing so now would be too early
249
+	 * and the required resources may not be available
250
+	 *
251
+	 * @param int $TXN_ID
252
+	 * @param int $PAY_ID
253
+	 */
254
+	public static function setup_update_for_transaction_with_payment($TXN_ID = 0, $PAY_ID = 0)
255
+	{
256
+		do_action('AHEE_log', __CLASS__, __FUNCTION__, $TXN_ID, '$TXN_ID');
257
+		if (absint($TXN_ID)) {
258
+			self::$_update_transactions_with_payment[ $TXN_ID ] = $PAY_ID;
259
+			add_action(
260
+				'shutdown',
261
+				array('EE_Cron_Tasks', 'update_transaction_with_payment'),
262
+				5
263
+			);
264
+		}
265
+	}
266
+
267
+
268
+	/**
269
+	 * update_transaction_with_payment
270
+	 * loops through the self::$_abandoned_transactions array
271
+	 * and attempts to finalize any TXNs that have not been completed
272
+	 * but have had their sessions expired, most likely due to a user not
273
+	 * returning from an off-site payment gateway
274
+	 *
275
+	 * @throws EE_Error
276
+	 * @throws DomainException
277
+	 * @throws InvalidDataTypeException
278
+	 * @throws InvalidInterfaceException
279
+	 * @throws InvalidArgumentException
280
+	 * @throws ReflectionException
281
+	 * @throws RuntimeException
282
+	 */
283
+	public static function update_transaction_with_payment()
284
+	{
285
+		do_action('AHEE_log', __CLASS__, __FUNCTION__);
286
+		if (
287
+			// are there any TXNs that need cleaning up ?
288
+			empty(self::$_update_transactions_with_payment)
289
+			// reschedule the cron if we can't hit the db right now
290
+			|| EE_Cron_Tasks::reschedule_cron_for_transactions_if_maintenance_mode(
291
+				'schedule_update_transaction_with_payment',
292
+				self::$_update_transactions_with_payment
293
+			)
294
+		) {
295
+			return;
296
+		}
297
+		/** @type EE_Payment_Processor $payment_processor */
298
+		$payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
299
+		// set revisit flag for payment processor
300
+		$payment_processor->set_revisit();
301
+		// load EEM_Transaction
302
+		EE_Registry::instance()->load_model('Transaction');
303
+		foreach (self::$_update_transactions_with_payment as $TXN_ID => $PAY_ID) {
304
+			// reschedule the cron if we can't hit the db right now
305
+			if (! EE_Maintenance_Mode::instance()->models_can_query()) {
306
+				// reset cron job for updating the TXN
307
+				EE_Cron_Tasks::schedule_update_transaction_with_payment(
308
+					time() + EE_Cron_Tasks::reschedule_timeout,
309
+					$TXN_ID,
310
+					$PAY_ID
311
+				);
312
+				continue;
313
+			}
314
+			$transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
315
+			$payment     = EEM_Payment::instance()->get_one_by_ID($PAY_ID);
316
+			// verify transaction
317
+			if ($transaction instanceof EE_Transaction && $payment instanceof EE_Payment) {
318
+				// now try to update the TXN with any payments
319
+				$payment_processor->update_txn_based_on_payment($transaction, $payment, true, true);
320
+			}
321
+			unset(self::$_update_transactions_with_payment[ $TXN_ID ]);
322
+		}
323
+	}
324
+
325
+
326
+
327
+	/************  END OF UPDATE TRANSACTION WITH PAYMENT  ************/
328
+
329
+
330
+
331
+	/*****************  EXPIRED TRANSACTION CHECK *****************/
332
+
333
+
334
+
335
+	/**
336
+	 * array of TXN IDs
337
+	 *
338
+	 * @var array
339
+	 */
340
+	protected static $_expired_transactions = array();
341
+
342
+
343
+
344
+	/**
345
+	 * schedule_expired_transaction_check
346
+	 * sets a wp_schedule_single_event() for following up on TXNs after their session has expired
347
+	 *
348
+	 * @param int $timestamp
349
+	 * @param int $TXN_ID
350
+	 */
351
+	public static function schedule_expired_transaction_check(
352
+		$timestamp,
353
+		$TXN_ID
354
+	) {
355
+		// validate $TXN_ID and $timestamp
356
+		$TXN_ID    = absint($TXN_ID);
357
+		$timestamp = absint($timestamp);
358
+		if ($TXN_ID && $timestamp) {
359
+			wp_schedule_single_event(
360
+				$timestamp,
361
+				'AHEE__EE_Cron_Tasks__expired_transaction_check',
362
+				array($TXN_ID)
363
+			);
364
+		}
365
+	}
366
+
367
+
368
+
369
+	/**
370
+	 * expired_transaction_check
371
+	 * this is the callback for the action hook:
372
+	 * 'AHEE__EE_Cron_Tasks__transaction_session_expiration_check'
373
+	 * which is utilized by wp_schedule_single_event()
374
+	 * in \EED_Single_Page_Checkout::_initialize_transaction().
375
+	 * The passed TXN_ID gets added to an array, and then the
376
+	 * process_expired_transactions() function is hooked into
377
+	 * 'AHEE__EE_System__core_loaded_and_ready' which will actually handle the
378
+	 * processing of any failed transactions, because doing so now would be
379
+	 * too early and the required resources may not be available
380
+	 *
381
+	 * @param int $TXN_ID
382
+	 */
383
+	public static function expired_transaction_check($TXN_ID = 0)
384
+	{
385
+		if (absint($TXN_ID)) {
386
+			self::$_expired_transactions[ $TXN_ID ] = $TXN_ID;
387
+			add_action(
388
+				'shutdown',
389
+				array('EE_Cron_Tasks', 'process_expired_transactions'),
390
+				5
391
+			);
392
+		}
393
+	}
394
+
395
+
396
+
397
+	/**
398
+	 * process_expired_transactions
399
+	 * loops through the self::$_expired_transactions array and processes any failed TXNs
400
+	 *
401
+	 * @throws EE_Error
402
+	 * @throws InvalidDataTypeException
403
+	 * @throws InvalidInterfaceException
404
+	 * @throws InvalidArgumentException
405
+	 * @throws ReflectionException
406
+	 * @throws DomainException
407
+	 * @throws RuntimeException
408
+	 */
409
+	public static function process_expired_transactions()
410
+	{
411
+		if (
412
+			// are there any TXNs that need cleaning up ?
413
+			empty(self::$_expired_transactions)
414
+			// reschedule the cron if we can't hit the db right now
415
+			|| EE_Cron_Tasks::reschedule_cron_for_transactions_if_maintenance_mode(
416
+				'schedule_expired_transaction_check',
417
+				self::$_expired_transactions
418
+			)
419
+		) {
420
+			return;
421
+		}
422
+		/** @type EE_Transaction_Processor $transaction_processor */
423
+		$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
424
+		// set revisit flag for txn processor
425
+		$transaction_processor->set_revisit();
426
+		// load EEM_Transaction
427
+		EE_Registry::instance()->load_model('Transaction');
428
+		foreach (self::$_expired_transactions as $TXN_ID) {
429
+			$transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
430
+			// verify transaction and whether it is failed or not
431
+			if ($transaction instanceof EE_Transaction) {
432
+				switch ($transaction->status_ID()) {
433
+					// Completed TXNs
434
+					case EEM_Transaction::complete_status_code :
435
+						do_action(
436
+							'AHEE__EE_Cron_Tasks__process_expired_transactions__completed_transaction',
437
+							$transaction
438
+						);
439
+						break;
440
+					// Overpaid TXNs
441
+					case EEM_Transaction::overpaid_status_code :
442
+						do_action(
443
+							'AHEE__EE_Cron_Tasks__process_expired_transactions__overpaid_transaction',
444
+							$transaction
445
+						);
446
+						break;
447
+					// Incomplete TXNs
448
+					case EEM_Transaction::incomplete_status_code :
449
+						do_action(
450
+							'AHEE__EE_Cron_Tasks__process_expired_transactions__incomplete_transaction',
451
+							$transaction
452
+						);
453
+						// todo : move business logic into EE_Transaction_Processor for finalizing abandoned transactions
454
+						break;
455
+					// Abandoned TXNs
456
+					case EEM_Transaction::abandoned_status_code :
457
+						// run hook before updating transaction, primarily so
458
+						// EED_Ticket_Sales_Monitor::process_abandoned_transactions() can release reserved tickets
459
+						do_action(
460
+							'AHEE__EE_Cron_Tasks__process_expired_transactions__abandoned_transaction',
461
+							$transaction
462
+						);
463
+						// don't finalize the TXN if it has already been completed
464
+						if ($transaction->all_reg_steps_completed() !== true) {
465
+							/** @type EE_Payment_Processor $payment_processor */
466
+							$payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
467
+							// let's simulate an IPN here which will trigger any notifications that need to go out
468
+							$payment_processor->update_txn_based_on_payment(
469
+								$transaction,
470
+								$transaction->last_payment(),
471
+								true,
472
+								true
473
+							);
474
+						}
475
+						break;
476
+					// Failed TXNs
477
+					case EEM_Transaction::failed_status_code :
478
+						do_action(
479
+							'AHEE__EE_Cron_Tasks__process_expired_transactions__failed_transaction',
480
+							$transaction
481
+						);
482
+						// todo : perform garbage collection here and remove clean_out_junk_transactions()
483
+						//$registrations = $transaction->registrations();
484
+						//if ( ! empty( $registrations ) ) {
485
+						//	foreach ( $registrations as $registration ) {
486
+						//		if ( $registration instanceof EE_Registration ) {
487
+						//$delete_registration = true;
488
+						//if ( $registration->attendee() instanceof EE_Attendee ) {
489
+						//	$delete_registration = false;
490
+						//}
491
+						//if ( $delete_registration ) {
492
+						//	$registration->delete_permanently();
493
+						//	$registration->delete_related_permanently();
494
+						//}
495
+						//		}
496
+						//	}
497
+						//}
498
+						break;
499
+				}
500
+			}
501
+			unset(self::$_expired_transactions[ $TXN_ID ]);
502
+		}
503
+	}
504
+
505
+
506
+
507
+	/*************  END OF EXPIRED TRANSACTION CHECK  *************/
508
+
509
+
510
+
511
+	/************* START CLEAN UP BOT TRANSACTIONS **********************/
512
+
513
+
514
+
515
+	/**
516
+	 * callback for 'AHEE__EE_Cron_Tasks__clean_up_junk_transactions'
517
+	 * which is setup during activation to run on an hourly cron
518
+	 *
519
+	 * @throws EE_Error
520
+	 * @throws InvalidArgumentException
521
+	 * @throws InvalidDataTypeException
522
+	 * @throws InvalidInterfaceException
523
+	 * @throws DomainException
524
+	 */
525
+	public static function clean_out_junk_transactions()
526
+	{
527
+		if (EE_Maintenance_Mode::instance()->models_can_query()) {
528
+			EED_Ticket_Sales_Monitor::reset_reservation_counts();
529
+			EEM_Transaction::instance('')->delete_junk_transactions();
530
+			EEM_Registration::instance('')->delete_registrations_with_no_transaction();
531
+			EEM_Line_Item::instance('')->delete_line_items_with_no_transaction();
532
+		}
533
+	}
534
+
535
+
536
+
537
+	/**
538
+	 * Deletes old gateway logs. After about a week we usually don't need them for debugging. But folks can filter that.
539
+	 *
540
+	 * @throws EE_Error
541
+	 * @throws InvalidDataTypeException
542
+	 * @throws InvalidInterfaceException
543
+	 * @throws InvalidArgumentException
544
+	 */
545
+	public static function clean_out_old_gateway_logs()
546
+	{
547
+		if (EE_Maintenance_Mode::instance()->models_can_query()) {
548
+			$time_diff_for_comparison = apply_filters(
549
+				'FHEE__EE_Cron_Tasks__clean_out_old_gateway_logs__time_diff_for_comparison',
550
+				'-1 week'
551
+			);
552
+			EEM_Change_Log::instance()->delete_gateway_logs_older_than(new DateTime($time_diff_for_comparison));
553
+		}
554
+	}
555
+
556
+
557
+	/*****************  FINALIZE ABANDONED TRANSACTIONS *****************/
558
+
559
+
560
+
561
+	/**
562
+	 * @var array
563
+	 */
564
+	protected static $_abandoned_transactions = array();
565
+
566
+
567
+	/**
568
+	 * @deprecated
569
+	 * @param int $timestamp
570
+	 * @param int $TXN_ID
571
+	 */
572
+	public static function schedule_finalize_abandoned_transactions_check($timestamp, $TXN_ID)
573
+	{
574
+		EE_Cron_Tasks::schedule_expired_transaction_check($timestamp, $TXN_ID);
575
+	}
576
+
577
+
578
+	/**
579
+	 * @deprecated
580
+	 * @param int $TXN_ID
581
+	 */
582
+	public static function check_for_abandoned_transactions($TXN_ID = 0)
583
+	{
584
+		EE_Cron_Tasks::expired_transaction_check($TXN_ID);
585
+	}
586
+
587
+
588
+	/**
589
+	 * @deprecated
590
+	 * @throws EE_Error
591
+	 * @throws DomainException
592
+	 * @throws InvalidDataTypeException
593
+	 * @throws InvalidInterfaceException
594
+	 * @throws InvalidArgumentException
595
+	 * @throws ReflectionException
596
+	 * @throws RuntimeException
597
+	 */
598
+	public static function finalize_abandoned_transactions()
599
+	{
600
+		do_action('AHEE_log', __CLASS__, __FUNCTION__);
601
+		if (
602
+			// are there any TXNs that need cleaning up ?
603
+			empty(self::$_abandoned_transactions)
604
+			// reschedule the cron if we can't hit the db right now
605
+			|| EE_Cron_Tasks::reschedule_cron_for_transactions_if_maintenance_mode(
606
+				'schedule_expired_transaction_check',
607
+				self::$_abandoned_transactions
608
+			)
609
+		) {
610
+			return;
611
+		}
612
+		// combine our arrays of transaction IDs
613
+		self::$_expired_transactions = self::$_abandoned_transactions + self::$_expired_transactions;
614
+		// and deal with abandoned transactions here now...
615
+		EE_Cron_Tasks::process_expired_transactions();
616
+	}
617
+
618
+
619
+
620
+	/*************  END OF FINALIZE ABANDONED TRANSACTIONS  *************/
621 621
 }
622 622
 // End of file EE_Cron_Tasks.core.php
623 623
 // Location: /EE_Cron_Tasks.core.php
Please login to merge, or discard this patch.
Spacing   +14 added lines, -14 removed lines patch added patch discarded remove patch
@@ -40,7 +40,7 @@  discard block
 block discarded – undo
40 40
      */
41 41
     public static function instance()
42 42
     {
43
-        if (! self::$_instance instanceof EE_Cron_Tasks) {
43
+        if ( ! self::$_instance instanceof EE_Cron_Tasks) {
44 44
             self::$_instance = new self();
45 45
         }
46 46
         return self::$_instance;
@@ -74,7 +74,7 @@  discard block
 block discarded – undo
74 74
              */
75 75
             add_action(
76 76
                 'AHEE__EE_System__load_core_configuration__complete',
77
-                function ()
77
+                function()
78 78
                 {
79 79
                     EE_Registry::instance()->NET_CFG->core->do_messages_on_same_request = true;
80 80
                     EE_Registry::instance()->NET_CFG->update_config(true, false);
@@ -126,17 +126,17 @@  discard block
 block discarded – undo
126 126
             'AHEE__EE_Cron_Tasks__finalize_abandoned_transactions',
127 127
             'AHEE__EE_Cron_Tasks__clean_up_junk_transactions',
128 128
         );
129
-        $crons    = (array) get_option('cron');
130
-        if (! is_array($crons)) {
129
+        $crons = (array) get_option('cron');
130
+        if ( ! is_array($crons)) {
131 131
             return;
132 132
         }
133 133
         foreach ($crons as $timestamp => $cron) {
134 134
             /** @var array[] $cron */
135 135
             foreach ($ee_crons as $ee_cron) {
136
-                if (isset($cron[ $ee_cron ]) && is_array($cron[ $ee_cron ])) {
136
+                if (isset($cron[$ee_cron]) && is_array($cron[$ee_cron])) {
137 137
                     do_action('AHEE_log', __CLASS__, __FUNCTION__, $ee_cron, 'scheduled EE cron');
138
-                    foreach ($cron[ $ee_cron ] as $ee_cron_details) {
139
-                        if (! empty($ee_cron_details['args'])) {
138
+                    foreach ($cron[$ee_cron] as $ee_cron_details) {
139
+                        if ( ! empty($ee_cron_details['args'])) {
140 140
                             do_action(
141 141
                                 'AHEE_log',
142 142
                                 __CLASS__,
@@ -164,7 +164,7 @@  discard block
 block discarded – undo
164 164
      */
165 165
     public static function reschedule_cron_for_transactions_if_maintenance_mode($cron_task, array $TXN_IDs)
166 166
     {
167
-        if (! method_exists('EE_Cron_Tasks', $cron_task)) {
167
+        if ( ! method_exists('EE_Cron_Tasks', $cron_task)) {
168 168
             throw new DomainException(
169 169
                 sprintf(
170 170
                     __('"%1$s" is not valid method on EE_Cron_Tasks.', 'event_espresso'),
@@ -173,7 +173,7 @@  discard block
 block discarded – undo
173 173
             );
174 174
         }
175 175
         // reschedule the cron if we can't hit the db right now
176
-        if (! EE_Maintenance_Mode::instance()->models_can_query()) {
176
+        if ( ! EE_Maintenance_Mode::instance()->models_can_query()) {
177 177
             foreach ($TXN_IDs as $TXN_ID => $additional_vars) {
178 178
                 // ensure $additional_vars is an array
179 179
                 $additional_vars = is_array($additional_vars) ? $additional_vars : array($additional_vars);
@@ -255,7 +255,7 @@  discard block
 block discarded – undo
255 255
     {
256 256
         do_action('AHEE_log', __CLASS__, __FUNCTION__, $TXN_ID, '$TXN_ID');
257 257
         if (absint($TXN_ID)) {
258
-            self::$_update_transactions_with_payment[ $TXN_ID ] = $PAY_ID;
258
+            self::$_update_transactions_with_payment[$TXN_ID] = $PAY_ID;
259 259
             add_action(
260 260
                 'shutdown',
261 261
                 array('EE_Cron_Tasks', 'update_transaction_with_payment'),
@@ -302,7 +302,7 @@  discard block
 block discarded – undo
302 302
         EE_Registry::instance()->load_model('Transaction');
303 303
         foreach (self::$_update_transactions_with_payment as $TXN_ID => $PAY_ID) {
304 304
             // reschedule the cron if we can't hit the db right now
305
-            if (! EE_Maintenance_Mode::instance()->models_can_query()) {
305
+            if ( ! EE_Maintenance_Mode::instance()->models_can_query()) {
306 306
                 // reset cron job for updating the TXN
307 307
                 EE_Cron_Tasks::schedule_update_transaction_with_payment(
308 308
                     time() + EE_Cron_Tasks::reschedule_timeout,
@@ -318,7 +318,7 @@  discard block
 block discarded – undo
318 318
                 // now try to update the TXN with any payments
319 319
                 $payment_processor->update_txn_based_on_payment($transaction, $payment, true, true);
320 320
             }
321
-            unset(self::$_update_transactions_with_payment[ $TXN_ID ]);
321
+            unset(self::$_update_transactions_with_payment[$TXN_ID]);
322 322
         }
323 323
     }
324 324
 
@@ -383,7 +383,7 @@  discard block
 block discarded – undo
383 383
     public static function expired_transaction_check($TXN_ID = 0)
384 384
     {
385 385
         if (absint($TXN_ID)) {
386
-            self::$_expired_transactions[ $TXN_ID ] = $TXN_ID;
386
+            self::$_expired_transactions[$TXN_ID] = $TXN_ID;
387 387
             add_action(
388 388
                 'shutdown',
389 389
                 array('EE_Cron_Tasks', 'process_expired_transactions'),
@@ -498,7 +498,7 @@  discard block
 block discarded – undo
498 498
                         break;
499 499
                 }
500 500
             }
501
-            unset(self::$_expired_transactions[ $TXN_ID ]);
501
+            unset(self::$_expired_transactions[$TXN_ID]);
502 502
         }
503 503
     }
504 504
 
Please login to merge, or discard this patch.
core/db_models/EEM_Transaction.model.php 1 patch
Indentation   +401 added lines, -401 removed lines patch added patch discarded remove patch
@@ -4,7 +4,7 @@  discard block
 block discarded – undo
4 4
 use EventEspresso\core\exceptions\InvalidInterfaceException;
5 5
 
6 6
 if ( ! defined('EVENT_ESPRESSO_VERSION')) {
7
-    exit('No direct script access allowed');
7
+	exit('No direct script access allowed');
8 8
 }
9 9
 require_once(EE_MODELS . 'EEM_Base.model.php');
10 10
 
@@ -20,193 +20,193 @@  discard block
 block discarded – undo
20 20
 class EEM_Transaction extends EEM_Base
21 21
 {
22 22
 
23
-    // private instance of the Transaction object
24
-    protected static $_instance;
25
-
26
-    /**
27
-     * Status ID(STS_ID on esp_status table) to indicate the transaction is complete,
28
-     * but payment is pending. This is the state for transactions where payment is promised
29
-     * from an offline gateway.
30
-     */
31
-    //	const open_status_code = 'TPN';
32
-
33
-    /**
34
-     * Status ID(STS_ID on esp_status table) to indicate the transaction failed,
35
-     * either due to a technical reason (server or computer crash during registration),
36
-     *  or some other reason that prevent the collection of any useful contact information from any of the registrants
37
-     */
38
-    const failed_status_code = 'TFL';
39
-
40
-    /**
41
-     * Status ID(STS_ID on esp_status table) to indicate the transaction was abandoned,
42
-     * either due to a technical reason (server or computer crash during registration),
43
-     * or due to an abandoned cart after registrant chose not to complete the registration process
44
-     * HOWEVER...
45
-     * an abandoned TXN differs from a failed TXN in that it was able to capture contact information for at least one
46
-     * registrant
47
-     */
48
-    const abandoned_status_code = 'TAB';
49
-
50
-    /**
51
-     * Status ID(STS_ID on esp_status table) to indicate an incomplete transaction,
52
-     * meaning that monies are still owing: TXN_paid < TXN_total
53
-     */
54
-    const incomplete_status_code = 'TIN';
55
-
56
-    /**
57
-     * Status ID (STS_ID on esp_status table) to indicate a complete transaction.
58
-     * meaning that NO monies are owing: TXN_paid == TXN_total
59
-     */
60
-    const complete_status_code = 'TCM';
61
-
62
-    /**
63
-     *  Status ID(STS_ID on esp_status table) to indicate the transaction is overpaid.
64
-     *  This is the same as complete, but site admins actually owe clients the moneys!  TXN_paid > TXN_total
65
-     */
66
-    const overpaid_status_code = 'TOP';
67
-
68
-
69
-    /**
70
-     *    private constructor to prevent direct creation
71
-     *
72
-     * @Constructor
73
-     * @access protected
74
-     *
75
-     * @param string $timezone string representing the timezone we want to set for returned Date Time Strings (and any
76
-     *                         incoming timezone data that gets saved). Note this just sends the timezone info to the
77
-     *                         date time model field objects.  Default is NULL (and will be assumed using the set
78
-     *                         timezone in the 'timezone_string' wp option)
79
-     *
80
-     * @return EEM_Transaction
81
-     * @throws \EE_Error
82
-     */
83
-    protected function __construct($timezone)
84
-    {
85
-        $this->singular_item = __('Transaction', 'event_espresso');
86
-        $this->plural_item   = __('Transactions', 'event_espresso');
87
-
88
-        $this->_tables                 = array(
89
-            'TransactionTable' => new EE_Primary_Table('esp_transaction', 'TXN_ID')
90
-        );
91
-        $this->_fields                 = array(
92
-            'TransactionTable' => array(
93
-                'TXN_ID'           => new EE_Primary_Key_Int_Field('TXN_ID', __('Transaction ID', 'event_espresso')),
94
-                'TXN_timestamp'    => new EE_Datetime_Field('TXN_timestamp',
95
-                    __('date when transaction was created', 'event_espresso'), false, EE_Datetime_Field::now,
96
-                    $timezone),
97
-                'TXN_total'        => new EE_Money_Field('TXN_total',
98
-                    __('Total value of Transaction', 'event_espresso'), false, 0),
99
-                'TXN_paid'         => new EE_Money_Field('TXN_paid',
100
-                    __('Amount paid towards transaction to date', 'event_espresso'), false, 0),
101
-                'STS_ID'           => new EE_Foreign_Key_String_Field('STS_ID', __('Status ID', 'event_espresso'),
102
-                    false, EEM_Transaction::failed_status_code, 'Status'),
103
-                'TXN_session_data' => new EE_Serialized_Text_Field('TXN_session_data',
104
-                    __('Serialized session data', 'event_espresso'), true, ''),
105
-                'TXN_hash_salt'    => new EE_Plain_Text_Field('TXN_hash_salt',
106
-                    __('Transaction Hash Salt', 'event_espresso'), true, ''),
107
-                'PMD_ID'           => new EE_Foreign_Key_Int_Field('PMD_ID',
108
-                    __("Last Used Payment Method", 'event_espresso'), true, null, 'Payment_Method'),
109
-                'TXN_reg_steps'    => new EE_Serialized_Text_Field('TXN_reg_steps',
110
-                    __('Registration Steps', 'event_espresso'), false, array()),
111
-            )
112
-        );
113
-        $this->_model_relations        = array(
114
-            'Registration'   => new EE_Has_Many_Relation(),
115
-            'Payment'        => new EE_Has_Many_Relation(),
116
-            'Status'         => new EE_Belongs_To_Relation(),
117
-            'Line_Item'      => new EE_Has_Many_Relation(false),
118
-            //you can delete a transaction without needing to delete its line items
119
-            'Payment_Method' => new EE_Belongs_To_Relation(),
120
-            'Message'        => new EE_Has_Many_Relation()
121
-        );
122
-        $this->_model_chain_to_wp_user = 'Registration.Event';
123
-        parent::__construct($timezone);
124
-
125
-    }
126
-
127
-
128
-    /**
129
-     *    txn_status_array
130
-     * get list of transaction statuses
131
-     *
132
-     * @access public
133
-     * @return array
134
-     */
135
-    public static function txn_status_array()
136
-    {
137
-        return apply_filters(
138
-            'FHEE__EEM_Transaction__txn_status_array',
139
-            array(
140
-                EEM_Transaction::overpaid_status_code,
141
-                EEM_Transaction::complete_status_code,
142
-                EEM_Transaction::incomplete_status_code,
143
-                EEM_Transaction::abandoned_status_code,
144
-                EEM_Transaction::failed_status_code,
145
-            )
146
-        );
147
-    }
148
-
149
-    /**
150
-     *        get the revenue per day  for the Transaction Admin page Reports Tab
151
-     *
152
-     * @access        public
153
-     *
154
-     * @param string $period
155
-     *
156
-     * @return \stdClass[]
157
-     */
158
-    public function get_revenue_per_day_report($period = '-1 month')
159
-    {
160
-        $sql_date = $this->convert_datetime_for_query('TXN_timestamp', date('Y-m-d H:i:s', strtotime($period)),
161
-            'Y-m-d H:i:s', 'UTC');
162
-
163
-        $query_interval = EEH_DTT_Helper::get_sql_query_interval_for_offset($this->get_timezone(), 'TXN_timestamp');
164
-
165
-        return $this->_get_all_wpdb_results(
166
-            array(
167
-                array(
168
-                    'TXN_timestamp' => array('>=', $sql_date)
169
-                ),
170
-                'group_by' => 'txnDate',
171
-                'order_by' => array('TXN_timestamp' => 'ASC')
172
-            ),
173
-            OBJECT,
174
-            array(
175
-                'txnDate' => array('DATE(' . $query_interval . ')', '%s'),
176
-                'revenue' => array('SUM(TransactionTable.TXN_paid)', '%d')
177
-            )
178
-        );
179
-    }
180
-
181
-
182
-    /**
183
-     *        get the revenue per event  for the Transaction Admin page Reports Tab
184
-     *
185
-     * @access        public
186
-     *
187
-     * @param string $period
188
-     *
189
-     * @throws \EE_Error
190
-     * @return mixed
191
-     */
192
-    public function get_revenue_per_event_report($period = '-1 month')
193
-    {
194
-        global $wpdb;
195
-        $transaction_table          = $wpdb->prefix . 'esp_transaction';
196
-        $registration_table         = $wpdb->prefix . 'esp_registration';
197
-        $registration_payment_table = $wpdb->prefix . 'esp_registration_payment';
198
-        $event_table                = $wpdb->posts;
199
-        $payment_table              = $wpdb->prefix . 'esp_payment';
200
-        $sql_date                   = date('Y-m-d H:i:s', strtotime($period));
201
-        $approved_payment_status    = EEM_Payment::status_id_approved;
202
-        $extra_event_on_join        = '';
203
-        //exclude events not authored by user if permissions in effect
204
-        if ( ! EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_event_report')) {
205
-            $extra_event_on_join = ' AND Event.post_author = ' . get_current_user_id();
206
-        }
207
-
208
-        return $wpdb->get_results(
209
-            "SELECT
23
+	// private instance of the Transaction object
24
+	protected static $_instance;
25
+
26
+	/**
27
+	 * Status ID(STS_ID on esp_status table) to indicate the transaction is complete,
28
+	 * but payment is pending. This is the state for transactions where payment is promised
29
+	 * from an offline gateway.
30
+	 */
31
+	//	const open_status_code = 'TPN';
32
+
33
+	/**
34
+	 * Status ID(STS_ID on esp_status table) to indicate the transaction failed,
35
+	 * either due to a technical reason (server or computer crash during registration),
36
+	 *  or some other reason that prevent the collection of any useful contact information from any of the registrants
37
+	 */
38
+	const failed_status_code = 'TFL';
39
+
40
+	/**
41
+	 * Status ID(STS_ID on esp_status table) to indicate the transaction was abandoned,
42
+	 * either due to a technical reason (server or computer crash during registration),
43
+	 * or due to an abandoned cart after registrant chose not to complete the registration process
44
+	 * HOWEVER...
45
+	 * an abandoned TXN differs from a failed TXN in that it was able to capture contact information for at least one
46
+	 * registrant
47
+	 */
48
+	const abandoned_status_code = 'TAB';
49
+
50
+	/**
51
+	 * Status ID(STS_ID on esp_status table) to indicate an incomplete transaction,
52
+	 * meaning that monies are still owing: TXN_paid < TXN_total
53
+	 */
54
+	const incomplete_status_code = 'TIN';
55
+
56
+	/**
57
+	 * Status ID (STS_ID on esp_status table) to indicate a complete transaction.
58
+	 * meaning that NO monies are owing: TXN_paid == TXN_total
59
+	 */
60
+	const complete_status_code = 'TCM';
61
+
62
+	/**
63
+	 *  Status ID(STS_ID on esp_status table) to indicate the transaction is overpaid.
64
+	 *  This is the same as complete, but site admins actually owe clients the moneys!  TXN_paid > TXN_total
65
+	 */
66
+	const overpaid_status_code = 'TOP';
67
+
68
+
69
+	/**
70
+	 *    private constructor to prevent direct creation
71
+	 *
72
+	 * @Constructor
73
+	 * @access protected
74
+	 *
75
+	 * @param string $timezone string representing the timezone we want to set for returned Date Time Strings (and any
76
+	 *                         incoming timezone data that gets saved). Note this just sends the timezone info to the
77
+	 *                         date time model field objects.  Default is NULL (and will be assumed using the set
78
+	 *                         timezone in the 'timezone_string' wp option)
79
+	 *
80
+	 * @return EEM_Transaction
81
+	 * @throws \EE_Error
82
+	 */
83
+	protected function __construct($timezone)
84
+	{
85
+		$this->singular_item = __('Transaction', 'event_espresso');
86
+		$this->plural_item   = __('Transactions', 'event_espresso');
87
+
88
+		$this->_tables                 = array(
89
+			'TransactionTable' => new EE_Primary_Table('esp_transaction', 'TXN_ID')
90
+		);
91
+		$this->_fields                 = array(
92
+			'TransactionTable' => array(
93
+				'TXN_ID'           => new EE_Primary_Key_Int_Field('TXN_ID', __('Transaction ID', 'event_espresso')),
94
+				'TXN_timestamp'    => new EE_Datetime_Field('TXN_timestamp',
95
+					__('date when transaction was created', 'event_espresso'), false, EE_Datetime_Field::now,
96
+					$timezone),
97
+				'TXN_total'        => new EE_Money_Field('TXN_total',
98
+					__('Total value of Transaction', 'event_espresso'), false, 0),
99
+				'TXN_paid'         => new EE_Money_Field('TXN_paid',
100
+					__('Amount paid towards transaction to date', 'event_espresso'), false, 0),
101
+				'STS_ID'           => new EE_Foreign_Key_String_Field('STS_ID', __('Status ID', 'event_espresso'),
102
+					false, EEM_Transaction::failed_status_code, 'Status'),
103
+				'TXN_session_data' => new EE_Serialized_Text_Field('TXN_session_data',
104
+					__('Serialized session data', 'event_espresso'), true, ''),
105
+				'TXN_hash_salt'    => new EE_Plain_Text_Field('TXN_hash_salt',
106
+					__('Transaction Hash Salt', 'event_espresso'), true, ''),
107
+				'PMD_ID'           => new EE_Foreign_Key_Int_Field('PMD_ID',
108
+					__("Last Used Payment Method", 'event_espresso'), true, null, 'Payment_Method'),
109
+				'TXN_reg_steps'    => new EE_Serialized_Text_Field('TXN_reg_steps',
110
+					__('Registration Steps', 'event_espresso'), false, array()),
111
+			)
112
+		);
113
+		$this->_model_relations        = array(
114
+			'Registration'   => new EE_Has_Many_Relation(),
115
+			'Payment'        => new EE_Has_Many_Relation(),
116
+			'Status'         => new EE_Belongs_To_Relation(),
117
+			'Line_Item'      => new EE_Has_Many_Relation(false),
118
+			//you can delete a transaction without needing to delete its line items
119
+			'Payment_Method' => new EE_Belongs_To_Relation(),
120
+			'Message'        => new EE_Has_Many_Relation()
121
+		);
122
+		$this->_model_chain_to_wp_user = 'Registration.Event';
123
+		parent::__construct($timezone);
124
+
125
+	}
126
+
127
+
128
+	/**
129
+	 *    txn_status_array
130
+	 * get list of transaction statuses
131
+	 *
132
+	 * @access public
133
+	 * @return array
134
+	 */
135
+	public static function txn_status_array()
136
+	{
137
+		return apply_filters(
138
+			'FHEE__EEM_Transaction__txn_status_array',
139
+			array(
140
+				EEM_Transaction::overpaid_status_code,
141
+				EEM_Transaction::complete_status_code,
142
+				EEM_Transaction::incomplete_status_code,
143
+				EEM_Transaction::abandoned_status_code,
144
+				EEM_Transaction::failed_status_code,
145
+			)
146
+		);
147
+	}
148
+
149
+	/**
150
+	 *        get the revenue per day  for the Transaction Admin page Reports Tab
151
+	 *
152
+	 * @access        public
153
+	 *
154
+	 * @param string $period
155
+	 *
156
+	 * @return \stdClass[]
157
+	 */
158
+	public function get_revenue_per_day_report($period = '-1 month')
159
+	{
160
+		$sql_date = $this->convert_datetime_for_query('TXN_timestamp', date('Y-m-d H:i:s', strtotime($period)),
161
+			'Y-m-d H:i:s', 'UTC');
162
+
163
+		$query_interval = EEH_DTT_Helper::get_sql_query_interval_for_offset($this->get_timezone(), 'TXN_timestamp');
164
+
165
+		return $this->_get_all_wpdb_results(
166
+			array(
167
+				array(
168
+					'TXN_timestamp' => array('>=', $sql_date)
169
+				),
170
+				'group_by' => 'txnDate',
171
+				'order_by' => array('TXN_timestamp' => 'ASC')
172
+			),
173
+			OBJECT,
174
+			array(
175
+				'txnDate' => array('DATE(' . $query_interval . ')', '%s'),
176
+				'revenue' => array('SUM(TransactionTable.TXN_paid)', '%d')
177
+			)
178
+		);
179
+	}
180
+
181
+
182
+	/**
183
+	 *        get the revenue per event  for the Transaction Admin page Reports Tab
184
+	 *
185
+	 * @access        public
186
+	 *
187
+	 * @param string $period
188
+	 *
189
+	 * @throws \EE_Error
190
+	 * @return mixed
191
+	 */
192
+	public function get_revenue_per_event_report($period = '-1 month')
193
+	{
194
+		global $wpdb;
195
+		$transaction_table          = $wpdb->prefix . 'esp_transaction';
196
+		$registration_table         = $wpdb->prefix . 'esp_registration';
197
+		$registration_payment_table = $wpdb->prefix . 'esp_registration_payment';
198
+		$event_table                = $wpdb->posts;
199
+		$payment_table              = $wpdb->prefix . 'esp_payment';
200
+		$sql_date                   = date('Y-m-d H:i:s', strtotime($period));
201
+		$approved_payment_status    = EEM_Payment::status_id_approved;
202
+		$extra_event_on_join        = '';
203
+		//exclude events not authored by user if permissions in effect
204
+		if ( ! EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_event_report')) {
205
+			$extra_event_on_join = ' AND Event.post_author = ' . get_current_user_id();
206
+		}
207
+
208
+		return $wpdb->get_results(
209
+			"SELECT
210 210
 			Transaction_Event.event_name AS event_name,
211 211
 			SUM(Transaction_Event.paid) AS revenue
212 212
 			FROM
@@ -234,223 +234,223 @@  discard block
 block discarded – undo
234 234
 					$extra_event_on_join
235 235
 				) AS Transaction_Event
236 236
 			GROUP BY event_name",
237
-            OBJECT
238
-        );
239
-    }
240
-
241
-
242
-    /**
243
-     * Gets the current transaction given the reg_url_link, or assumes the reg_url_link is in the
244
-     * $_REQUEST global variable. Either way, tries to find the current transaction (through
245
-     * the registration pointed to by reg_url_link), if not returns null
246
-     *
247
-     * @param string $reg_url_link
248
-     *
249
-     * @return EE_Transaction
250
-     */
251
-    public function get_transaction_from_reg_url_link($reg_url_link = '')
252
-    {
253
-        return $this->get_one(array(
254
-            array(
255
-                'Registration.REG_url_link' => ! empty($reg_url_link) ? $reg_url_link : EE_Registry::instance()->REQ->get('e_reg_url_link',
256
-                    '')
257
-            )
258
-        ));
259
-    }
260
-
261
-
262
-    /**
263
-     * Updates the provided EE_Transaction with all the applicable payments
264
-     * (or fetch the EE_Transaction from its ID)
265
-     *
266
-     * @deprecated
267
-     *
268
-     * @param EE_Transaction|int $transaction_obj_or_id
269
-     * @param boolean            $save_txn whether or not to save the transaction during this function call
270
-     *
271
-     * @return boolean
272
-     * @throws \EE_Error
273
-     */
274
-    public function update_based_on_payments($transaction_obj_or_id, $save_txn = true)
275
-    {
276
-        EE_Error::doing_it_wrong(
277
-            __CLASS__ . '::' . __FUNCTION__,
278
-            sprintf(__('This method is deprecated. Please use "%s" instead', 'event_espresso'),
279
-                'EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()'),
280
-            '4.6.0'
281
-        );
282
-        /** @type EE_Transaction_Processor $transaction_processor */
283
-        $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
284
-
285
-        return $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment(
286
-            $this->ensure_is_obj($transaction_obj_or_id)
287
-        );
288
-    }
289
-
290
-    /**
291
-     * Deletes "junk" transactions that were probably added by bots. There might be TONS
292
-     * of these, so we are very careful to NOT select (which the models do even when deleting),
293
-     * and so we only use wpdb directly and only do minimal joins.
294
-     * Transactions are considered "junk" if they're failed for longer than a week.
295
-     * Also, there is an extra check for payments related to the transaction, because if a transaction has a payment on
296
-     * it, it's probably not junk (regardless of what status it has).
297
-     * The downside to this approach is that is addons are listening for object deletions
298
-     * on EEM_Base::delete() they won't be notified of this.  However, there is an action that plugins can hook into
299
-     * to catch these types of deletions.
300
-     *
301
-     * @global WPDB $wpdb
302
-     * @return mixed
303
-     */
304
-    public function delete_junk_transactions()
305
-    {
306
-        /** @type WPDB $wpdb */
307
-        global $wpdb;
308
-        $deleted             = false;
309
-        $time_to_leave_alone = apply_filters(
310
-            'FHEE__EEM_Transaction__delete_junk_transactions__time_to_leave_alone'
311
-            , WEEK_IN_SECONDS
312
-        );
313
-
314
-
315
-        /**
316
-         * This allows code to filter the query arguments used for retrieving the transaction IDs to delete.
317
-         * Useful for plugins that want to exclude transactions matching certain query parameters.
318
-         * The query parameters should be in the format accepted by the EEM_Base model queries.
319
-         */
320
-        $ids_query = apply_filters(
321
-            'FHEE__EEM_Transaction__delete_junk_transactions__initial_query_args',
322
-            array(
323
-                0 => array(
324
-                    'STS_ID'        => EEM_Transaction::failed_status_code,
325
-                    'Payment.PAY_ID' => array( 'IS NULL' ),
326
-                    'TXN_timestamp' => array('<', time() - $time_to_leave_alone)
327
-                )
328
-            ),
329
-            $time_to_leave_alone
330
-        );
331
-
332
-
333
-        /**
334
-         * This filter is for when code needs to filter the list of transaction ids that represent transactions
335
-         * about to be deleted based on some other criteria that isn't easily done via the query args filter.
336
-         */
337
-        $txn_ids = apply_filters(
338
-            'FHEE__EEM_Transaction__delete_junk_transactions__transaction_ids_to_delete',
339
-            EEM_Transaction::instance()->get_col($ids_query, 'TXN_ID'),
340
-            $time_to_leave_alone
341
-        );
342
-        //now that we have the ids to delete
343
-        if (! empty($txn_ids) && is_array($txn_ids)) {
344
-            // first, make sure these TXN's are removed the "ee_locked_transactions" array
345
-            EEM_Transaction::unset_locked_transactions($txn_ids);
346
-            // let's get deletin'...
347
-            // Why no wpdb->prepare?  Because the data is trusted.
348
-            // We got the ids from the original query to get them FROM
349
-            // the db (which is sanitized) so no need to prepare them again.
350
-            $query   = '
237
+			OBJECT
238
+		);
239
+	}
240
+
241
+
242
+	/**
243
+	 * Gets the current transaction given the reg_url_link, or assumes the reg_url_link is in the
244
+	 * $_REQUEST global variable. Either way, tries to find the current transaction (through
245
+	 * the registration pointed to by reg_url_link), if not returns null
246
+	 *
247
+	 * @param string $reg_url_link
248
+	 *
249
+	 * @return EE_Transaction
250
+	 */
251
+	public function get_transaction_from_reg_url_link($reg_url_link = '')
252
+	{
253
+		return $this->get_one(array(
254
+			array(
255
+				'Registration.REG_url_link' => ! empty($reg_url_link) ? $reg_url_link : EE_Registry::instance()->REQ->get('e_reg_url_link',
256
+					'')
257
+			)
258
+		));
259
+	}
260
+
261
+
262
+	/**
263
+	 * Updates the provided EE_Transaction with all the applicable payments
264
+	 * (or fetch the EE_Transaction from its ID)
265
+	 *
266
+	 * @deprecated
267
+	 *
268
+	 * @param EE_Transaction|int $transaction_obj_or_id
269
+	 * @param boolean            $save_txn whether or not to save the transaction during this function call
270
+	 *
271
+	 * @return boolean
272
+	 * @throws \EE_Error
273
+	 */
274
+	public function update_based_on_payments($transaction_obj_or_id, $save_txn = true)
275
+	{
276
+		EE_Error::doing_it_wrong(
277
+			__CLASS__ . '::' . __FUNCTION__,
278
+			sprintf(__('This method is deprecated. Please use "%s" instead', 'event_espresso'),
279
+				'EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()'),
280
+			'4.6.0'
281
+		);
282
+		/** @type EE_Transaction_Processor $transaction_processor */
283
+		$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
284
+
285
+		return $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment(
286
+			$this->ensure_is_obj($transaction_obj_or_id)
287
+		);
288
+	}
289
+
290
+	/**
291
+	 * Deletes "junk" transactions that were probably added by bots. There might be TONS
292
+	 * of these, so we are very careful to NOT select (which the models do even when deleting),
293
+	 * and so we only use wpdb directly and only do minimal joins.
294
+	 * Transactions are considered "junk" if they're failed for longer than a week.
295
+	 * Also, there is an extra check for payments related to the transaction, because if a transaction has a payment on
296
+	 * it, it's probably not junk (regardless of what status it has).
297
+	 * The downside to this approach is that is addons are listening for object deletions
298
+	 * on EEM_Base::delete() they won't be notified of this.  However, there is an action that plugins can hook into
299
+	 * to catch these types of deletions.
300
+	 *
301
+	 * @global WPDB $wpdb
302
+	 * @return mixed
303
+	 */
304
+	public function delete_junk_transactions()
305
+	{
306
+		/** @type WPDB $wpdb */
307
+		global $wpdb;
308
+		$deleted             = false;
309
+		$time_to_leave_alone = apply_filters(
310
+			'FHEE__EEM_Transaction__delete_junk_transactions__time_to_leave_alone'
311
+			, WEEK_IN_SECONDS
312
+		);
313
+
314
+
315
+		/**
316
+		 * This allows code to filter the query arguments used for retrieving the transaction IDs to delete.
317
+		 * Useful for plugins that want to exclude transactions matching certain query parameters.
318
+		 * The query parameters should be in the format accepted by the EEM_Base model queries.
319
+		 */
320
+		$ids_query = apply_filters(
321
+			'FHEE__EEM_Transaction__delete_junk_transactions__initial_query_args',
322
+			array(
323
+				0 => array(
324
+					'STS_ID'        => EEM_Transaction::failed_status_code,
325
+					'Payment.PAY_ID' => array( 'IS NULL' ),
326
+					'TXN_timestamp' => array('<', time() - $time_to_leave_alone)
327
+				)
328
+			),
329
+			$time_to_leave_alone
330
+		);
331
+
332
+
333
+		/**
334
+		 * This filter is for when code needs to filter the list of transaction ids that represent transactions
335
+		 * about to be deleted based on some other criteria that isn't easily done via the query args filter.
336
+		 */
337
+		$txn_ids = apply_filters(
338
+			'FHEE__EEM_Transaction__delete_junk_transactions__transaction_ids_to_delete',
339
+			EEM_Transaction::instance()->get_col($ids_query, 'TXN_ID'),
340
+			$time_to_leave_alone
341
+		);
342
+		//now that we have the ids to delete
343
+		if (! empty($txn_ids) && is_array($txn_ids)) {
344
+			// first, make sure these TXN's are removed the "ee_locked_transactions" array
345
+			EEM_Transaction::unset_locked_transactions($txn_ids);
346
+			// let's get deletin'...
347
+			// Why no wpdb->prepare?  Because the data is trusted.
348
+			// We got the ids from the original query to get them FROM
349
+			// the db (which is sanitized) so no need to prepare them again.
350
+			$query   = '
351 351
 				DELETE
352 352
 				FROM ' . $this->table() . '
353 353
 				WHERE
354 354
 					TXN_ID IN ( ' . implode(",", $txn_ids) . ')';
355
-            $deleted = $wpdb->query($query);
356
-        }
357
-        if ($deleted) {
358
-            /**
359
-             * Allows code to do something after the transactions have been deleted.
360
-             */
361
-            do_action('AHEE__EEM_Transaction__delete_junk_transactions__successful_deletion', $txn_ids);
362
-        }
363
-
364
-        return $deleted;
365
-    }
366
-
367
-
368
-    /**
369
-     * @param array $transaction_IDs
370
-     *
371
-     * @return bool
372
-     */
373
-    public static function unset_locked_transactions(array $transaction_IDs)
374
-    {
375
-        $locked_transactions = get_option('ee_locked_transactions', array());
376
-        $update              = false;
377
-        foreach ($transaction_IDs as $TXN_ID) {
378
-            if (isset($locked_transactions[$TXN_ID])) {
379
-                unset($locked_transactions[$TXN_ID]);
380
-                $update = true;
381
-            }
382
-        }
383
-        if ($update) {
384
-            update_option('ee_locked_transactions', $locked_transactions);
385
-        }
386
-
387
-        return $update;
388
-    }
389
-
390
-
391
-
392
-    /**
393
-     * returns an array of EE_Transaction objects whose timestamp is greater than
394
-     * the current time minus the session lifespan, which defaults to 60 minutes
395
-     *
396
-     * @return EE_Base_Class[]|EE_Transaction[]
397
-     * @throws EE_Error
398
-     * @throws InvalidArgumentException
399
-     * @throws InvalidDataTypeException
400
-     * @throws InvalidInterfaceException
401
-     */
402
-    public function get_transactions_in_progress()
403
-    {
404
-        return $this->_get_transactions_in_progress();
405
-    }
406
-
407
-
408
-
409
-    /**
410
-     * returns an array of EE_Transaction objects whose timestamp is less than
411
-     * the current time minus the session lifespan, which defaults to 60 minutes
412
-     *
413
-     * @return EE_Base_Class[]|EE_Transaction[]
414
-     * @throws EE_Error
415
-     * @throws InvalidArgumentException
416
-     * @throws InvalidDataTypeException
417
-     * @throws InvalidInterfaceException
418
-     */
419
-    public function get_transactions_not_in_progress()
420
-    {
421
-        return $this->_get_transactions_in_progress('<=');
422
-    }
423
-
424
-
425
-
426
-    /**
427
-     * @param string $comparison
428
-     * @return EE_Base_Class[]|EE_Transaction[]
429
-     * @throws EE_Error
430
-     * @throws InvalidArgumentException
431
-     * @throws InvalidDataTypeException
432
-     * @throws InvalidInterfaceException
433
-     */
434
-    private function _get_transactions_in_progress($comparison = '>=')
435
-    {
436
-        $comparison = $comparison === '>=' || $comparison === '<='
437
-            ? $comparison
438
-            : '>=';
439
-        return $this->get_all(
440
-            array(
441
-                array(
442
-                    'TXN_timestamp' => array(
443
-                        $comparison,
444
-                        time() - EE_Registry::instance()->SSN->lifespan()
445
-                    ),
446
-                    'STS_ID' => array(
447
-                        '!=',
448
-                        EEM_Transaction::complete_status_code
449
-                    ),
450
-                )
451
-            )
452
-        );
453
-    }
355
+			$deleted = $wpdb->query($query);
356
+		}
357
+		if ($deleted) {
358
+			/**
359
+			 * Allows code to do something after the transactions have been deleted.
360
+			 */
361
+			do_action('AHEE__EEM_Transaction__delete_junk_transactions__successful_deletion', $txn_ids);
362
+		}
363
+
364
+		return $deleted;
365
+	}
366
+
367
+
368
+	/**
369
+	 * @param array $transaction_IDs
370
+	 *
371
+	 * @return bool
372
+	 */
373
+	public static function unset_locked_transactions(array $transaction_IDs)
374
+	{
375
+		$locked_transactions = get_option('ee_locked_transactions', array());
376
+		$update              = false;
377
+		foreach ($transaction_IDs as $TXN_ID) {
378
+			if (isset($locked_transactions[$TXN_ID])) {
379
+				unset($locked_transactions[$TXN_ID]);
380
+				$update = true;
381
+			}
382
+		}
383
+		if ($update) {
384
+			update_option('ee_locked_transactions', $locked_transactions);
385
+		}
386
+
387
+		return $update;
388
+	}
389
+
390
+
391
+
392
+	/**
393
+	 * returns an array of EE_Transaction objects whose timestamp is greater than
394
+	 * the current time minus the session lifespan, which defaults to 60 minutes
395
+	 *
396
+	 * @return EE_Base_Class[]|EE_Transaction[]
397
+	 * @throws EE_Error
398
+	 * @throws InvalidArgumentException
399
+	 * @throws InvalidDataTypeException
400
+	 * @throws InvalidInterfaceException
401
+	 */
402
+	public function get_transactions_in_progress()
403
+	{
404
+		return $this->_get_transactions_in_progress();
405
+	}
406
+
407
+
408
+
409
+	/**
410
+	 * returns an array of EE_Transaction objects whose timestamp is less than
411
+	 * the current time minus the session lifespan, which defaults to 60 minutes
412
+	 *
413
+	 * @return EE_Base_Class[]|EE_Transaction[]
414
+	 * @throws EE_Error
415
+	 * @throws InvalidArgumentException
416
+	 * @throws InvalidDataTypeException
417
+	 * @throws InvalidInterfaceException
418
+	 */
419
+	public function get_transactions_not_in_progress()
420
+	{
421
+		return $this->_get_transactions_in_progress('<=');
422
+	}
423
+
424
+
425
+
426
+	/**
427
+	 * @param string $comparison
428
+	 * @return EE_Base_Class[]|EE_Transaction[]
429
+	 * @throws EE_Error
430
+	 * @throws InvalidArgumentException
431
+	 * @throws InvalidDataTypeException
432
+	 * @throws InvalidInterfaceException
433
+	 */
434
+	private function _get_transactions_in_progress($comparison = '>=')
435
+	{
436
+		$comparison = $comparison === '>=' || $comparison === '<='
437
+			? $comparison
438
+			: '>=';
439
+		return $this->get_all(
440
+			array(
441
+				array(
442
+					'TXN_timestamp' => array(
443
+						$comparison,
444
+						time() - EE_Registry::instance()->SSN->lifespan()
445
+					),
446
+					'STS_ID' => array(
447
+						'!=',
448
+						EEM_Transaction::complete_status_code
449
+					),
450
+				)
451
+			)
452
+		);
453
+	}
454 454
 
455 455
 
456 456
 }
Please login to merge, or discard this patch.
modules/ticket_sales_monitor/EED_Ticket_Sales_Monitor.module.php 2 patches
Indentation   +958 added lines, -958 removed lines patch added patch discarded remove patch
@@ -23,965 +23,965 @@
 block discarded – undo
23 23
 class EED_Ticket_Sales_Monitor extends EED_Module
24 24
 {
25 25
 
26
-    const debug = false;    //	true false
27
-
28
-    /**
29
-     * an array of raw ticket data from EED_Ticket_Selector
30
-     *
31
-     * @var array $ticket_selections
32
-     */
33
-    protected $ticket_selections = array();
34
-
35
-    /**
36
-     * the raw ticket data from EED_Ticket_Selector is organized in rows
37
-     * according to how they are displayed in the actual Ticket_Selector
38
-     * this tracks the current row being processed
39
-     *
40
-     * @var int $current_row
41
-     */
42
-    protected $current_row = 0;
43
-
44
-    /**
45
-     * an array for tracking names of tickets that have sold out
46
-     *
47
-     * @var array $sold_out_tickets
48
-     */
49
-    protected $sold_out_tickets = array();
50
-
51
-    /**
52
-     * an array for tracking names of tickets that have had their quantities reduced
53
-     *
54
-     * @var array $decremented_tickets
55
-     */
56
-    protected $decremented_tickets = array();
57
-
58
-
59
-
60
-    /**
61
-     * set_hooks - for hooking into EE Core, other modules, etc
62
-     *
63
-     * @return    void
64
-     */
65
-    public static function set_hooks()
66
-    {
67
-        // release tickets for expired carts
68
-        add_action(
69
-            'EED_Ticket_Selector__process_ticket_selections__before',
70
-            array('EED_Ticket_Sales_Monitor', 'release_tickets_for_expired_carts'),
71
-            1
72
-        );
73
-        // check ticket reserves AFTER MER does it's check (hence priority 20)
74
-        add_filter(
75
-            'FHEE__EE_Ticket_Selector___add_ticket_to_cart__ticket_qty',
76
-            array('EED_Ticket_Sales_Monitor', 'validate_ticket_sale'),
77
-            20,
78
-            3
79
-        );
80
-        // add notices for sold out tickets
81
-        add_action(
82
-            'AHEE__EE_Ticket_Selector__process_ticket_selections__after_tickets_added_to_cart',
83
-            array('EED_Ticket_Sales_Monitor', 'post_notices'),
84
-            10
85
-        );
86
-        // handle ticket quantities adjusted in cart
87
-        //add_action(
88
-        //	'FHEE__EED_Multi_Event_Registration__adjust_line_item_quantity__line_item_quantity_updated',
89
-        //	array( 'EED_Ticket_Sales_Monitor', 'ticket_quantity_updated' ),
90
-        //	10, 2
91
-        //);
92
-        // handle tickets deleted from cart
93
-        add_action(
94
-            'FHEE__EED_Multi_Event_Registration__delete_ticket__ticket_removed_from_cart',
95
-            array('EED_Ticket_Sales_Monitor', 'ticket_removed_from_cart'),
96
-            10,
97
-            2
98
-        );
99
-        // handle emptied carts
100
-        add_action(
101
-            'AHEE__EE_Session__reset_cart__before_reset',
102
-            array('EED_Ticket_Sales_Monitor', 'session_cart_reset'),
103
-            10,
104
-            1
105
-        );
106
-        add_action(
107
-            'AHEE__EED_Multi_Event_Registration__empty_event_cart__before_delete_cart',
108
-            array('EED_Ticket_Sales_Monitor', 'session_cart_reset'),
109
-            10,
110
-            1
111
-        );
112
-        // handle cancelled registrations
113
-        add_action(
114
-            'AHEE__EE_Session__reset_checkout__before_reset',
115
-            array('EED_Ticket_Sales_Monitor', 'session_checkout_reset'),
116
-            10,
117
-            1
118
-        );
119
-        // cron tasks
120
-        add_action(
121
-            'AHEE__EE_Cron_Tasks__process_expired_transactions__abandoned_transaction',
122
-            array('EED_Ticket_Sales_Monitor', 'process_abandoned_transactions'),
123
-            10,
124
-            1
125
-        );
126
-        add_action(
127
-            'AHEE__EE_Cron_Tasks__process_expired_transactions__incomplete_transaction',
128
-            array('EED_Ticket_Sales_Monitor', 'process_abandoned_transactions'),
129
-            10,
130
-            1
131
-        );
132
-        add_action(
133
-            'AHEE__EE_Cron_Tasks__process_expired_transactions__failed_transaction',
134
-            array('EED_Ticket_Sales_Monitor', 'process_failed_transactions'),
135
-            10,
136
-            1
137
-        );
138
-    }
139
-
140
-
141
-
142
-    /**
143
-     * set_hooks_admin - for hooking into EE Admin Core, other modules, etc
144
-     *
145
-     * @return void
146
-     */
147
-    public static function set_hooks_admin()
148
-    {
149
-        EED_Ticket_Sales_Monitor::set_hooks();
150
-    }
151
-
152
-
153
-
154
-    /**
155
-     * @return EED_Ticket_Sales_Monitor|EED_Module
156
-     */
157
-    public static function instance()
158
-    {
159
-        return parent::get_instance(__CLASS__);
160
-    }
161
-
162
-
163
-
164
-    /**
165
-     * @param WP_Query $WP_Query
166
-     * @return    void
167
-     */
168
-    public function run($WP_Query)
169
-    {
170
-    }
171
-
172
-
173
-
174
-    /********************************** PRE_TICKET_SALES  **********************************/
175
-
176
-
177
-
178
-    /**
179
-     * Retrieves grand totals from the line items that have no TXN ID
180
-     * and timestamps less than the current time minus the session lifespan.
181
-     * These are carts that have been abandoned before the "registrant" even attempted to checkout.
182
-     * We're going to release the tickets for these line items before attempting to add more to the cart.
183
-     *
184
-     * @return void
185
-     * @throws EE_Error
186
-     * @throws InvalidArgumentException
187
-     * @throws InvalidDataTypeException
188
-     * @throws InvalidInterfaceException
189
-     */
190
-    public static function release_tickets_for_expired_carts()
191
-    {
192
-        $expired_ticket_IDs      = array();
193
-        $valid_ticket_line_items = array();
194
-        $total_line_items        = EEM_Line_Item::instance()->get_total_line_items_with_no_transaction();
195
-        if (empty($total_line_items)) {
196
-            return;
197
-        }
198
-        $expired = current_time('timestamp') - EE_Registry::instance()->SSN->lifespan();
199
-        foreach ($total_line_items as $total_line_item) {
200
-            /** @var EE_Line_Item $total_line_item */
201
-            $ticket_line_items = EED_Ticket_Sales_Monitor::get_ticket_line_items_for_grand_total($total_line_item);
202
-            foreach ($ticket_line_items as $ticket_line_item) {
203
-                if (! $ticket_line_item instanceof EE_Line_Item) {
204
-                    continue;
205
-                }
206
-                if ($total_line_item->timestamp(true) <= $expired) {
207
-                    $expired_ticket_IDs[ $ticket_line_item->OBJ_ID() ] = $ticket_line_item->OBJ_ID();
208
-                } else {
209
-                    $valid_ticket_line_items[ $ticket_line_item->OBJ_ID() ] = $ticket_line_item;
210
-                }
211
-            }
212
-        }
213
-        if (! empty($expired_ticket_IDs)) {
214
-            EED_Ticket_Sales_Monitor::release_reservations_for_tickets(
215
-                \EEM_Ticket::instance()->get_tickets_with_IDs($expired_ticket_IDs),
216
-                $valid_ticket_line_items
217
-            );
218
-            // let's get rid of expired line items so that they can't interfere with tracking
219
-            add_action(
220
-                'shutdown',
221
-                array('EED_Ticket_Sales_Monitor', 'clear_expired_line_items_with_no_transaction'),
222
-                999
223
-            );
224
-        }
225
-    }
226
-
227
-
228
-
229
-    /********************************** VALIDATE_TICKET_SALE  **********************************/
230
-
231
-
232
-
233
-    /**
234
-     * callback for 'FHEE__EED_Ticket_Selector__process_ticket_selections__valid_post_data'
235
-     *
236
-     * @param int       $qty
237
-     * @param EE_Ticket $ticket
238
-     * @return bool
239
-     * @throws UnexpectedEntityException
240
-     * @throws EE_Error
241
-     */
242
-    public static function validate_ticket_sale($qty = 1, EE_Ticket $ticket)
243
-    {
244
-        $qty = absint($qty);
245
-        if ($qty > 0) {
246
-            $qty = EED_Ticket_Sales_Monitor::instance()->_validate_ticket_sale($ticket, $qty);
247
-        }
248
-        if (self::debug) {
249
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '()';
250
-            echo '<br /><br /><b> RETURNED QTY: ' . $qty . '</b>';
251
-        }
252
-        return $qty;
253
-    }
254
-
255
-
256
-
257
-    /**
258
-     * checks whether an individual ticket is available for purchase based on datetime, and ticket details
259
-     *
260
-     * @param   EE_Ticket $ticket
261
-     * @param int         $qty
262
-     * @return int
263
-     * @throws UnexpectedEntityException
264
-     * @throws EE_Error
265
-     */
266
-    protected function _validate_ticket_sale(EE_Ticket $ticket, $qty = 1)
267
-    {
268
-        if (self::debug) {
269
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
270
-        }
271
-        if (! $ticket instanceof EE_Ticket) {
272
-            return 0;
273
-        }
274
-        if (self::debug) {
275
-            echo '<br /><b> . ticket->ID: ' . $ticket->ID() . '</b>';
276
-            echo '<br /> . original ticket->reserved: ' . $ticket->reserved();
277
-        }
278
-        $ticket->refresh_from_db();
279
-        // first let's determine the ticket availability based on sales
280
-        $available = $ticket->qty('saleable');
281
-        if (self::debug) {
282
-            echo '<br /> . . . ticket->qty: ' . $ticket->qty();
283
-            echo '<br /> . . . ticket->sold: ' . $ticket->sold();
284
-            echo '<br /> . . . ticket->reserved: ' . $ticket->reserved();
285
-            echo '<br /> . . . ticket->qty(saleable): ' . $ticket->qty('saleable');
286
-            echo '<br /> . . . available: ' . $available;
287
-        }
288
-        if ($available < 1) {
289
-            $this->_ticket_sold_out($ticket);
290
-            return 0;
291
-        }
292
-        if (self::debug) {
293
-            echo '<br /> . . . qty: ' . $qty;
294
-        }
295
-        if ($available < $qty) {
296
-            $qty = $available;
297
-            if (self::debug) {
298
-                echo '<br /> . . . QTY ADJUSTED: ' . $qty;
299
-            }
300
-            $this->_ticket_quantity_decremented($ticket);
301
-        }
302
-        $this->_reserve_ticket($ticket, $qty);
303
-        return $qty;
304
-    }
305
-
306
-
307
-
308
-    /**
309
-     * increments ticket reserved based on quantity passed
310
-     *
311
-     * @param    EE_Ticket $ticket
312
-     * @param int          $quantity
313
-     * @return bool
314
-     * @throws EE_Error
315
-     */
316
-    protected function _reserve_ticket(EE_Ticket $ticket, $quantity = 1)
317
-    {
318
-        if (self::debug) {
319
-            echo '<br /><br /> . . . INCREASE RESERVED: ' . $quantity;
320
-        }
321
-        $ticket->increase_reserved($quantity);
322
-        return $ticket->save();
323
-    }
324
-
325
-
326
-
327
-    /**
328
-     * @param  EE_Ticket $ticket
329
-     * @param  int       $quantity
330
-     * @return bool
331
-     * @throws EE_Error
332
-     */
333
-    protected function _release_reserved_ticket(EE_Ticket $ticket, $quantity = 1)
334
-    {
335
-        if (self::debug) {
336
-            echo '<br /> . . . ticket->ID: ' . $ticket->ID();
337
-            echo '<br /> . . . ticket->reserved: ' . $ticket->reserved();
338
-        }
339
-        $ticket->decrease_reserved($quantity);
340
-        if (self::debug) {
341
-            echo '<br /> . . . ticket->reserved: ' . $ticket->reserved();
342
-        }
343
-        return $ticket->save() ? 1 : 0;
344
-    }
345
-
346
-
347
-
348
-    /**
349
-     * removes quantities within the ticket selector based on zero ticket availability
350
-     *
351
-     * @param    EE_Ticket $ticket
352
-     * @return    void
353
-     * @throws UnexpectedEntityException
354
-     * @throws EE_Error
355
-     */
356
-    protected function _ticket_sold_out(EE_Ticket $ticket)
357
-    {
358
-        if (self::debug) {
359
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
360
-            echo '<br /> . . ticket->name: ' . $this->_get_ticket_and_event_name($ticket);
361
-        }
362
-        $this->sold_out_tickets[] = $this->_get_ticket_and_event_name($ticket);
363
-    }
364
-
365
-
366
-
367
-    /**
368
-     * adjusts quantities within the ticket selector based on decreased ticket availability
369
-     *
370
-     * @param    EE_Ticket $ticket
371
-     * @return void
372
-     * @throws UnexpectedEntityException
373
-     * @throws EE_Error
374
-     */
375
-    protected function _ticket_quantity_decremented(EE_Ticket $ticket)
376
-    {
377
-        if (self::debug) {
378
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
379
-            echo '<br /> . . ticket->name: ' . $this->_get_ticket_and_event_name($ticket);
380
-        }
381
-        $this->decremented_tickets[] = $this->_get_ticket_and_event_name($ticket);
382
-    }
383
-
384
-
385
-
386
-    /**
387
-     * builds string out of ticket and event name
388
-     *
389
-     * @param    EE_Ticket $ticket
390
-     * @return string
391
-     * @throws UnexpectedEntityException
392
-     * @throws EE_Error
393
-     */
394
-    protected function _get_ticket_and_event_name(EE_Ticket $ticket)
395
-    {
396
-        $event = $ticket->get_related_event();
397
-        if ($event instanceof EE_Event) {
398
-            $ticket_name = sprintf(
399
-                _x('%1$s for %2$s', 'ticket name for event name', 'event_espresso'),
400
-                $ticket->name(),
401
-                $event->name()
402
-            );
403
-        } else {
404
-            $ticket_name = $ticket->name();
405
-        }
406
-        return $ticket_name;
407
-    }
408
-
409
-
410
-
411
-    /********************************** EVENT CART  **********************************/
412
-
413
-
414
-
415
-    /**
416
-     * releases or reserves ticket(s) based on quantity passed
417
-     *
418
-     * @param  EE_Line_Item $line_item
419
-     * @param  int          $quantity
420
-     * @return void
421
-     * @throws EE_Error
422
-     * @throws InvalidArgumentException
423
-     * @throws InvalidDataTypeException
424
-     * @throws InvalidInterfaceException
425
-     */
426
-    public static function ticket_quantity_updated(EE_Line_Item $line_item, $quantity = 1)
427
-    {
428
-        $ticket = EEM_Ticket::instance()->get_one_by_ID(absint($line_item->OBJ_ID()));
429
-        if ($ticket instanceof EE_Ticket) {
430
-            if ($quantity > 0) {
431
-                EED_Ticket_Sales_Monitor::instance()->_reserve_ticket($ticket, $quantity);
432
-            } else {
433
-                EED_Ticket_Sales_Monitor::instance()->_release_reserved_ticket($ticket, $quantity);
434
-            }
435
-        }
436
-    }
437
-
438
-
439
-
440
-    /**
441
-     * releases reserved ticket(s) based on quantity passed
442
-     *
443
-     * @param  EE_Ticket $ticket
444
-     * @param  int       $quantity
445
-     * @return void
446
-     * @throws EE_Error
447
-     */
448
-    public static function ticket_removed_from_cart(EE_Ticket $ticket, $quantity = 1)
449
-    {
450
-        EED_Ticket_Sales_Monitor::instance()->_release_reserved_ticket($ticket, $quantity);
451
-    }
452
-
453
-
454
-
455
-    /********************************** POST_NOTICES  **********************************/
456
-
457
-
458
-
459
-    /**
460
-     * @return void
461
-     * @throws EE_Error
462
-     * @throws InvalidArgumentException
463
-     * @throws ReflectionException
464
-     * @throws InvalidDataTypeException
465
-     * @throws InvalidInterfaceException
466
-     */
467
-    public static function post_notices()
468
-    {
469
-        EED_Ticket_Sales_Monitor::instance()->_post_notices();
470
-    }
471
-
472
-
473
-
474
-    /**
475
-     * @return void
476
-     * @throws EE_Error
477
-     * @throws InvalidArgumentException
478
-     * @throws ReflectionException
479
-     * @throws InvalidDataTypeException
480
-     * @throws InvalidInterfaceException
481
-     */
482
-    protected function _post_notices()
483
-    {
484
-        if (self::debug) {
485
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
486
-        }
487
-        $refresh_msg    = '';
488
-        $none_added_msg = '';
489
-        if (defined('DOING_AJAX') && DOING_AJAX) {
490
-            $refresh_msg    = __(
491
-                'Please refresh the page to view updated ticket quantities.',
492
-                'event_espresso'
493
-            );
494
-            $none_added_msg = __('No tickets were added for the event.', 'event_espresso');
495
-        }
496
-        if (! empty($this->sold_out_tickets)) {
497
-            EE_Error::add_attention(
498
-                sprintf(
499
-                    apply_filters(
500
-                        'FHEE__EED_Ticket_Sales_Monitor___post_notices__sold_out_tickets_notice',
501
-                        __(
502
-                            'We\'re sorry...%1$sThe following items have sold out since you first viewed this page, and can no longer be registered for:%1$s%1$s%2$s%1$s%1$sPlease note that availability can change at any time due to cancellations, so please check back again later if registration for this event(s) is important to you.%1$s%1$s%3$s%1$s%4$s%1$s',
503
-                            'event_espresso'
504
-                        )
505
-                    ),
506
-                    '<br />',
507
-                    implode('<br />', $this->sold_out_tickets),
508
-                    $none_added_msg,
509
-                    $refresh_msg
510
-                )
511
-            );
512
-            // alter code flow in the Ticket Selector for better UX
513
-            add_filter('FHEE__EED_Ticket_Selector__process_ticket_selections__tckts_slctd', '__return_true');
514
-            add_filter('FHEE__EED_Ticket_Selector__process_ticket_selections__success', '__return_false');
515
-            $this->sold_out_tickets = array();
516
-            // and reset the cart
517
-            EED_Ticket_Sales_Monitor::session_cart_reset(EE_Registry::instance()->SSN);
518
-        }
519
-        if (! empty($this->decremented_tickets)) {
520
-            EE_Error::add_attention(
521
-                sprintf(
522
-                    apply_filters(
523
-                        'FHEE__EED_Ticket_Sales_Monitor___ticket_quantity_decremented__notice',
524
-                        __(
525
-                            'We\'re sorry...%1$sDue to sales that have occurred since you first viewed the last page, the following items have had their quantities adjusted to match the current available amount:%1$s%1$s%2$s%1$s%1$sPlease note that availability can change at any time due to cancellations, so please check back again later if registration for this event(s) is important to you.%1$s%1$s%3$s%1$s%4$s%1$s',
526
-                            'event_espresso'
527
-                        )
528
-                    ),
529
-                    '<br />',
530
-                    implode('<br />', $this->decremented_tickets),
531
-                    $none_added_msg,
532
-                    $refresh_msg
533
-                )
534
-            );
535
-            $this->decremented_tickets = array();
536
-        }
537
-    }
538
-
539
-
540
-
541
-    /********************************** RELEASE_ALL_RESERVED_TICKETS_FOR_TRANSACTION  **********************************/
542
-
543
-
544
-
545
-    /**
546
-     * releases reserved tickets for all registrations of an EE_Transaction
547
-     * by default, will NOT release tickets for finalized transactions
548
-     *
549
-     * @param    EE_Transaction $transaction
550
-     * @return int
551
-     * @throws EE_Error
552
-     * @throws InvalidSessionDataException
553
-     */
554
-    protected function _release_all_reserved_tickets_for_transaction(EE_Transaction $transaction)
555
-    {
556
-        if (self::debug) {
557
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
558
-            echo '<br /> . transaction->ID: ' . $transaction->ID();
559
-        }
560
-        // check if 'finalize_registration' step has been completed...
561
-        $finalized = $transaction->reg_step_completed('finalize_registration');
562
-        if (self::debug) {
563
-            // DEBUG LOG
564
-            EEH_Debug_Tools::log(
565
-                __CLASS__,
566
-                __FUNCTION__,
567
-                __LINE__,
568
-                array('finalized' => $finalized),
569
-                false,
570
-                'EE_Transaction: ' . $transaction->ID()
571
-            );
572
-        }
573
-        // how many tickets were released
574
-        $count = 0;
575
-        if (self::debug) {
576
-            echo '<br /> . . . finalized: ' . $finalized;
577
-        }
578
-        $release_tickets_with_TXN_status = array(
579
-            EEM_Transaction::failed_status_code,
580
-            EEM_Transaction::abandoned_status_code,
581
-            EEM_Transaction::incomplete_status_code,
582
-        );
583
-        // if the session is getting cleared BEFORE the TXN has been finalized
584
-        if (! $finalized || in_array($transaction->status_ID(), $release_tickets_with_TXN_status, true)) {
585
-            // let's cancel any reserved tickets
586
-            $registrations = $transaction->registrations();
587
-            if (! empty($registrations)) {
588
-                foreach ($registrations as $registration) {
589
-                    if ($registration instanceof EE_Registration) {
590
-                        $count += $this->_release_reserved_ticket_for_registration($registration, $transaction);
591
-                    }
592
-                }
593
-            }
594
-        }
595
-        return $count;
596
-    }
597
-
598
-
599
-
600
-    /**
601
-     * releases reserved tickets for an EE_Registration
602
-     * by default, will NOT release tickets for APPROVED registrations
603
-     *
604
-     * @param EE_Registration $registration
605
-     * @param EE_Transaction  $transaction
606
-     * @return int
607
-     * @throws EE_Error
608
-     */
609
-    protected function _release_reserved_ticket_for_registration(
610
-        EE_Registration $registration,
611
-        EE_Transaction $transaction
612
-    ) {
613
-        $STS_ID = $transaction->status_ID();
614
-        if (self::debug) {
615
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
616
-            echo '<br /> . . registration->ID: ' . $registration->ID();
617
-            echo '<br /> . . registration->status_ID: ' . $registration->status_ID();
618
-            echo '<br /> . . transaction->status_ID(): ' . $STS_ID;
619
-        }
620
-        if (
621
-            // release Tickets for Failed Transactions and Abandoned Transactions
622
-            $STS_ID === EEM_Transaction::failed_status_code
623
-            || $STS_ID === EEM_Transaction::abandoned_status_code
624
-            || (
625
-                // also release Tickets for Incomplete Transactions, but ONLY if the Registrations are NOT Approved
626
-                $STS_ID === EEM_Transaction::incomplete_status_code
627
-                && $registration->status_ID() !== EEM_Registration::status_id_approved
628
-            )
629
-        ) {
630
-            $ticket = $registration->ticket();
631
-            if ($ticket instanceof EE_Ticket) {
632
-                return $this->_release_reserved_ticket($ticket);
633
-            }
634
-        }
635
-        return 0;
636
-    }
637
-
638
-
639
-
640
-    /********************************** SESSION_CART_RESET  **********************************/
641
-
642
-
643
-
644
-    /**
645
-     * callback hooked into 'AHEE__EE_Session__reset_cart__before_reset'
646
-     *
647
-     * @param EE_Session $session
648
-     * @return void
649
-     * @throws EE_Error
650
-     * @throws InvalidArgumentException
651
-     * @throws ReflectionException
652
-     * @throws InvalidDataTypeException
653
-     * @throws InvalidInterfaceException
654
-     */
655
-    public static function session_cart_reset(EE_Session $session)
656
-    {
657
-        if (self::debug) {
658
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
659
-        }
660
-        $cart = $session->cart();
661
-        if ($cart instanceof EE_Cart) {
662
-            if (self::debug) {
663
-                echo '<br /><br /> cart instance of EE_Cart: ';
664
-            }
665
-            EED_Ticket_Sales_Monitor::instance()->_session_cart_reset($cart);
666
-        } else {
667
-            if (self::debug) {
668
-                echo '<br /><br /> invalid EE_Cart: ';
669
-                var_export($cart, true);
670
-            }
671
-        }
672
-    }
673
-
674
-
675
-
676
-    /**
677
-     * releases reserved tickets in the EE_Cart
678
-     *
679
-     * @param EE_Cart $cart
680
-     * @return void
681
-     * @throws EE_Error
682
-     * @throws InvalidArgumentException
683
-     * @throws ReflectionException
684
-     * @throws InvalidDataTypeException
685
-     * @throws InvalidInterfaceException
686
-     */
687
-    protected function _session_cart_reset(EE_Cart $cart)
688
-    {
689
-        if (self::debug) {
690
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
691
-        }
692
-        EE_Registry::instance()->load_helper('Line_Item');
693
-        $ticket_line_items = $cart->get_tickets();
694
-        if (empty($ticket_line_items)) {
695
-            return;
696
-        }
697
-        foreach ($ticket_line_items as $ticket_line_item) {
698
-            if (self::debug) {
699
-                echo '<br /> . ticket_line_item->ID(): ' . $ticket_line_item->ID();
700
-            }
701
-            if ($ticket_line_item instanceof EE_Line_Item && $ticket_line_item->OBJ_type() === 'Ticket') {
702
-                if (self::debug) {
703
-                    echo '<br /> . . ticket_line_item->OBJ_ID(): ' . $ticket_line_item->OBJ_ID();
704
-                }
705
-                $ticket = EEM_Ticket::instance()->get_one_by_ID($ticket_line_item->OBJ_ID());
706
-                if ($ticket instanceof EE_Ticket) {
707
-                    if (self::debug) {
708
-                        echo '<br /> . . ticket->ID(): ' . $ticket->ID();
709
-                        echo '<br /> . . ticket_line_item->quantity(): ' . $ticket_line_item->quantity();
710
-                    }
711
-                    $this->_release_reserved_ticket($ticket, $ticket_line_item->quantity());
712
-                }
713
-            }
714
-        }
715
-        if (self::debug) {
716
-            echo '<br /><br /> RESET COMPLETED ';
717
-        }
718
-    }
719
-
720
-
721
-
722
-    /********************************** SESSION_CHECKOUT_RESET  **********************************/
723
-
724
-
725
-
726
-    /**
727
-     * callback hooked into 'AHEE__EE_Session__reset_checkout__before_reset'
728
-     *
729
-     * @param EE_Session $session
730
-     * @return void
731
-     * @throws EE_Error
732
-     * @throws InvalidSessionDataException
733
-     */
734
-    public static function session_checkout_reset(EE_Session $session)
735
-    {
736
-        $checkout = $session->checkout();
737
-        if ($checkout instanceof EE_Checkout) {
738
-            EED_Ticket_Sales_Monitor::instance()->_session_checkout_reset($checkout);
739
-        }
740
-    }
741
-
742
-
743
-
744
-    /**
745
-     * releases reserved tickets for the EE_Checkout->transaction
746
-     *
747
-     * @param EE_Checkout $checkout
748
-     * @return void
749
-     * @throws EE_Error
750
-     * @throws InvalidSessionDataException
751
-     */
752
-    protected function _session_checkout_reset(EE_Checkout $checkout)
753
-    {
754
-        if (self::debug) {
755
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
756
-        }
757
-        // we want to release the each registration's reserved tickets if the session was cleared, but not if this is a revisit
758
-        if ($checkout->revisit || ! $checkout->transaction instanceof EE_Transaction) {
759
-            return;
760
-        }
761
-        $this->_release_all_reserved_tickets_for_transaction($checkout->transaction);
762
-    }
763
-
764
-
765
-
766
-    /********************************** SESSION_EXPIRED_RESET  **********************************/
767
-
768
-
769
-
770
-    /**
771
-     * @param    EE_Session $session
772
-     * @return    void
773
-     */
774
-    public static function session_expired_reset(EE_Session $session)
775
-    {
776
-    }
777
-
778
-
779
-
780
-    /********************************** PROCESS_ABANDONED_TRANSACTIONS  **********************************/
781
-
782
-
783
-
784
-    /**
785
-     * releases reserved tickets for all registrations of an ABANDONED EE_Transaction
786
-     * by default, will NOT release tickets for free transactions, or any that have received a payment
787
-     *
788
-     * @param EE_Transaction $transaction
789
-     * @return void
790
-     * @throws EE_Error
791
-     * @throws InvalidSessionDataException
792
-     */
793
-    public static function process_abandoned_transactions(EE_Transaction $transaction)
794
-    {
795
-        // is this TXN free or has any money been paid towards this TXN? If so, then leave it alone
796
-        if ($transaction->is_free() || $transaction->paid() > 0) {
797
-            if (self::debug) {
798
-                // DEBUG LOG
799
-                EEH_Debug_Tools::log(
800
-                    __CLASS__,
801
-                    __FUNCTION__,
802
-                    __LINE__,
803
-                    array($transaction),
804
-                    false,
805
-                    'EE_Transaction: ' . $transaction->ID()
806
-                );
807
-            }
808
-            return;
809
-        }
810
-        // have their been any successful payments made ?
811
-        $payments = $transaction->payments();
812
-        foreach ($payments as $payment) {
813
-            if ($payment instanceof EE_Payment && $payment->status() === EEM_Payment::status_id_approved) {
814
-                if (self::debug) {
815
-                    // DEBUG LOG
816
-                    EEH_Debug_Tools::log(
817
-                        __CLASS__,
818
-                        __FUNCTION__,
819
-                        __LINE__,
820
-                        array($payment),
821
-                        false,
822
-                        'EE_Transaction: ' . $transaction->ID()
823
-                    );
824
-                }
825
-                return;
826
-            }
827
-        }
828
-        // since you haven't even attempted to pay for your ticket...
829
-        EED_Ticket_Sales_Monitor::instance()->_release_all_reserved_tickets_for_transaction($transaction);
830
-    }
831
-
832
-
833
-
834
-    /********************************** PROCESS_FAILED_TRANSACTIONS  **********************************/
835
-
836
-
837
-
838
-    /**
839
-     * releases reserved tickets for absolutely ALL registrations of a FAILED EE_Transaction
840
-     *
841
-     * @param EE_Transaction $transaction
842
-     * @return void
843
-     * @throws EE_Error
844
-     * @throws InvalidSessionDataException
845
-     */
846
-    public static function process_failed_transactions(EE_Transaction $transaction)
847
-    {
848
-        // since you haven't even attempted to pay for your ticket...
849
-        EED_Ticket_Sales_Monitor::instance()->_release_all_reserved_tickets_for_transaction($transaction);
850
-    }
851
-
852
-
853
-
854
-    /********************************** RESET RESERVATION COUNTS  *********************************/
855
-
856
-
857
-
858
-    /**
859
-     * Resets all ticket and datetime reserved counts to zero
860
-     * Tickets that are currently associated with a Transaction that is in progress
861
-     *
862
-     * @throws EE_Error
863
-     * @throws DomainException
864
-     * @throws InvalidDataTypeException
865
-     * @throws InvalidInterfaceException
866
-     * @throws InvalidArgumentException
867
-     */
868
-    public static function reset_reservation_counts()
869
-    {
870
-        /** @var EE_Line_Item[] $valid_reserved_tickets */
871
-        $valid_reserved_tickets = array();
872
-        /** @var EE_Transaction[] $transactions_not_in_progress */
873
-        $transactions_not_in_progress = EEM_Transaction::instance()->get_transactions_not_in_progress();
874
-        foreach ($transactions_not_in_progress as $transaction) {
875
-            // if this TXN has been fully completed, then skip it
876
-            if ($transaction->reg_step_completed('finalize_registration')) {
877
-                continue;
878
-            }
879
-            $total_line_item = $transaction->total_line_item();
880
-            // $transaction_in_progress->line
881
-            if (! $total_line_item instanceof EE_Line_Item) {
882
-                throw new DomainException(
883
-                    esc_html__(
884
-                        'Transaction does not have a valid Total Line Item associated with it.',
885
-                        'event_espresso'
886
-                    )
887
-                );
888
-            }
889
-            $valid_reserved_tickets += EED_Ticket_Sales_Monitor::get_ticket_line_items_for_grand_total(
890
-                $total_line_item
891
-            );
892
-        }
893
-        $total_line_items = EEM_Line_Item::instance()->get_total_line_items_for_active_carts();
894
-        foreach ($total_line_items as $total_line_item) {
895
-            $valid_reserved_tickets += EED_Ticket_Sales_Monitor::get_ticket_line_items_for_grand_total(
896
-                $total_line_item
897
-            );
898
-        }
899
-        return EED_Ticket_Sales_Monitor::release_reservations_for_tickets(
900
-            EEM_Ticket::instance()->get_tickets_with_reservations(),
901
-            $valid_reserved_tickets
902
-        );
903
-    }
904
-
905
-
906
-
907
-    /**
908
-     * @param EE_Line_Item $total_line_item
909
-     * @return EE_Line_Item[]
910
-     */
911
-    private static function get_ticket_line_items_for_grand_total(EE_Line_Item $total_line_item)
912
-    {
913
-        /** @var EE_Line_Item[] $valid_reserved_tickets */
914
-        $valid_reserved_tickets = array();
915
-        $ticket_line_items      = EEH_Line_Item::get_ticket_line_items($total_line_item);
916
-        foreach ($ticket_line_items as $ticket_line_item) {
917
-            if ($ticket_line_item instanceof EE_Line_Item) {
918
-                $valid_reserved_tickets[] = $ticket_line_item;
919
-            }
920
-        }
921
-        return $valid_reserved_tickets;
922
-    }
923
-
924
-
925
-
926
-    /**
927
-     * @param EE_Ticket[]    $tickets_with_reservations
928
-     * @param EE_Line_Item[] $valid_reserved_ticket_line_items
929
-     * @return int
930
-     * @throws EE_Error
931
-     */
932
-    private static function release_reservations_for_tickets(
933
-        array $tickets_with_reservations,
934
-        array $valid_reserved_ticket_line_items = array()
935
-    ) {
936
-        $total_tickets_released = 0;
937
-        foreach ($tickets_with_reservations as $ticket_with_reservations) {
938
-            if (! $ticket_with_reservations instanceof EE_Ticket) {
939
-                continue;
940
-            }
941
-            $reserved_qty = $ticket_with_reservations->reserved();
942
-            foreach ($valid_reserved_ticket_line_items as $valid_reserved_ticket_line_item) {
943
-                if (
944
-                    $valid_reserved_ticket_line_item instanceof EE_Line_Item
945
-                    && $valid_reserved_ticket_line_item->OBJ_ID() === $ticket_with_reservations->ID()
946
-                ) {
947
-                    $reserved_qty -= $valid_reserved_ticket_line_item->quantity();
948
-                }
949
-            }
950
-            if ($reserved_qty > 0) {
951
-                $ticket_with_reservations->decrease_reserved($reserved_qty);
952
-                $ticket_with_reservations->save();
953
-                $total_tickets_released += $reserved_qty;
954
-            }
955
-        }
956
-        return $total_tickets_released;
957
-    }
958
-
959
-
960
-
961
-    /********************************** SHUTDOWN  **********************************/
962
-
963
-
964
-
965
-    /**
966
-     * @return false|int
967
-     * @throws EE_Error
968
-     * @throws InvalidArgumentException
969
-     * @throws InvalidDataTypeException
970
-     * @throws InvalidInterfaceException
971
-     */
972
-    public static function clear_expired_line_items_with_no_transaction()
973
-    {
974
-        /** @type WPDB $wpdb */
975
-        global $wpdb;
976
-        return $wpdb->query(
977
-            $wpdb->prepare(
978
-                'DELETE FROM ' . EEM_Line_Item::instance()->table() . '
26
+	const debug = false;    //	true false
27
+
28
+	/**
29
+	 * an array of raw ticket data from EED_Ticket_Selector
30
+	 *
31
+	 * @var array $ticket_selections
32
+	 */
33
+	protected $ticket_selections = array();
34
+
35
+	/**
36
+	 * the raw ticket data from EED_Ticket_Selector is organized in rows
37
+	 * according to how they are displayed in the actual Ticket_Selector
38
+	 * this tracks the current row being processed
39
+	 *
40
+	 * @var int $current_row
41
+	 */
42
+	protected $current_row = 0;
43
+
44
+	/**
45
+	 * an array for tracking names of tickets that have sold out
46
+	 *
47
+	 * @var array $sold_out_tickets
48
+	 */
49
+	protected $sold_out_tickets = array();
50
+
51
+	/**
52
+	 * an array for tracking names of tickets that have had their quantities reduced
53
+	 *
54
+	 * @var array $decremented_tickets
55
+	 */
56
+	protected $decremented_tickets = array();
57
+
58
+
59
+
60
+	/**
61
+	 * set_hooks - for hooking into EE Core, other modules, etc
62
+	 *
63
+	 * @return    void
64
+	 */
65
+	public static function set_hooks()
66
+	{
67
+		// release tickets for expired carts
68
+		add_action(
69
+			'EED_Ticket_Selector__process_ticket_selections__before',
70
+			array('EED_Ticket_Sales_Monitor', 'release_tickets_for_expired_carts'),
71
+			1
72
+		);
73
+		// check ticket reserves AFTER MER does it's check (hence priority 20)
74
+		add_filter(
75
+			'FHEE__EE_Ticket_Selector___add_ticket_to_cart__ticket_qty',
76
+			array('EED_Ticket_Sales_Monitor', 'validate_ticket_sale'),
77
+			20,
78
+			3
79
+		);
80
+		// add notices for sold out tickets
81
+		add_action(
82
+			'AHEE__EE_Ticket_Selector__process_ticket_selections__after_tickets_added_to_cart',
83
+			array('EED_Ticket_Sales_Monitor', 'post_notices'),
84
+			10
85
+		);
86
+		// handle ticket quantities adjusted in cart
87
+		//add_action(
88
+		//	'FHEE__EED_Multi_Event_Registration__adjust_line_item_quantity__line_item_quantity_updated',
89
+		//	array( 'EED_Ticket_Sales_Monitor', 'ticket_quantity_updated' ),
90
+		//	10, 2
91
+		//);
92
+		// handle tickets deleted from cart
93
+		add_action(
94
+			'FHEE__EED_Multi_Event_Registration__delete_ticket__ticket_removed_from_cart',
95
+			array('EED_Ticket_Sales_Monitor', 'ticket_removed_from_cart'),
96
+			10,
97
+			2
98
+		);
99
+		// handle emptied carts
100
+		add_action(
101
+			'AHEE__EE_Session__reset_cart__before_reset',
102
+			array('EED_Ticket_Sales_Monitor', 'session_cart_reset'),
103
+			10,
104
+			1
105
+		);
106
+		add_action(
107
+			'AHEE__EED_Multi_Event_Registration__empty_event_cart__before_delete_cart',
108
+			array('EED_Ticket_Sales_Monitor', 'session_cart_reset'),
109
+			10,
110
+			1
111
+		);
112
+		// handle cancelled registrations
113
+		add_action(
114
+			'AHEE__EE_Session__reset_checkout__before_reset',
115
+			array('EED_Ticket_Sales_Monitor', 'session_checkout_reset'),
116
+			10,
117
+			1
118
+		);
119
+		// cron tasks
120
+		add_action(
121
+			'AHEE__EE_Cron_Tasks__process_expired_transactions__abandoned_transaction',
122
+			array('EED_Ticket_Sales_Monitor', 'process_abandoned_transactions'),
123
+			10,
124
+			1
125
+		);
126
+		add_action(
127
+			'AHEE__EE_Cron_Tasks__process_expired_transactions__incomplete_transaction',
128
+			array('EED_Ticket_Sales_Monitor', 'process_abandoned_transactions'),
129
+			10,
130
+			1
131
+		);
132
+		add_action(
133
+			'AHEE__EE_Cron_Tasks__process_expired_transactions__failed_transaction',
134
+			array('EED_Ticket_Sales_Monitor', 'process_failed_transactions'),
135
+			10,
136
+			1
137
+		);
138
+	}
139
+
140
+
141
+
142
+	/**
143
+	 * set_hooks_admin - for hooking into EE Admin Core, other modules, etc
144
+	 *
145
+	 * @return void
146
+	 */
147
+	public static function set_hooks_admin()
148
+	{
149
+		EED_Ticket_Sales_Monitor::set_hooks();
150
+	}
151
+
152
+
153
+
154
+	/**
155
+	 * @return EED_Ticket_Sales_Monitor|EED_Module
156
+	 */
157
+	public static function instance()
158
+	{
159
+		return parent::get_instance(__CLASS__);
160
+	}
161
+
162
+
163
+
164
+	/**
165
+	 * @param WP_Query $WP_Query
166
+	 * @return    void
167
+	 */
168
+	public function run($WP_Query)
169
+	{
170
+	}
171
+
172
+
173
+
174
+	/********************************** PRE_TICKET_SALES  **********************************/
175
+
176
+
177
+
178
+	/**
179
+	 * Retrieves grand totals from the line items that have no TXN ID
180
+	 * and timestamps less than the current time minus the session lifespan.
181
+	 * These are carts that have been abandoned before the "registrant" even attempted to checkout.
182
+	 * We're going to release the tickets for these line items before attempting to add more to the cart.
183
+	 *
184
+	 * @return void
185
+	 * @throws EE_Error
186
+	 * @throws InvalidArgumentException
187
+	 * @throws InvalidDataTypeException
188
+	 * @throws InvalidInterfaceException
189
+	 */
190
+	public static function release_tickets_for_expired_carts()
191
+	{
192
+		$expired_ticket_IDs      = array();
193
+		$valid_ticket_line_items = array();
194
+		$total_line_items        = EEM_Line_Item::instance()->get_total_line_items_with_no_transaction();
195
+		if (empty($total_line_items)) {
196
+			return;
197
+		}
198
+		$expired = current_time('timestamp') - EE_Registry::instance()->SSN->lifespan();
199
+		foreach ($total_line_items as $total_line_item) {
200
+			/** @var EE_Line_Item $total_line_item */
201
+			$ticket_line_items = EED_Ticket_Sales_Monitor::get_ticket_line_items_for_grand_total($total_line_item);
202
+			foreach ($ticket_line_items as $ticket_line_item) {
203
+				if (! $ticket_line_item instanceof EE_Line_Item) {
204
+					continue;
205
+				}
206
+				if ($total_line_item->timestamp(true) <= $expired) {
207
+					$expired_ticket_IDs[ $ticket_line_item->OBJ_ID() ] = $ticket_line_item->OBJ_ID();
208
+				} else {
209
+					$valid_ticket_line_items[ $ticket_line_item->OBJ_ID() ] = $ticket_line_item;
210
+				}
211
+			}
212
+		}
213
+		if (! empty($expired_ticket_IDs)) {
214
+			EED_Ticket_Sales_Monitor::release_reservations_for_tickets(
215
+				\EEM_Ticket::instance()->get_tickets_with_IDs($expired_ticket_IDs),
216
+				$valid_ticket_line_items
217
+			);
218
+			// let's get rid of expired line items so that they can't interfere with tracking
219
+			add_action(
220
+				'shutdown',
221
+				array('EED_Ticket_Sales_Monitor', 'clear_expired_line_items_with_no_transaction'),
222
+				999
223
+			);
224
+		}
225
+	}
226
+
227
+
228
+
229
+	/********************************** VALIDATE_TICKET_SALE  **********************************/
230
+
231
+
232
+
233
+	/**
234
+	 * callback for 'FHEE__EED_Ticket_Selector__process_ticket_selections__valid_post_data'
235
+	 *
236
+	 * @param int       $qty
237
+	 * @param EE_Ticket $ticket
238
+	 * @return bool
239
+	 * @throws UnexpectedEntityException
240
+	 * @throws EE_Error
241
+	 */
242
+	public static function validate_ticket_sale($qty = 1, EE_Ticket $ticket)
243
+	{
244
+		$qty = absint($qty);
245
+		if ($qty > 0) {
246
+			$qty = EED_Ticket_Sales_Monitor::instance()->_validate_ticket_sale($ticket, $qty);
247
+		}
248
+		if (self::debug) {
249
+			echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '()';
250
+			echo '<br /><br /><b> RETURNED QTY: ' . $qty . '</b>';
251
+		}
252
+		return $qty;
253
+	}
254
+
255
+
256
+
257
+	/**
258
+	 * checks whether an individual ticket is available for purchase based on datetime, and ticket details
259
+	 *
260
+	 * @param   EE_Ticket $ticket
261
+	 * @param int         $qty
262
+	 * @return int
263
+	 * @throws UnexpectedEntityException
264
+	 * @throws EE_Error
265
+	 */
266
+	protected function _validate_ticket_sale(EE_Ticket $ticket, $qty = 1)
267
+	{
268
+		if (self::debug) {
269
+			echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
270
+		}
271
+		if (! $ticket instanceof EE_Ticket) {
272
+			return 0;
273
+		}
274
+		if (self::debug) {
275
+			echo '<br /><b> . ticket->ID: ' . $ticket->ID() . '</b>';
276
+			echo '<br /> . original ticket->reserved: ' . $ticket->reserved();
277
+		}
278
+		$ticket->refresh_from_db();
279
+		// first let's determine the ticket availability based on sales
280
+		$available = $ticket->qty('saleable');
281
+		if (self::debug) {
282
+			echo '<br /> . . . ticket->qty: ' . $ticket->qty();
283
+			echo '<br /> . . . ticket->sold: ' . $ticket->sold();
284
+			echo '<br /> . . . ticket->reserved: ' . $ticket->reserved();
285
+			echo '<br /> . . . ticket->qty(saleable): ' . $ticket->qty('saleable');
286
+			echo '<br /> . . . available: ' . $available;
287
+		}
288
+		if ($available < 1) {
289
+			$this->_ticket_sold_out($ticket);
290
+			return 0;
291
+		}
292
+		if (self::debug) {
293
+			echo '<br /> . . . qty: ' . $qty;
294
+		}
295
+		if ($available < $qty) {
296
+			$qty = $available;
297
+			if (self::debug) {
298
+				echo '<br /> . . . QTY ADJUSTED: ' . $qty;
299
+			}
300
+			$this->_ticket_quantity_decremented($ticket);
301
+		}
302
+		$this->_reserve_ticket($ticket, $qty);
303
+		return $qty;
304
+	}
305
+
306
+
307
+
308
+	/**
309
+	 * increments ticket reserved based on quantity passed
310
+	 *
311
+	 * @param    EE_Ticket $ticket
312
+	 * @param int          $quantity
313
+	 * @return bool
314
+	 * @throws EE_Error
315
+	 */
316
+	protected function _reserve_ticket(EE_Ticket $ticket, $quantity = 1)
317
+	{
318
+		if (self::debug) {
319
+			echo '<br /><br /> . . . INCREASE RESERVED: ' . $quantity;
320
+		}
321
+		$ticket->increase_reserved($quantity);
322
+		return $ticket->save();
323
+	}
324
+
325
+
326
+
327
+	/**
328
+	 * @param  EE_Ticket $ticket
329
+	 * @param  int       $quantity
330
+	 * @return bool
331
+	 * @throws EE_Error
332
+	 */
333
+	protected function _release_reserved_ticket(EE_Ticket $ticket, $quantity = 1)
334
+	{
335
+		if (self::debug) {
336
+			echo '<br /> . . . ticket->ID: ' . $ticket->ID();
337
+			echo '<br /> . . . ticket->reserved: ' . $ticket->reserved();
338
+		}
339
+		$ticket->decrease_reserved($quantity);
340
+		if (self::debug) {
341
+			echo '<br /> . . . ticket->reserved: ' . $ticket->reserved();
342
+		}
343
+		return $ticket->save() ? 1 : 0;
344
+	}
345
+
346
+
347
+
348
+	/**
349
+	 * removes quantities within the ticket selector based on zero ticket availability
350
+	 *
351
+	 * @param    EE_Ticket $ticket
352
+	 * @return    void
353
+	 * @throws UnexpectedEntityException
354
+	 * @throws EE_Error
355
+	 */
356
+	protected function _ticket_sold_out(EE_Ticket $ticket)
357
+	{
358
+		if (self::debug) {
359
+			echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
360
+			echo '<br /> . . ticket->name: ' . $this->_get_ticket_and_event_name($ticket);
361
+		}
362
+		$this->sold_out_tickets[] = $this->_get_ticket_and_event_name($ticket);
363
+	}
364
+
365
+
366
+
367
+	/**
368
+	 * adjusts quantities within the ticket selector based on decreased ticket availability
369
+	 *
370
+	 * @param    EE_Ticket $ticket
371
+	 * @return void
372
+	 * @throws UnexpectedEntityException
373
+	 * @throws EE_Error
374
+	 */
375
+	protected function _ticket_quantity_decremented(EE_Ticket $ticket)
376
+	{
377
+		if (self::debug) {
378
+			echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
379
+			echo '<br /> . . ticket->name: ' . $this->_get_ticket_and_event_name($ticket);
380
+		}
381
+		$this->decremented_tickets[] = $this->_get_ticket_and_event_name($ticket);
382
+	}
383
+
384
+
385
+
386
+	/**
387
+	 * builds string out of ticket and event name
388
+	 *
389
+	 * @param    EE_Ticket $ticket
390
+	 * @return string
391
+	 * @throws UnexpectedEntityException
392
+	 * @throws EE_Error
393
+	 */
394
+	protected function _get_ticket_and_event_name(EE_Ticket $ticket)
395
+	{
396
+		$event = $ticket->get_related_event();
397
+		if ($event instanceof EE_Event) {
398
+			$ticket_name = sprintf(
399
+				_x('%1$s for %2$s', 'ticket name for event name', 'event_espresso'),
400
+				$ticket->name(),
401
+				$event->name()
402
+			);
403
+		} else {
404
+			$ticket_name = $ticket->name();
405
+		}
406
+		return $ticket_name;
407
+	}
408
+
409
+
410
+
411
+	/********************************** EVENT CART  **********************************/
412
+
413
+
414
+
415
+	/**
416
+	 * releases or reserves ticket(s) based on quantity passed
417
+	 *
418
+	 * @param  EE_Line_Item $line_item
419
+	 * @param  int          $quantity
420
+	 * @return void
421
+	 * @throws EE_Error
422
+	 * @throws InvalidArgumentException
423
+	 * @throws InvalidDataTypeException
424
+	 * @throws InvalidInterfaceException
425
+	 */
426
+	public static function ticket_quantity_updated(EE_Line_Item $line_item, $quantity = 1)
427
+	{
428
+		$ticket = EEM_Ticket::instance()->get_one_by_ID(absint($line_item->OBJ_ID()));
429
+		if ($ticket instanceof EE_Ticket) {
430
+			if ($quantity > 0) {
431
+				EED_Ticket_Sales_Monitor::instance()->_reserve_ticket($ticket, $quantity);
432
+			} else {
433
+				EED_Ticket_Sales_Monitor::instance()->_release_reserved_ticket($ticket, $quantity);
434
+			}
435
+		}
436
+	}
437
+
438
+
439
+
440
+	/**
441
+	 * releases reserved ticket(s) based on quantity passed
442
+	 *
443
+	 * @param  EE_Ticket $ticket
444
+	 * @param  int       $quantity
445
+	 * @return void
446
+	 * @throws EE_Error
447
+	 */
448
+	public static function ticket_removed_from_cart(EE_Ticket $ticket, $quantity = 1)
449
+	{
450
+		EED_Ticket_Sales_Monitor::instance()->_release_reserved_ticket($ticket, $quantity);
451
+	}
452
+
453
+
454
+
455
+	/********************************** POST_NOTICES  **********************************/
456
+
457
+
458
+
459
+	/**
460
+	 * @return void
461
+	 * @throws EE_Error
462
+	 * @throws InvalidArgumentException
463
+	 * @throws ReflectionException
464
+	 * @throws InvalidDataTypeException
465
+	 * @throws InvalidInterfaceException
466
+	 */
467
+	public static function post_notices()
468
+	{
469
+		EED_Ticket_Sales_Monitor::instance()->_post_notices();
470
+	}
471
+
472
+
473
+
474
+	/**
475
+	 * @return void
476
+	 * @throws EE_Error
477
+	 * @throws InvalidArgumentException
478
+	 * @throws ReflectionException
479
+	 * @throws InvalidDataTypeException
480
+	 * @throws InvalidInterfaceException
481
+	 */
482
+	protected function _post_notices()
483
+	{
484
+		if (self::debug) {
485
+			echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
486
+		}
487
+		$refresh_msg    = '';
488
+		$none_added_msg = '';
489
+		if (defined('DOING_AJAX') && DOING_AJAX) {
490
+			$refresh_msg    = __(
491
+				'Please refresh the page to view updated ticket quantities.',
492
+				'event_espresso'
493
+			);
494
+			$none_added_msg = __('No tickets were added for the event.', 'event_espresso');
495
+		}
496
+		if (! empty($this->sold_out_tickets)) {
497
+			EE_Error::add_attention(
498
+				sprintf(
499
+					apply_filters(
500
+						'FHEE__EED_Ticket_Sales_Monitor___post_notices__sold_out_tickets_notice',
501
+						__(
502
+							'We\'re sorry...%1$sThe following items have sold out since you first viewed this page, and can no longer be registered for:%1$s%1$s%2$s%1$s%1$sPlease note that availability can change at any time due to cancellations, so please check back again later if registration for this event(s) is important to you.%1$s%1$s%3$s%1$s%4$s%1$s',
503
+							'event_espresso'
504
+						)
505
+					),
506
+					'<br />',
507
+					implode('<br />', $this->sold_out_tickets),
508
+					$none_added_msg,
509
+					$refresh_msg
510
+				)
511
+			);
512
+			// alter code flow in the Ticket Selector for better UX
513
+			add_filter('FHEE__EED_Ticket_Selector__process_ticket_selections__tckts_slctd', '__return_true');
514
+			add_filter('FHEE__EED_Ticket_Selector__process_ticket_selections__success', '__return_false');
515
+			$this->sold_out_tickets = array();
516
+			// and reset the cart
517
+			EED_Ticket_Sales_Monitor::session_cart_reset(EE_Registry::instance()->SSN);
518
+		}
519
+		if (! empty($this->decremented_tickets)) {
520
+			EE_Error::add_attention(
521
+				sprintf(
522
+					apply_filters(
523
+						'FHEE__EED_Ticket_Sales_Monitor___ticket_quantity_decremented__notice',
524
+						__(
525
+							'We\'re sorry...%1$sDue to sales that have occurred since you first viewed the last page, the following items have had their quantities adjusted to match the current available amount:%1$s%1$s%2$s%1$s%1$sPlease note that availability can change at any time due to cancellations, so please check back again later if registration for this event(s) is important to you.%1$s%1$s%3$s%1$s%4$s%1$s',
526
+							'event_espresso'
527
+						)
528
+					),
529
+					'<br />',
530
+					implode('<br />', $this->decremented_tickets),
531
+					$none_added_msg,
532
+					$refresh_msg
533
+				)
534
+			);
535
+			$this->decremented_tickets = array();
536
+		}
537
+	}
538
+
539
+
540
+
541
+	/********************************** RELEASE_ALL_RESERVED_TICKETS_FOR_TRANSACTION  **********************************/
542
+
543
+
544
+
545
+	/**
546
+	 * releases reserved tickets for all registrations of an EE_Transaction
547
+	 * by default, will NOT release tickets for finalized transactions
548
+	 *
549
+	 * @param    EE_Transaction $transaction
550
+	 * @return int
551
+	 * @throws EE_Error
552
+	 * @throws InvalidSessionDataException
553
+	 */
554
+	protected function _release_all_reserved_tickets_for_transaction(EE_Transaction $transaction)
555
+	{
556
+		if (self::debug) {
557
+			echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
558
+			echo '<br /> . transaction->ID: ' . $transaction->ID();
559
+		}
560
+		// check if 'finalize_registration' step has been completed...
561
+		$finalized = $transaction->reg_step_completed('finalize_registration');
562
+		if (self::debug) {
563
+			// DEBUG LOG
564
+			EEH_Debug_Tools::log(
565
+				__CLASS__,
566
+				__FUNCTION__,
567
+				__LINE__,
568
+				array('finalized' => $finalized),
569
+				false,
570
+				'EE_Transaction: ' . $transaction->ID()
571
+			);
572
+		}
573
+		// how many tickets were released
574
+		$count = 0;
575
+		if (self::debug) {
576
+			echo '<br /> . . . finalized: ' . $finalized;
577
+		}
578
+		$release_tickets_with_TXN_status = array(
579
+			EEM_Transaction::failed_status_code,
580
+			EEM_Transaction::abandoned_status_code,
581
+			EEM_Transaction::incomplete_status_code,
582
+		);
583
+		// if the session is getting cleared BEFORE the TXN has been finalized
584
+		if (! $finalized || in_array($transaction->status_ID(), $release_tickets_with_TXN_status, true)) {
585
+			// let's cancel any reserved tickets
586
+			$registrations = $transaction->registrations();
587
+			if (! empty($registrations)) {
588
+				foreach ($registrations as $registration) {
589
+					if ($registration instanceof EE_Registration) {
590
+						$count += $this->_release_reserved_ticket_for_registration($registration, $transaction);
591
+					}
592
+				}
593
+			}
594
+		}
595
+		return $count;
596
+	}
597
+
598
+
599
+
600
+	/**
601
+	 * releases reserved tickets for an EE_Registration
602
+	 * by default, will NOT release tickets for APPROVED registrations
603
+	 *
604
+	 * @param EE_Registration $registration
605
+	 * @param EE_Transaction  $transaction
606
+	 * @return int
607
+	 * @throws EE_Error
608
+	 */
609
+	protected function _release_reserved_ticket_for_registration(
610
+		EE_Registration $registration,
611
+		EE_Transaction $transaction
612
+	) {
613
+		$STS_ID = $transaction->status_ID();
614
+		if (self::debug) {
615
+			echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
616
+			echo '<br /> . . registration->ID: ' . $registration->ID();
617
+			echo '<br /> . . registration->status_ID: ' . $registration->status_ID();
618
+			echo '<br /> . . transaction->status_ID(): ' . $STS_ID;
619
+		}
620
+		if (
621
+			// release Tickets for Failed Transactions and Abandoned Transactions
622
+			$STS_ID === EEM_Transaction::failed_status_code
623
+			|| $STS_ID === EEM_Transaction::abandoned_status_code
624
+			|| (
625
+				// also release Tickets for Incomplete Transactions, but ONLY if the Registrations are NOT Approved
626
+				$STS_ID === EEM_Transaction::incomplete_status_code
627
+				&& $registration->status_ID() !== EEM_Registration::status_id_approved
628
+			)
629
+		) {
630
+			$ticket = $registration->ticket();
631
+			if ($ticket instanceof EE_Ticket) {
632
+				return $this->_release_reserved_ticket($ticket);
633
+			}
634
+		}
635
+		return 0;
636
+	}
637
+
638
+
639
+
640
+	/********************************** SESSION_CART_RESET  **********************************/
641
+
642
+
643
+
644
+	/**
645
+	 * callback hooked into 'AHEE__EE_Session__reset_cart__before_reset'
646
+	 *
647
+	 * @param EE_Session $session
648
+	 * @return void
649
+	 * @throws EE_Error
650
+	 * @throws InvalidArgumentException
651
+	 * @throws ReflectionException
652
+	 * @throws InvalidDataTypeException
653
+	 * @throws InvalidInterfaceException
654
+	 */
655
+	public static function session_cart_reset(EE_Session $session)
656
+	{
657
+		if (self::debug) {
658
+			echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
659
+		}
660
+		$cart = $session->cart();
661
+		if ($cart instanceof EE_Cart) {
662
+			if (self::debug) {
663
+				echo '<br /><br /> cart instance of EE_Cart: ';
664
+			}
665
+			EED_Ticket_Sales_Monitor::instance()->_session_cart_reset($cart);
666
+		} else {
667
+			if (self::debug) {
668
+				echo '<br /><br /> invalid EE_Cart: ';
669
+				var_export($cart, true);
670
+			}
671
+		}
672
+	}
673
+
674
+
675
+
676
+	/**
677
+	 * releases reserved tickets in the EE_Cart
678
+	 *
679
+	 * @param EE_Cart $cart
680
+	 * @return void
681
+	 * @throws EE_Error
682
+	 * @throws InvalidArgumentException
683
+	 * @throws ReflectionException
684
+	 * @throws InvalidDataTypeException
685
+	 * @throws InvalidInterfaceException
686
+	 */
687
+	protected function _session_cart_reset(EE_Cart $cart)
688
+	{
689
+		if (self::debug) {
690
+			echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
691
+		}
692
+		EE_Registry::instance()->load_helper('Line_Item');
693
+		$ticket_line_items = $cart->get_tickets();
694
+		if (empty($ticket_line_items)) {
695
+			return;
696
+		}
697
+		foreach ($ticket_line_items as $ticket_line_item) {
698
+			if (self::debug) {
699
+				echo '<br /> . ticket_line_item->ID(): ' . $ticket_line_item->ID();
700
+			}
701
+			if ($ticket_line_item instanceof EE_Line_Item && $ticket_line_item->OBJ_type() === 'Ticket') {
702
+				if (self::debug) {
703
+					echo '<br /> . . ticket_line_item->OBJ_ID(): ' . $ticket_line_item->OBJ_ID();
704
+				}
705
+				$ticket = EEM_Ticket::instance()->get_one_by_ID($ticket_line_item->OBJ_ID());
706
+				if ($ticket instanceof EE_Ticket) {
707
+					if (self::debug) {
708
+						echo '<br /> . . ticket->ID(): ' . $ticket->ID();
709
+						echo '<br /> . . ticket_line_item->quantity(): ' . $ticket_line_item->quantity();
710
+					}
711
+					$this->_release_reserved_ticket($ticket, $ticket_line_item->quantity());
712
+				}
713
+			}
714
+		}
715
+		if (self::debug) {
716
+			echo '<br /><br /> RESET COMPLETED ';
717
+		}
718
+	}
719
+
720
+
721
+
722
+	/********************************** SESSION_CHECKOUT_RESET  **********************************/
723
+
724
+
725
+
726
+	/**
727
+	 * callback hooked into 'AHEE__EE_Session__reset_checkout__before_reset'
728
+	 *
729
+	 * @param EE_Session $session
730
+	 * @return void
731
+	 * @throws EE_Error
732
+	 * @throws InvalidSessionDataException
733
+	 */
734
+	public static function session_checkout_reset(EE_Session $session)
735
+	{
736
+		$checkout = $session->checkout();
737
+		if ($checkout instanceof EE_Checkout) {
738
+			EED_Ticket_Sales_Monitor::instance()->_session_checkout_reset($checkout);
739
+		}
740
+	}
741
+
742
+
743
+
744
+	/**
745
+	 * releases reserved tickets for the EE_Checkout->transaction
746
+	 *
747
+	 * @param EE_Checkout $checkout
748
+	 * @return void
749
+	 * @throws EE_Error
750
+	 * @throws InvalidSessionDataException
751
+	 */
752
+	protected function _session_checkout_reset(EE_Checkout $checkout)
753
+	{
754
+		if (self::debug) {
755
+			echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
756
+		}
757
+		// we want to release the each registration's reserved tickets if the session was cleared, but not if this is a revisit
758
+		if ($checkout->revisit || ! $checkout->transaction instanceof EE_Transaction) {
759
+			return;
760
+		}
761
+		$this->_release_all_reserved_tickets_for_transaction($checkout->transaction);
762
+	}
763
+
764
+
765
+
766
+	/********************************** SESSION_EXPIRED_RESET  **********************************/
767
+
768
+
769
+
770
+	/**
771
+	 * @param    EE_Session $session
772
+	 * @return    void
773
+	 */
774
+	public static function session_expired_reset(EE_Session $session)
775
+	{
776
+	}
777
+
778
+
779
+
780
+	/********************************** PROCESS_ABANDONED_TRANSACTIONS  **********************************/
781
+
782
+
783
+
784
+	/**
785
+	 * releases reserved tickets for all registrations of an ABANDONED EE_Transaction
786
+	 * by default, will NOT release tickets for free transactions, or any that have received a payment
787
+	 *
788
+	 * @param EE_Transaction $transaction
789
+	 * @return void
790
+	 * @throws EE_Error
791
+	 * @throws InvalidSessionDataException
792
+	 */
793
+	public static function process_abandoned_transactions(EE_Transaction $transaction)
794
+	{
795
+		// is this TXN free or has any money been paid towards this TXN? If so, then leave it alone
796
+		if ($transaction->is_free() || $transaction->paid() > 0) {
797
+			if (self::debug) {
798
+				// DEBUG LOG
799
+				EEH_Debug_Tools::log(
800
+					__CLASS__,
801
+					__FUNCTION__,
802
+					__LINE__,
803
+					array($transaction),
804
+					false,
805
+					'EE_Transaction: ' . $transaction->ID()
806
+				);
807
+			}
808
+			return;
809
+		}
810
+		// have their been any successful payments made ?
811
+		$payments = $transaction->payments();
812
+		foreach ($payments as $payment) {
813
+			if ($payment instanceof EE_Payment && $payment->status() === EEM_Payment::status_id_approved) {
814
+				if (self::debug) {
815
+					// DEBUG LOG
816
+					EEH_Debug_Tools::log(
817
+						__CLASS__,
818
+						__FUNCTION__,
819
+						__LINE__,
820
+						array($payment),
821
+						false,
822
+						'EE_Transaction: ' . $transaction->ID()
823
+					);
824
+				}
825
+				return;
826
+			}
827
+		}
828
+		// since you haven't even attempted to pay for your ticket...
829
+		EED_Ticket_Sales_Monitor::instance()->_release_all_reserved_tickets_for_transaction($transaction);
830
+	}
831
+
832
+
833
+
834
+	/********************************** PROCESS_FAILED_TRANSACTIONS  **********************************/
835
+
836
+
837
+
838
+	/**
839
+	 * releases reserved tickets for absolutely ALL registrations of a FAILED EE_Transaction
840
+	 *
841
+	 * @param EE_Transaction $transaction
842
+	 * @return void
843
+	 * @throws EE_Error
844
+	 * @throws InvalidSessionDataException
845
+	 */
846
+	public static function process_failed_transactions(EE_Transaction $transaction)
847
+	{
848
+		// since you haven't even attempted to pay for your ticket...
849
+		EED_Ticket_Sales_Monitor::instance()->_release_all_reserved_tickets_for_transaction($transaction);
850
+	}
851
+
852
+
853
+
854
+	/********************************** RESET RESERVATION COUNTS  *********************************/
855
+
856
+
857
+
858
+	/**
859
+	 * Resets all ticket and datetime reserved counts to zero
860
+	 * Tickets that are currently associated with a Transaction that is in progress
861
+	 *
862
+	 * @throws EE_Error
863
+	 * @throws DomainException
864
+	 * @throws InvalidDataTypeException
865
+	 * @throws InvalidInterfaceException
866
+	 * @throws InvalidArgumentException
867
+	 */
868
+	public static function reset_reservation_counts()
869
+	{
870
+		/** @var EE_Line_Item[] $valid_reserved_tickets */
871
+		$valid_reserved_tickets = array();
872
+		/** @var EE_Transaction[] $transactions_not_in_progress */
873
+		$transactions_not_in_progress = EEM_Transaction::instance()->get_transactions_not_in_progress();
874
+		foreach ($transactions_not_in_progress as $transaction) {
875
+			// if this TXN has been fully completed, then skip it
876
+			if ($transaction->reg_step_completed('finalize_registration')) {
877
+				continue;
878
+			}
879
+			$total_line_item = $transaction->total_line_item();
880
+			// $transaction_in_progress->line
881
+			if (! $total_line_item instanceof EE_Line_Item) {
882
+				throw new DomainException(
883
+					esc_html__(
884
+						'Transaction does not have a valid Total Line Item associated with it.',
885
+						'event_espresso'
886
+					)
887
+				);
888
+			}
889
+			$valid_reserved_tickets += EED_Ticket_Sales_Monitor::get_ticket_line_items_for_grand_total(
890
+				$total_line_item
891
+			);
892
+		}
893
+		$total_line_items = EEM_Line_Item::instance()->get_total_line_items_for_active_carts();
894
+		foreach ($total_line_items as $total_line_item) {
895
+			$valid_reserved_tickets += EED_Ticket_Sales_Monitor::get_ticket_line_items_for_grand_total(
896
+				$total_line_item
897
+			);
898
+		}
899
+		return EED_Ticket_Sales_Monitor::release_reservations_for_tickets(
900
+			EEM_Ticket::instance()->get_tickets_with_reservations(),
901
+			$valid_reserved_tickets
902
+		);
903
+	}
904
+
905
+
906
+
907
+	/**
908
+	 * @param EE_Line_Item $total_line_item
909
+	 * @return EE_Line_Item[]
910
+	 */
911
+	private static function get_ticket_line_items_for_grand_total(EE_Line_Item $total_line_item)
912
+	{
913
+		/** @var EE_Line_Item[] $valid_reserved_tickets */
914
+		$valid_reserved_tickets = array();
915
+		$ticket_line_items      = EEH_Line_Item::get_ticket_line_items($total_line_item);
916
+		foreach ($ticket_line_items as $ticket_line_item) {
917
+			if ($ticket_line_item instanceof EE_Line_Item) {
918
+				$valid_reserved_tickets[] = $ticket_line_item;
919
+			}
920
+		}
921
+		return $valid_reserved_tickets;
922
+	}
923
+
924
+
925
+
926
+	/**
927
+	 * @param EE_Ticket[]    $tickets_with_reservations
928
+	 * @param EE_Line_Item[] $valid_reserved_ticket_line_items
929
+	 * @return int
930
+	 * @throws EE_Error
931
+	 */
932
+	private static function release_reservations_for_tickets(
933
+		array $tickets_with_reservations,
934
+		array $valid_reserved_ticket_line_items = array()
935
+	) {
936
+		$total_tickets_released = 0;
937
+		foreach ($tickets_with_reservations as $ticket_with_reservations) {
938
+			if (! $ticket_with_reservations instanceof EE_Ticket) {
939
+				continue;
940
+			}
941
+			$reserved_qty = $ticket_with_reservations->reserved();
942
+			foreach ($valid_reserved_ticket_line_items as $valid_reserved_ticket_line_item) {
943
+				if (
944
+					$valid_reserved_ticket_line_item instanceof EE_Line_Item
945
+					&& $valid_reserved_ticket_line_item->OBJ_ID() === $ticket_with_reservations->ID()
946
+				) {
947
+					$reserved_qty -= $valid_reserved_ticket_line_item->quantity();
948
+				}
949
+			}
950
+			if ($reserved_qty > 0) {
951
+				$ticket_with_reservations->decrease_reserved($reserved_qty);
952
+				$ticket_with_reservations->save();
953
+				$total_tickets_released += $reserved_qty;
954
+			}
955
+		}
956
+		return $total_tickets_released;
957
+	}
958
+
959
+
960
+
961
+	/********************************** SHUTDOWN  **********************************/
962
+
963
+
964
+
965
+	/**
966
+	 * @return false|int
967
+	 * @throws EE_Error
968
+	 * @throws InvalidArgumentException
969
+	 * @throws InvalidDataTypeException
970
+	 * @throws InvalidInterfaceException
971
+	 */
972
+	public static function clear_expired_line_items_with_no_transaction()
973
+	{
974
+		/** @type WPDB $wpdb */
975
+		global $wpdb;
976
+		return $wpdb->query(
977
+			$wpdb->prepare(
978
+				'DELETE FROM ' . EEM_Line_Item::instance()->table() . '
979 979
                 WHERE TXN_ID = 0 AND LIN_timestamp <= %s',
980
-                // use GMT time because that's what LIN_timestamps are in
981
-                date('Y-m-d H:i:s', time() - EE_Registry::instance()->SSN->lifespan())
982
-            )
983
-        );
984
-    }
980
+				// use GMT time because that's what LIN_timestamps are in
981
+				date('Y-m-d H:i:s', time() - EE_Registry::instance()->SSN->lifespan())
982
+			)
983
+		);
984
+	}
985 985
 
986 986
 }
987 987
 // End of file EED_Ticket_Sales_Monitor.module.php
Please login to merge, or discard this patch.
Spacing   +52 added lines, -52 removed lines patch added patch discarded remove patch
@@ -23,7 +23,7 @@  discard block
 block discarded – undo
23 23
 class EED_Ticket_Sales_Monitor extends EED_Module
24 24
 {
25 25
 
26
-    const debug = false;    //	true false
26
+    const debug = false; //	true false
27 27
 
28 28
     /**
29 29
      * an array of raw ticket data from EED_Ticket_Selector
@@ -200,17 +200,17 @@  discard block
 block discarded – undo
200 200
             /** @var EE_Line_Item $total_line_item */
201 201
             $ticket_line_items = EED_Ticket_Sales_Monitor::get_ticket_line_items_for_grand_total($total_line_item);
202 202
             foreach ($ticket_line_items as $ticket_line_item) {
203
-                if (! $ticket_line_item instanceof EE_Line_Item) {
203
+                if ( ! $ticket_line_item instanceof EE_Line_Item) {
204 204
                     continue;
205 205
                 }
206 206
                 if ($total_line_item->timestamp(true) <= $expired) {
207
-                    $expired_ticket_IDs[ $ticket_line_item->OBJ_ID() ] = $ticket_line_item->OBJ_ID();
207
+                    $expired_ticket_IDs[$ticket_line_item->OBJ_ID()] = $ticket_line_item->OBJ_ID();
208 208
                 } else {
209
-                    $valid_ticket_line_items[ $ticket_line_item->OBJ_ID() ] = $ticket_line_item;
209
+                    $valid_ticket_line_items[$ticket_line_item->OBJ_ID()] = $ticket_line_item;
210 210
                 }
211 211
             }
212 212
         }
213
-        if (! empty($expired_ticket_IDs)) {
213
+        if ( ! empty($expired_ticket_IDs)) {
214 214
             EED_Ticket_Sales_Monitor::release_reservations_for_tickets(
215 215
                 \EEM_Ticket::instance()->get_tickets_with_IDs($expired_ticket_IDs),
216 216
                 $valid_ticket_line_items
@@ -246,8 +246,8 @@  discard block
 block discarded – undo
246 246
             $qty = EED_Ticket_Sales_Monitor::instance()->_validate_ticket_sale($ticket, $qty);
247 247
         }
248 248
         if (self::debug) {
249
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '()';
250
-            echo '<br /><br /><b> RETURNED QTY: ' . $qty . '</b>';
249
+            echo '<br /><br /> '.__LINE__.') '.__METHOD__.'()';
250
+            echo '<br /><br /><b> RETURNED QTY: '.$qty.'</b>';
251 251
         }
252 252
         return $qty;
253 253
     }
@@ -266,36 +266,36 @@  discard block
 block discarded – undo
266 266
     protected function _validate_ticket_sale(EE_Ticket $ticket, $qty = 1)
267 267
     {
268 268
         if (self::debug) {
269
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
269
+            echo '<br /><br /> '.__LINE__.') '.__METHOD__.'() ';
270 270
         }
271
-        if (! $ticket instanceof EE_Ticket) {
271
+        if ( ! $ticket instanceof EE_Ticket) {
272 272
             return 0;
273 273
         }
274 274
         if (self::debug) {
275
-            echo '<br /><b> . ticket->ID: ' . $ticket->ID() . '</b>';
276
-            echo '<br /> . original ticket->reserved: ' . $ticket->reserved();
275
+            echo '<br /><b> . ticket->ID: '.$ticket->ID().'</b>';
276
+            echo '<br /> . original ticket->reserved: '.$ticket->reserved();
277 277
         }
278 278
         $ticket->refresh_from_db();
279 279
         // first let's determine the ticket availability based on sales
280 280
         $available = $ticket->qty('saleable');
281 281
         if (self::debug) {
282
-            echo '<br /> . . . ticket->qty: ' . $ticket->qty();
283
-            echo '<br /> . . . ticket->sold: ' . $ticket->sold();
284
-            echo '<br /> . . . ticket->reserved: ' . $ticket->reserved();
285
-            echo '<br /> . . . ticket->qty(saleable): ' . $ticket->qty('saleable');
286
-            echo '<br /> . . . available: ' . $available;
282
+            echo '<br /> . . . ticket->qty: '.$ticket->qty();
283
+            echo '<br /> . . . ticket->sold: '.$ticket->sold();
284
+            echo '<br /> . . . ticket->reserved: '.$ticket->reserved();
285
+            echo '<br /> . . . ticket->qty(saleable): '.$ticket->qty('saleable');
286
+            echo '<br /> . . . available: '.$available;
287 287
         }
288 288
         if ($available < 1) {
289 289
             $this->_ticket_sold_out($ticket);
290 290
             return 0;
291 291
         }
292 292
         if (self::debug) {
293
-            echo '<br /> . . . qty: ' . $qty;
293
+            echo '<br /> . . . qty: '.$qty;
294 294
         }
295 295
         if ($available < $qty) {
296 296
             $qty = $available;
297 297
             if (self::debug) {
298
-                echo '<br /> . . . QTY ADJUSTED: ' . $qty;
298
+                echo '<br /> . . . QTY ADJUSTED: '.$qty;
299 299
             }
300 300
             $this->_ticket_quantity_decremented($ticket);
301 301
         }
@@ -316,7 +316,7 @@  discard block
 block discarded – undo
316 316
     protected function _reserve_ticket(EE_Ticket $ticket, $quantity = 1)
317 317
     {
318 318
         if (self::debug) {
319
-            echo '<br /><br /> . . . INCREASE RESERVED: ' . $quantity;
319
+            echo '<br /><br /> . . . INCREASE RESERVED: '.$quantity;
320 320
         }
321 321
         $ticket->increase_reserved($quantity);
322 322
         return $ticket->save();
@@ -333,12 +333,12 @@  discard block
 block discarded – undo
333 333
     protected function _release_reserved_ticket(EE_Ticket $ticket, $quantity = 1)
334 334
     {
335 335
         if (self::debug) {
336
-            echo '<br /> . . . ticket->ID: ' . $ticket->ID();
337
-            echo '<br /> . . . ticket->reserved: ' . $ticket->reserved();
336
+            echo '<br /> . . . ticket->ID: '.$ticket->ID();
337
+            echo '<br /> . . . ticket->reserved: '.$ticket->reserved();
338 338
         }
339 339
         $ticket->decrease_reserved($quantity);
340 340
         if (self::debug) {
341
-            echo '<br /> . . . ticket->reserved: ' . $ticket->reserved();
341
+            echo '<br /> . . . ticket->reserved: '.$ticket->reserved();
342 342
         }
343 343
         return $ticket->save() ? 1 : 0;
344 344
     }
@@ -356,8 +356,8 @@  discard block
 block discarded – undo
356 356
     protected function _ticket_sold_out(EE_Ticket $ticket)
357 357
     {
358 358
         if (self::debug) {
359
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
360
-            echo '<br /> . . ticket->name: ' . $this->_get_ticket_and_event_name($ticket);
359
+            echo '<br /><br /> '.__LINE__.') '.__METHOD__.'() ';
360
+            echo '<br /> . . ticket->name: '.$this->_get_ticket_and_event_name($ticket);
361 361
         }
362 362
         $this->sold_out_tickets[] = $this->_get_ticket_and_event_name($ticket);
363 363
     }
@@ -375,8 +375,8 @@  discard block
 block discarded – undo
375 375
     protected function _ticket_quantity_decremented(EE_Ticket $ticket)
376 376
     {
377 377
         if (self::debug) {
378
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
379
-            echo '<br /> . . ticket->name: ' . $this->_get_ticket_and_event_name($ticket);
378
+            echo '<br /><br /> '.__LINE__.') '.__METHOD__.'() ';
379
+            echo '<br /> . . ticket->name: '.$this->_get_ticket_and_event_name($ticket);
380 380
         }
381 381
         $this->decremented_tickets[] = $this->_get_ticket_and_event_name($ticket);
382 382
     }
@@ -482,18 +482,18 @@  discard block
 block discarded – undo
482 482
     protected function _post_notices()
483 483
     {
484 484
         if (self::debug) {
485
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
485
+            echo '<br /><br /> '.__LINE__.') '.__METHOD__.'() ';
486 486
         }
487 487
         $refresh_msg    = '';
488 488
         $none_added_msg = '';
489 489
         if (defined('DOING_AJAX') && DOING_AJAX) {
490
-            $refresh_msg    = __(
490
+            $refresh_msg = __(
491 491
                 'Please refresh the page to view updated ticket quantities.',
492 492
                 'event_espresso'
493 493
             );
494 494
             $none_added_msg = __('No tickets were added for the event.', 'event_espresso');
495 495
         }
496
-        if (! empty($this->sold_out_tickets)) {
496
+        if ( ! empty($this->sold_out_tickets)) {
497 497
             EE_Error::add_attention(
498 498
                 sprintf(
499 499
                     apply_filters(
@@ -516,7 +516,7 @@  discard block
 block discarded – undo
516 516
             // and reset the cart
517 517
             EED_Ticket_Sales_Monitor::session_cart_reset(EE_Registry::instance()->SSN);
518 518
         }
519
-        if (! empty($this->decremented_tickets)) {
519
+        if ( ! empty($this->decremented_tickets)) {
520 520
             EE_Error::add_attention(
521 521
                 sprintf(
522 522
                     apply_filters(
@@ -554,8 +554,8 @@  discard block
 block discarded – undo
554 554
     protected function _release_all_reserved_tickets_for_transaction(EE_Transaction $transaction)
555 555
     {
556 556
         if (self::debug) {
557
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
558
-            echo '<br /> . transaction->ID: ' . $transaction->ID();
557
+            echo '<br /><br /> '.__LINE__.') '.__METHOD__.'() ';
558
+            echo '<br /> . transaction->ID: '.$transaction->ID();
559 559
         }
560 560
         // check if 'finalize_registration' step has been completed...
561 561
         $finalized = $transaction->reg_step_completed('finalize_registration');
@@ -567,13 +567,13 @@  discard block
 block discarded – undo
567 567
                 __LINE__,
568 568
                 array('finalized' => $finalized),
569 569
                 false,
570
-                'EE_Transaction: ' . $transaction->ID()
570
+                'EE_Transaction: '.$transaction->ID()
571 571
             );
572 572
         }
573 573
         // how many tickets were released
574 574
         $count = 0;
575 575
         if (self::debug) {
576
-            echo '<br /> . . . finalized: ' . $finalized;
576
+            echo '<br /> . . . finalized: '.$finalized;
577 577
         }
578 578
         $release_tickets_with_TXN_status = array(
579 579
             EEM_Transaction::failed_status_code,
@@ -581,10 +581,10 @@  discard block
 block discarded – undo
581 581
             EEM_Transaction::incomplete_status_code,
582 582
         );
583 583
         // if the session is getting cleared BEFORE the TXN has been finalized
584
-        if (! $finalized || in_array($transaction->status_ID(), $release_tickets_with_TXN_status, true)) {
584
+        if ( ! $finalized || in_array($transaction->status_ID(), $release_tickets_with_TXN_status, true)) {
585 585
             // let's cancel any reserved tickets
586 586
             $registrations = $transaction->registrations();
587
-            if (! empty($registrations)) {
587
+            if ( ! empty($registrations)) {
588 588
                 foreach ($registrations as $registration) {
589 589
                     if ($registration instanceof EE_Registration) {
590 590
                         $count += $this->_release_reserved_ticket_for_registration($registration, $transaction);
@@ -612,10 +612,10 @@  discard block
 block discarded – undo
612 612
     ) {
613 613
         $STS_ID = $transaction->status_ID();
614 614
         if (self::debug) {
615
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
616
-            echo '<br /> . . registration->ID: ' . $registration->ID();
617
-            echo '<br /> . . registration->status_ID: ' . $registration->status_ID();
618
-            echo '<br /> . . transaction->status_ID(): ' . $STS_ID;
615
+            echo '<br /><br /> '.__LINE__.') '.__METHOD__.'() ';
616
+            echo '<br /> . . registration->ID: '.$registration->ID();
617
+            echo '<br /> . . registration->status_ID: '.$registration->status_ID();
618
+            echo '<br /> . . transaction->status_ID(): '.$STS_ID;
619 619
         }
620 620
         if (
621 621
             // release Tickets for Failed Transactions and Abandoned Transactions
@@ -655,7 +655,7 @@  discard block
 block discarded – undo
655 655
     public static function session_cart_reset(EE_Session $session)
656 656
     {
657 657
         if (self::debug) {
658
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
658
+            echo '<br /><br /> '.__LINE__.') '.__METHOD__.'() ';
659 659
         }
660 660
         $cart = $session->cart();
661 661
         if ($cart instanceof EE_Cart) {
@@ -687,7 +687,7 @@  discard block
 block discarded – undo
687 687
     protected function _session_cart_reset(EE_Cart $cart)
688 688
     {
689 689
         if (self::debug) {
690
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
690
+            echo '<br /><br /> '.__LINE__.') '.__METHOD__.'() ';
691 691
         }
692 692
         EE_Registry::instance()->load_helper('Line_Item');
693 693
         $ticket_line_items = $cart->get_tickets();
@@ -696,17 +696,17 @@  discard block
 block discarded – undo
696 696
         }
697 697
         foreach ($ticket_line_items as $ticket_line_item) {
698 698
             if (self::debug) {
699
-                echo '<br /> . ticket_line_item->ID(): ' . $ticket_line_item->ID();
699
+                echo '<br /> . ticket_line_item->ID(): '.$ticket_line_item->ID();
700 700
             }
701 701
             if ($ticket_line_item instanceof EE_Line_Item && $ticket_line_item->OBJ_type() === 'Ticket') {
702 702
                 if (self::debug) {
703
-                    echo '<br /> . . ticket_line_item->OBJ_ID(): ' . $ticket_line_item->OBJ_ID();
703
+                    echo '<br /> . . ticket_line_item->OBJ_ID(): '.$ticket_line_item->OBJ_ID();
704 704
                 }
705 705
                 $ticket = EEM_Ticket::instance()->get_one_by_ID($ticket_line_item->OBJ_ID());
706 706
                 if ($ticket instanceof EE_Ticket) {
707 707
                     if (self::debug) {
708
-                        echo '<br /> . . ticket->ID(): ' . $ticket->ID();
709
-                        echo '<br /> . . ticket_line_item->quantity(): ' . $ticket_line_item->quantity();
708
+                        echo '<br /> . . ticket->ID(): '.$ticket->ID();
709
+                        echo '<br /> . . ticket_line_item->quantity(): '.$ticket_line_item->quantity();
710 710
                     }
711 711
                     $this->_release_reserved_ticket($ticket, $ticket_line_item->quantity());
712 712
                 }
@@ -752,7 +752,7 @@  discard block
 block discarded – undo
752 752
     protected function _session_checkout_reset(EE_Checkout $checkout)
753 753
     {
754 754
         if (self::debug) {
755
-            echo '<br /><br /> ' . __LINE__ . ') ' . __METHOD__ . '() ';
755
+            echo '<br /><br /> '.__LINE__.') '.__METHOD__.'() ';
756 756
         }
757 757
         // we want to release the each registration's reserved tickets if the session was cleared, but not if this is a revisit
758 758
         if ($checkout->revisit || ! $checkout->transaction instanceof EE_Transaction) {
@@ -802,7 +802,7 @@  discard block
 block discarded – undo
802 802
                     __LINE__,
803 803
                     array($transaction),
804 804
                     false,
805
-                    'EE_Transaction: ' . $transaction->ID()
805
+                    'EE_Transaction: '.$transaction->ID()
806 806
                 );
807 807
             }
808 808
             return;
@@ -819,7 +819,7 @@  discard block
 block discarded – undo
819 819
                         __LINE__,
820 820
                         array($payment),
821 821
                         false,
822
-                        'EE_Transaction: ' . $transaction->ID()
822
+                        'EE_Transaction: '.$transaction->ID()
823 823
                     );
824 824
                 }
825 825
                 return;
@@ -878,7 +878,7 @@  discard block
 block discarded – undo
878 878
             }
879 879
             $total_line_item = $transaction->total_line_item();
880 880
             // $transaction_in_progress->line
881
-            if (! $total_line_item instanceof EE_Line_Item) {
881
+            if ( ! $total_line_item instanceof EE_Line_Item) {
882 882
                 throw new DomainException(
883 883
                     esc_html__(
884 884
                         'Transaction does not have a valid Total Line Item associated with it.',
@@ -935,7 +935,7 @@  discard block
 block discarded – undo
935 935
     ) {
936 936
         $total_tickets_released = 0;
937 937
         foreach ($tickets_with_reservations as $ticket_with_reservations) {
938
-            if (! $ticket_with_reservations instanceof EE_Ticket) {
938
+            if ( ! $ticket_with_reservations instanceof EE_Ticket) {
939 939
                 continue;
940 940
             }
941 941
             $reserved_qty = $ticket_with_reservations->reserved();
@@ -975,7 +975,7 @@  discard block
 block discarded – undo
975 975
         global $wpdb;
976 976
         return $wpdb->query(
977 977
             $wpdb->prepare(
978
-                'DELETE FROM ' . EEM_Line_Item::instance()->table() . '
978
+                'DELETE FROM '.EEM_Line_Item::instance()->table().'
979 979
                 WHERE TXN_ID = 0 AND LIN_timestamp <= %s',
980 980
                 // use GMT time because that's what LIN_timestamps are in
981 981
                 date('Y-m-d H:i:s', time() - EE_Registry::instance()->SSN->lifespan())
Please login to merge, or discard this patch.