Completed
Branch FET/rule-specific-exclusions-l... (334422)
by
unknown
17:10 queued 32s
created

EE_Checkout::payment_required()   B

Complexity

Conditions 5
Paths 8

Size

Total Lines 13
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 5
nc 8
nop 0
dl 0
loc 13
rs 8.8571
c 0
b 0
f 0
1
<?php
2
3
/**
4
 *
5
 * Class EE_Checkout
6
 *
7
 * Description
8
 *
9
 * @package               Event Espresso
10
 * @subpackage            core
11
 * @author                Brent Christensen
12
 * @since                 4.5.0
13
 *
14
 */
15
class EE_Checkout
16
{
17
18
    /**
19
     *    whether current request originated from the EE admin
20
     *
21
     * @type bool
22
     */
23
    public $admin_request = false;
24
25
    /**
26
     * whether returning to edit attendee information or to retry a payment
27
     *
28
     * @type bool
29
     */
30
    public $revisit = false;
31
32
    /**
33
     * whether the primary registrant is returning to edit attendee information or to retry a payment
34
     *
35
     * @type bool
36
     */
37
    public $primary_revisit = false;
38
39
    /**
40
     * is registration allowed to progress or halted for some reason such as failing to pass recaptcha?
41
     *
42
     * @type bool
43
     */
44
    public $continue_reg = true;
45
46
    /**
47
     * redirect to thank you page ?
48
     *
49
     * @type bool
50
     */
51
    public $redirect = false;
52
53
    /**
54
     * generate the reg form or not ?
55
     *
56
     * @type bool
57
     */
58
    public $generate_reg_form = true;
59
60
    /**
61
     * process a reg form submission or not ?
62
     *
63
     * @type bool
64
     */
65
    public $process_form_submission = false;
66
67
    /**
68
     * tracks whether the TXN status modified during this checkout
69
     *
70
     * @type bool
71
     */
72
    public $txn_status_updated = false;
73
74
    /**
75
     * only triggered to true after absolutely everything has finished.
76
     *
77
     * @type bool
78
     */
79
    protected $exit_spco = false;
80
81
    /**
82
     * tracks whether any of the TXN's Registrations statuses modified during this checkout
83
     * indexed by registration ID
84
     *
85
     * @type array
86
     */
87
    protected $reg_status_updated = array();
88
89
    /**
90
     * timestamp when redirected from Ticket Selector to the checkout
91
     *
92
     * @type int
93
     */
94
    public $uts = 0;
95
96
    /**
97
     * total number of tickets that were in the cart
98
     *
99
     * @type int
100
     */
101
    public $total_ticket_count = 0;
102
103
    /**
104
     * corresponds loosely to EE_Transaction::remaining()
105
     * but can be modified by SPCO
106
     *
107
     * @type float
108
     */
109
    public $amount_owing = 0;
110
111
    /**
112
     * the reg step slug from the incoming request
113
     *
114
     * @type string
115
     */
116
    public $step = '';
117
118
    /**
119
     * the reg step slug for a step being edited
120
     *
121
     * @type string
122
     */
123
    public $edit_step = '';
124
125
    /**
126
     * the action being performed on the current step
127
     *
128
     * @type string
129
     */
130
    public $action = '';
131
132
    /**
133
     * reg_url_link for a previously saved registration
134
     *
135
     * @type string
136
     */
137
    public $reg_url_link = '';
138
139
    /**
140
     * string slug for the payment method that was selected during the payment options step
141
     *
142
     * @type string
143
     */
144
    public $selected_method_of_payment = '';
145
146
    /**
147
     * base url for the site's registration checkout page - additional url params will be added to this
148
     *
149
     * @type string
150
     */
151
    public $reg_page_base_url = '';
152
153
    /**
154
     * base url for the site's registration cancelled page - additional url params will be added to this
155
     *
156
     * @type string
157
     */
158
    public $cancel_page_url = '';
159
160
    /**
161
     * base url for the site's thank you page - additional url params will be added to this
162
     *
163
     * @type string
164
     */
165
    public $thank_you_page_url = '';
166
167
    /**
168
     * base url for any redirects - additional url params will be added to this
169
     *
170
     * @type string
171
     */
172
    public $redirect_url = '';
173
174
    /**
175
     * form of POST data for use with off-site gateways
176
     *
177
     * @type string
178
     */
179
    public $redirect_form = '';
180
181
    /**
182
     * array of query where params to use when retrieving cached registrations from $this->checkout->transaction
183
     *
184
     * @type array
185
     */
186
    public $reg_cache_where_params = array();
187
188
    /**
189
     * a class for managing and creating the JSON encoded array of data that gets passed back to the client during AJAX
190
     * requests
191
     *
192
     * @type EE_SPCO_JSON_Response
193
     */
194
    public $json_response;
195
196
    /**
197
     * where we are going next in the reg process
198
     *
199
     * @type EE_SPCO_Reg_Step
200
     */
201
    public $next_step;
202
203
    /**
204
     * where we are in the reg process
205
     *
206
     * @type EE_SPCO_Reg_Step
207
     */
208
    public $current_step;
209
210
    /**
211
     *    $_cart - the current cart object
212
     *
213
     * @var EE_CART
214
     */
215
    public $cart;
216
217
    /**
218
     *    $_transaction - the current transaction object
219
     *
220
     * @var EE_Transaction
221
     */
222
    public $transaction;
223
224
    /**
225
     *    the related attendee object for the primary registrant
226
     *
227
     * @type EE_Attendee
228
     */
229
    public $primary_attendee_obj;
230
231
    /**
232
     *    $payment_method - the payment method object for the selected method of payment
233
     *
234
     * @type EE_Payment_Method
235
     */
236
    public $payment_method;
237
238
    /**
239
     *    $payment - if a payment was successfully made during the reg process,
240
     *    then here it is !!!
241
     *
242
     * @type EE_Payment
243
     */
244
    public $payment;
245
246
    /**
247
     *    if a payment method was selected that uses an on-site gateway, then this is the billing form
248
     *
249
     * @type EE_Billing_Info_Form | EE_Billing_Attendee_Info_Form
250
     */
251
    public $billing_form;
252
253
    /**
254
     *    the entire registration form composed of ALL of the subsections generated by the various reg steps
255
     *
256
     * @type EE_Form_Section_Proper
257
     */
258
    public $registration_form;
259
260
    /**
261
     * array of EE_SPCO_Reg_Step objects
262
     *
263
     * @type EE_SPCO_Reg_Step[]
264
     */
265
    public $reg_steps = array();
266
267
    /**
268
     * array of EE_Payment_Method objects
269
     *
270
     * @type EE_Payment_Method[]
271
     */
272
    public $available_payment_methods = array();
273
274
275
    /**
276
     *    class constructor
277
     *
278
     * @access    public
279
     */
280
    public function __construct()
281
    {
282
        $this->reg_page_base_url = EE_Registry::instance()->CFG->core->reg_page_url();
283
        $this->thank_you_page_url = EE_Registry::instance()->CFG->core->thank_you_page_url();
284
        $this->cancel_page_url = EE_Registry::instance()->CFG->core->cancel_page_url();
285
        $this->continue_reg = apply_filters('FHEE__EE_Checkout___construct___continue_reg', true);
286
        $this->admin_request = is_admin() && ! EE_Registry::instance()->REQ->ajax;
287
        $this->reg_cache_where_params = array(
288
            0          => array('REG_deleted' => false),
289
            'order_by' => array('REG_count' => 'ASC'),
290
        );
291
    }
292
293
294
    /**
295
     * returns true if ANY reg status was updated during checkout
296
     *
297
     * @return boolean
298
     */
299
    public function any_reg_status_updated()
300
    {
301
        foreach ($this->reg_status_updated as $reg_status) {
302
            if ($reg_status) {
303
                return true;
304
            }
305
        }
306
        return false;
307
    }
308
309
310
    /**
311
     * @param $REG_ID
312
     * @return boolean
313
     */
314
    public function reg_status_updated($REG_ID)
315
    {
316
        return isset($this->reg_status_updated[ $REG_ID ]) ? $this->reg_status_updated[ $REG_ID ] : false;
317
    }
318
319
320
    /**
321
     * @param $REG_ID
322
     * @param $reg_status
323
     */
324
    public function set_reg_status_updated($REG_ID, $reg_status)
325
    {
326
        $this->reg_status_updated[ $REG_ID ] = filter_var($reg_status, FILTER_VALIDATE_BOOLEAN);
327
    }
328
329
330
    /**
331
     * exit_spco
332
     *
333
     * @return bool
334
     */
335
    public function exit_spco()
336
    {
337
        return $this->exit_spco;
338
    }
339
340
341
    /**
342
     * set_exit_spco
343
     * can ONLY be set by the  Finalize_Registration reg step
344
     */
345
    public function set_exit_spco()
346
    {
347
        if ($this->current_step instanceof EE_SPCO_Reg_Step_Finalize_Registration) {
348
            $this->exit_spco = true;
349
        }
350
    }
351
352
353
    /**
354
     *    reset_for_current_request
355
     *
356
     * @access    public
357
     * @return    void
358
     */
359
    public function reset_for_current_request()
360
    {
361
        $this->process_form_submission = false;
362
        $this->continue_reg = apply_filters('FHEE__EE_Checkout___construct___continue_reg', true);
363
        $this->admin_request = is_admin() && ! EE_Registry::instance()->REQ->front_ajax;
364
        $this->continue_reg = true;
365
        $this->redirect = false;
366
        // don't reset the cached redirect form if we're about to be asked to display it !!!
367
        if (EE_Registry::instance()->REQ->get('action', 'display_spco_reg_step') !== 'redirect_form') {
368
            $this->redirect_form = '';
369
        }
370
        $this->redirect_url = '';
371
        $this->json_response = new EE_SPCO_JSON_Response();
372
        EE_Form_Section_Proper::reset_js_localization();
373
    }
374
375
376
    /**
377
     *    add_reg_step
378
     *
379
     * @access    public
380
     * @param EE_SPCO_Reg_Step $reg_step_obj
381
     * @return    void
382
     */
383
    public function add_reg_step(EE_SPCO_Reg_Step $reg_step_obj)
384
    {
385
        $this->reg_steps[ $reg_step_obj->slug() ] = $reg_step_obj;
386
    }
387
388
389
    /**
390
     * skip_reg_step
391
     * if the current reg step does not need to run for some reason,
392
     * then this will advance SPCO to the next reg step,
393
     * and mark the skipped step as completed
394
     *
395
     * @access    public
396
     * @param string $reg_step_slug
397
     * @return    void
398
     * @throws \EE_Error
399
     */
400
    public function skip_reg_step($reg_step_slug = '')
401
    {
402
        $step_to_skip = $this->find_reg_step($reg_step_slug);
403
        if ($step_to_skip instanceof EE_SPCO_Reg_Step && $step_to_skip->is_current_step()) {
404
            $step_to_skip->set_is_current_step(false);
405
            $step_to_skip->set_completed();
406
            // advance to the next step
407
            $this->set_current_step($this->next_step->slug());
408
            // also reset the step param in the request in case any other code references that directly
409
            EE_Registry::instance()->REQ->set('step', $this->current_step->slug());
410
            // since we are skipping a step and setting the current step to be what was previously the next step,
411
            // we need to check that the next step is now correct, and not still set to the current step.
412
            if ($this->current_step->slug() === $this->next_step->slug()) {
413
                // correctly setup the next step
414
                $this->set_next_step();
415
            }
416
            $this->set_reg_step_initiated($this->current_step);
417
        }
418
    }
419
420
421
    /**
422
     *    remove_reg_step
423
     *
424
     * @access    public
425
     * @param string $reg_step_slug
426
     * @param bool   $reset whether to reset reg steps after removal
427
     * @throws EE_Error
428
     */
429
    public function remove_reg_step($reg_step_slug = '', $reset = true)
430
    {
431
        unset($this->reg_steps[ $reg_step_slug ]);
432
        if ($this->transaction instanceof EE_Transaction) {
433
            // now remove reg step from TXN and save
434
            $this->transaction->remove_reg_step($reg_step_slug);
435
            $this->transaction->save();
436
        }
437
        if ($reset) {
438
            $this->reset_reg_steps();
439
        }
440
    }
441
442
443
    /**
444
     *    set_reg_step_order
445
     *
446
     * @access    public
447
     * @param string $reg_step_slug
448
     * @param int    $order
449
     * @return    void
450
     */
451
    public function set_reg_step_order($reg_step_slug = '', $order = 100)
452
    {
453
        if (isset($this->reg_steps[ $reg_step_slug ])) {
454
            $this->reg_steps[ $reg_step_slug ]->set_order($order);
455
        }
456
    }
457
458
459
    /**
460
     *    set_current_step
461
     *
462
     * @access    public
463
     * @param string $current_step
464
     * @return    void
465
     */
466
    public function set_current_step($current_step)
467
    {
468
        // grab what step we're on
469
        $this->current_step = isset($this->reg_steps[ $current_step ])
470
            ? $this->reg_steps[ $current_step ]
471
            : reset(
472
                $this->reg_steps
473
            );
474
        // verify instance
475
        if ($this->current_step instanceof EE_SPCO_Reg_Step) {
476
            // we don't want to repeat completed steps if this is the first time through SPCO
477
            if ($this->continue_reg && ! $this->revisit && $this->current_step->completed()) {
478
                // so advance to the next step
479
                $this->set_next_step();
480
                if ($this->next_step instanceof EE_SPCO_Reg_Step) {
481
                    // and attempt to set it as the current step
482
                    $this->set_current_step($this->next_step->slug());
483
                }
484
                return;
485
            }
486
            $this->current_step->set_is_current_step(true);
487
        } else {
488
            EE_Error::add_error(
489
                __('The current step could not be set.', 'event_espresso'),
490
                __FILE__,
491
                __FUNCTION__,
492
                __LINE__
493
            );
494
        }
495
    }
496
497
498
    /**
499
     *    set_next_step
500
     * advances the reg_steps array pointer and sets the next step, then reverses pointer back to the current step
501
     *
502
     * @access    public
503
     * @return    void
504
     */
505
    public function set_next_step()
506
    {
507
        // set pointer to start of array
508
        reset($this->reg_steps);
509
        // if there is more than one step
510
        if (count($this->reg_steps) > 1) {
511
            // advance to the current step and set pointer
512
            while (key($this->reg_steps) !== $this->current_step->slug() && key($this->reg_steps) !== '') {
513
                next($this->reg_steps);
514
            }
515
        }
516
        // advance one more spot ( if it exists )
517
        $this->next_step = next($this->reg_steps);
518
        // verify instance
519
        $this->next_step = $this->next_step instanceof EE_SPCO_Reg_Step ? $this->next_step : null;
520
        // then back to current step to reset
521
        prev($this->reg_steps);
522
    }
523
524
525
    /**
526
     *    get_next_reg_step
527
     *    this simply returns the next step from reg_steps array
528
     *
529
     * @access    public
530
     * @return    EE_SPCO_Reg_Step | null
531
     */
532
    public function get_next_reg_step()
533
    {
534
        $next = next($this->reg_steps);
535
        prev($this->reg_steps);
536
        return $next instanceof EE_SPCO_Reg_Step ? $next : null;
537
    }
538
539
540
    /**
541
     * get_prev_reg_step
542
     *    this simply returns the previous step from reg_steps array
543
     *
544
     * @access    public
545
     * @return    EE_SPCO_Reg_Step | null
546
     */
547
    public function get_prev_reg_step()
548
    {
549
        $prev = prev($this->reg_steps);
550
        next($this->reg_steps);
551
        return $prev instanceof EE_SPCO_Reg_Step ? $prev : null;
552
    }
553
554
555
    /**
556
     * sort_reg_steps
557
     *
558
     * @access public
559
     * @return void
560
     */
561
    public function sort_reg_steps()
562
    {
563
        $reg_step_sorting_callback = apply_filters(
564
            'FHEE__EE_Checkout__sort_reg_steps__reg_step_sorting_callback',
565
            'reg_step_sorting_callback'
566
        );
567
        uasort($this->reg_steps, array($this, $reg_step_sorting_callback));
568
    }
569
570
571
    /**
572
     * find_reg_step
573
     * finds a reg step by the given slug
574
     *
575
     * @access    public
576
     * @param string $reg_step_slug
577
     * @return EE_SPCO_Reg_Step|null
578
     */
579
    public function find_reg_step($reg_step_slug = '')
580
    {
581
        if (! empty($reg_step_slug)) {
582
            // copy reg step array
583
            $reg_steps = $this->reg_steps;
584
            // set pointer to start of array
585
            reset($reg_steps);
586
            // if there is more than one step
587
            if (count($reg_steps) > 1) {
588
                // advance to the current step and set pointer
589
                while (key($reg_steps) !== $reg_step_slug && key($reg_steps) !== '') {
590
                    next($reg_steps);
591
                }
592
                return current($reg_steps);
593
            }
594
        }
595
        return null;
596
    }
597
598
599
    /**
600
     * reg_step_sorting_callback
601
     *
602
     * @access public
603
     * @param EE_SPCO_Reg_Step $reg_step_A
604
     * @param EE_SPCO_Reg_Step $reg_step_B
605
     * @return int
606
     */
607
    public function reg_step_sorting_callback(EE_SPCO_Reg_Step $reg_step_A, EE_SPCO_Reg_Step $reg_step_B)
608
    {
609
        // send finalize_registration step to the end of the array
610
        if ($reg_step_A->slug() === 'finalize_registration') {
611
            return 1;
612
        } elseif ($reg_step_B->slug() === 'finalize_registration') {
613
            return -1;
614
        }
615
        if ($reg_step_A->order() === $reg_step_B->order()) {
616
            return 0;
617
        }
618
        return ($reg_step_A->order() > $reg_step_B->order()) ? 1 : -1;
619
    }
620
621
622
    /**
623
     * set_reg_step_initiated
624
     *
625
     * @access    public
626
     * @param    EE_SPCO_Reg_Step $reg_step
627
     * @throws \EE_Error
628
     */
629
    public function set_reg_step_initiated(EE_SPCO_Reg_Step $reg_step)
630
    {
631
        // call set_reg_step_initiated ???
632
        if (// first time visiting SPCO ?
633
            ! $this->revisit
634
            && (
635
                // and displaying the reg step form for the first time ?
636
                $this->action === 'display_spco_reg_step'
637
                // or initializing the final step
638
                || $reg_step instanceof EE_SPCO_Reg_Step_Finalize_Registration
639
            )
640
        ) {
641
            // set the start time for this reg step
642
            if (! $this->transaction->set_reg_step_initiated($reg_step->slug())) {
643 View Code Duplication
                if (WP_DEBUG) {
644
                    EE_Error::add_error(
645
                        sprintf(
646
                            __('The "%1$s" registration step was not initialized properly.', 'event_espresso'),
647
                            $reg_step->name()
648
                        ),
649
                        __FILE__,
650
                        __FUNCTION__,
651
                        __LINE__
652
                    );
653
                }
654
            }
655
        }
656
    }
657
658
659
    /**
660
     *    set_reg_step_JSON_info
661
     *
662
     * @access public
663
     * @return    void
664
     */
665
    public function set_reg_step_JSON_info()
666
    {
667
        EE_Registry::$i18n_js_strings['reg_steps'] = array();
668
        // pass basic reg step data to JS
669
        foreach ($this->reg_steps as $reg_step) {
670
            EE_Registry::$i18n_js_strings['reg_steps'][] = $reg_step->slug();
671
        }
672
        // reset reg step html
673
        // $this->json_response->set_reg_step_html('');
674
    }
675
676
677
    /**
678
     *    reset_reg_steps
679
     *
680
     * @access public
681
     * @return void
682
     */
683
    public function reset_reg_steps()
684
    {
685
        $this->sort_reg_steps();
686
        $this->set_current_step(EE_Registry::instance()->REQ->get('step'));
687
        $this->set_next_step();
688
        // the text that appears on the reg step form submit button
689
        $this->current_step->set_submit_button_text();
690
        $this->set_reg_step_JSON_info();
691
    }
692
693
694
    /**
695
     *    get_registration_time_limit
696
     *
697
     * @access    public
698
     * @return        string
699
     */
700
    public function get_registration_time_limit()
701
    {
702
703
        $registration_time_limit = (float) (EE_Registry::instance()->SSN->expiration() - time());
704
        $time_limit_format = $registration_time_limit > 60 * MINUTE_IN_SECONDS ? 'H:i:s' : 'i:s';
705
        $registration_time_limit = date($time_limit_format, $registration_time_limit);
706
        return apply_filters(
707
            'FHEE__EE_Checkout__get_registration_time_limit__registration_time_limit',
708
            $registration_time_limit
709
        );
710
    }
711
712
713
    /**
714
     * payment_required
715
     *
716
     * @return boolean
717
     */
718
    public function payment_required()
719
    {
720
        // if NOT:
721
        //     registration via admin
722
        //      completed TXN
723
        //      overpaid TXN
724
        //      free TXN(total = 0.00)
725
        //      then payment required is TRUE
726
        return ! ($this->admin_request
727
                  || $this->transaction->is_completed()
728
                  || $this->transaction->is_overpaid()
729
                  || $this->transaction->is_free()) ? true : false;
730
    }
731
732
733
    /**
734
     * get_cart_for_transaction
735
     *
736
     * @access public
737
     * @param EE_Transaction $transaction
738
     * @return EE_Cart
739
     */
740
    public function get_cart_for_transaction($transaction)
741
    {
742
        $session = EE_Registry::instance()->load_core('Session');
743
        $cart = $transaction instanceof EE_Transaction ? EE_Cart::get_cart_from_txn($transaction, $session) : null;
744
        // verify cart
745
        if (! $cart instanceof EE_Cart) {
746
            $cart = EE_Registry::instance()->load_core('Cart');
747
        }
748
749
        return $cart;
750
    }
751
752
753
    /**
754
     *    initialize_txn_reg_steps_array
755
     *
756
     * @access public
757
     * @return    array
758
     */
759
    public function initialize_txn_reg_steps_array()
760
    {
761
        $txn_reg_steps_array = array();
762
        foreach ($this->reg_steps as $reg_step) {
763
            $txn_reg_steps_array[ $reg_step->slug() ] = false;
764
        }
765
        return $txn_reg_steps_array;
766
    }
767
768
769
    /**
770
     *    update_txn_reg_steps_array
771
     *
772
     * @access public
773
     * @return    bool
774
     * @throws \EE_Error
775
     */
776
    public function update_txn_reg_steps_array()
777
    {
778
        $updated = false;
779
        foreach ($this->reg_steps as $reg_step) {
780
            if ($reg_step->completed()) {
781
                $updated = $this->transaction->set_reg_step_completed($reg_step->slug())
782
                    ? true
783
                    : $updated;
784
            }
785
        }
786
        if ($updated) {
787
            $this->transaction->save();
788
        }
789
        return $updated;
790
    }
791
792
793
    /**
794
     *    stash_transaction_and_checkout
795
     *
796
     * @access public
797
     * @return    void
798
     * @throws \EE_Error
799
     */
800
    public function stash_transaction_and_checkout()
801
    {
802
        if (! $this->revisit) {
803
            $this->update_txn_reg_steps_array();
804
        }
805
        $this->track_transaction_and_registration_status_updates();
806
        // save all data to the db, but suppress errors
807
        // $this->save_all_data( FALSE );
808
        // cache the checkout in the session
809
        EE_Registry::instance()->SSN->set_checkout($this);
810
    }
811
812
813
    /**
814
     *    track_transaction_and_registration_status_updates
815
     *    stores whether any updates were made to the TXN or it's related registrations
816
     *
817
     * @access public
818
     * @return void
819
     * @throws \EE_Error
820
     */
821
    public function track_transaction_and_registration_status_updates()
822
    {
823
        // verify the transaction
824
        if ($this->transaction instanceof EE_Transaction) {
825
            // has there been a TXN status change during this checkout?
826
            $this->txn_status_updated = $this->transaction->txn_status_updated();
827
            /** @type EE_Registration_Processor $registration_processor */
828
            $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
829
            // grab the saved registrations from the transaction
830
            foreach ($this->transaction->registrations($this->reg_cache_where_params) as $registration) {
831
                if ($registration_processor->reg_status_updated($registration->ID())) {
832
                    $this->set_reg_status_updated($registration->ID(), true);
833
                }
834
            }
835
        }
836
    }
837
838
839
    /**
840
     *    visit_allows_processing_of_this_registration
841
     *    determines if the current SPCO visit should allow the passed EE_Registration to be used in processing.
842
     *    one of the following conditions must be met:
843
     *        EITHER:    A) first time thru SPCO -> process ALL registrations ( NOT a revisit )
844
     *        OR :        B) primary registrant is editing info -> process ALL registrations ( primary_revisit )
845
     *        OR :        C) another registrant is editing info -> ONLY process their registration ( revisit AND their
846
     *        reg_url_link matches )
847
     *
848
     * @access public
849
     * @param    EE_Registration $registration
850
     * @return    bool
851
     * @throws \EE_Error
852
     */
853
    public function visit_allows_processing_of_this_registration(EE_Registration $registration)
854
    {
855
        return ! $this->revisit
856
               || $this->primary_revisit
857
               || (
858
                   $this->revisit && $this->reg_url_link === $registration->reg_url_link()
859
               )
860
            ? true
861
            : false;
862
    }
863
864
865
    /**
866
     *    _transaction_has_primary_registration
867
     *
868
     * @access        private
869
     * @return        bool
870
     */
871
    public function transaction_has_primary_registrant()
872
    {
873
        return $this->primary_attendee_obj instanceof EE_Attendee ? true : false;
874
    }
875
876
877
    /**
878
     *    save_all_data
879
     *    simply loops through the current transaction and saves all data for each registration
880
     *
881
     * @access public
882
     * @param bool $show_errors
883
     * @return bool
884
     * @throws \EE_Error
885
     */
886
    public function save_all_data($show_errors = true)
887
    {
888
        // verify the transaction
889
        if ($this->transaction instanceof EE_Transaction) {
890
            // save to ensure that TXN has ID
891
            $this->transaction->save();
892
            // grab the saved registrations from the transaction
893
            foreach ($this->transaction->registrations($this->reg_cache_where_params) as $registration) {
894
                $this->_save_registration($registration, $show_errors);
895
            }
896
        } else {
897
            if ($show_errors) {
898
                EE_Error::add_error(
899
                    __(
900
                        'A valid Transaction was not found when attempting to save your registration information.',
901
                        'event_espresso'
902
                    ),
903
                    __FILE__,
904
                    __FUNCTION__,
905
                    __LINE__
906
                );
907
            }
908
            return false;
909
        }
910
        return true;
911
    }
912
913
914
    /**
915
     * _save_registration_attendee
916
     *
917
     * @param    EE_Registration $registration
918
     * @param bool               $show_errors
919
     * @return void
920
     * @throws \EE_Error
921
     */
922
    private function _save_registration($registration, $show_errors = true)
923
    {
924
        // verify object
925
        if ($registration instanceof EE_Registration) {
926
            // should this registration be processed during this visit ?
927
            if ($this->visit_allows_processing_of_this_registration($registration)) {
928
                // set TXN ID
929
                if (! $registration->transaction_ID()) {
930
                    $registration->set_transaction_id($this->transaction->ID());
931
                }
932
                // verify and save the attendee
933
                $this->_save_registration_attendee($registration, $show_errors);
934
                // save answers to reg form questions
935
                $this->_save_registration_answers($registration, $show_errors);
936
                // save changes
937
                $registration->save();
938
                // update txn cache
939 View Code Duplication
                if (! $this->transaction->update_cache_after_object_save('Registration', $registration)) {
940
                    if ($show_errors) {
941
                        EE_Error::add_error(
942
                            __(
943
                                'The newly saved Registration object could not be cached on the Transaction.',
944
                                'event_espresso'
945
                            ),
946
                            __FILE__,
947
                            __FUNCTION__,
948
                            __LINE__
949
                        );
950
                    }
951
                }
952
            }
953
        } else {
954
            if ($show_errors) {
955
                EE_Error::add_error(
956
                    __(
957
                        'An invalid Registration object was discovered when attempting to save your registration information.',
958
                        'event_espresso'
959
                    ),
960
                    __FILE__,
961
                    __FUNCTION__,
962
                    __LINE__
963
                );
964
            }
965
        }
966
    }
967
968
969
    /**
970
     * _save_registration_attendee
971
     *
972
     * @param    EE_Registration $registration
973
     * @param bool               $show_errors
974
     * @return void
975
     * @throws \EE_Error
976
     */
977
    private function _save_registration_attendee($registration, $show_errors = true)
978
    {
979
        if ($registration->attendee() instanceof EE_Attendee) {
980
            // save so that ATT has ID
981
            $registration->attendee()->save();
982 View Code Duplication
            if (! $registration->update_cache_after_object_save('Attendee', $registration->attendee())) {
983
                if ($show_errors) {
984
                    EE_Error::add_error(
985
                        __(
986
                            'The newly saved Attendee object could not be cached on the registration.',
987
                            'event_espresso'
988
                        ),
989
                        __FILE__,
990
                        __FUNCTION__,
991
                        __LINE__
992
                    );
993
                }
994
            }
995
        } else {
996
            if ($show_errors) {
997
                EE_Error::add_error(
998
                    sprintf(
999
                        '%1$s||%1$s $attendee = %2$s',
1000
                        __(
1001
                            'Either no Attendee information was found, or an invalid Attendee object was discovered when attempting to save your registration information.',
1002
                            'event_espresso'
1003
                        ),
1004
                        var_export($registration->attendee(), true)
1005
                    ),
1006
                    __FILE__,
1007
                    __FUNCTION__,
1008
                    __LINE__
1009
                );
1010
            }
1011
        }
1012
    }
1013
1014
1015
    /**
1016
     * _save_question_answers
1017
     *
1018
     * @param    EE_Registration $registration
1019
     * @param bool               $show_errors
1020
     * @return void
1021
     * @throws \EE_Error
1022
     */
1023
    private function _save_registration_answers($registration, $show_errors = true)
1024
    {
1025
        // now save the answers
1026
        foreach ($registration->answers() as $cache_key => $answer) {
1027
            // verify object
1028
            if ($answer instanceof EE_Answer) {
1029
                $answer->set_registration($registration->ID());
1030
                $answer->save();
1031
                if (! $registration->update_cache_after_object_save('Answer', $answer, $cache_key)) {
1032
                    if ($show_errors) {
1033
                        EE_Error::add_error(
1034
                            __(
1035
                                'The newly saved Answer object could not be cached on the registration.',
1036
                                'event_espresso'
1037
                            ),
1038
                            __FILE__,
1039
                            __FUNCTION__,
1040
                            __LINE__
1041
                        );
1042
                    }
1043
                }
1044
            } else {
1045
                if ($show_errors) {
1046
                    EE_Error::add_error(
1047
                        __(
1048
                            'An invalid Answer object was discovered when attempting to save your registration information.',
1049
                            'event_espresso'
1050
                        ),
1051
                        __FILE__,
1052
                        __FUNCTION__,
1053
                        __LINE__
1054
                    );
1055
                }
1056
            }
1057
        }
1058
    }
1059
1060
1061
    /**
1062
     *    refresh_all_entities
1063
     *   will either refresh the entity map with objects form the db or from the checkout cache
1064
     *
1065
     * @access public
1066
     * @param bool $from_db
1067
     * @return bool
1068
     * @throws \EE_Error
1069
     */
1070
    public function refresh_all_entities($from_db = false)
1071
    {
1072
        $from_db = $this->current_step->is_final_step() || $this->action === 'process_gateway_response'
1073
            ? true
1074
            : $from_db;
1075
        // $this->log(
1076
        //     __CLASS__,
1077
        //     __FUNCTION__,
1078
        //     __LINE__,
1079
        //     array('from_db' => $from_db)
1080
        // );
1081
        return $from_db ? $this->refresh_from_db() : $this->refresh_entity_map();
1082
    }
1083
1084
1085
    /**
1086
     *  refresh_entity_map
1087
     *  simply loops through the current transaction and updates each
1088
     *  model's entity map using EEM_Base::refresh_entity_map_from_db()
1089
     *
1090
     * @access public
1091
     * @return bool
1092
     * @throws \EE_Error
1093
     */
1094
    protected function refresh_from_db()
1095
    {
1096
        // verify the transaction
1097
        if ($this->transaction instanceof EE_Transaction && $this->transaction->ID()) {
1098
            // pull fresh TXN data from the db
1099
            $this->transaction = $this->transaction->get_model()->refresh_entity_map_from_db($this->transaction->ID());
1100
            // update EE_Checkout's cached primary_attendee object
1101
            $this->primary_attendee_obj = $this->_refresh_primary_attendee_obj_from_db($this->transaction);
1102
            // update EE_Checkout's cached payment object
1103
            $payment = $this->transaction->last_payment();
1104
            $this->payment = $payment instanceof EE_Payment ? $payment : $this->payment;
1105
            // update EE_Checkout's cached payment_method object
1106
            $payment_method = $this->payment instanceof EE_Payment ? $this->payment->payment_method() : null;
1107
            $this->payment_method = $payment_method instanceof EE_Payment_Method ? $payment_method
1108
                : $this->payment_method;
1109
            // now refresh the cart, based on the TXN
1110
            $this->cart = $this->get_cart_for_transaction($this->transaction);
1111
        } else {
1112
            EE_Error::add_error(
1113
                __(
1114
                    'A valid Transaction was not found when attempting to update the model entity mapper.',
1115
                    'event_espresso'
1116
                ),
1117
                __FILE__,
1118
                __FUNCTION__,
1119
                __LINE__
1120
            );
1121
            return false;
1122
        }
1123
        return true;
1124
    }
1125
1126
1127
    /**
1128
     * _refresh_primary_attendee_obj_from_db
1129
     *
1130
     * @param   EE_Transaction $transaction
1131
     * @return  EE_Attendee | null
1132
     * @throws \EE_Error
1133
     */
1134
    protected function _refresh_primary_attendee_obj_from_db(EE_Transaction $transaction)
1135
    {
1136
1137
        $primary_attendee_obj = null;
1138
        // grab the saved registrations from the transaction
1139
        foreach ($transaction->registrations($this->reg_cache_where_params, true) as $registration) {
1140
            // verify object
1141
            if ($registration instanceof EE_Registration) {
1142
                $attendee = $registration->attendee();
1143
                // verify object && maybe cache primary_attendee_obj ?
1144
                if ($attendee instanceof EE_Attendee && $registration->is_primary_registrant()) {
1145
                    $primary_attendee_obj = $attendee;
1146
                }
1147
            } else {
1148
                EE_Error::add_error(
1149
                    __(
1150
                        'An invalid Registration object was discovered when attempting to update the model entity mapper.',
1151
                        'event_espresso'
1152
                    ),
1153
                    __FILE__,
1154
                    __FUNCTION__,
1155
                    __LINE__
1156
                );
1157
            }
1158
        }
1159
        return $primary_attendee_obj;
1160
    }
1161
1162
1163
    /**
1164
     *  refresh_entity_map
1165
     *  simply loops through the current transaction and updates
1166
     *  each model's entity map using EEM_Base::refresh_entity_map_with()
1167
     *
1168
     * @access public
1169
     * @return bool
1170
     * @throws \EE_Error
1171
     */
1172
    protected function refresh_entity_map()
1173
    {
1174
        // verify the transaction
1175
        if ($this->transaction instanceof EE_Transaction && $this->transaction->ID()) {
1176
            // never cache payment info
1177
            $this->transaction->clear_cache('Payment');
1178
            // is the Payment Options Reg Step completed ?
1179
            if ($this->transaction->reg_step_completed('payment_options')) {
1180
                // then check for payments and update TXN accordingly
1181
                /** @type EE_Transaction_Payments $transaction_payments */
1182
                $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
1183
                $transaction_payments->calculate_total_payments_and_update_status($this->transaction);
1184
            }
1185
            // grab the saved registrations from the transaction
1186
            foreach ($this->transaction->registrations($this->reg_cache_where_params) as $reg_cache_ID => $registration) {
1187
                $this->_refresh_registration($reg_cache_ID, $registration);
1188
            }
1189
            // make sure our cached TXN is added to the model entity mapper
1190
            $this->transaction = $this->transaction->get_model()->refresh_entity_map_with(
1191
                $this->transaction->ID(),
1192
                $this->transaction
1193
            );
1194
        } else {
1195
            EE_Error::add_error(
1196
                __(
1197
                    'A valid Transaction was not found when attempting to update the model entity mapper.',
1198
                    'event_espresso'
1199
                ),
1200
                __FILE__,
1201
                __FUNCTION__,
1202
                __LINE__
1203
            );
1204
            return false;
1205
        }
1206
        // verify and update the cart because inaccurate totals are not so much fun
1207
        if ($this->cart instanceof EE_Cart) {
1208
            $grand_total = $this->cart->get_grand_total();
1209
            if ($grand_total instanceof EE_Line_Item && $grand_total->ID()) {
1210
                $grand_total->recalculate_total_including_taxes();
1211
                $grand_total = $grand_total->get_model()->refresh_entity_map_with(
1212
                    $this->cart->get_grand_total()->ID(),
1213
                    $this->cart->get_grand_total()
1214
                );
1215
            }
1216 View Code Duplication
            if ($grand_total instanceof EE_Line_Item) {
1217
                $this->cart = EE_Cart::instance($grand_total);
1218
            } else {
1219
                EE_Error::add_error(
1220
                    __(
1221
                        'A valid Cart was not found when attempting to update the model entity mapper.',
1222
                        'event_espresso'
1223
                    ),
1224
                    __FILE__,
1225
                    __FUNCTION__,
1226
                    __LINE__
1227
                );
1228
                return false;
1229
            }
1230
        }
1231
        return true;
1232
    }
1233
1234
1235
    /**
1236
     * _refresh_registration
1237
     *
1238
     * @param    string | int    $reg_cache_ID
1239
     * @param    EE_Registration $registration
1240
     * @return void
1241
     * @throws \EE_Error
1242
     */
1243
    protected function _refresh_registration($reg_cache_ID, $registration)
1244
    {
1245
1246
        // verify object
1247 View Code Duplication
        if ($registration instanceof EE_Registration) {
1248
            // update the entity mapper attendee
1249
            $this->_refresh_registration_attendee($registration);
1250
            // update the entity mapper answers for reg form questions
1251
            $this->_refresh_registration_answers($registration);
1252
            // make sure the cached registration is added to the model entity mapper
1253
            $registration->get_model()->refresh_entity_map_with($reg_cache_ID, $registration);
1254
        } else {
1255
            EE_Error::add_error(
1256
                __(
1257
                    'An invalid Registration object was discovered when attempting to update the model entity mapper.',
1258
                    'event_espresso'
1259
                ),
1260
                __FILE__,
1261
                __FUNCTION__,
1262
                __LINE__
1263
            );
1264
        }
1265
    }
1266
1267
1268
    /**
1269
     * _save_registration_attendee
1270
     *
1271
     * @param    EE_Registration $registration
1272
     * @return void
1273
     * @throws \EE_Error
1274
     */
1275
    protected function _refresh_registration_attendee($registration)
1276
    {
1277
1278
        $attendee = $registration->attendee();
1279
        // verify object
1280
        if ($attendee instanceof EE_Attendee && $attendee->ID()) {
1281
            // make sure the cached attendee is added to the model entity mapper
1282
            $registration->attendee()->get_model()->refresh_entity_map_with($attendee->ID(), $attendee);
1283
            // maybe cache primary_attendee_obj ?
1284
            if ($registration->is_primary_registrant()) {
1285
                $this->primary_attendee_obj = $attendee;
1286
            }
1287
        }
1288
    }
1289
1290
1291
    /**
1292
     * _refresh_registration_answers
1293
     *
1294
     * @param    EE_Registration $registration
1295
     * @return void
1296
     * @throws \EE_Error
1297
     */
1298
    protected function _refresh_registration_answers($registration)
1299
    {
1300
1301
        // now update the answers
1302
        foreach ($registration->answers() as $cache_key => $answer) {
1303
            // verify object
1304 View Code Duplication
            if ($answer instanceof EE_Answer) {
1305
                if ($answer->ID()) {
1306
                    // make sure the cached answer is added to the model entity mapper
1307
                    $answer->get_model()->refresh_entity_map_with($answer->ID(), $answer);
1308
                }
1309
            } else {
1310
                EE_Error::add_error(
1311
                    __(
1312
                        'An invalid Answer object was discovered when attempting to update the model entity mapper.',
1313
                        'event_espresso'
1314
                    ),
1315
                    __FILE__,
1316
                    __FUNCTION__,
1317
                    __LINE__
1318
                );
1319
            }
1320
        }
1321
    }
1322
1323
1324
    /**
1325
     *    __sleep
1326
     * to conserve db space, let's remove the reg_form and the EE_Checkout object from EE_SPCO_Reg_Step objects upon
1327
     * serialization EE_Checkout will handle the reimplementation of itself upon waking, but we won't bother with the
1328
     * reg form, because if needed, it will be regenerated anyways
1329
     *
1330
     * @return array
1331
     * @throws \EE_Error
1332
     */
1333
    public function __sleep()
1334
    {
1335
        if ($this->primary_attendee_obj instanceof EE_Attendee && $this->primary_attendee_obj->ID()) {
1336
            $this->primary_attendee_obj = $this->primary_attendee_obj->ID();
1337
        }        // remove the reg form and the checkout
1338
        if ($this->transaction instanceof EE_Transaction && $this->transaction->ID()) {
1339
            $this->transaction = $this->transaction->ID();
1340
        }        // remove the reg form and the checkout
1341
        return array_diff(array_keys(get_object_vars($this)), array('billing_form', 'registration_form'));
1342
    }
1343
1344
1345
    /**
1346
     *    __wakeup
1347
     * to conserve db space, we are removing the EE_Checkout object from EE_SPCO_Reg_Step objects upon serialization
1348
     * this will reinstate the EE_Checkout object on each EE_SPCO_Reg_Step object
1349
     */
1350
    public function __wakeup()
1351
    {
1352
        if (! $this->primary_attendee_obj instanceof EE_Attendee && absint($this->primary_attendee_obj) !== 0) {
1353
            // $this->primary_attendee_obj is actually just an ID, so use it to get the object from the db
1354
            $this->primary_attendee_obj = EEM_Attendee::instance()->get_one_by_ID($this->primary_attendee_obj);
1355
        }
1356
        if (! $this->transaction instanceof EE_Transaction && absint($this->transaction) !== 0) {
1357
            // $this->transaction is actually just an ID, so use it to get the object from the db
1358
            $this->transaction = EEM_Transaction::instance()->get_one_by_ID($this->transaction);
1359
        }
1360
        foreach ($this->reg_steps as $reg_step) {
1361
            $reg_step->checkout = $this;
1362
        }
1363
    }
1364
1365
1366
    /**
1367
     * debug
1368
     *
1369
     * @param string $class
1370
     * @param string $func
1371
     * @param string $line
1372
     * @param array  $info
1373
     * @param bool   $display_request
1374
     * @throws \EE_Error
1375
     */
1376
    public function log($class = '', $func = '', $line = '', $info = array(), $display_request = false)
1377
    {
1378
        $disabled = true;
1379
        if (WP_DEBUG && ! $disabled) {
1380
            $debug_data = get_option('EE_DEBUG_SPCO_' . EE_Session::instance()->id(), array());
1381
            $default_data = array(
1382
                $class                    => $func . '() : ' . $line,
1383
                'request->step'           => $this->step,
1384
                'request->action'         => $this->action,
1385
                'current_step->slug'      => $this->current_step instanceof EE_SPCO_Reg_Step ?
1386
                    $this->current_step->slug() : '',
1387
                'current_step->completed' => $this->current_step instanceof EE_SPCO_Reg_Step ?
1388
                    $this->current_step->completed() : '',
1389
                'txn_status_updated'      => $this->transaction->txn_status_updated(),
1390
                'reg_status_updated'      => $this->reg_status_updated,
1391
                'reg_url_link'            => $this->reg_url_link,
1392
                'REQ'                     => $display_request ? $_REQUEST : '',
1393
            );
1394
            if ($this->transaction instanceof EE_Transaction) {
1395
                $default_data['TXN_status'] = $this->transaction->status_ID();
1396
                $default_data['TXN_reg_steps'] = $this->transaction->reg_steps();
1397
                foreach ($this->transaction->registrations($this->reg_cache_where_params) as $REG_ID => $registration) {
1398
                    $default_data['registrations'][ $REG_ID ] = $registration->status_ID();
1399
                }
1400
                if ($this->transaction->ID()) {
1401
                    $TXN_ID = 'EE_Transaction: ' . $this->transaction->ID();
1402
                    // don't serialize objects
1403
                    $info = $this->_strip_objects($info);
1404
                    if (! isset($debug_data[ $TXN_ID ])) {
1405
                        $debug_data[ $TXN_ID ] = array();
1406
                    }
1407
                    $debug_data[ $TXN_ID ][ microtime() ] = array_merge(
1408
                        $default_data,
1409
                        $info
1410
                    );
1411
                    update_option('EE_DEBUG_SPCO_' . EE_Session::instance()->id(), $debug_data);
1412
                }
1413
            }
1414
        }
1415
    }
1416
1417
1418
    /**
1419
     * _strip_objects
1420
     *
1421
     * @param array $info
1422
     * @return array
1423
     */
1424
    public function _strip_objects($info = array())
1425
    {
1426
        foreach ((array) $info as $key => $value) {
1427
            if (is_array($value)) {
1428
                $info[ $key ] = $this->_strip_objects($value);
1429
            } elseif (is_object($value)) {
1430
                $object_class = get_class($value);
1431
                $info[ $object_class ] = array();
1432
                $info[ $object_class ]['ID'] = method_exists($value, 'ID') ? $value->ID() : 0;
1433 View Code Duplication
                if (method_exists($value, 'status')) {
1434
                    $info[ $object_class ]['status'] = $value->status();
1435
                } elseif (method_exists($value, 'status_ID')) {
1436
                    $info[ $object_class ]['status'] = $value->status_ID();
1437
                }
1438
                unset($info[ $key ]);
1439
            }
1440
        }
1441
        return (array) $info;
1442
    }
1443
}
1444