Completed
Branch decaf-fixes/replace-request-ha... (dd0ac0)
by
unknown
04:45 queued 03:02
created
reg_steps/payment_options/EE_SPCO_Reg_Step_Payment_Options.class.php 2 patches
Indentation   +2829 added lines, -2829 removed lines patch added patch discarded remove patch
@@ -20,2833 +20,2833 @@
 block discarded – undo
20 20
 class EE_SPCO_Reg_Step_Payment_Options extends EE_SPCO_Reg_Step
21 21
 {
22 22
 
23
-    /**
24
-     * @var EE_Line_Item_Display $Line_Item_Display
25
-     */
26
-    protected $line_item_display;
27
-
28
-    /**
29
-     * @var boolean $handle_IPN_in_this_request
30
-     */
31
-    protected $handle_IPN_in_this_request = false;
32
-
33
-
34
-    /**
35
-     *    set_hooks - for hooking into EE Core, other modules, etc
36
-     *
37
-     * @access    public
38
-     * @return    void
39
-     */
40
-    public static function set_hooks()
41
-    {
42
-        add_filter(
43
-            'FHEE__SPCO__EE_Line_Item_Filter_Collection',
44
-            ['EE_SPCO_Reg_Step_Payment_Options', 'add_spco_line_item_filters']
45
-        );
46
-        add_action(
47
-            'wp_ajax_switch_spco_billing_form',
48
-            ['EE_SPCO_Reg_Step_Payment_Options', 'switch_spco_billing_form']
49
-        );
50
-        add_action(
51
-            'wp_ajax_nopriv_switch_spco_billing_form',
52
-            ['EE_SPCO_Reg_Step_Payment_Options', 'switch_spco_billing_form']
53
-        );
54
-        add_action('wp_ajax_save_payer_details', ['EE_SPCO_Reg_Step_Payment_Options', 'save_payer_details']);
55
-        add_action(
56
-            'wp_ajax_nopriv_save_payer_details',
57
-            ['EE_SPCO_Reg_Step_Payment_Options', 'save_payer_details']
58
-        );
59
-        add_action(
60
-            'wp_ajax_get_transaction_details_for_gateways',
61
-            ['EE_SPCO_Reg_Step_Payment_Options', 'get_transaction_details']
62
-        );
63
-        add_action(
64
-            'wp_ajax_nopriv_get_transaction_details_for_gateways',
65
-            ['EE_SPCO_Reg_Step_Payment_Options', 'get_transaction_details']
66
-        );
67
-        add_filter(
68
-            'FHEE__EED_Recaptcha___bypass_recaptcha__bypass_request_params_array',
69
-            ['EE_SPCO_Reg_Step_Payment_Options', 'bypass_recaptcha_for_load_payment_method'],
70
-            10,
71
-            1
72
-        );
73
-    }
74
-
75
-
76
-    /**
77
-     *    ajax switch_spco_billing_form
78
-     *
79
-     */
80
-    public static function switch_spco_billing_form()
81
-    {
82
-        EED_Single_Page_Checkout::process_ajax_request('switch_payment_method');
83
-    }
84
-
85
-
86
-    /**
87
-     *    ajax save_payer_details
88
-     *
89
-     */
90
-    public static function save_payer_details()
91
-    {
92
-        EED_Single_Page_Checkout::process_ajax_request('save_payer_details_via_ajax');
93
-    }
94
-
95
-
96
-    /**
97
-     *    ajax get_transaction_details
98
-     *
99
-     */
100
-    public static function get_transaction_details()
101
-    {
102
-        EED_Single_Page_Checkout::process_ajax_request('get_transaction_details_for_gateways');
103
-    }
104
-
105
-
106
-    /**
107
-     * bypass_recaptcha_for_load_payment_method
108
-     *
109
-     * @access public
110
-     * @return array
111
-     * @throws InvalidArgumentException
112
-     * @throws InvalidDataTypeException
113
-     * @throws InvalidInterfaceException
114
-     */
115
-    public static function bypass_recaptcha_for_load_payment_method()
116
-    {
117
-        return [
118
-            'EESID'  => EE_Registry::instance()->SSN->id(),
119
-            'step'   => 'payment_options',
120
-            'action' => 'spco_billing_form',
121
-        ];
122
-    }
123
-
124
-
125
-    /**
126
-     *    class constructor
127
-     *
128
-     * @access    public
129
-     * @param EE_Checkout $checkout
130
-     */
131
-    public function __construct(EE_Checkout $checkout)
132
-    {
133
-        $this->request   = EED_Single_Page_Checkout::getRequest();
134
-        $this->_slug     = 'payment_options';
135
-        $this->_name     = esc_html__('Payment Options', 'event_espresso');
136
-        $this->_template = SPCO_REG_STEPS_PATH . $this->_slug . '/payment_options_main.template.php';
137
-        $this->checkout  = $checkout;
138
-        $this->_reset_success_message();
139
-        $this->set_instructions(
140
-            esc_html__(
141
-                'Please select a method of payment and provide any necessary billing information before proceeding.',
142
-                'event_espresso'
143
-            )
144
-        );
145
-    }
146
-
147
-
148
-    /**
149
-     * @return null
150
-     */
151
-    public function line_item_display()
152
-    {
153
-        return $this->line_item_display;
154
-    }
155
-
156
-
157
-    /**
158
-     * @param null $line_item_display
159
-     */
160
-    public function set_line_item_display($line_item_display)
161
-    {
162
-        $this->line_item_display = $line_item_display;
163
-    }
164
-
165
-
166
-    /**
167
-     * @return boolean
168
-     */
169
-    public function handle_IPN_in_this_request()
170
-    {
171
-        return $this->handle_IPN_in_this_request;
172
-    }
173
-
174
-
175
-    /**
176
-     * @param boolean $handle_IPN_in_this_request
177
-     */
178
-    public function set_handle_IPN_in_this_request($handle_IPN_in_this_request)
179
-    {
180
-        $this->handle_IPN_in_this_request = filter_var($handle_IPN_in_this_request, FILTER_VALIDATE_BOOLEAN);
181
-    }
182
-
183
-
184
-    /**
185
-     * translate_js_strings
186
-     *
187
-     * @return void
188
-     */
189
-    public function translate_js_strings()
190
-    {
191
-        EE_Registry::$i18n_js_strings['no_payment_method']      = esc_html__(
192
-            'Please select a method of payment in order to continue.',
193
-            'event_espresso'
194
-        );
195
-        EE_Registry::$i18n_js_strings['invalid_payment_method'] = esc_html__(
196
-            'A valid method of payment could not be determined. Please refresh the page and try again.',
197
-            'event_espresso'
198
-        );
199
-        EE_Registry::$i18n_js_strings['forwarding_to_offsite']  = esc_html__(
200
-            'Forwarding to Secure Payment Provider.',
201
-            'event_espresso'
202
-        );
203
-    }
204
-
205
-
206
-    /**
207
-     * enqueue_styles_and_scripts
208
-     *
209
-     * @return void
210
-     * @throws EE_Error
211
-     * @throws InvalidArgumentException
212
-     * @throws InvalidDataTypeException
213
-     * @throws InvalidInterfaceException
214
-     * @throws ReflectionException
215
-     */
216
-    public function enqueue_styles_and_scripts()
217
-    {
218
-        $transaction = $this->checkout->transaction;
219
-        // if the transaction isn't set or nothing is owed on it, don't enqueue any JS
220
-        if (! $transaction instanceof EE_Transaction || EEH_Money::compare_floats($transaction->remaining(), 0)) {
221
-            return;
222
-        }
223
-        foreach (EEM_Payment_Method::instance()->get_all_for_transaction(
224
-            $transaction,
225
-            EEM_Payment_Method::scope_cart
226
-        ) as $payment_method) {
227
-            $type_obj = $payment_method->type_obj();
228
-            if ($type_obj instanceof EE_PMT_Base) {
229
-                $billing_form = $type_obj->generate_new_billing_form($transaction);
230
-                if ($billing_form instanceof EE_Form_Section_Proper) {
231
-                    $billing_form->enqueue_js();
232
-                }
233
-            }
234
-        }
235
-    }
236
-
237
-
238
-    /**
239
-     * initialize_reg_step
240
-     *
241
-     * @return bool
242
-     * @throws EE_Error
243
-     * @throws InvalidArgumentException
244
-     * @throws ReflectionException
245
-     * @throws InvalidDataTypeException
246
-     * @throws InvalidInterfaceException
247
-     */
248
-    public function initialize_reg_step()
249
-    {
250
-        // TODO: if /when we implement donations, then this will need overriding
251
-        if (// don't need payment options for:
252
-            // registrations made via the admin
253
-            // completed transactions
254
-            // overpaid transactions
255
-            // $ 0.00 transactions(no payment required)
256
-            ! $this->checkout->payment_required()
257
-            // but do NOT remove if current action being called belongs to this reg step
258
-            && ! is_callable([$this, $this->checkout->action])
259
-            && ! $this->completed()
260
-        ) {
261
-            // and if so, then we no longer need the Payment Options step
262
-            if ($this->is_current_step()) {
263
-                $this->checkout->generate_reg_form = false;
264
-            }
265
-            $this->checkout->remove_reg_step($this->_slug);
266
-            // DEBUG LOG
267
-            // $this->checkout->log( __CLASS__, __FUNCTION__, __LINE__ );
268
-            return false;
269
-        }
270
-        // load EEM_Payment_Method
271
-        EE_Registry::instance()->load_model('Payment_Method');
272
-        // get all active payment methods
273
-        $this->checkout->available_payment_methods = EEM_Payment_Method::instance()->get_all_for_transaction(
274
-            $this->checkout->transaction,
275
-            EEM_Payment_Method::scope_cart
276
-        );
277
-        return true;
278
-    }
279
-
280
-
281
-    /**
282
-     * @return EE_Form_Section_Proper
283
-     * @throws EE_Error
284
-     * @throws InvalidArgumentException
285
-     * @throws ReflectionException
286
-     * @throws EntityNotFoundException
287
-     * @throws InvalidDataTypeException
288
-     * @throws InvalidInterfaceException
289
-     * @throws InvalidStatusException
290
-     */
291
-    public function generate_reg_form()
292
-    {
293
-        // reset in case someone changes their mind
294
-        $this->_reset_selected_method_of_payment();
295
-        // set some defaults
296
-        $this->checkout->selected_method_of_payment = 'payments_closed';
297
-        $registrations_requiring_payment            = [];
298
-        $registrations_for_free_events              = [];
299
-        $registrations_requiring_pre_approval       = [];
300
-        $sold_out_events                            = [];
301
-        $insufficient_spaces_available              = [];
302
-        $no_payment_required                        = true;
303
-        // loop thru registrations to gather info
304
-        $registrations         = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
305
-        $ejected_registrations = EE_SPCO_Reg_Step_Payment_Options::find_registrations_that_lost_their_space(
306
-            $registrations,
307
-            $this->checkout->revisit
308
-        );
309
-        foreach ($registrations as $REG_ID => $registration) {
310
-            /** @var $registration EE_Registration */
311
-            // has this registration lost it's space ?
312
-            if (isset($ejected_registrations[ $REG_ID ])) {
313
-                if ($registration->event()->is_sold_out() || $registration->event()->is_sold_out(true)) {
314
-                    $sold_out_events[ $registration->event()->ID() ] = $registration->event();
315
-                } else {
316
-                    $insufficient_spaces_available[ $registration->event()->ID() ] = $registration->event();
317
-                }
318
-                continue;
319
-            }
320
-            // event requires admin approval
321
-            if ($registration->status_ID() === EEM_Registration::status_id_not_approved) {
322
-                // add event to list of events with pre-approval reg status
323
-                $registrations_requiring_pre_approval[ $REG_ID ] = $registration;
324
-                do_action(
325
-                    'AHEE__EE_SPCO_Reg_Step_Payment_Options__generate_reg_form__event_requires_pre_approval',
326
-                    $registration->event(),
327
-                    $this
328
-                );
329
-                continue;
330
-            }
331
-            if ($this->checkout->revisit
332
-                && $registration->status_ID() !== EEM_Registration::status_id_approved
333
-                && (
334
-                    $registration->event()->is_sold_out()
335
-                    || $registration->event()->is_sold_out(true)
336
-                )
337
-            ) {
338
-                // add event to list of events that are sold out
339
-                $sold_out_events[ $registration->event()->ID() ] = $registration->event();
340
-                do_action(
341
-                    'AHEE__EE_SPCO_Reg_Step_Payment_Options__generate_reg_form__sold_out_event',
342
-                    $registration->event(),
343
-                    $this
344
-                );
345
-                continue;
346
-            }
347
-            // are they allowed to pay now and is there monies owing?
348
-            if ($registration->owes_monies_and_can_pay()) {
349
-                $registrations_requiring_payment[ $REG_ID ] = $registration;
350
-                do_action(
351
-                    'AHEE__EE_SPCO_Reg_Step_Payment_Options__generate_reg_form__event_requires_payment',
352
-                    $registration->event(),
353
-                    $this
354
-                );
355
-            } elseif (! $this->checkout->revisit
356
-                      && $registration->status_ID() !== EEM_Registration::status_id_not_approved
357
-                      && $registration->ticket()->is_free()
358
-            ) {
359
-                $registrations_for_free_events[ $registration->ticket()->ID() ] = $registration;
360
-            }
361
-        }
362
-        $subsections = [];
363
-        // now decide which template to load
364
-        if (! empty($sold_out_events)) {
365
-            $subsections['sold_out_events'] = $this->_sold_out_events($sold_out_events);
366
-        }
367
-        if (! empty($insufficient_spaces_available)) {
368
-            $subsections['insufficient_space'] = $this->_insufficient_spaces_available(
369
-                $insufficient_spaces_available
370
-            );
371
-        }
372
-        if (! empty($registrations_requiring_pre_approval)) {
373
-            $subsections['registrations_requiring_pre_approval'] = $this->_registrations_requiring_pre_approval(
374
-                $registrations_requiring_pre_approval
375
-            );
376
-        }
377
-        if (! empty($registrations_for_free_events)) {
378
-            $subsections['no_payment_required'] = $this->_no_payment_required($registrations_for_free_events);
379
-        }
380
-        if (! empty($registrations_requiring_payment)) {
381
-            if ($this->checkout->amount_owing > 0) {
382
-                // autoload Line_Item_Display classes
383
-                EEH_Autoloader::register_line_item_filter_autoloaders();
384
-                $line_item_filter_processor = new EE_Line_Item_Filter_Processor(
385
-                    apply_filters(
386
-                        'FHEE__SPCO__EE_Line_Item_Filter_Collection',
387
-                        new EE_Line_Item_Filter_Collection()
388
-                    ),
389
-                    $this->checkout->cart->get_grand_total()
390
-                );
391
-                /** @var EE_Line_Item $filtered_line_item_tree */
392
-                $filtered_line_item_tree = $line_item_filter_processor->process();
393
-                EEH_Autoloader::register_line_item_display_autoloaders();
394
-                $this->set_line_item_display(new EE_Line_Item_Display('spco'));
395
-                $subsections['payment_options'] = $this->_display_payment_options(
396
-                    $this->line_item_display->display_line_item(
397
-                        $filtered_line_item_tree,
398
-                        ['registrations' => $registrations]
399
-                    )
400
-                );
401
-                $this->checkout->amount_owing   = $filtered_line_item_tree->total();
402
-                $this->_apply_registration_payments_to_amount_owing($registrations);
403
-            }
404
-            $no_payment_required = false;
405
-        } else {
406
-            $this->_hide_reg_step_submit_button_if_revisit();
407
-        }
408
-        $this->_save_selected_method_of_payment();
409
-
410
-        $subsections['default_hidden_inputs'] = $this->reg_step_hidden_inputs();
411
-        $subsections['extra_hidden_inputs']   = $this->_extra_hidden_inputs($no_payment_required);
412
-
413
-        return new EE_Form_Section_Proper(
414
-            [
415
-                'name'            => $this->reg_form_name(),
416
-                'html_id'         => $this->reg_form_name(),
417
-                'subsections'     => $subsections,
418
-                'layout_strategy' => new EE_No_Layout(),
419
-            ]
420
-        );
421
-    }
422
-
423
-
424
-    /**
425
-     * add line item filters required for this reg step
426
-     * these filters are applied via this line in EE_SPCO_Reg_Step_Payment_Options::set_hooks():
427
-     *        add_filter( 'FHEE__SPCO__EE_Line_Item_Filter_Collection', array( 'EE_SPCO_Reg_Step_Payment_Options',
428
-     *        'add_spco_line_item_filters' ) ); so any code that wants to use the same set of filters during the
429
-     *        payment options reg step, can apply these filters via the following: apply_filters(
430
-     *        'FHEE__SPCO__EE_Line_Item_Filter_Collection', new EE_Line_Item_Filter_Collection() ) or to an existing
431
-     *        filter collection by passing that instead of instantiating a new collection
432
-     *
433
-     * @param EE_Line_Item_Filter_Collection $line_item_filter_collection
434
-     * @return EE_Line_Item_Filter_Collection
435
-     * @throws EE_Error
436
-     * @throws InvalidArgumentException
437
-     * @throws ReflectionException
438
-     * @throws EntityNotFoundException
439
-     * @throws InvalidDataTypeException
440
-     * @throws InvalidInterfaceException
441
-     * @throws InvalidStatusException
442
-     */
443
-    public static function add_spco_line_item_filters(EE_Line_Item_Filter_Collection $line_item_filter_collection)
444
-    {
445
-        if (! EE_Registry::instance()->SSN instanceof EE_Session) {
446
-            return $line_item_filter_collection;
447
-        }
448
-        if (! EE_Registry::instance()->SSN->checkout() instanceof EE_Checkout) {
449
-            return $line_item_filter_collection;
450
-        }
451
-        if (! EE_Registry::instance()->SSN->checkout()->transaction instanceof EE_Transaction) {
452
-            return $line_item_filter_collection;
453
-        }
454
-        $line_item_filter_collection->add(
455
-            new EE_Billable_Line_Item_Filter(
456
-                EE_SPCO_Reg_Step_Payment_Options::remove_ejected_registrations(
457
-                    EE_Registry::instance()->SSN->checkout()->transaction->registrations(
458
-                        EE_Registry::instance()->SSN->checkout()->reg_cache_where_params
459
-                    )
460
-                )
461
-            )
462
-        );
463
-        $line_item_filter_collection->add(new EE_Non_Zero_Line_Item_Filter());
464
-        return $line_item_filter_collection;
465
-    }
466
-
467
-
468
-    /**
469
-     * remove_ejected_registrations
470
-     * if a registrant has lost their potential space at an event due to lack of payment,
471
-     * then this method removes them from the list of registrations being paid for during this request
472
-     *
473
-     * @param EE_Registration[] $registrations
474
-     * @return EE_Registration[]
475
-     * @throws EE_Error
476
-     * @throws InvalidArgumentException
477
-     * @throws ReflectionException
478
-     * @throws EntityNotFoundException
479
-     * @throws InvalidDataTypeException
480
-     * @throws InvalidInterfaceException
481
-     * @throws InvalidStatusException
482
-     */
483
-    public static function remove_ejected_registrations(array $registrations)
484
-    {
485
-        $ejected_registrations = EE_SPCO_Reg_Step_Payment_Options::find_registrations_that_lost_their_space(
486
-            $registrations,
487
-            EE_Registry::instance()->SSN->checkout()->revisit
488
-        );
489
-        foreach ($registrations as $REG_ID => $registration) {
490
-            // has this registration lost it's space ?
491
-            if (isset($ejected_registrations[ $REG_ID ])) {
492
-                unset($registrations[ $REG_ID ]);
493
-            }
494
-        }
495
-        return $registrations;
496
-    }
497
-
498
-
499
-    /**
500
-     * find_registrations_that_lost_their_space
501
-     * If a registrant chooses an offline payment method like Invoice,
502
-     * then no space is reserved for them at the event until they fully pay fo that site
503
-     * (unless the event's default reg status is set to APPROVED)
504
-     * if a registrant then later returns to pay, but the number of spaces available has been reduced due to sales,
505
-     * then this method will determine which registrations have lost the ability to complete the reg process.
506
-     *
507
-     * @param EE_Registration[] $registrations
508
-     * @param bool              $revisit
509
-     * @return array
510
-     * @throws EE_Error
511
-     * @throws InvalidArgumentException
512
-     * @throws ReflectionException
513
-     * @throws EntityNotFoundException
514
-     * @throws InvalidDataTypeException
515
-     * @throws InvalidInterfaceException
516
-     * @throws InvalidStatusException
517
-     */
518
-    public static function find_registrations_that_lost_their_space(array $registrations, $revisit = false)
519
-    {
520
-        // registrations per event
521
-        $event_reg_count = [];
522
-        // spaces left per event
523
-        $event_spaces_remaining = [];
524
-        // tickets left sorted by ID
525
-        $tickets_remaining = [];
526
-        // registrations that have lost their space
527
-        $ejected_registrations = [];
528
-        foreach ($registrations as $REG_ID => $registration) {
529
-            if ($registration->status_ID() === EEM_Registration::status_id_approved
530
-                || apply_filters(
531
-                    'FHEE__EE_SPCO_Reg_Step_Payment_Options__find_registrations_that_lost_their_space__allow_reg_payment',
532
-                    false,
533
-                    $registration,
534
-                    $revisit
535
-                )
536
-            ) {
537
-                continue;
538
-            }
539
-            $EVT_ID = $registration->event_ID();
540
-            $ticket = $registration->ticket();
541
-            if (! isset($tickets_remaining[ $ticket->ID() ])) {
542
-                $tickets_remaining[ $ticket->ID() ] = $ticket->remaining();
543
-            }
544
-            if ($tickets_remaining[ $ticket->ID() ] > 0) {
545
-                if (! isset($event_reg_count[ $EVT_ID ])) {
546
-                    $event_reg_count[ $EVT_ID ] = 0;
547
-                }
548
-                $event_reg_count[ $EVT_ID ]++;
549
-                if (! isset($event_spaces_remaining[ $EVT_ID ])) {
550
-                    $event_spaces_remaining[ $EVT_ID ] = $registration->event()->spaces_remaining_for_sale();
551
-                }
552
-            }
553
-            if ($revisit
554
-                && ($tickets_remaining[ $ticket->ID() ] === 0
555
-                    || $event_reg_count[ $EVT_ID ] > $event_spaces_remaining[ $EVT_ID ]
556
-                )
557
-            ) {
558
-                $ejected_registrations[ $REG_ID ] = $registration->event();
559
-                if ($registration->status_ID() !== EEM_Registration::status_id_wait_list) {
560
-                    /** @type EE_Registration_Processor $registration_processor */
561
-                    $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
562
-                    // at this point, we should have enough details about the registrant to consider the registration
563
-                    // NOT incomplete
564
-                    $registration_processor->manually_update_registration_status(
565
-                        $registration,
566
-                        EEM_Registration::status_id_wait_list
567
-                    );
568
-                }
569
-            }
570
-        }
571
-        return $ejected_registrations;
572
-    }
573
-
574
-
575
-    /**
576
-     * _hide_reg_step_submit_button
577
-     * removes the html for the reg step submit button
578
-     * by replacing it with an empty string via filter callback
579
-     *
580
-     * @return void
581
-     */
582
-    protected function _adjust_registration_status_if_event_old_sold()
583
-    {
584
-    }
585
-
586
-
587
-    /**
588
-     * _hide_reg_step_submit_button
589
-     * removes the html for the reg step submit button
590
-     * by replacing it with an empty string via filter callback
591
-     *
592
-     * @return void
593
-     */
594
-    protected function _hide_reg_step_submit_button_if_revisit()
595
-    {
596
-        if ($this->checkout->revisit) {
597
-            add_filter('FHEE__EE_SPCO_Reg_Step__reg_step_submit_button__sbmt_btn_html', '__return_empty_string');
598
-        }
599
-    }
600
-
601
-
602
-    /**
603
-     * sold_out_events
604
-     * displays notices regarding events that have sold out since hte registrant first signed up
605
-     *
606
-     * @param EE_Event[] $sold_out_events_array
607
-     * @return EE_Form_Section_Proper
608
-     * @throws EE_Error
609
-     */
610
-    private function _sold_out_events($sold_out_events_array = [])
611
-    {
612
-        // set some defaults
613
-        $this->checkout->selected_method_of_payment = 'events_sold_out';
614
-        $sold_out_events                            = '';
615
-        foreach ($sold_out_events_array as $sold_out_event) {
616
-            $sold_out_events .= EEH_HTML::li(
617
-                EEH_HTML::span(
618
-                    '  ' . $sold_out_event->name(),
619
-                    '',
620
-                    'dashicons dashicons-marker ee-icon-size-16 pink-text'
621
-                )
622
-            );
623
-        }
624
-        return new EE_Form_Section_Proper(
625
-            [
626
-                'layout_strategy' => new EE_Template_Layout(
627
-                    [
628
-                        'layout_template_file' => SPCO_REG_STEPS_PATH
629
-                                                  . $this->_slug
630
-                                                  . '/sold_out_events.template.php',
631
-                        'template_args'        => apply_filters(
632
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___sold_out_events__template_args',
633
-                            [
634
-                                'sold_out_events'     => $sold_out_events,
635
-                                'sold_out_events_msg' => apply_filters(
636
-                                    'FHEE__EE_SPCO_Reg_Step_Payment_Options___sold_out_events__sold_out_events_msg',
637
-                                    sprintf(
638
-                                        esc_html__(
639
-                                            'It appears that the event you were about to make a payment for has sold out since you first registered. If you have already made a partial payment towards this event, please contact the event administrator for a refund.%3$s%3$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.%2$s',
640
-                                            'event_espresso'
641
-                                        ),
642
-                                        '<strong>',
643
-                                        '</strong>',
644
-                                        '<br />'
645
-                                    )
646
-                                ),
647
-                            ]
648
-                        ),
649
-                    ]
650
-                ),
651
-            ]
652
-        );
653
-    }
654
-
655
-
656
-    /**
657
-     * _insufficient_spaces_available
658
-     * displays notices regarding events that do not have enough remaining spaces
659
-     * to satisfy the current number of registrations looking to pay
660
-     *
661
-     * @param EE_Event[] $insufficient_spaces_events_array
662
-     * @return EE_Form_Section_Proper
663
-     * @throws EE_Error
664
-     * @throws ReflectionException
665
-     */
666
-    private function _insufficient_spaces_available($insufficient_spaces_events_array = [])
667
-    {
668
-        // set some defaults
669
-        $this->checkout->selected_method_of_payment = 'invoice';
670
-        $insufficient_space_events                  = '';
671
-        foreach ($insufficient_spaces_events_array as $event) {
672
-            if ($event instanceof EE_Event) {
673
-                $insufficient_space_events .= EEH_HTML::li(
674
-                    EEH_HTML::span(' ' . $event->name(), '', 'dashicons dashicons-marker ee-icon-size-16 pink-text')
675
-                );
676
-            }
677
-        }
678
-        return new EE_Form_Section_Proper(
679
-            [
680
-                'subsections'     => [
681
-                    'default_hidden_inputs' => $this->reg_step_hidden_inputs(),
682
-                    'extra_hidden_inputs'   => $this->_extra_hidden_inputs(),
683
-                ],
684
-                'layout_strategy' => new EE_Template_Layout(
685
-                    [
686
-                        'layout_template_file' => SPCO_REG_STEPS_PATH
687
-                                                  . $this->_slug
688
-                                                  . '/sold_out_events.template.php',
689
-                        'template_args'        => apply_filters(
690
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___insufficient_spaces_available__template_args',
691
-                            [
692
-                                'sold_out_events'     => $insufficient_space_events,
693
-                                'sold_out_events_msg' => apply_filters(
694
-                                    'FHEE__EE_SPCO_Reg_Step_Payment_Options___insufficient_spaces_available__insufficient_space_msg',
695
-                                    esc_html__(
696
-                                        'It appears that the event you were about to make a payment for has sold additional tickets since you first registered, and there are no longer enough spaces left to accommodate your selections. You may continue to pay and secure the available space(s) remaining, or simply cancel if you no longer wish to purchase. If you have already made a partial payment towards this event, please contact the event administrator for a refund.',
697
-                                        'event_espresso'
698
-                                    )
699
-                                ),
700
-                            ]
701
-                        ),
702
-                    ]
703
-                ),
704
-            ]
705
-        );
706
-    }
707
-
708
-
709
-    /**
710
-     * registrations_requiring_pre_approval
711
-     *
712
-     * @param array $registrations_requiring_pre_approval
713
-     * @return EE_Form_Section_Proper
714
-     * @throws EE_Error
715
-     * @throws EntityNotFoundException
716
-     * @throws ReflectionException
717
-     */
718
-    private function _registrations_requiring_pre_approval($registrations_requiring_pre_approval = [])
719
-    {
720
-        $events_requiring_pre_approval = [];
721
-        foreach ($registrations_requiring_pre_approval as $registration) {
722
-            if ($registration instanceof EE_Registration && $registration->event() instanceof EE_Event) {
723
-                $events_requiring_pre_approval[ $registration->event()->ID() ] = EEH_HTML::li(
724
-                    EEH_HTML::span(
725
-                        '',
726
-                        '',
727
-                        'dashicons dashicons-marker ee-icon-size-16 orange-text'
728
-                    )
729
-                    . EEH_HTML::span($registration->event()->name(), '', 'orange-text')
730
-                );
731
-            }
732
-        }
733
-        return new EE_Form_Section_Proper(
734
-            [
735
-                'layout_strategy' => new EE_Template_Layout(
736
-                    [
737
-                        'layout_template_file' => SPCO_REG_STEPS_PATH
738
-                                                  . $this->_slug
739
-                                                  . '/events_requiring_pre_approval.template.php', // layout_template
740
-                        'template_args'        => apply_filters(
741
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___sold_out_events__template_args',
742
-                            [
743
-                                'events_requiring_pre_approval'     => implode('', $events_requiring_pre_approval),
744
-                                'events_requiring_pre_approval_msg' => apply_filters(
745
-                                    'FHEE__EE_SPCO_Reg_Step_Payment_Options___events_requiring_pre_approval__events_requiring_pre_approval_msg',
746
-                                    esc_html__(
747
-                                        'The following events do not require payment at this time and will not be billed during this transaction. Billing will only occur after the attendee has been approved by the event organizer. You will be notified when your registration has been processed. If this is a free event, then no billing will occur.',
748
-                                        'event_espresso'
749
-                                    )
750
-                                ),
751
-                            ]
752
-                        ),
753
-                    ]
754
-                ),
755
-            ]
756
-        );
757
-    }
758
-
759
-
760
-    /**
761
-     * _no_payment_required
762
-     *
763
-     * @param EE_Event[] $registrations_for_free_events
764
-     * @return EE_Form_Section_Proper
765
-     * @throws EE_Error
766
-     */
767
-    private function _no_payment_required($registrations_for_free_events = [])
768
-    {
769
-        // set some defaults
770
-        $this->checkout->selected_method_of_payment = 'no_payment_required';
771
-        // generate no_payment_required form
772
-        return new EE_Form_Section_Proper(
773
-            [
774
-                'layout_strategy' => new EE_Template_Layout(
775
-                    [
776
-                        'layout_template_file' => SPCO_REG_STEPS_PATH
777
-                                                  . $this->_slug
778
-                                                  . '/no_payment_required.template.php', // layout_template
779
-                        'template_args'        => apply_filters(
780
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___no_payment_required__template_args',
781
-                            [
782
-                                'revisit'                       => $this->checkout->revisit,
783
-                                'registrations'                 => [],
784
-                                'ticket_count'                  => [],
785
-                                'registrations_for_free_events' => $registrations_for_free_events,
786
-                                'no_payment_required_msg'       => EEH_HTML::p(
787
-                                    esc_html__('This is a free event, so no billing will occur.', 'event_espresso')
788
-                                ),
789
-                            ]
790
-                        ),
791
-                    ]
792
-                ),
793
-            ]
794
-        );
795
-    }
796
-
797
-
798
-    /**
799
-     * _display_payment_options
800
-     *
801
-     * @param string $transaction_details
802
-     * @return EE_Form_Section_Proper
803
-     * @throws EE_Error
804
-     * @throws InvalidArgumentException
805
-     * @throws InvalidDataTypeException
806
-     * @throws InvalidInterfaceException
807
-     */
808
-    private function _display_payment_options($transaction_details = '')
809
-    {
810
-        // has method_of_payment been set by no-js user?
811
-        $this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment();
812
-        // build payment options form
813
-        return apply_filters(
814
-            'FHEE__EE_SPCO_Reg_Step_Payment_Options___display_payment_options__payment_options_form',
815
-            new EE_Form_Section_Proper(
816
-                [
817
-                    'subsections'     => [
818
-                        'before_payment_options' => apply_filters(
819
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___display_payment_options__before_payment_options',
820
-                            new EE_Form_Section_Proper(
821
-                                ['layout_strategy' => new EE_Div_Per_Section_Layout()]
822
-                            )
823
-                        ),
824
-                        'payment_options'        => $this->_setup_payment_options(),
825
-                        'after_payment_options'  => apply_filters(
826
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___display_payment_options__after_payment_options',
827
-                            new EE_Form_Section_Proper(
828
-                                ['layout_strategy' => new EE_Div_Per_Section_Layout()]
829
-                            )
830
-                        ),
831
-                    ],
832
-                    'layout_strategy' => new EE_Template_Layout(
833
-                        [
834
-                            'layout_template_file' => $this->_template,
835
-                            'template_args'        => apply_filters(
836
-                                'FHEE__EE_SPCO_Reg_Step_Payment_Options___display_payment_options__template_args',
837
-                                [
838
-                                    'reg_count'                 => $this->line_item_display->total_items(),
839
-                                    'transaction_details'       => $transaction_details,
840
-                                    'available_payment_methods' => [],
841
-                                ]
842
-                            ),
843
-                        ]
844
-                    ),
845
-                ]
846
-            )
847
-        );
848
-    }
849
-
850
-
851
-    /**
852
-     * _extra_hidden_inputs
853
-     *
854
-     * @param bool $no_payment_required
855
-     * @return EE_Form_Section_Proper
856
-     * @throws EE_Error
857
-     * @throws ReflectionException
858
-     */
859
-    private function _extra_hidden_inputs($no_payment_required = true)
860
-    {
861
-        return new EE_Form_Section_Proper(
862
-            [
863
-                'html_id'         => 'ee-' . $this->slug() . '-extra-hidden-inputs',
864
-                'layout_strategy' => new EE_Div_Per_Section_Layout(),
865
-                'subsections'     => [
866
-                    'spco_no_payment_required' => new EE_Hidden_Input(
867
-                        [
868
-                            'normalization_strategy' => new EE_Boolean_Normalization(),
869
-                            'html_name'              => 'spco_no_payment_required',
870
-                            'html_id'                => 'spco-no-payment-required-payment_options',
871
-                            'default'                => $no_payment_required,
872
-                        ]
873
-                    ),
874
-                    'spco_transaction_id'      => new EE_Fixed_Hidden_Input(
875
-                        [
876
-                            'normalization_strategy' => new EE_Int_Normalization(),
877
-                            'html_name'              => 'spco_transaction_id',
878
-                            'html_id'                => 'spco-transaction-id',
879
-                            'default'                => $this->checkout->transaction->ID(),
880
-                        ]
881
-                    ),
882
-                ],
883
-            ]
884
-        );
885
-    }
886
-
887
-
888
-    /**
889
-     *    _apply_registration_payments_to_amount_owing
890
-     *
891
-     * @param array $registrations
892
-     * @throws EE_Error
893
-     */
894
-    protected function _apply_registration_payments_to_amount_owing(array $registrations)
895
-    {
896
-        $payments = [];
897
-        foreach ($registrations as $registration) {
898
-            if ($registration instanceof EE_Registration && $registration->owes_monies_and_can_pay()) {
899
-                $payments += $registration->registration_payments();
900
-            }
901
-        }
902
-        if (! empty($payments)) {
903
-            foreach ($payments as $payment) {
904
-                if ($payment instanceof EE_Registration_Payment) {
905
-                    $this->checkout->amount_owing -= $payment->amount();
906
-                }
907
-            }
908
-        }
909
-    }
910
-
911
-
912
-    /**
913
-     *    _reset_selected_method_of_payment
914
-     *
915
-     * @access    private
916
-     * @param bool $force_reset
917
-     * @return void
918
-     * @throws InvalidArgumentException
919
-     * @throws InvalidDataTypeException
920
-     * @throws InvalidInterfaceException
921
-     */
922
-    private function _reset_selected_method_of_payment($force_reset = false)
923
-    {
924
-        /** @var RequestInterface $request */
925
-        $request              = LoaderFactory::getLoader()->getShared(RequestInterface::class);
926
-        $reset_payment_method = $request->getRequestParam('reset_payment_method', $force_reset, 'bool');
927
-        if ($reset_payment_method) {
928
-            $this->checkout->selected_method_of_payment = null;
929
-            $this->checkout->payment_method             = null;
930
-            $this->checkout->billing_form               = null;
931
-            $this->_save_selected_method_of_payment();
932
-        }
933
-    }
934
-
935
-
936
-    /**
937
-     * _save_selected_method_of_payment
938
-     * stores the selected_method_of_payment in the session
939
-     * so that it's available for all subsequent requests including AJAX
940
-     *
941
-     * @access        private
942
-     * @param string $selected_method_of_payment
943
-     * @return void
944
-     * @throws InvalidArgumentException
945
-     * @throws InvalidDataTypeException
946
-     * @throws InvalidInterfaceException
947
-     */
948
-    private function _save_selected_method_of_payment($selected_method_of_payment = '')
949
-    {
950
-        $selected_method_of_payment = ! empty($selected_method_of_payment)
951
-            ? $selected_method_of_payment
952
-            : $this->checkout->selected_method_of_payment;
953
-        EE_Registry::instance()->SSN->set_session_data(
954
-            ['selected_method_of_payment' => $selected_method_of_payment]
955
-        );
956
-    }
957
-
958
-
959
-    /**
960
-     * _setup_payment_options
961
-     *
962
-     * @return EE_Form_Section_Proper
963
-     * @throws EE_Error
964
-     * @throws InvalidArgumentException
965
-     * @throws InvalidDataTypeException
966
-     * @throws InvalidInterfaceException
967
-     */
968
-    public function _setup_payment_options()
969
-    {
970
-        // load payment method classes
971
-        $this->checkout->available_payment_methods = $this->_get_available_payment_methods();
972
-        if (empty($this->checkout->available_payment_methods)) {
973
-            EE_Error::add_error(
974
-                apply_filters(
975
-                    'FHEE__EE_SPCO_Reg_Step_Payment_Options___setup_payment_options__error_message_no_payment_methods',
976
-                    sprintf(
977
-                        esc_html__(
978
-                            'Sorry, you cannot complete your purchase because a payment method is not active.%1$s Please contact %2$s for assistance and provide a description of the problem.',
979
-                            'event_espresso'
980
-                        ),
981
-                        '<br>',
982
-                        EE_Registry::instance()->CFG->organization->get_pretty('email')
983
-                    )
984
-                ),
985
-                __FILE__,
986
-                __FUNCTION__,
987
-                __LINE__
988
-            );
989
-        }
990
-        // switch up header depending on number of available payment methods
991
-        $payment_method_header     = count($this->checkout->available_payment_methods) > 1
992
-            ? apply_filters(
993
-                'FHEE__registration_page_payment_options__method_of_payment_hdr',
994
-                esc_html__('Please Select Your Method of Payment', 'event_espresso')
995
-            )
996
-            : apply_filters(
997
-                'FHEE__registration_page_payment_options__method_of_payment_hdr',
998
-                esc_html__('Method of Payment', 'event_espresso')
999
-            );
1000
-        $available_payment_methods = [
1001
-            // display the "Payment Method" header
1002
-            'payment_method_header' => new EE_Form_Section_HTML(
1003
-                apply_filters(
1004
-                    'FHEE__EE_SPCO_Reg_Step_Payment_Options___setup_payment_options__payment_method_header',
1005
-                    EEH_HTML::h4($payment_method_header, 'method-of-payment-hdr'),
1006
-                    $payment_method_header
1007
-                )
1008
-            ),
1009
-        ];
1010
-        // the list of actual payment methods ( invoice, paypal, etc ) in a  ( slug => HTML )  format
1011
-        $available_payment_method_options = [];
1012
-        $default_payment_method_option    = [];
1013
-        // additional instructions to be displayed and hidden below payment methods (adding a clearing div to start)
1014
-        $payment_methods_billing_info = [
1015
-            new EE_Form_Section_HTML(
1016
-                EEH_HTML::div('<br />', '', '', 'clear:both;')
1017
-            ),
1018
-        ];
1019
-        // loop through payment methods
1020
-        foreach ($this->checkout->available_payment_methods as $payment_method) {
1021
-            if ($payment_method instanceof EE_Payment_Method) {
1022
-                $payment_method_button = EEH_HTML::img(
1023
-                    $payment_method->button_url(),
1024
-                    $payment_method->name(),
1025
-                    'spco-payment-method-' . $payment_method->slug() . '-btn-img',
1026
-                    'spco-payment-method-btn-img'
1027
-                );
1028
-                // check if any payment methods are set as default
1029
-                // if payment method is already selected OR nothing is selected and this payment method should be
1030
-                // open_by_default
1031
-                if (($this->checkout->selected_method_of_payment === $payment_method->slug())
1032
-                    || (! $this->checkout->selected_method_of_payment && $payment_method->open_by_default())
1033
-                ) {
1034
-                    $this->checkout->selected_method_of_payment = $payment_method->slug();
1035
-                    $this->_save_selected_method_of_payment();
1036
-                    $default_payment_method_option[ $payment_method->slug() ] = $payment_method_button;
1037
-                } else {
1038
-                    $available_payment_method_options[ $payment_method->slug() ] = $payment_method_button;
1039
-                }
1040
-                $payment_methods_billing_info[ $payment_method->slug() . '-info' ] =
1041
-                    $this->_payment_method_billing_info(
1042
-                        $payment_method
1043
-                    );
1044
-            }
1045
-        }
1046
-        // prepend available_payment_method_options with default_payment_method_option so that it appears first in list
1047
-        // of PMs
1048
-        $available_payment_method_options = $default_payment_method_option + $available_payment_method_options;
1049
-        // now generate the actual form  inputs
1050
-        $available_payment_methods['available_payment_methods'] = $this->_available_payment_method_inputs(
1051
-            $available_payment_method_options
1052
-        );
1053
-        $available_payment_methods                              += $payment_methods_billing_info;
1054
-        // build the available payment methods form
1055
-        return new EE_Form_Section_Proper(
1056
-            [
1057
-                'html_id'         => 'spco-available-methods-of-payment-dv',
1058
-                'subsections'     => $available_payment_methods,
1059
-                'layout_strategy' => new EE_Div_Per_Section_Layout(),
1060
-            ]
1061
-        );
1062
-    }
1063
-
1064
-
1065
-    /**
1066
-     * _get_available_payment_methods
1067
-     *
1068
-     * @return EE_Payment_Method[]
1069
-     * @throws EE_Error
1070
-     * @throws InvalidArgumentException
1071
-     * @throws InvalidDataTypeException
1072
-     * @throws InvalidInterfaceException
1073
-     */
1074
-    protected function _get_available_payment_methods()
1075
-    {
1076
-        if (! empty($this->checkout->available_payment_methods)) {
1077
-            return $this->checkout->available_payment_methods;
1078
-        }
1079
-        $available_payment_methods = [];
1080
-        $EEM_Payment_Method        = EEM_Payment_Method::instance();
1081
-        // get all active payment methods
1082
-        $payment_methods = $EEM_Payment_Method->get_all_for_transaction(
1083
-            $this->checkout->transaction,
1084
-            EEM_Payment_Method::scope_cart
1085
-        );
1086
-        foreach ($payment_methods as $payment_method) {
1087
-            if ($payment_method instanceof EE_Payment_Method) {
1088
-                $available_payment_methods[ $payment_method->slug() ] = $payment_method;
1089
-            }
1090
-        }
1091
-        return $available_payment_methods;
1092
-    }
1093
-
1094
-
1095
-    /**
1096
-     *    _available_payment_method_inputs
1097
-     *
1098
-     * @access    private
1099
-     * @param array $available_payment_method_options
1100
-     * @return    EE_Form_Section_Proper
1101
-     * @throws EE_Error
1102
-     * @throws EE_Error
1103
-     */
1104
-    private function _available_payment_method_inputs($available_payment_method_options = [])
1105
-    {
1106
-        // generate inputs
1107
-        return new EE_Form_Section_Proper(
1108
-            [
1109
-                'html_id'         => 'ee-available-payment-method-inputs',
1110
-                'layout_strategy' => new EE_Div_Per_Section_Layout(),
1111
-                'subsections'     => [
1112
-                    '' => new EE_Radio_Button_Input(
1113
-                        $available_payment_method_options,
1114
-                        [
1115
-                            'html_name'          => 'selected_method_of_payment',
1116
-                            'html_class'         => 'spco-payment-method',
1117
-                            'default'            => $this->checkout->selected_method_of_payment,
1118
-                            'label_size'         => 11,
1119
-                            'enforce_label_size' => true,
1120
-                        ]
1121
-                    ),
1122
-                ],
1123
-            ]
1124
-        );
1125
-    }
1126
-
1127
-
1128
-    /**
1129
-     *    _payment_method_billing_info
1130
-     *
1131
-     * @access    private
1132
-     * @param EE_Payment_Method $payment_method
1133
-     * @return EE_Form_Section_Proper
1134
-     * @throws EE_Error
1135
-     * @throws InvalidArgumentException
1136
-     * @throws InvalidDataTypeException
1137
-     * @throws InvalidInterfaceException
1138
-     */
1139
-    private function _payment_method_billing_info(EE_Payment_Method $payment_method)
1140
-    {
1141
-        $currently_selected = $this->checkout->selected_method_of_payment === $payment_method->slug();
1142
-        // generate the billing form for payment method
1143
-        $billing_form                 = $currently_selected
1144
-            ? $this->_get_billing_form_for_payment_method($payment_method)
1145
-            : new EE_Form_Section_HTML();
1146
-        $this->checkout->billing_form = $currently_selected
1147
-            ? $billing_form
1148
-            : $this->checkout->billing_form;
1149
-        // it's all in the details
1150
-        $info_html = EEH_HTML::h3(
1151
-            esc_html__('Important information regarding your payment', 'event_espresso'),
1152
-            '',
1153
-            'spco-payment-method-hdr'
1154
-        );
1155
-        // add some info regarding the step, either from what's saved in the admin,
1156
-        // or a default string depending on whether the PM has a billing form or not
1157
-        if ($payment_method->description()) {
1158
-            $payment_method_info = $payment_method->description();
1159
-        } elseif ($billing_form instanceof EE_Billing_Info_Form) {
1160
-            $payment_method_info = sprintf(
1161
-                esc_html__(
1162
-                    'Please provide the following billing information, then click the "%1$s" button below in order to proceed.',
1163
-                    'event_espresso'
1164
-                ),
1165
-                $this->submit_button_text()
1166
-            );
1167
-        } else {
1168
-            $payment_method_info = sprintf(
1169
-                esc_html__('Please click the "%1$s" button below in order to proceed.', 'event_espresso'),
1170
-                $this->submit_button_text()
1171
-            );
1172
-        }
1173
-        $info_html .= EEH_HTML::div(
1174
-            apply_filters(
1175
-                'FHEE__EE_SPCO_Reg_Step_Payment_Options___payment_method_billing_info__payment_method_info',
1176
-                $payment_method_info
1177
-            ),
1178
-            '',
1179
-            'spco-payment-method-desc ee-attention'
1180
-        );
1181
-        return new EE_Form_Section_Proper(
1182
-            [
1183
-                'html_id'         => 'spco-payment-method-info-' . $payment_method->slug(),
1184
-                'html_class'      => 'spco-payment-method-info-dv',
1185
-                // only display the selected or default PM
1186
-                'html_style'      => $currently_selected ? '' : 'display:none;',
1187
-                'layout_strategy' => new EE_Div_Per_Section_Layout(),
1188
-                'subsections'     => [
1189
-                    'info'         => new EE_Form_Section_HTML($info_html),
1190
-                    'billing_form' => $currently_selected ? $billing_form : new EE_Form_Section_HTML(),
1191
-                ],
1192
-            ]
1193
-        );
1194
-    }
1195
-
1196
-
1197
-    /**
1198
-     * get_billing_form_html_for_payment_method
1199
-     *
1200
-     * @return bool
1201
-     * @throws EE_Error
1202
-     * @throws InvalidArgumentException
1203
-     * @throws ReflectionException
1204
-     * @throws InvalidDataTypeException
1205
-     * @throws InvalidInterfaceException
1206
-     */
1207
-    public function get_billing_form_html_for_payment_method()
1208
-    {
1209
-        // how have they chosen to pay?
1210
-        $this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment(true);
1211
-        $this->checkout->payment_method             = $this->_get_payment_method_for_selected_method_of_payment();
1212
-        if (! $this->checkout->payment_method instanceof EE_Payment_Method) {
1213
-            return false;
1214
-        }
1215
-        if (apply_filters(
1216
-            'FHEE__EE_SPCO_Reg_Step_Payment_Options__registration_checkout__selected_payment_method__display_success',
1217
-            false
1218
-        )) {
1219
-            EE_Error::add_success(
1220
-                apply_filters(
1221
-                    'FHEE__Single_Page_Checkout__registration_checkout__selected_payment_method',
1222
-                    sprintf(
1223
-                        esc_html__(
1224
-                            'You have selected "%s" as your method of payment. Please note the important payment information below.',
1225
-                            'event_espresso'
1226
-                        ),
1227
-                        $this->checkout->payment_method->name()
1228
-                    )
1229
-                )
1230
-            );
1231
-        }
1232
-        // now generate billing form for selected method of payment
1233
-        $payment_method_billing_form = $this->_get_billing_form_for_payment_method($this->checkout->payment_method);
1234
-        // fill form with attendee info if applicable
1235
-        if ($payment_method_billing_form instanceof EE_Billing_Attendee_Info_Form
1236
-            && $this->checkout->transaction_has_primary_registrant()
1237
-        ) {
1238
-            $payment_method_billing_form->populate_from_attendee(
1239
-                $this->checkout->transaction->primary_registration()->attendee()
1240
-            );
1241
-        }
1242
-        // and debug content
1243
-        if ($payment_method_billing_form instanceof EE_Billing_Info_Form
1244
-            && $this->checkout->payment_method->type_obj() instanceof EE_PMT_Base
1245
-        ) {
1246
-            $payment_method_billing_form =
1247
-                $this->checkout->payment_method->type_obj()->apply_billing_form_debug_settings(
1248
-                    $payment_method_billing_form
1249
-                );
1250
-        }
1251
-        $billing_info = $payment_method_billing_form instanceof EE_Form_Section_Proper
1252
-            ? $payment_method_billing_form->get_html()
1253
-            : '';
1254
-        $this->checkout->json_response->set_return_data(['payment_method_info' => $billing_info]);
1255
-        // localize validation rules for main form
1256
-        $this->checkout->current_step->reg_form->localize_validation_rules();
1257
-        $this->checkout->json_response->add_validation_rules(EE_Form_Section_Proper::js_localization());
1258
-        return true;
1259
-    }
1260
-
1261
-
1262
-    /**
1263
-     * _get_billing_form_for_payment_method
1264
-     *
1265
-     * @param EE_Payment_Method $payment_method
1266
-     * @return EE_Billing_Info_Form|EE_Form_Section_HTML
1267
-     * @throws EE_Error
1268
-     * @throws InvalidArgumentException
1269
-     * @throws InvalidDataTypeException
1270
-     * @throws InvalidInterfaceException
1271
-     */
1272
-    private function _get_billing_form_for_payment_method(EE_Payment_Method $payment_method)
1273
-    {
1274
-        $billing_form = $payment_method->type_obj()->billing_form(
1275
-            $this->checkout->transaction,
1276
-            ['amount_owing' => $this->checkout->amount_owing]
1277
-        );
1278
-        if ($billing_form instanceof EE_Billing_Info_Form) {
1279
-            if (apply_filters(
1280
-                    'FHEE__EE_SPCO_Reg_Step_Payment_Options__registration_checkout__selected_payment_method__display_success',
1281
-                    false
1282
-                )
1283
-                && $this->request->requestParamIsSet('payment_method')
1284
-            ) {
1285
-                EE_Error::add_success(
1286
-                    apply_filters(
1287
-                        'FHEE__Single_Page_Checkout__registration_checkout__selected_payment_method',
1288
-                        sprintf(
1289
-                            esc_html__(
1290
-                                'You have selected "%s" as your method of payment. Please note the important payment information below.',
1291
-                                'event_espresso'
1292
-                            ),
1293
-                            $payment_method->name()
1294
-                        )
1295
-                    )
1296
-                );
1297
-            }
1298
-            return apply_filters(
1299
-                'FHEE__EE_SPCO_Reg_Step_Payment_Options___get_billing_form_for_payment_method__billing_form',
1300
-                $billing_form,
1301
-                $payment_method
1302
-            );
1303
-        }
1304
-        // no actual billing form, so return empty HTML form section
1305
-        return new EE_Form_Section_HTML();
1306
-    }
1307
-
1308
-
1309
-    /**
1310
-     * _get_selected_method_of_payment
1311
-     *
1312
-     * @param boolean $required whether to throw an error if the "selected_method_of_payment"
1313
-     *                          is not found in the incoming request
1314
-     * @param string  $request_param
1315
-     * @return NULL|string
1316
-     * @throws EE_Error
1317
-     * @throws InvalidArgumentException
1318
-     * @throws InvalidDataTypeException
1319
-     * @throws InvalidInterfaceException
1320
-     */
1321
-    private function _get_selected_method_of_payment(
1322
-        $required = false,
1323
-        $request_param = 'selected_method_of_payment'
1324
-    ) {
1325
-        // is selected_method_of_payment set in the request ?
1326
-        $selected_method_of_payment = $this->request->getRequestParam($request_param);
1327
-        if ($selected_method_of_payment) {
1328
-            // sanitize it
1329
-            $selected_method_of_payment = is_array($selected_method_of_payment)
1330
-                ? array_shift($selected_method_of_payment)
1331
-                : $selected_method_of_payment;
1332
-            $selected_method_of_payment = sanitize_text_field($selected_method_of_payment);
1333
-            // store it in the session so that it's available for all subsequent requests including AJAX
1334
-            $this->_save_selected_method_of_payment($selected_method_of_payment);
1335
-        } else {
1336
-            // or is is set in the session ?
1337
-            $selected_method_of_payment = EE_Registry::instance()->SSN->get_session_data(
1338
-                'selected_method_of_payment'
1339
-            );
1340
-        }
1341
-        // do ya really really gotta have it?
1342
-        if (empty($selected_method_of_payment) && $required) {
1343
-            EE_Error::add_error(
1344
-                sprintf(
1345
-                    esc_html__(
1346
-                        'The selected method of payment could not be determined.%sPlease ensure that you have selected one before proceeding.%sIf you continue to experience difficulties, then refresh your browser and try again, or contact %s for assistance.',
1347
-                        'event_espresso'
1348
-                    ),
1349
-                    '<br/>',
1350
-                    '<br/>',
1351
-                    EE_Registry::instance()->CFG->organization->get_pretty('email')
1352
-                ),
1353
-                __FILE__,
1354
-                __FUNCTION__,
1355
-                __LINE__
1356
-            );
1357
-            return null;
1358
-        }
1359
-        return $selected_method_of_payment;
1360
-    }
1361
-
1362
-
1363
-
1364
-
1365
-
1366
-
1367
-    /********************************************************************************************************/
1368
-    /***********************************  SWITCH PAYMENT METHOD  ************************************/
1369
-    /********************************************************************************************************/
1370
-    /**
1371
-     * switch_payment_method
1372
-     *
1373
-     * @return bool
1374
-     * @throws EE_Error
1375
-     * @throws InvalidArgumentException
1376
-     * @throws InvalidDataTypeException
1377
-     * @throws InvalidInterfaceException
1378
-     * @throws ReflectionException
1379
-     */
1380
-    public function switch_payment_method()
1381
-    {
1382
-        if (! $this->_verify_payment_method_is_set()) {
1383
-            return false;
1384
-        }
1385
-        if (apply_filters(
1386
-            'FHEE__EE_SPCO_Reg_Step_Payment_Options__registration_checkout__selected_payment_method__display_success',
1387
-            false
1388
-        )) {
1389
-            EE_Error::add_success(
1390
-                apply_filters(
1391
-                    'FHEE__Single_Page_Checkout__registration_checkout__selected_payment_method',
1392
-                    sprintf(
1393
-                        esc_html__(
1394
-                            'You have selected "%s" as your method of payment. Please note the important payment information below.',
1395
-                            'event_espresso'
1396
-                        ),
1397
-                        $this->checkout->payment_method->name()
1398
-                    )
1399
-                )
1400
-            );
1401
-        }
1402
-        // generate billing form for selected method of payment if it hasn't been done already
1403
-        if ($this->checkout->payment_method->type_obj()->has_billing_form()) {
1404
-            $this->checkout->billing_form = $this->_get_billing_form_for_payment_method(
1405
-                $this->checkout->payment_method
1406
-            );
1407
-        }
1408
-        // fill form with attendee info if applicable
1409
-        if (apply_filters(
1410
-            'FHEE__populate_billing_form_fields_from_attendee',
1411
-            (
1412
-                $this->checkout->billing_form instanceof EE_Billing_Attendee_Info_Form
1413
-                && $this->checkout->transaction_has_primary_registrant()
1414
-            ),
1415
-            $this->checkout->billing_form,
1416
-            $this->checkout->transaction
1417
-        )
1418
-        ) {
1419
-            $this->checkout->billing_form->populate_from_attendee(
1420
-                $this->checkout->transaction->primary_registration()->attendee()
1421
-            );
1422
-        }
1423
-        // and debug content
1424
-        if ($this->checkout->billing_form instanceof EE_Billing_Info_Form
1425
-            && $this->checkout->payment_method->type_obj() instanceof EE_PMT_Base
1426
-        ) {
1427
-            $this->checkout->billing_form =
1428
-                $this->checkout->payment_method->type_obj()->apply_billing_form_debug_settings(
1429
-                    $this->checkout->billing_form
1430
-                );
1431
-        }
1432
-        // get html and validation rules for form
1433
-        if ($this->checkout->billing_form instanceof EE_Form_Section_Proper) {
1434
-            $this->checkout->json_response->set_return_data(
1435
-                ['payment_method_info' => $this->checkout->billing_form->get_html()]
1436
-            );
1437
-            // localize validation rules for main form
1438
-            $this->checkout->billing_form->localize_validation_rules(true);
1439
-            $this->checkout->json_response->add_validation_rules(EE_Form_Section_Proper::js_localization());
1440
-        } else {
1441
-            $this->checkout->json_response->set_return_data(['payment_method_info' => '']);
1442
-        }
1443
-        // prevents advancement to next step
1444
-        $this->checkout->continue_reg = false;
1445
-        return true;
1446
-    }
1447
-
1448
-
1449
-    /**
1450
-     * _verify_payment_method_is_set
1451
-     *
1452
-     * @return bool
1453
-     * @throws EE_Error
1454
-     * @throws InvalidArgumentException
1455
-     * @throws ReflectionException
1456
-     * @throws InvalidDataTypeException
1457
-     * @throws InvalidInterfaceException
1458
-     */
1459
-    protected function _verify_payment_method_is_set()
1460
-    {
1461
-        // generate billing form for selected method of payment if it hasn't been done already
1462
-        if (empty($this->checkout->selected_method_of_payment)) {
1463
-            // how have they chosen to pay?
1464
-            $this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment(true);
1465
-        } else {
1466
-            // choose your own adventure based on method_of_payment
1467
-            switch ($this->checkout->selected_method_of_payment) {
1468
-                case 'events_sold_out':
1469
-                    EE_Error::add_attention(
1470
-                        apply_filters(
1471
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___verify_payment_method_is_set__sold_out_events_msg',
1472
-                            esc_html__(
1473
-                                'It appears that the event you were about to make a payment for has sold out since this form first loaded. Please contact the event administrator if you believe this is an error.',
1474
-                                'event_espresso'
1475
-                            )
1476
-                        ),
1477
-                        __FILE__,
1478
-                        __FUNCTION__,
1479
-                        __LINE__
1480
-                    );
1481
-                    return false;
1482
-                case 'payments_closed':
1483
-                    EE_Error::add_attention(
1484
-                        apply_filters(
1485
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___verify_payment_method_is_set__payments_closed_msg',
1486
-                            esc_html__(
1487
-                                'It appears that the event you were about to make a payment for is not accepting payments at this time. Please contact the event administrator if you believe this is an error.',
1488
-                                'event_espresso'
1489
-                            )
1490
-                        ),
1491
-                        __FILE__,
1492
-                        __FUNCTION__,
1493
-                        __LINE__
1494
-                    );
1495
-                    return false;
1496
-                case 'no_payment_required':
1497
-                    EE_Error::add_attention(
1498
-                        apply_filters(
1499
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___verify_payment_method_is_set__no_payment_required_msg',
1500
-                            esc_html__(
1501
-                                'It appears that the event you were about to make a payment for does not require payment. Please contact the event administrator if you believe this is an error.',
1502
-                                'event_espresso'
1503
-                            )
1504
-                        ),
1505
-                        __FILE__,
1506
-                        __FUNCTION__,
1507
-                        __LINE__
1508
-                    );
1509
-                    return false;
1510
-                default:
1511
-            }
1512
-        }
1513
-        // verify payment method
1514
-        if (! $this->checkout->payment_method instanceof EE_Payment_Method) {
1515
-            // get payment method for selected method of payment
1516
-            $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment();
1517
-        }
1518
-        return $this->checkout->payment_method instanceof EE_Payment_Method;
1519
-    }
1520
-
1521
-
1522
-
1523
-    /********************************************************************************************************/
1524
-    /***************************************  SAVE PAYER DETAILS  ****************************************/
1525
-    /********************************************************************************************************/
1526
-    /**
1527
-     * save_payer_details_via_ajax
1528
-     *
1529
-     * @return void
1530
-     * @throws EE_Error
1531
-     * @throws InvalidArgumentException
1532
-     * @throws ReflectionException
1533
-     * @throws RuntimeException
1534
-     * @throws InvalidDataTypeException
1535
-     * @throws InvalidInterfaceException
1536
-     */
1537
-    public function save_payer_details_via_ajax()
1538
-    {
1539
-        if (! $this->_verify_payment_method_is_set()) {
1540
-            return;
1541
-        }
1542
-        // generate billing form for selected method of payment if it hasn't been done already
1543
-        if ($this->checkout->payment_method->type_obj()->has_billing_form()) {
1544
-            $this->checkout->billing_form = $this->_get_billing_form_for_payment_method(
1545
-                $this->checkout->payment_method
1546
-            );
1547
-        }
1548
-        // generate primary attendee from payer info if applicable
1549
-        if (! $this->checkout->transaction_has_primary_registrant()) {
1550
-            $attendee = $this->_create_attendee_from_request_data();
1551
-            if ($attendee instanceof EE_Attendee) {
1552
-                foreach ($this->checkout->transaction->registrations() as $registration) {
1553
-                    if ($registration->is_primary_registrant()) {
1554
-                        $this->checkout->primary_attendee_obj = $attendee;
1555
-                        $registration->_add_relation_to($attendee, 'Attendee');
1556
-                        $registration->set_attendee_id($attendee->ID());
1557
-                        $registration->update_cache_after_object_save('Attendee', $attendee);
1558
-                    }
1559
-                }
1560
-            }
1561
-        }
1562
-    }
1563
-
1564
-
1565
-    /**
1566
-     * create_attendee_from_request_data
1567
-     * uses info from alternate GET or POST data (such as AJAX) to create a new attendee
1568
-     *
1569
-     * @return EE_Attendee
1570
-     * @throws EE_Error
1571
-     * @throws InvalidArgumentException
1572
-     * @throws ReflectionException
1573
-     * @throws InvalidDataTypeException
1574
-     * @throws InvalidInterfaceException
1575
-     */
1576
-    protected function _create_attendee_from_request_data()
1577
-    {
1578
-        // get State ID
1579
-        $STA_ID = $this->request->getRequestParam('state');
1580
-        if (! empty($STA_ID)) {
1581
-            // can we get state object from name ?
1582
-            EE_Registry::instance()->load_model('State');
1583
-            $state  = EEM_State::instance()->get_col([['STA_name' => $STA_ID], 'limit' => 1], 'STA_ID');
1584
-            $STA_ID = is_array($state) && ! empty($state) ? reset($state) : $STA_ID;
1585
-        }
1586
-        // get Country ISO
1587
-        $CNT_ISO = $this->request->getRequestParam('country');
1588
-        if (! empty($CNT_ISO)) {
1589
-            // can we get country object from name ?
1590
-            EE_Registry::instance()->load_model('Country');
1591
-            $country = EEM_Country::instance()->get_col(
1592
-                [['CNT_name' => $CNT_ISO], 'limit' => 1],
1593
-                'CNT_ISO'
1594
-            );
1595
-            $CNT_ISO = is_array($country) && ! empty($country) ? reset($country) : $CNT_ISO;
1596
-        }
1597
-        // grab attendee data
1598
-        $attendee_data = [
1599
-            'ATT_fname'    => $this->request->getRequestParam('first_name'),
1600
-            'ATT_lname'    => $this->request->getRequestParam('last_name'),
1601
-            'ATT_email'    => $this->request->getRequestParam('email'),
1602
-            'ATT_address'  => $this->request->getRequestParam('address'),
1603
-            'ATT_address2' => $this->request->getRequestParam('address2'),
1604
-            'ATT_city'     => $this->request->getRequestParam('city'),
1605
-            'STA_ID'       => $STA_ID,
1606
-            'CNT_ISO'      => $CNT_ISO,
1607
-            'ATT_zip'      => $this->request->getRequestParam('zip'),
1608
-            'ATT_phone'    => $this->request->getRequestParam('phone'),
1609
-        ];
1610
-        // validate the email address since it is the most important piece of info
1611
-        if (empty($attendee_data['ATT_email'])) {
1612
-            EE_Error::add_error(
1613
-                esc_html__('An invalid email address was submitted.', 'event_espresso'),
1614
-                __FILE__,
1615
-                __FUNCTION__,
1616
-                __LINE__
1617
-            );
1618
-        }
1619
-        // does this attendee already exist in the db ? we're searching using a combination of first name, last name,
1620
-        // AND email address
1621
-        if (! empty($attendee_data['ATT_fname'])
1622
-            && ! empty($attendee_data['ATT_lname'])
1623
-            && ! empty($attendee_data['ATT_email'])
1624
-        ) {
1625
-            $existing_attendee = EEM_Attendee::instance()->find_existing_attendee(
1626
-                [
1627
-                    'ATT_fname' => $attendee_data['ATT_fname'],
1628
-                    'ATT_lname' => $attendee_data['ATT_lname'],
1629
-                    'ATT_email' => $attendee_data['ATT_email'],
1630
-                ]
1631
-            );
1632
-            if ($existing_attendee instanceof EE_Attendee) {
1633
-                return $existing_attendee;
1634
-            }
1635
-        }
1636
-        // no existing attendee? kk let's create a new one
1637
-        // kinda lame, but we need a first and last name to create an attendee, so use the email address if those
1638
-        // don't exist
1639
-        $attendee_data['ATT_fname'] = ! empty($attendee_data['ATT_fname'])
1640
-            ? $attendee_data['ATT_fname']
1641
-            : $attendee_data['ATT_email'];
1642
-        $attendee_data['ATT_lname'] = ! empty($attendee_data['ATT_lname'])
1643
-            ? $attendee_data['ATT_lname']
1644
-            : $attendee_data['ATT_email'];
1645
-        return EE_Attendee::new_instance($attendee_data);
1646
-    }
1647
-
1648
-
1649
-
1650
-    /********************************************************************************************************/
1651
-    /****************************************  PROCESS REG STEP  *****************************************/
1652
-    /********************************************************************************************************/
1653
-    /**
1654
-     * process_reg_step
1655
-     *
1656
-     * @return bool
1657
-     * @throws EE_Error
1658
-     * @throws InvalidArgumentException
1659
-     * @throws ReflectionException
1660
-     * @throws EntityNotFoundException
1661
-     * @throws InvalidDataTypeException
1662
-     * @throws InvalidInterfaceException
1663
-     * @throws InvalidStatusException
1664
-     */
1665
-    public function process_reg_step()
1666
-    {
1667
-        // how have they chosen to pay?
1668
-        $this->checkout->selected_method_of_payment = $this->checkout->transaction->is_free()
1669
-            ? 'no_payment_required'
1670
-            : $this->_get_selected_method_of_payment(true);
1671
-        // choose your own adventure based on method_of_payment
1672
-        switch ($this->checkout->selected_method_of_payment) {
1673
-            case 'events_sold_out':
1674
-                $this->checkout->redirect     = true;
1675
-                $this->checkout->redirect_url = $this->checkout->cancel_page_url;
1676
-                $this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
1677
-                // mark this reg step as completed
1678
-                $this->set_completed();
1679
-                return false;
1680
-
1681
-            case 'payments_closed':
1682
-                if (apply_filters(
1683
-                    'FHEE__EE_SPCO_Reg_Step_Payment_Options__process_reg_step__payments_closed__display_success',
1684
-                    false
1685
-                )) {
1686
-                    EE_Error::add_success(
1687
-                        esc_html__('no payment required at this time.', 'event_espresso'),
1688
-                        __FILE__,
1689
-                        __FUNCTION__,
1690
-                        __LINE__
1691
-                    );
1692
-                }
1693
-                // mark this reg step as completed
1694
-                $this->set_completed();
1695
-                return true;
1696
-
1697
-            case 'no_payment_required':
1698
-                if (apply_filters(
1699
-                    'FHEE__EE_SPCO_Reg_Step_Payment_Options__process_reg_step__no_payment_required__display_success',
1700
-                    false
1701
-                )) {
1702
-                    EE_Error::add_success(
1703
-                        esc_html__('no payment required.', 'event_espresso'),
1704
-                        __FILE__,
1705
-                        __FUNCTION__,
1706
-                        __LINE__
1707
-                    );
1708
-                }
1709
-                // mark this reg step as completed
1710
-                $this->set_completed();
1711
-                return true;
1712
-
1713
-            default:
1714
-                $registrations         = EE_Registry::instance()->SSN->checkout()->transaction->registrations(
1715
-                    EE_Registry::instance()->SSN->checkout()->reg_cache_where_params
1716
-                );
1717
-                $ejected_registrations = EE_SPCO_Reg_Step_Payment_Options::find_registrations_that_lost_their_space(
1718
-                    $registrations,
1719
-                    EE_Registry::instance()->SSN->checkout()->revisit
1720
-                );
1721
-                // calculate difference between the two arrays
1722
-                $registrations = array_diff($registrations, $ejected_registrations);
1723
-                if (empty($registrations)) {
1724
-                    $this->_redirect_because_event_sold_out();
1725
-                    return false;
1726
-                }
1727
-                $payment_successful = $this->_process_payment();
1728
-                if ($payment_successful) {
1729
-                    $this->checkout->continue_reg = true;
1730
-                    $this->_maybe_set_completed($this->checkout->payment_method);
1731
-                } else {
1732
-                    $this->checkout->continue_reg = false;
1733
-                }
1734
-                return $payment_successful;
1735
-        }
1736
-    }
1737
-
1738
-
1739
-    /**
1740
-     * _redirect_because_event_sold_out
1741
-     *
1742
-     * @return void
1743
-     */
1744
-    protected function _redirect_because_event_sold_out()
1745
-    {
1746
-        $this->checkout->continue_reg = false;
1747
-        // set redirect URL
1748
-        $this->checkout->redirect_url = add_query_arg(
1749
-            ['e_reg_url_link' => $this->checkout->reg_url_link],
1750
-            $this->checkout->current_step->reg_step_url()
1751
-        );
1752
-        $this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
1753
-    }
1754
-
1755
-
1756
-    /**
1757
-     * _maybe_set_completed
1758
-     *
1759
-     * @param EE_Payment_Method $payment_method
1760
-     * @return void
1761
-     * @throws EE_Error
1762
-     */
1763
-    protected function _maybe_set_completed(EE_Payment_Method $payment_method)
1764
-    {
1765
-        switch ($payment_method->type_obj()->payment_occurs()) {
1766
-            case EE_PMT_Base::offsite:
1767
-                break;
1768
-            case EE_PMT_Base::onsite:
1769
-            case EE_PMT_Base::offline:
1770
-                // mark this reg step as completed
1771
-                $this->set_completed();
1772
-                break;
1773
-        }
1774
-    }
1775
-
1776
-
1777
-    /**
1778
-     *    update_reg_step
1779
-     *    this is the final step after a user  revisits the site to retry a payment
1780
-     *
1781
-     * @return bool
1782
-     * @throws EE_Error
1783
-     * @throws InvalidArgumentException
1784
-     * @throws ReflectionException
1785
-     * @throws EntityNotFoundException
1786
-     * @throws InvalidDataTypeException
1787
-     * @throws InvalidInterfaceException
1788
-     * @throws InvalidStatusException
1789
-     */
1790
-    public function update_reg_step()
1791
-    {
1792
-        $success = true;
1793
-        // if payment required
1794
-        if ($this->checkout->transaction->total() > 0) {
1795
-            do_action(
1796
-                'AHEE__EE_Single_Page_Checkout__process_finalize_registration__before_gateway',
1797
-                $this->checkout->transaction
1798
-            );
1799
-            // attempt payment via payment method
1800
-            $success = $this->process_reg_step();
1801
-        }
1802
-        if ($success && ! $this->checkout->redirect) {
1803
-            $this->checkout->cart->get_grand_total()->save_this_and_descendants_to_txn(
1804
-                $this->checkout->transaction->ID()
1805
-            );
1806
-            // set return URL
1807
-            $this->checkout->redirect_url = add_query_arg(
1808
-                ['e_reg_url_link' => $this->checkout->reg_url_link],
1809
-                $this->checkout->thank_you_page_url
1810
-            );
1811
-        }
1812
-        return $success;
1813
-    }
1814
-
1815
-
1816
-    /**
1817
-     *    _process_payment
1818
-     *
1819
-     * @return bool
1820
-     * @throws EE_Error
1821
-     * @throws InvalidArgumentException
1822
-     * @throws ReflectionException
1823
-     * @throws RuntimeException
1824
-     * @throws InvalidDataTypeException
1825
-     * @throws InvalidInterfaceException
1826
-     */
1827
-    private function _process_payment()
1828
-    {
1829
-        // basically confirm that the event hasn't sold out since they hit the page
1830
-        if (! $this->_last_second_ticket_verifications()) {
1831
-            return false;
1832
-        }
1833
-        // ya gotta make a choice man
1834
-        if (empty($this->checkout->selected_method_of_payment)) {
1835
-            $this->checkout->json_response->set_plz_select_method_of_payment(
1836
-                esc_html__('Please select a method of payment before proceeding.', 'event_espresso')
1837
-            );
1838
-            return false;
1839
-        }
1840
-        // get EE_Payment_Method object
1841
-        if (! $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment()) {
1842
-            return false;
1843
-        }
1844
-        // setup billing form
1845
-        if ($this->checkout->payment_method->is_on_site()) {
1846
-            $this->checkout->billing_form = $this->_get_billing_form_for_payment_method(
1847
-                $this->checkout->payment_method
1848
-            );
1849
-            // bad billing form ?
1850
-            if (! $this->_billing_form_is_valid()) {
1851
-                return false;
1852
-            }
1853
-        }
1854
-        // ensure primary registrant has been fully processed
1855
-        if (! $this->_setup_primary_registrant_prior_to_payment()) {
1856
-            return false;
1857
-        }
1858
-        // if session is close to expiring (under 10 minutes by default)
1859
-        if ((time() - EE_Registry::instance()->SSN->expiration()) < EE_Registry::instance()->SSN->extension()) {
1860
-            // add some time to session expiration so that payment can be completed
1861
-            EE_Registry::instance()->SSN->extend_expiration();
1862
-        }
1863
-        /** @type EE_Transaction_Processor $transaction_processor */
1864
-        // $transaction_processor = EE_Registry::instance()->load_class( 'Transaction_Processor' );
1865
-        // in case a registrant leaves to an Off-Site Gateway and never returns, we want to approve any registrations
1866
-        // for events with a default reg status of Approved
1867
-        // $transaction_processor->toggle_registration_statuses_for_default_approved_events(
1868
-        //      $this->checkout->transaction, $this->checkout->reg_cache_where_params
1869
-        // );
1870
-        // attempt payment
1871
-        $payment = $this->_attempt_payment($this->checkout->payment_method);
1872
-        // process results
1873
-        $payment = $this->_validate_payment($payment);
1874
-        $payment = $this->_post_payment_processing($payment);
1875
-        // verify payment
1876
-        if ($payment instanceof EE_Payment) {
1877
-            // store that for later
1878
-            $this->checkout->payment = $payment;
1879
-            // we can also consider the TXN to not have been failed, so temporarily upgrade it's status to abandoned
1880
-            $this->checkout->transaction->toggle_failed_transaction_status();
1881
-            $payment_status = $payment->status();
1882
-            return $payment_status === EEM_Payment::status_id_approved
1883
-                   || $payment_status === EEM_Payment::status_id_pending;
1884
-        }
1885
-        if ($payment === true) {
1886
-            // please note that offline payment methods will NOT make a payment,
1887
-            // but instead just mark themselves as the PMD_ID on the transaction, and return true
1888
-            $this->checkout->payment = $payment;
1889
-            return true;
1890
-        }
1891
-        // where's my money?
1892
-        return false;
1893
-    }
1894
-
1895
-
1896
-    /**
1897
-     * _last_second_ticket_verifications
1898
-     *
1899
-     * @return bool
1900
-     * @throws EE_Error
1901
-     * @throws ReflectionException
1902
-     */
1903
-    protected function _last_second_ticket_verifications()
1904
-    {
1905
-        // don't bother re-validating if not a return visit
1906
-        if (! $this->checkout->revisit) {
1907
-            return true;
1908
-        }
1909
-        $registrations = $this->checkout->transaction->registrations();
1910
-        if (empty($registrations)) {
1911
-            return false;
1912
-        }
1913
-        foreach ($registrations as $registration) {
1914
-            if ($registration instanceof EE_Registration && ! $registration->is_approved()) {
1915
-                $event = $registration->event_obj();
1916
-                if ($event instanceof EE_Event && $event->is_sold_out(true)) {
1917
-                    EE_Error::add_error(
1918
-                        apply_filters(
1919
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___last_second_ticket_verifications__sold_out_events_msg',
1920
-                            sprintf(
1921
-                                esc_html__(
1922
-                                    'It appears that the %1$s event that you were about to make a payment for has sold out since you first registered and/or arrived at this page. Please refresh the page and try again. If you have already made a partial payment towards this event, please contact the event administrator for a refund.',
1923
-                                    'event_espresso'
1924
-                                ),
1925
-                                $event->name()
1926
-                            )
1927
-                        ),
1928
-                        __FILE__,
1929
-                        __FUNCTION__,
1930
-                        __LINE__
1931
-                    );
1932
-                    return false;
1933
-                }
1934
-            }
1935
-        }
1936
-        return true;
1937
-    }
1938
-
1939
-
1940
-    /**
1941
-     * redirect_form
1942
-     *
1943
-     * @return bool
1944
-     * @throws EE_Error
1945
-     * @throws InvalidArgumentException
1946
-     * @throws ReflectionException
1947
-     * @throws InvalidDataTypeException
1948
-     * @throws InvalidInterfaceException
1949
-     */
1950
-    public function redirect_form()
1951
-    {
1952
-        $payment_method_billing_info = $this->_payment_method_billing_info(
1953
-            $this->_get_payment_method_for_selected_method_of_payment()
1954
-        );
1955
-        $html                        = $payment_method_billing_info->get_html();
1956
-        $html                        .= $this->checkout->redirect_form;
1957
-        /** @var ResponseInterface $response */
1958
-        $response = LoaderFactory::getLoader()->getShared(ResponseInterface::class);
1959
-        $response->addOutput($html);
1960
-        return true;
1961
-    }
1962
-
1963
-
1964
-    /**
1965
-     * _billing_form_is_valid
1966
-     *
1967
-     * @return bool
1968
-     * @throws EE_Error
1969
-     */
1970
-    private function _billing_form_is_valid()
1971
-    {
1972
-        if (! $this->checkout->payment_method->type_obj()->has_billing_form()) {
1973
-            return true;
1974
-        }
1975
-        if ($this->checkout->billing_form instanceof EE_Billing_Info_Form) {
1976
-            if ($this->checkout->billing_form->was_submitted()) {
1977
-                $this->checkout->billing_form->receive_form_submission();
1978
-                if ($this->checkout->billing_form->is_valid()) {
1979
-                    return true;
1980
-                }
1981
-                $validation_errors = $this->checkout->billing_form->get_validation_errors_accumulated();
1982
-                $error_strings     = [];
1983
-                foreach ($validation_errors as $validation_error) {
1984
-                    if ($validation_error instanceof EE_Validation_Error) {
1985
-                        $form_section = $validation_error->get_form_section();
1986
-                        if ($form_section instanceof EE_Form_Input_Base) {
1987
-                            $label = $form_section->html_label_text();
1988
-                        } elseif ($form_section instanceof EE_Form_Section_Base) {
1989
-                            $label = $form_section->name();
1990
-                        } else {
1991
-                            $label = esc_html__('Validation Error', 'event_espresso');
1992
-                        }
1993
-                        $error_strings[] = sprintf('%1$s: %2$s', $label, $validation_error->getMessage());
1994
-                    }
1995
-                }
1996
-                EE_Error::add_error(
1997
-                    sprintf(
1998
-                        esc_html__(
1999
-                            'One or more billing form inputs are invalid and require correction before proceeding. %1$s %2$s',
2000
-                            'event_espresso'
2001
-                        ),
2002
-                        '<br/>',
2003
-                        implode('<br/>', $error_strings)
2004
-                    ),
2005
-                    __FILE__,
2006
-                    __FUNCTION__,
2007
-                    __LINE__
2008
-                );
2009
-            } else {
2010
-                EE_Error::add_error(
2011
-                    esc_html__(
2012
-                        'The billing form was not submitted or something prevented it\'s submission.',
2013
-                        'event_espresso'
2014
-                    ),
2015
-                    __FILE__,
2016
-                    __FUNCTION__,
2017
-                    __LINE__
2018
-                );
2019
-            }
2020
-        } else {
2021
-            EE_Error::add_error(
2022
-                esc_html__(
2023
-                    'The submitted billing form is invalid possibly due to a technical reason.',
2024
-                    'event_espresso'
2025
-                ),
2026
-                __FILE__,
2027
-                __FUNCTION__,
2028
-                __LINE__
2029
-            );
2030
-        }
2031
-        return false;
2032
-    }
2033
-
2034
-
2035
-    /**
2036
-     * _setup_primary_registrant_prior_to_payment
2037
-     * ensures that the primary registrant has a valid attendee object created with the critical details populated
2038
-     * (first & last name & email) and that both the transaction object and primary registration object have been saved
2039
-     * plz note that any other registrations will NOT be saved at this point (because they may not have any details
2040
-     * yet)
2041
-     *
2042
-     * @return bool
2043
-     * @throws EE_Error
2044
-     * @throws InvalidArgumentException
2045
-     * @throws ReflectionException
2046
-     * @throws RuntimeException
2047
-     * @throws InvalidDataTypeException
2048
-     * @throws InvalidInterfaceException
2049
-     */
2050
-    private function _setup_primary_registrant_prior_to_payment()
2051
-    {
2052
-        // check if transaction has a primary registrant and that it has a related Attendee object
2053
-        // if not, then we need to at least gather some primary registrant data before attempting payment
2054
-        if ($this->checkout->billing_form instanceof EE_Billing_Attendee_Info_Form
2055
-            && ! $this->checkout->transaction_has_primary_registrant()
2056
-            && ! $this->_capture_primary_registration_data_from_billing_form()
2057
-        ) {
2058
-            return false;
2059
-        }
2060
-        // because saving an object clears it's cache, we need to do the chevy shuffle
2061
-        // grab the primary_registration object
2062
-        $primary_registration = $this->checkout->transaction->primary_registration();
2063
-        // at this point we'll consider a TXN to not have been failed
2064
-        $this->checkout->transaction->toggle_failed_transaction_status();
2065
-        // save the TXN ( which clears cached copy of primary_registration)
2066
-        $this->checkout->transaction->save();
2067
-        // grab TXN ID and save it to the primary_registration
2068
-        $primary_registration->set_transaction_id($this->checkout->transaction->ID());
2069
-        // save what we have so far
2070
-        $primary_registration->save();
2071
-        return true;
2072
-    }
2073
-
2074
-
2075
-    /**
2076
-     * _capture_primary_registration_data_from_billing_form
2077
-     *
2078
-     * @return bool
2079
-     * @throws EE_Error
2080
-     * @throws InvalidArgumentException
2081
-     * @throws ReflectionException
2082
-     * @throws InvalidDataTypeException
2083
-     * @throws InvalidInterfaceException
2084
-     */
2085
-    private function _capture_primary_registration_data_from_billing_form()
2086
-    {
2087
-        // convert billing form data into an attendee
2088
-        $this->checkout->primary_attendee_obj = $this->checkout->billing_form->create_attendee_from_billing_form_data();
2089
-        if (! $this->checkout->primary_attendee_obj instanceof EE_Attendee) {
2090
-            EE_Error::add_error(
2091
-                sprintf(
2092
-                    esc_html__(
2093
-                        'The billing form details could not be used for attendee details due to a technical issue.%sPlease try again or contact %s for assistance.',
2094
-                        'event_espresso'
2095
-                    ),
2096
-                    '<br/>',
2097
-                    EE_Registry::instance()->CFG->organization->get_pretty('email')
2098
-                ),
2099
-                __FILE__,
2100
-                __FUNCTION__,
2101
-                __LINE__
2102
-            );
2103
-            return false;
2104
-        }
2105
-        $primary_registration = $this->checkout->transaction->primary_registration();
2106
-        if (! $primary_registration instanceof EE_Registration) {
2107
-            EE_Error::add_error(
2108
-                sprintf(
2109
-                    esc_html__(
2110
-                        'The primary registrant for this transaction could not be determined due to a technical issue.%sPlease try again or contact %s for assistance.',
2111
-                        'event_espresso'
2112
-                    ),
2113
-                    '<br/>',
2114
-                    EE_Registry::instance()->CFG->organization->get_pretty('email')
2115
-                ),
2116
-                __FILE__,
2117
-                __FUNCTION__,
2118
-                __LINE__
2119
-            );
2120
-            return false;
2121
-        }
2122
-        if (! $primary_registration->_add_relation_to($this->checkout->primary_attendee_obj, 'Attendee')
2123
-              instanceof
2124
-              EE_Attendee
2125
-        ) {
2126
-            EE_Error::add_error(
2127
-                sprintf(
2128
-                    esc_html__(
2129
-                        'The primary registrant could not be associated with this transaction due to a technical issue.%sPlease try again or contact %s for assistance.',
2130
-                        'event_espresso'
2131
-                    ),
2132
-                    '<br/>',
2133
-                    EE_Registry::instance()->CFG->organization->get_pretty('email')
2134
-                ),
2135
-                __FILE__,
2136
-                __FUNCTION__,
2137
-                __LINE__
2138
-            );
2139
-            return false;
2140
-        }
2141
-        /** @type EE_Registration_Processor $registration_processor */
2142
-        $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
2143
-        // at this point, we should have enough details about the registrant to consider the registration NOT incomplete
2144
-        $registration_processor->toggle_incomplete_registration_status_to_default($primary_registration);
2145
-        return true;
2146
-    }
2147
-
2148
-
2149
-    /**
2150
-     * _get_payment_method_for_selected_method_of_payment
2151
-     * retrieves a valid payment method
2152
-     *
2153
-     * @return EE_Payment_Method
2154
-     * @throws EE_Error
2155
-     * @throws InvalidArgumentException
2156
-     * @throws ReflectionException
2157
-     * @throws InvalidDataTypeException
2158
-     * @throws InvalidInterfaceException
2159
-     */
2160
-    private function _get_payment_method_for_selected_method_of_payment()
2161
-    {
2162
-        if ($this->checkout->selected_method_of_payment === 'events_sold_out') {
2163
-            $this->_redirect_because_event_sold_out();
2164
-            return null;
2165
-        }
2166
-        // get EE_Payment_Method object
2167
-        if (isset($this->checkout->available_payment_methods[ $this->checkout->selected_method_of_payment ])) {
2168
-            $payment_method = $this->checkout->available_payment_methods[ $this->checkout->selected_method_of_payment ];
2169
-        } else {
2170
-            // load EEM_Payment_Method
2171
-            EE_Registry::instance()->load_model('Payment_Method');
2172
-            $EEM_Payment_Method = EEM_Payment_Method::instance();
2173
-            $payment_method     = $EEM_Payment_Method->get_one_by_slug($this->checkout->selected_method_of_payment);
2174
-        }
2175
-        // verify $payment_method
2176
-        if (! $payment_method instanceof EE_Payment_Method) {
2177
-            // not a payment
2178
-            EE_Error::add_error(
2179
-                sprintf(
2180
-                    esc_html__(
2181
-                        'The selected method of payment could not be determined due to a technical issue.%sPlease try again or contact %s for assistance.',
2182
-                        'event_espresso'
2183
-                    ),
2184
-                    '<br/>',
2185
-                    EE_Registry::instance()->CFG->organization->get_pretty('email')
2186
-                ),
2187
-                __FILE__,
2188
-                __FUNCTION__,
2189
-                __LINE__
2190
-            );
2191
-            return null;
2192
-        }
2193
-        // and verify it has a valid Payment_Method Type object
2194
-        if (! $payment_method->type_obj() instanceof EE_PMT_Base) {
2195
-            // not a payment
2196
-            EE_Error::add_error(
2197
-                sprintf(
2198
-                    esc_html__(
2199
-                        'A valid payment method could not be determined due to a technical issue.%sPlease try again or contact %s for assistance.',
2200
-                        'event_espresso'
2201
-                    ),
2202
-                    '<br/>',
2203
-                    EE_Registry::instance()->CFG->organization->get_pretty('email')
2204
-                ),
2205
-                __FILE__,
2206
-                __FUNCTION__,
2207
-                __LINE__
2208
-            );
2209
-            return null;
2210
-        }
2211
-        return $payment_method;
2212
-    }
2213
-
2214
-
2215
-    /**
2216
-     *    _attempt_payment
2217
-     *
2218
-     * @access    private
2219
-     * @type    EE_Payment_Method $payment_method
2220
-     * @return mixed EE_Payment | boolean
2221
-     * @throws EE_Error
2222
-     * @throws InvalidArgumentException
2223
-     * @throws ReflectionException
2224
-     * @throws InvalidDataTypeException
2225
-     * @throws InvalidInterfaceException
2226
-     */
2227
-    private function _attempt_payment(EE_Payment_Method $payment_method)
2228
-    {
2229
-        $payment = null;
2230
-        $this->checkout->transaction->save();
2231
-        $payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
2232
-        if (! $payment_processor instanceof EE_Payment_Processor) {
2233
-            return false;
2234
-        }
2235
-        try {
2236
-            $payment_processor->set_revisit($this->checkout->revisit);
2237
-            // generate payment object
2238
-            $payment = $payment_processor->process_payment(
2239
-                $payment_method,
2240
-                $this->checkout->transaction,
2241
-                $this->checkout->amount_owing,
2242
-                $this->checkout->billing_form,
2243
-                $this->_get_return_url($payment_method),
2244
-                'CART',
2245
-                $this->checkout->admin_request,
2246
-                true,
2247
-                $this->reg_step_url()
2248
-            );
2249
-        } catch (Exception $e) {
2250
-            $this->_handle_payment_processor_exception($e);
2251
-        }
2252
-        return $payment;
2253
-    }
2254
-
2255
-
2256
-    /**
2257
-     * _handle_payment_processor_exception
2258
-     *
2259
-     * @param Exception $e
2260
-     * @return void
2261
-     * @throws EE_Error
2262
-     * @throws InvalidArgumentException
2263
-     * @throws InvalidDataTypeException
2264
-     * @throws InvalidInterfaceException
2265
-     */
2266
-    protected function _handle_payment_processor_exception(Exception $e)
2267
-    {
2268
-        EE_Error::add_error(
2269
-            sprintf(
2270
-                esc_html__(
2271
-                    'The payment could not br processed due to a technical issue.%1$sPlease try again or contact %2$s for assistance.||The following Exception was thrown in %4$s on line %5$s:%1$s%3$s',
2272
-                    'event_espresso'
2273
-                ),
2274
-                '<br/>',
2275
-                EE_Registry::instance()->CFG->organization->get_pretty('email'),
2276
-                $e->getMessage(),
2277
-                $e->getFile(),
2278
-                $e->getLine()
2279
-            ),
2280
-            __FILE__,
2281
-            __FUNCTION__,
2282
-            __LINE__
2283
-        );
2284
-    }
2285
-
2286
-
2287
-    /**
2288
-     * _get_return_url
2289
-     *
2290
-     * @param EE_Payment_Method $payment_method
2291
-     * @return string
2292
-     * @throws EE_Error
2293
-     * @throws ReflectionException
2294
-     */
2295
-    protected function _get_return_url(EE_Payment_Method $payment_method)
2296
-    {
2297
-        $return_url = '';
2298
-        switch ($payment_method->type_obj()->payment_occurs()) {
2299
-            case EE_PMT_Base::offsite:
2300
-                $return_url = add_query_arg(
2301
-                    [
2302
-                        'action'                     => 'process_gateway_response',
2303
-                        'selected_method_of_payment' => $this->checkout->selected_method_of_payment,
2304
-                        'spco_txn'                   => $this->checkout->transaction->ID(),
2305
-                    ],
2306
-                    $this->reg_step_url()
2307
-                );
2308
-                break;
2309
-            case EE_PMT_Base::onsite:
2310
-            case EE_PMT_Base::offline:
2311
-                $return_url = $this->checkout->next_step->reg_step_url();
2312
-                break;
2313
-        }
2314
-        return $return_url;
2315
-    }
2316
-
2317
-
2318
-    /**
2319
-     * _validate_payment
2320
-     *
2321
-     * @param EE_Payment $payment
2322
-     * @return EE_Payment|FALSE
2323
-     * @throws EE_Error
2324
-     * @throws InvalidArgumentException
2325
-     * @throws InvalidDataTypeException
2326
-     * @throws InvalidInterfaceException
2327
-     */
2328
-    private function _validate_payment($payment = null)
2329
-    {
2330
-        if ($this->checkout->payment_method->is_off_line()) {
2331
-            return true;
2332
-        }
2333
-        // verify payment object
2334
-        if (! $payment instanceof EE_Payment) {
2335
-            // not a payment
2336
-            EE_Error::add_error(
2337
-                sprintf(
2338
-                    esc_html__(
2339
-                        'A valid payment was not generated due to a technical issue.%1$sPlease try again or contact %2$s for assistance.',
2340
-                        'event_espresso'
2341
-                    ),
2342
-                    '<br/>',
2343
-                    EE_Registry::instance()->CFG->organization->get_pretty('email')
2344
-                ),
2345
-                __FILE__,
2346
-                __FUNCTION__,
2347
-                __LINE__
2348
-            );
2349
-            return false;
2350
-        }
2351
-        return $payment;
2352
-    }
2353
-
2354
-
2355
-    /**
2356
-     * _post_payment_processing
2357
-     *
2358
-     * @param EE_Payment|bool $payment
2359
-     * @return bool
2360
-     * @throws EE_Error
2361
-     * @throws InvalidArgumentException
2362
-     * @throws InvalidDataTypeException
2363
-     * @throws InvalidInterfaceException
2364
-     * @throws ReflectionException
2365
-     */
2366
-    private function _post_payment_processing($payment = null)
2367
-    {
2368
-        // Off-Line payment?
2369
-        if ($payment === true) {
2370
-            // $this->_setup_redirect_for_next_step();
2371
-            return true;
2372
-            // On-Site payment?
2373
-        } elseif ($this->checkout->payment_method->is_on_site()) {
2374
-            if (! $this->_process_payment_status($payment, EE_PMT_Base::onsite)) {
2375
-                // $this->_setup_redirect_for_next_step();
2376
-                $this->checkout->continue_reg = false;
2377
-            }
2378
-            // Off-Site payment?
2379
-        } elseif ($this->checkout->payment_method->is_off_site()) {
2380
-            // if a payment object was made and it specifies a redirect url, then we'll setup that redirect info
2381
-            if ($payment instanceof EE_Payment && $payment->redirect_url()) {
2382
-                do_action('AHEE_log', __CLASS__, __FUNCTION__, $payment->redirect_url(), '$payment->redirect_url()');
2383
-                $this->checkout->redirect      = true;
2384
-                $this->checkout->redirect_form = $payment->redirect_form();
2385
-                $this->checkout->redirect_url  = $this->reg_step_url('redirect_form');
2386
-                // set JSON response
2387
-                $this->checkout->json_response->set_redirect_form($this->checkout->redirect_form);
2388
-                // and lastly, let's bump the payment status to pending
2389
-                $payment->set_status(EEM_Payment::status_id_pending);
2390
-                $payment->save();
2391
-            } else {
2392
-                // we couldn't redirect the user. Let's tell them why.
2393
-                $error_message = sprintf(
2394
-                    esc_html__(
2395
-                        'It appears the Off Site Payment Method was not configured properly.%sPlease try again or contact %s for assistance.',
2396
-                        'event_espresso'
2397
-                    ),
2398
-                    '<br/>',
2399
-                    EE_Registry::instance()->CFG->organization->get_pretty('email')
2400
-                );
2401
-                if ($payment instanceof EE_Payment && $payment->gateway_response()) {
2402
-                    $error_message = $error_message . '<br/>' . $payment->gateway_response();
2403
-                }
2404
-                $this->checkout->continue_reg = false;
2405
-                EE_Error::add_error(
2406
-                    $error_message,
2407
-                    __FILE__,
2408
-                    __FUNCTION__,
2409
-                    __LINE__
2410
-                );
2411
-            }
2412
-        } else {
2413
-            // ummm ya... not Off-Line, not On-Site, not off-Site ????
2414
-            $this->checkout->continue_reg = false;
2415
-            return false;
2416
-        }
2417
-        return $payment;
2418
-    }
2419
-
2420
-
2421
-    /**
2422
-     *    _process_payment_status
2423
-     *
2424
-     * @type    EE_Payment $payment
2425
-     * @param string       $payment_occurs
2426
-     * @return bool
2427
-     * @throws EE_Error
2428
-     * @throws InvalidArgumentException
2429
-     * @throws InvalidDataTypeException
2430
-     * @throws InvalidInterfaceException
2431
-     */
2432
-    private function _process_payment_status($payment, $payment_occurs = EE_PMT_Base::offline)
2433
-    {
2434
-        // off-line payment? carry on
2435
-        if ($payment_occurs === EE_PMT_Base::offline) {
2436
-            return true;
2437
-        }
2438
-        // verify payment validity
2439
-        if ($payment instanceof EE_Payment) {
2440
-            do_action('AHEE_log', __CLASS__, __FUNCTION__, $payment->status(), '$payment->status()');
2441
-            $msg = $payment->gateway_response();
2442
-            // check results
2443
-            switch ($payment->status()) {
2444
-                // good payment
2445
-                case EEM_Payment::status_id_approved:
2446
-                    EE_Error::add_success(
2447
-                        esc_html__('Your payment was processed successfully.', 'event_espresso'),
2448
-                        __FILE__,
2449
-                        __FUNCTION__,
2450
-                        __LINE__
2451
-                    );
2452
-                    return true;
2453
-                // slow payment
2454
-                case EEM_Payment::status_id_pending:
2455
-                    if (empty($msg)) {
2456
-                        $msg = esc_html__(
2457
-                            'Your payment appears to have been processed successfully, but the Instant Payment Notification has not yet been received. It should arrive shortly.',
2458
-                            'event_espresso'
2459
-                        );
2460
-                    }
2461
-                    EE_Error::add_success($msg, __FILE__, __FUNCTION__, __LINE__);
2462
-                    return true;
2463
-                // don't wanna payment
2464
-                case EEM_Payment::status_id_cancelled:
2465
-                    if (empty($msg)) {
2466
-                        $msg = _n(
2467
-                            'Payment cancelled. Please try again.',
2468
-                            'Payment cancelled. Please try again or select another method of payment.',
2469
-                            count($this->checkout->available_payment_methods),
2470
-                            'event_espresso'
2471
-                        );
2472
-                    }
2473
-                    EE_Error::add_attention($msg, __FILE__, __FUNCTION__, __LINE__);
2474
-                    return false;
2475
-                // not enough payment
2476
-                case EEM_Payment::status_id_declined:
2477
-                    if (empty($msg)) {
2478
-                        $msg = _n(
2479
-                            'We\'re sorry but your payment was declined. Please try again.',
2480
-                            'We\'re sorry but your payment was declined. Please try again or select another method of payment.',
2481
-                            count($this->checkout->available_payment_methods),
2482
-                            'event_espresso'
2483
-                        );
2484
-                    }
2485
-                    EE_Error::add_attention($msg, __FILE__, __FUNCTION__, __LINE__);
2486
-                    return false;
2487
-                // bad payment
2488
-                case EEM_Payment::status_id_failed:
2489
-                    if (! empty($msg)) {
2490
-                        EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2491
-                        return false;
2492
-                    }
2493
-                    // default to error below
2494
-                    break;
2495
-            }
2496
-        }
2497
-        // off-site payment gateway responses are too unreliable, so let's just assume that
2498
-        // the payment processing is just running slower than the registrant's request
2499
-        if ($payment_occurs === EE_PMT_Base::offsite) {
2500
-            return true;
2501
-        }
2502
-        EE_Error::add_error(
2503
-            sprintf(
2504
-                esc_html__(
2505
-                    'Your payment could not be processed successfully due to a technical issue.%sPlease try again or contact %s for assistance.',
2506
-                    'event_espresso'
2507
-                ),
2508
-                '<br/>',
2509
-                EE_Registry::instance()->CFG->organization->get_pretty('email')
2510
-            ),
2511
-            __FILE__,
2512
-            __FUNCTION__,
2513
-            __LINE__
2514
-        );
2515
-        return false;
2516
-    }
2517
-
2518
-
2519
-
2520
-
2521
-
2522
-
2523
-    /********************************************************************************************************/
2524
-    /**********************************  PROCESS GATEWAY RESPONSE  **********************************/
2525
-    /********************************************************************************************************/
2526
-    /**
2527
-     * process_gateway_response
2528
-     * this is the return point for Off-Site Payment Methods
2529
-     * It will attempt to "handle the IPN" if it appears that this has not already occurred,
2530
-     * otherwise, it will load up the last payment made for the TXN.
2531
-     * If the payment retrieved looks good, it will then either:
2532
-     *    complete the current step and allow advancement to the next reg step
2533
-     *        or present the payment options again
2534
-     *
2535
-     * @return bool
2536
-     * @throws EE_Error
2537
-     * @throws InvalidArgumentException
2538
-     * @throws ReflectionException
2539
-     * @throws InvalidDataTypeException
2540
-     * @throws InvalidInterfaceException
2541
-     */
2542
-    public function process_gateway_response()
2543
-    {
2544
-        // how have they chosen to pay?
2545
-        $this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment(true);
2546
-        // get EE_Payment_Method object
2547
-        if (! $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment()) {
2548
-            $this->checkout->continue_reg = false;
2549
-            return false;
2550
-        }
2551
-        if (! $this->checkout->payment_method->is_off_site()) {
2552
-            return false;
2553
-        }
2554
-        $this->_validate_offsite_return();
2555
-        // verify TXN
2556
-        if ($this->checkout->transaction instanceof EE_Transaction) {
2557
-            $gateway = $this->checkout->payment_method->type_obj()->get_gateway();
2558
-            if (! $gateway instanceof EE_Offsite_Gateway) {
2559
-                $this->checkout->continue_reg = false;
2560
-                return false;
2561
-            }
2562
-            $payment = $this->_process_off_site_payment($gateway);
2563
-            $payment = $this->_process_cancelled_payments($payment);
2564
-            $payment = $this->_validate_payment($payment);
2565
-            // if payment was not declined by the payment gateway or cancelled by the registrant
2566
-            if ($this->_process_payment_status($payment, EE_PMT_Base::offsite)) {
2567
-                // $this->_setup_redirect_for_next_step();
2568
-                // store that for later
2569
-                $this->checkout->payment = $payment;
2570
-                // mark this reg step as completed, as long as gateway doesn't use a separate IPN request,
2571
-                // because we will complete this step during the IPN processing then
2572
-                if (! $this->handle_IPN_in_this_request()) {
2573
-                    $this->set_completed();
2574
-                }
2575
-                return true;
2576
-            }
2577
-        }
2578
-        // DEBUG LOG
2579
-        // $this->checkout->log(
2580
-        //     __CLASS__,
2581
-        //     __FUNCTION__,
2582
-        //     __LINE__,
2583
-        //     array('payment' => $payment)
2584
-        // );
2585
-        $this->checkout->continue_reg = false;
2586
-        return false;
2587
-    }
2588
-
2589
-
2590
-    /**
2591
-     * _validate_return
2592
-     *
2593
-     * @return void
2594
-     * @throws EE_Error
2595
-     * @throws InvalidArgumentException
2596
-     * @throws InvalidDataTypeException
2597
-     * @throws InvalidInterfaceException
2598
-     * @throws ReflectionException
2599
-     */
2600
-    private function _validate_offsite_return()
2601
-    {
2602
-        $TXN_ID = $this->request->getRequestParam('spco_txn', 0, 'int');
2603
-        if ($TXN_ID !== $this->checkout->transaction->ID()) {
2604
-            // Houston... we might have a problem
2605
-            $invalid_TXN = false;
2606
-            // first gather some info
2607
-            $valid_TXN          = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
2608
-            $primary_registrant = $valid_TXN instanceof EE_Transaction
2609
-                ? $valid_TXN->primary_registration()
2610
-                : null;
2611
-            // let's start by retrieving the cart for this TXN
2612
-            $cart = $this->checkout->get_cart_for_transaction($this->checkout->transaction);
2613
-            if ($cart instanceof EE_Cart) {
2614
-                // verify that the current cart has tickets
2615
-                $tickets = $cart->get_tickets();
2616
-                if (empty($tickets)) {
2617
-                    $invalid_TXN = true;
2618
-                }
2619
-            } else {
2620
-                $invalid_TXN = true;
2621
-            }
2622
-            $valid_TXN_SID = $primary_registrant instanceof EE_Registration
2623
-                ? $primary_registrant->session_ID()
2624
-                : null;
2625
-            // validate current Session ID and compare against valid TXN session ID
2626
-            if ($invalid_TXN // if this is already true, then skip other checks
2627
-                || EE_Session::instance()->id() === null
2628
-                || (
2629
-                    // WARNING !!!
2630
-                    // this could be PayPal sending back duplicate requests (ya they do that)
2631
-                    // or it **could** mean someone is simply registering AGAIN after having just done so
2632
-                    // so now we need to determine if this current TXN looks valid or not
2633
-                    // and whether this reg step has even been started ?
2634
-                    EE_Session::instance()->id() === $valid_TXN_SID
2635
-                    // really? you're half way through this reg step, but you never started it ?
2636
-                    && $this->checkout->transaction->reg_step_completed($this->slug()) === false
2637
-                )
2638
-            ) {
2639
-                $invalid_TXN = true;
2640
-            }
2641
-            if ($invalid_TXN) {
2642
-                // is the valid TXN completed ?
2643
-                if ($valid_TXN instanceof EE_Transaction) {
2644
-                    // has this step even been started ?
2645
-                    $reg_step_completed = $valid_TXN->reg_step_completed($this->slug());
2646
-                    if ($reg_step_completed !== false && $reg_step_completed !== true) {
2647
-                        // so it **looks** like this is a double request from PayPal
2648
-                        // so let's try to pick up where we left off
2649
-                        $this->checkout->transaction = $valid_TXN;
2650
-                        $this->checkout->refresh_all_entities(true);
2651
-                        return;
2652
-                    }
2653
-                }
2654
-                // you appear to be lost?
2655
-                $this->_redirect_wayward_request($primary_registrant);
2656
-            }
2657
-        }
2658
-    }
2659
-
2660
-
2661
-    /**
2662
-     * _redirect_wayward_request
2663
-     *
2664
-     * @param EE_Registration|null $primary_registrant
2665
-     * @return void
2666
-     * @throws EE_Error
2667
-     * @throws InvalidArgumentException
2668
-     * @throws InvalidDataTypeException
2669
-     * @throws InvalidInterfaceException
2670
-     * @throws ReflectionException
2671
-     */
2672
-    private function _redirect_wayward_request(EE_Registration $primary_registrant)
2673
-    {
2674
-        if (! $primary_registrant instanceof EE_Registration) {
2675
-            // try redirecting based on the current TXN
2676
-            $primary_registrant = $this->checkout->transaction instanceof EE_Transaction
2677
-                ? $this->checkout->transaction->primary_registration()
2678
-                : null;
2679
-        }
2680
-        if (! $primary_registrant instanceof EE_Registration) {
2681
-            EE_Error::add_error(
2682
-                sprintf(
2683
-                    esc_html__(
2684
-                        'Invalid information was received from the Off-Site Payment Processor and your Transaction details could not be retrieved from the database.%1$sPlease try again or contact %2$s for assistance.',
2685
-                        'event_espresso'
2686
-                    ),
2687
-                    '<br/>',
2688
-                    EE_Registry::instance()->CFG->organization->get_pretty('email')
2689
-                ),
2690
-                __FILE__,
2691
-                __FUNCTION__,
2692
-                __LINE__
2693
-            );
2694
-            return;
2695
-        }
2696
-        // make sure transaction is not locked
2697
-        $this->checkout->transaction->unlock();
2698
-        wp_safe_redirect(
2699
-            add_query_arg(
2700
-                [
2701
-                    'e_reg_url_link' => $primary_registrant->reg_url_link(),
2702
-                ],
2703
-                $this->checkout->thank_you_page_url
2704
-            )
2705
-        );
2706
-        exit();
2707
-    }
2708
-
2709
-
2710
-    /**
2711
-     * _process_off_site_payment
2712
-     *
2713
-     * @param EE_Offsite_Gateway $gateway
2714
-     * @return EE_Payment
2715
-     * @throws EE_Error
2716
-     * @throws InvalidArgumentException
2717
-     * @throws InvalidDataTypeException
2718
-     * @throws InvalidInterfaceException
2719
-     * @throws ReflectionException
2720
-     */
2721
-    private function _process_off_site_payment(EE_Offsite_Gateway $gateway)
2722
-    {
2723
-        try {
2724
-            $request      = LoaderFactory::getLoader()->getShared(RequestInterface::class);
2725
-            $request_data = $request->requestParams();
2726
-            // if gateway uses_separate_IPN_request, then we don't have to process the IPN manually
2727
-            $this->set_handle_IPN_in_this_request(
2728
-                $gateway->handle_IPN_in_this_request($request_data, false)
2729
-            );
2730
-            if ($this->handle_IPN_in_this_request()) {
2731
-                // get payment details and process results
2732
-                /** @type EE_Payment_Processor $payment_processor */
2733
-                $payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
2734
-                $payment           = $payment_processor->process_ipn(
2735
-                    $request_data,
2736
-                    $this->checkout->transaction,
2737
-                    $this->checkout->payment_method,
2738
-                    true,
2739
-                    false
2740
-                );
2741
-                // $payment_source = 'process_ipn';
2742
-            } else {
2743
-                $payment = $this->checkout->transaction->last_payment();
2744
-                // $payment_source = 'last_payment';
2745
-            }
2746
-        } catch (Exception $e) {
2747
-            // let's just eat the exception and try to move on using any previously set payment info
2748
-            $payment = $this->checkout->transaction->last_payment();
2749
-            // $payment_source = 'last_payment after Exception';
2750
-            // but if we STILL don't have a payment object
2751
-            if (! $payment instanceof EE_Payment) {
2752
-                // then we'll object ! ( not object like a thing... but object like what a lawyer says ! )
2753
-                $this->_handle_payment_processor_exception($e);
2754
-            }
2755
-        }
2756
-        return $payment;
2757
-    }
2758
-
2759
-
2760
-    /**
2761
-     * _process_cancelled_payments
2762
-     * just makes sure that the payment status gets updated correctly
2763
-     * so tha tan error isn't generated during payment validation
2764
-     *
2765
-     * @param EE_Payment $payment
2766
-     * @return EE_Payment|null
2767
-     * @throws EE_Error
2768
-     */
2769
-    private function _process_cancelled_payments($payment = null)
2770
-    {
2771
-        if ($payment instanceof EE_Payment
2772
-            && $this->request->requestParamIsSet('ee_cancel_payment')
2773
-            && $payment->status() === EEM_Payment::status_id_failed
2774
-        ) {
2775
-            $payment->set_status(EEM_Payment::status_id_cancelled);
2776
-        }
2777
-        return $payment;
2778
-    }
2779
-
2780
-
2781
-    /**
2782
-     *    get_transaction_details_for_gateways
2783
-     *
2784
-     * @access    public
2785
-     * @return void
2786
-     * @throws EE_Error
2787
-     * @throws InvalidArgumentException
2788
-     * @throws ReflectionException
2789
-     * @throws InvalidDataTypeException
2790
-     * @throws InvalidInterfaceException
2791
-     */
2792
-    public function get_transaction_details_for_gateways()
2793
-    {
2794
-        $txn_details = [];
2795
-        // ya gotta make a choice man
2796
-        if (empty($this->checkout->selected_method_of_payment)) {
2797
-            $txn_details = [
2798
-                'error' => esc_html__('Please select a method of payment before proceeding.', 'event_espresso'),
2799
-            ];
2800
-        }
2801
-        // get EE_Payment_Method object
2802
-        if (empty($txn_details)
2803
-            && ! $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment()
2804
-        ) {
2805
-            $txn_details = [
2806
-                'selected_method_of_payment' => $this->checkout->selected_method_of_payment,
2807
-                'error'                      => esc_html__(
2808
-                    'A valid Payment Method could not be determined.',
2809
-                    'event_espresso'
2810
-                ),
2811
-            ];
2812
-        }
2813
-        if (empty($txn_details) && $this->checkout->transaction instanceof EE_Transaction) {
2814
-            $return_url  = $this->_get_return_url($this->checkout->payment_method);
2815
-            $txn_details = [
2816
-                'TXN_ID'         => $this->checkout->transaction->ID(),
2817
-                'TXN_timestamp'  => $this->checkout->transaction->datetime(),
2818
-                'TXN_total'      => $this->checkout->transaction->total(),
2819
-                'TXN_paid'       => $this->checkout->transaction->paid(),
2820
-                'TXN_reg_steps'  => $this->checkout->transaction->reg_steps(),
2821
-                'STS_ID'         => $this->checkout->transaction->status_ID(),
2822
-                'PMD_ID'         => $this->checkout->transaction->payment_method_ID(),
2823
-                'payment_amount' => $this->checkout->amount_owing,
2824
-                'return_url'     => $return_url,
2825
-                'cancel_url'     => add_query_arg(['ee_cancel_payment' => true], $return_url),
2826
-                'notify_url'     => EE_Config::instance()->core->txn_page_url(
2827
-                    [
2828
-                        'e_reg_url_link'    => $this->checkout->transaction->primary_registration()->reg_url_link(),
2829
-                        'ee_payment_method' => $this->checkout->payment_method->slug(),
2830
-                    ]
2831
-                ),
2832
-            ];
2833
-        }
2834
-        echo wp_json_encode($txn_details);
2835
-        exit();
2836
-    }
2837
-
2838
-
2839
-    /**
2840
-     *    __sleep
2841
-     * to conserve db space, let's remove the reg_form and the EE_Checkout object from EE_SPCO_Reg_Step objects upon
2842
-     * serialization EE_Checkout will handle the reimplementation of itself upon waking, but we won't bother with the
2843
-     * reg form, because if needed, it will be regenerated anyways
2844
-     *
2845
-     * @return array
2846
-     */
2847
-    public function __sleep()
2848
-    {
2849
-        // remove the reg form and the checkout
2850
-        return array_diff(array_keys(get_object_vars($this)), ['reg_form', 'checkout', 'line_item_display']);
2851
-    }
23
+	/**
24
+	 * @var EE_Line_Item_Display $Line_Item_Display
25
+	 */
26
+	protected $line_item_display;
27
+
28
+	/**
29
+	 * @var boolean $handle_IPN_in_this_request
30
+	 */
31
+	protected $handle_IPN_in_this_request = false;
32
+
33
+
34
+	/**
35
+	 *    set_hooks - for hooking into EE Core, other modules, etc
36
+	 *
37
+	 * @access    public
38
+	 * @return    void
39
+	 */
40
+	public static function set_hooks()
41
+	{
42
+		add_filter(
43
+			'FHEE__SPCO__EE_Line_Item_Filter_Collection',
44
+			['EE_SPCO_Reg_Step_Payment_Options', 'add_spco_line_item_filters']
45
+		);
46
+		add_action(
47
+			'wp_ajax_switch_spco_billing_form',
48
+			['EE_SPCO_Reg_Step_Payment_Options', 'switch_spco_billing_form']
49
+		);
50
+		add_action(
51
+			'wp_ajax_nopriv_switch_spco_billing_form',
52
+			['EE_SPCO_Reg_Step_Payment_Options', 'switch_spco_billing_form']
53
+		);
54
+		add_action('wp_ajax_save_payer_details', ['EE_SPCO_Reg_Step_Payment_Options', 'save_payer_details']);
55
+		add_action(
56
+			'wp_ajax_nopriv_save_payer_details',
57
+			['EE_SPCO_Reg_Step_Payment_Options', 'save_payer_details']
58
+		);
59
+		add_action(
60
+			'wp_ajax_get_transaction_details_for_gateways',
61
+			['EE_SPCO_Reg_Step_Payment_Options', 'get_transaction_details']
62
+		);
63
+		add_action(
64
+			'wp_ajax_nopriv_get_transaction_details_for_gateways',
65
+			['EE_SPCO_Reg_Step_Payment_Options', 'get_transaction_details']
66
+		);
67
+		add_filter(
68
+			'FHEE__EED_Recaptcha___bypass_recaptcha__bypass_request_params_array',
69
+			['EE_SPCO_Reg_Step_Payment_Options', 'bypass_recaptcha_for_load_payment_method'],
70
+			10,
71
+			1
72
+		);
73
+	}
74
+
75
+
76
+	/**
77
+	 *    ajax switch_spco_billing_form
78
+	 *
79
+	 */
80
+	public static function switch_spco_billing_form()
81
+	{
82
+		EED_Single_Page_Checkout::process_ajax_request('switch_payment_method');
83
+	}
84
+
85
+
86
+	/**
87
+	 *    ajax save_payer_details
88
+	 *
89
+	 */
90
+	public static function save_payer_details()
91
+	{
92
+		EED_Single_Page_Checkout::process_ajax_request('save_payer_details_via_ajax');
93
+	}
94
+
95
+
96
+	/**
97
+	 *    ajax get_transaction_details
98
+	 *
99
+	 */
100
+	public static function get_transaction_details()
101
+	{
102
+		EED_Single_Page_Checkout::process_ajax_request('get_transaction_details_for_gateways');
103
+	}
104
+
105
+
106
+	/**
107
+	 * bypass_recaptcha_for_load_payment_method
108
+	 *
109
+	 * @access public
110
+	 * @return array
111
+	 * @throws InvalidArgumentException
112
+	 * @throws InvalidDataTypeException
113
+	 * @throws InvalidInterfaceException
114
+	 */
115
+	public static function bypass_recaptcha_for_load_payment_method()
116
+	{
117
+		return [
118
+			'EESID'  => EE_Registry::instance()->SSN->id(),
119
+			'step'   => 'payment_options',
120
+			'action' => 'spco_billing_form',
121
+		];
122
+	}
123
+
124
+
125
+	/**
126
+	 *    class constructor
127
+	 *
128
+	 * @access    public
129
+	 * @param EE_Checkout $checkout
130
+	 */
131
+	public function __construct(EE_Checkout $checkout)
132
+	{
133
+		$this->request   = EED_Single_Page_Checkout::getRequest();
134
+		$this->_slug     = 'payment_options';
135
+		$this->_name     = esc_html__('Payment Options', 'event_espresso');
136
+		$this->_template = SPCO_REG_STEPS_PATH . $this->_slug . '/payment_options_main.template.php';
137
+		$this->checkout  = $checkout;
138
+		$this->_reset_success_message();
139
+		$this->set_instructions(
140
+			esc_html__(
141
+				'Please select a method of payment and provide any necessary billing information before proceeding.',
142
+				'event_espresso'
143
+			)
144
+		);
145
+	}
146
+
147
+
148
+	/**
149
+	 * @return null
150
+	 */
151
+	public function line_item_display()
152
+	{
153
+		return $this->line_item_display;
154
+	}
155
+
156
+
157
+	/**
158
+	 * @param null $line_item_display
159
+	 */
160
+	public function set_line_item_display($line_item_display)
161
+	{
162
+		$this->line_item_display = $line_item_display;
163
+	}
164
+
165
+
166
+	/**
167
+	 * @return boolean
168
+	 */
169
+	public function handle_IPN_in_this_request()
170
+	{
171
+		return $this->handle_IPN_in_this_request;
172
+	}
173
+
174
+
175
+	/**
176
+	 * @param boolean $handle_IPN_in_this_request
177
+	 */
178
+	public function set_handle_IPN_in_this_request($handle_IPN_in_this_request)
179
+	{
180
+		$this->handle_IPN_in_this_request = filter_var($handle_IPN_in_this_request, FILTER_VALIDATE_BOOLEAN);
181
+	}
182
+
183
+
184
+	/**
185
+	 * translate_js_strings
186
+	 *
187
+	 * @return void
188
+	 */
189
+	public function translate_js_strings()
190
+	{
191
+		EE_Registry::$i18n_js_strings['no_payment_method']      = esc_html__(
192
+			'Please select a method of payment in order to continue.',
193
+			'event_espresso'
194
+		);
195
+		EE_Registry::$i18n_js_strings['invalid_payment_method'] = esc_html__(
196
+			'A valid method of payment could not be determined. Please refresh the page and try again.',
197
+			'event_espresso'
198
+		);
199
+		EE_Registry::$i18n_js_strings['forwarding_to_offsite']  = esc_html__(
200
+			'Forwarding to Secure Payment Provider.',
201
+			'event_espresso'
202
+		);
203
+	}
204
+
205
+
206
+	/**
207
+	 * enqueue_styles_and_scripts
208
+	 *
209
+	 * @return void
210
+	 * @throws EE_Error
211
+	 * @throws InvalidArgumentException
212
+	 * @throws InvalidDataTypeException
213
+	 * @throws InvalidInterfaceException
214
+	 * @throws ReflectionException
215
+	 */
216
+	public function enqueue_styles_and_scripts()
217
+	{
218
+		$transaction = $this->checkout->transaction;
219
+		// if the transaction isn't set or nothing is owed on it, don't enqueue any JS
220
+		if (! $transaction instanceof EE_Transaction || EEH_Money::compare_floats($transaction->remaining(), 0)) {
221
+			return;
222
+		}
223
+		foreach (EEM_Payment_Method::instance()->get_all_for_transaction(
224
+			$transaction,
225
+			EEM_Payment_Method::scope_cart
226
+		) as $payment_method) {
227
+			$type_obj = $payment_method->type_obj();
228
+			if ($type_obj instanceof EE_PMT_Base) {
229
+				$billing_form = $type_obj->generate_new_billing_form($transaction);
230
+				if ($billing_form instanceof EE_Form_Section_Proper) {
231
+					$billing_form->enqueue_js();
232
+				}
233
+			}
234
+		}
235
+	}
236
+
237
+
238
+	/**
239
+	 * initialize_reg_step
240
+	 *
241
+	 * @return bool
242
+	 * @throws EE_Error
243
+	 * @throws InvalidArgumentException
244
+	 * @throws ReflectionException
245
+	 * @throws InvalidDataTypeException
246
+	 * @throws InvalidInterfaceException
247
+	 */
248
+	public function initialize_reg_step()
249
+	{
250
+		// TODO: if /when we implement donations, then this will need overriding
251
+		if (// don't need payment options for:
252
+			// registrations made via the admin
253
+			// completed transactions
254
+			// overpaid transactions
255
+			// $ 0.00 transactions(no payment required)
256
+			! $this->checkout->payment_required()
257
+			// but do NOT remove if current action being called belongs to this reg step
258
+			&& ! is_callable([$this, $this->checkout->action])
259
+			&& ! $this->completed()
260
+		) {
261
+			// and if so, then we no longer need the Payment Options step
262
+			if ($this->is_current_step()) {
263
+				$this->checkout->generate_reg_form = false;
264
+			}
265
+			$this->checkout->remove_reg_step($this->_slug);
266
+			// DEBUG LOG
267
+			// $this->checkout->log( __CLASS__, __FUNCTION__, __LINE__ );
268
+			return false;
269
+		}
270
+		// load EEM_Payment_Method
271
+		EE_Registry::instance()->load_model('Payment_Method');
272
+		// get all active payment methods
273
+		$this->checkout->available_payment_methods = EEM_Payment_Method::instance()->get_all_for_transaction(
274
+			$this->checkout->transaction,
275
+			EEM_Payment_Method::scope_cart
276
+		);
277
+		return true;
278
+	}
279
+
280
+
281
+	/**
282
+	 * @return EE_Form_Section_Proper
283
+	 * @throws EE_Error
284
+	 * @throws InvalidArgumentException
285
+	 * @throws ReflectionException
286
+	 * @throws EntityNotFoundException
287
+	 * @throws InvalidDataTypeException
288
+	 * @throws InvalidInterfaceException
289
+	 * @throws InvalidStatusException
290
+	 */
291
+	public function generate_reg_form()
292
+	{
293
+		// reset in case someone changes their mind
294
+		$this->_reset_selected_method_of_payment();
295
+		// set some defaults
296
+		$this->checkout->selected_method_of_payment = 'payments_closed';
297
+		$registrations_requiring_payment            = [];
298
+		$registrations_for_free_events              = [];
299
+		$registrations_requiring_pre_approval       = [];
300
+		$sold_out_events                            = [];
301
+		$insufficient_spaces_available              = [];
302
+		$no_payment_required                        = true;
303
+		// loop thru registrations to gather info
304
+		$registrations         = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
305
+		$ejected_registrations = EE_SPCO_Reg_Step_Payment_Options::find_registrations_that_lost_their_space(
306
+			$registrations,
307
+			$this->checkout->revisit
308
+		);
309
+		foreach ($registrations as $REG_ID => $registration) {
310
+			/** @var $registration EE_Registration */
311
+			// has this registration lost it's space ?
312
+			if (isset($ejected_registrations[ $REG_ID ])) {
313
+				if ($registration->event()->is_sold_out() || $registration->event()->is_sold_out(true)) {
314
+					$sold_out_events[ $registration->event()->ID() ] = $registration->event();
315
+				} else {
316
+					$insufficient_spaces_available[ $registration->event()->ID() ] = $registration->event();
317
+				}
318
+				continue;
319
+			}
320
+			// event requires admin approval
321
+			if ($registration->status_ID() === EEM_Registration::status_id_not_approved) {
322
+				// add event to list of events with pre-approval reg status
323
+				$registrations_requiring_pre_approval[ $REG_ID ] = $registration;
324
+				do_action(
325
+					'AHEE__EE_SPCO_Reg_Step_Payment_Options__generate_reg_form__event_requires_pre_approval',
326
+					$registration->event(),
327
+					$this
328
+				);
329
+				continue;
330
+			}
331
+			if ($this->checkout->revisit
332
+				&& $registration->status_ID() !== EEM_Registration::status_id_approved
333
+				&& (
334
+					$registration->event()->is_sold_out()
335
+					|| $registration->event()->is_sold_out(true)
336
+				)
337
+			) {
338
+				// add event to list of events that are sold out
339
+				$sold_out_events[ $registration->event()->ID() ] = $registration->event();
340
+				do_action(
341
+					'AHEE__EE_SPCO_Reg_Step_Payment_Options__generate_reg_form__sold_out_event',
342
+					$registration->event(),
343
+					$this
344
+				);
345
+				continue;
346
+			}
347
+			// are they allowed to pay now and is there monies owing?
348
+			if ($registration->owes_monies_and_can_pay()) {
349
+				$registrations_requiring_payment[ $REG_ID ] = $registration;
350
+				do_action(
351
+					'AHEE__EE_SPCO_Reg_Step_Payment_Options__generate_reg_form__event_requires_payment',
352
+					$registration->event(),
353
+					$this
354
+				);
355
+			} elseif (! $this->checkout->revisit
356
+					  && $registration->status_ID() !== EEM_Registration::status_id_not_approved
357
+					  && $registration->ticket()->is_free()
358
+			) {
359
+				$registrations_for_free_events[ $registration->ticket()->ID() ] = $registration;
360
+			}
361
+		}
362
+		$subsections = [];
363
+		// now decide which template to load
364
+		if (! empty($sold_out_events)) {
365
+			$subsections['sold_out_events'] = $this->_sold_out_events($sold_out_events);
366
+		}
367
+		if (! empty($insufficient_spaces_available)) {
368
+			$subsections['insufficient_space'] = $this->_insufficient_spaces_available(
369
+				$insufficient_spaces_available
370
+			);
371
+		}
372
+		if (! empty($registrations_requiring_pre_approval)) {
373
+			$subsections['registrations_requiring_pre_approval'] = $this->_registrations_requiring_pre_approval(
374
+				$registrations_requiring_pre_approval
375
+			);
376
+		}
377
+		if (! empty($registrations_for_free_events)) {
378
+			$subsections['no_payment_required'] = $this->_no_payment_required($registrations_for_free_events);
379
+		}
380
+		if (! empty($registrations_requiring_payment)) {
381
+			if ($this->checkout->amount_owing > 0) {
382
+				// autoload Line_Item_Display classes
383
+				EEH_Autoloader::register_line_item_filter_autoloaders();
384
+				$line_item_filter_processor = new EE_Line_Item_Filter_Processor(
385
+					apply_filters(
386
+						'FHEE__SPCO__EE_Line_Item_Filter_Collection',
387
+						new EE_Line_Item_Filter_Collection()
388
+					),
389
+					$this->checkout->cart->get_grand_total()
390
+				);
391
+				/** @var EE_Line_Item $filtered_line_item_tree */
392
+				$filtered_line_item_tree = $line_item_filter_processor->process();
393
+				EEH_Autoloader::register_line_item_display_autoloaders();
394
+				$this->set_line_item_display(new EE_Line_Item_Display('spco'));
395
+				$subsections['payment_options'] = $this->_display_payment_options(
396
+					$this->line_item_display->display_line_item(
397
+						$filtered_line_item_tree,
398
+						['registrations' => $registrations]
399
+					)
400
+				);
401
+				$this->checkout->amount_owing   = $filtered_line_item_tree->total();
402
+				$this->_apply_registration_payments_to_amount_owing($registrations);
403
+			}
404
+			$no_payment_required = false;
405
+		} else {
406
+			$this->_hide_reg_step_submit_button_if_revisit();
407
+		}
408
+		$this->_save_selected_method_of_payment();
409
+
410
+		$subsections['default_hidden_inputs'] = $this->reg_step_hidden_inputs();
411
+		$subsections['extra_hidden_inputs']   = $this->_extra_hidden_inputs($no_payment_required);
412
+
413
+		return new EE_Form_Section_Proper(
414
+			[
415
+				'name'            => $this->reg_form_name(),
416
+				'html_id'         => $this->reg_form_name(),
417
+				'subsections'     => $subsections,
418
+				'layout_strategy' => new EE_No_Layout(),
419
+			]
420
+		);
421
+	}
422
+
423
+
424
+	/**
425
+	 * add line item filters required for this reg step
426
+	 * these filters are applied via this line in EE_SPCO_Reg_Step_Payment_Options::set_hooks():
427
+	 *        add_filter( 'FHEE__SPCO__EE_Line_Item_Filter_Collection', array( 'EE_SPCO_Reg_Step_Payment_Options',
428
+	 *        'add_spco_line_item_filters' ) ); so any code that wants to use the same set of filters during the
429
+	 *        payment options reg step, can apply these filters via the following: apply_filters(
430
+	 *        'FHEE__SPCO__EE_Line_Item_Filter_Collection', new EE_Line_Item_Filter_Collection() ) or to an existing
431
+	 *        filter collection by passing that instead of instantiating a new collection
432
+	 *
433
+	 * @param EE_Line_Item_Filter_Collection $line_item_filter_collection
434
+	 * @return EE_Line_Item_Filter_Collection
435
+	 * @throws EE_Error
436
+	 * @throws InvalidArgumentException
437
+	 * @throws ReflectionException
438
+	 * @throws EntityNotFoundException
439
+	 * @throws InvalidDataTypeException
440
+	 * @throws InvalidInterfaceException
441
+	 * @throws InvalidStatusException
442
+	 */
443
+	public static function add_spco_line_item_filters(EE_Line_Item_Filter_Collection $line_item_filter_collection)
444
+	{
445
+		if (! EE_Registry::instance()->SSN instanceof EE_Session) {
446
+			return $line_item_filter_collection;
447
+		}
448
+		if (! EE_Registry::instance()->SSN->checkout() instanceof EE_Checkout) {
449
+			return $line_item_filter_collection;
450
+		}
451
+		if (! EE_Registry::instance()->SSN->checkout()->transaction instanceof EE_Transaction) {
452
+			return $line_item_filter_collection;
453
+		}
454
+		$line_item_filter_collection->add(
455
+			new EE_Billable_Line_Item_Filter(
456
+				EE_SPCO_Reg_Step_Payment_Options::remove_ejected_registrations(
457
+					EE_Registry::instance()->SSN->checkout()->transaction->registrations(
458
+						EE_Registry::instance()->SSN->checkout()->reg_cache_where_params
459
+					)
460
+				)
461
+			)
462
+		);
463
+		$line_item_filter_collection->add(new EE_Non_Zero_Line_Item_Filter());
464
+		return $line_item_filter_collection;
465
+	}
466
+
467
+
468
+	/**
469
+	 * remove_ejected_registrations
470
+	 * if a registrant has lost their potential space at an event due to lack of payment,
471
+	 * then this method removes them from the list of registrations being paid for during this request
472
+	 *
473
+	 * @param EE_Registration[] $registrations
474
+	 * @return EE_Registration[]
475
+	 * @throws EE_Error
476
+	 * @throws InvalidArgumentException
477
+	 * @throws ReflectionException
478
+	 * @throws EntityNotFoundException
479
+	 * @throws InvalidDataTypeException
480
+	 * @throws InvalidInterfaceException
481
+	 * @throws InvalidStatusException
482
+	 */
483
+	public static function remove_ejected_registrations(array $registrations)
484
+	{
485
+		$ejected_registrations = EE_SPCO_Reg_Step_Payment_Options::find_registrations_that_lost_their_space(
486
+			$registrations,
487
+			EE_Registry::instance()->SSN->checkout()->revisit
488
+		);
489
+		foreach ($registrations as $REG_ID => $registration) {
490
+			// has this registration lost it's space ?
491
+			if (isset($ejected_registrations[ $REG_ID ])) {
492
+				unset($registrations[ $REG_ID ]);
493
+			}
494
+		}
495
+		return $registrations;
496
+	}
497
+
498
+
499
+	/**
500
+	 * find_registrations_that_lost_their_space
501
+	 * If a registrant chooses an offline payment method like Invoice,
502
+	 * then no space is reserved for them at the event until they fully pay fo that site
503
+	 * (unless the event's default reg status is set to APPROVED)
504
+	 * if a registrant then later returns to pay, but the number of spaces available has been reduced due to sales,
505
+	 * then this method will determine which registrations have lost the ability to complete the reg process.
506
+	 *
507
+	 * @param EE_Registration[] $registrations
508
+	 * @param bool              $revisit
509
+	 * @return array
510
+	 * @throws EE_Error
511
+	 * @throws InvalidArgumentException
512
+	 * @throws ReflectionException
513
+	 * @throws EntityNotFoundException
514
+	 * @throws InvalidDataTypeException
515
+	 * @throws InvalidInterfaceException
516
+	 * @throws InvalidStatusException
517
+	 */
518
+	public static function find_registrations_that_lost_their_space(array $registrations, $revisit = false)
519
+	{
520
+		// registrations per event
521
+		$event_reg_count = [];
522
+		// spaces left per event
523
+		$event_spaces_remaining = [];
524
+		// tickets left sorted by ID
525
+		$tickets_remaining = [];
526
+		// registrations that have lost their space
527
+		$ejected_registrations = [];
528
+		foreach ($registrations as $REG_ID => $registration) {
529
+			if ($registration->status_ID() === EEM_Registration::status_id_approved
530
+				|| apply_filters(
531
+					'FHEE__EE_SPCO_Reg_Step_Payment_Options__find_registrations_that_lost_their_space__allow_reg_payment',
532
+					false,
533
+					$registration,
534
+					$revisit
535
+				)
536
+			) {
537
+				continue;
538
+			}
539
+			$EVT_ID = $registration->event_ID();
540
+			$ticket = $registration->ticket();
541
+			if (! isset($tickets_remaining[ $ticket->ID() ])) {
542
+				$tickets_remaining[ $ticket->ID() ] = $ticket->remaining();
543
+			}
544
+			if ($tickets_remaining[ $ticket->ID() ] > 0) {
545
+				if (! isset($event_reg_count[ $EVT_ID ])) {
546
+					$event_reg_count[ $EVT_ID ] = 0;
547
+				}
548
+				$event_reg_count[ $EVT_ID ]++;
549
+				if (! isset($event_spaces_remaining[ $EVT_ID ])) {
550
+					$event_spaces_remaining[ $EVT_ID ] = $registration->event()->spaces_remaining_for_sale();
551
+				}
552
+			}
553
+			if ($revisit
554
+				&& ($tickets_remaining[ $ticket->ID() ] === 0
555
+					|| $event_reg_count[ $EVT_ID ] > $event_spaces_remaining[ $EVT_ID ]
556
+				)
557
+			) {
558
+				$ejected_registrations[ $REG_ID ] = $registration->event();
559
+				if ($registration->status_ID() !== EEM_Registration::status_id_wait_list) {
560
+					/** @type EE_Registration_Processor $registration_processor */
561
+					$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
562
+					// at this point, we should have enough details about the registrant to consider the registration
563
+					// NOT incomplete
564
+					$registration_processor->manually_update_registration_status(
565
+						$registration,
566
+						EEM_Registration::status_id_wait_list
567
+					);
568
+				}
569
+			}
570
+		}
571
+		return $ejected_registrations;
572
+	}
573
+
574
+
575
+	/**
576
+	 * _hide_reg_step_submit_button
577
+	 * removes the html for the reg step submit button
578
+	 * by replacing it with an empty string via filter callback
579
+	 *
580
+	 * @return void
581
+	 */
582
+	protected function _adjust_registration_status_if_event_old_sold()
583
+	{
584
+	}
585
+
586
+
587
+	/**
588
+	 * _hide_reg_step_submit_button
589
+	 * removes the html for the reg step submit button
590
+	 * by replacing it with an empty string via filter callback
591
+	 *
592
+	 * @return void
593
+	 */
594
+	protected function _hide_reg_step_submit_button_if_revisit()
595
+	{
596
+		if ($this->checkout->revisit) {
597
+			add_filter('FHEE__EE_SPCO_Reg_Step__reg_step_submit_button__sbmt_btn_html', '__return_empty_string');
598
+		}
599
+	}
600
+
601
+
602
+	/**
603
+	 * sold_out_events
604
+	 * displays notices regarding events that have sold out since hte registrant first signed up
605
+	 *
606
+	 * @param EE_Event[] $sold_out_events_array
607
+	 * @return EE_Form_Section_Proper
608
+	 * @throws EE_Error
609
+	 */
610
+	private function _sold_out_events($sold_out_events_array = [])
611
+	{
612
+		// set some defaults
613
+		$this->checkout->selected_method_of_payment = 'events_sold_out';
614
+		$sold_out_events                            = '';
615
+		foreach ($sold_out_events_array as $sold_out_event) {
616
+			$sold_out_events .= EEH_HTML::li(
617
+				EEH_HTML::span(
618
+					'  ' . $sold_out_event->name(),
619
+					'',
620
+					'dashicons dashicons-marker ee-icon-size-16 pink-text'
621
+				)
622
+			);
623
+		}
624
+		return new EE_Form_Section_Proper(
625
+			[
626
+				'layout_strategy' => new EE_Template_Layout(
627
+					[
628
+						'layout_template_file' => SPCO_REG_STEPS_PATH
629
+												  . $this->_slug
630
+												  . '/sold_out_events.template.php',
631
+						'template_args'        => apply_filters(
632
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___sold_out_events__template_args',
633
+							[
634
+								'sold_out_events'     => $sold_out_events,
635
+								'sold_out_events_msg' => apply_filters(
636
+									'FHEE__EE_SPCO_Reg_Step_Payment_Options___sold_out_events__sold_out_events_msg',
637
+									sprintf(
638
+										esc_html__(
639
+											'It appears that the event you were about to make a payment for has sold out since you first registered. If you have already made a partial payment towards this event, please contact the event administrator for a refund.%3$s%3$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.%2$s',
640
+											'event_espresso'
641
+										),
642
+										'<strong>',
643
+										'</strong>',
644
+										'<br />'
645
+									)
646
+								),
647
+							]
648
+						),
649
+					]
650
+				),
651
+			]
652
+		);
653
+	}
654
+
655
+
656
+	/**
657
+	 * _insufficient_spaces_available
658
+	 * displays notices regarding events that do not have enough remaining spaces
659
+	 * to satisfy the current number of registrations looking to pay
660
+	 *
661
+	 * @param EE_Event[] $insufficient_spaces_events_array
662
+	 * @return EE_Form_Section_Proper
663
+	 * @throws EE_Error
664
+	 * @throws ReflectionException
665
+	 */
666
+	private function _insufficient_spaces_available($insufficient_spaces_events_array = [])
667
+	{
668
+		// set some defaults
669
+		$this->checkout->selected_method_of_payment = 'invoice';
670
+		$insufficient_space_events                  = '';
671
+		foreach ($insufficient_spaces_events_array as $event) {
672
+			if ($event instanceof EE_Event) {
673
+				$insufficient_space_events .= EEH_HTML::li(
674
+					EEH_HTML::span(' ' . $event->name(), '', 'dashicons dashicons-marker ee-icon-size-16 pink-text')
675
+				);
676
+			}
677
+		}
678
+		return new EE_Form_Section_Proper(
679
+			[
680
+				'subsections'     => [
681
+					'default_hidden_inputs' => $this->reg_step_hidden_inputs(),
682
+					'extra_hidden_inputs'   => $this->_extra_hidden_inputs(),
683
+				],
684
+				'layout_strategy' => new EE_Template_Layout(
685
+					[
686
+						'layout_template_file' => SPCO_REG_STEPS_PATH
687
+												  . $this->_slug
688
+												  . '/sold_out_events.template.php',
689
+						'template_args'        => apply_filters(
690
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___insufficient_spaces_available__template_args',
691
+							[
692
+								'sold_out_events'     => $insufficient_space_events,
693
+								'sold_out_events_msg' => apply_filters(
694
+									'FHEE__EE_SPCO_Reg_Step_Payment_Options___insufficient_spaces_available__insufficient_space_msg',
695
+									esc_html__(
696
+										'It appears that the event you were about to make a payment for has sold additional tickets since you first registered, and there are no longer enough spaces left to accommodate your selections. You may continue to pay and secure the available space(s) remaining, or simply cancel if you no longer wish to purchase. If you have already made a partial payment towards this event, please contact the event administrator for a refund.',
697
+										'event_espresso'
698
+									)
699
+								),
700
+							]
701
+						),
702
+					]
703
+				),
704
+			]
705
+		);
706
+	}
707
+
708
+
709
+	/**
710
+	 * registrations_requiring_pre_approval
711
+	 *
712
+	 * @param array $registrations_requiring_pre_approval
713
+	 * @return EE_Form_Section_Proper
714
+	 * @throws EE_Error
715
+	 * @throws EntityNotFoundException
716
+	 * @throws ReflectionException
717
+	 */
718
+	private function _registrations_requiring_pre_approval($registrations_requiring_pre_approval = [])
719
+	{
720
+		$events_requiring_pre_approval = [];
721
+		foreach ($registrations_requiring_pre_approval as $registration) {
722
+			if ($registration instanceof EE_Registration && $registration->event() instanceof EE_Event) {
723
+				$events_requiring_pre_approval[ $registration->event()->ID() ] = EEH_HTML::li(
724
+					EEH_HTML::span(
725
+						'',
726
+						'',
727
+						'dashicons dashicons-marker ee-icon-size-16 orange-text'
728
+					)
729
+					. EEH_HTML::span($registration->event()->name(), '', 'orange-text')
730
+				);
731
+			}
732
+		}
733
+		return new EE_Form_Section_Proper(
734
+			[
735
+				'layout_strategy' => new EE_Template_Layout(
736
+					[
737
+						'layout_template_file' => SPCO_REG_STEPS_PATH
738
+												  . $this->_slug
739
+												  . '/events_requiring_pre_approval.template.php', // layout_template
740
+						'template_args'        => apply_filters(
741
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___sold_out_events__template_args',
742
+							[
743
+								'events_requiring_pre_approval'     => implode('', $events_requiring_pre_approval),
744
+								'events_requiring_pre_approval_msg' => apply_filters(
745
+									'FHEE__EE_SPCO_Reg_Step_Payment_Options___events_requiring_pre_approval__events_requiring_pre_approval_msg',
746
+									esc_html__(
747
+										'The following events do not require payment at this time and will not be billed during this transaction. Billing will only occur after the attendee has been approved by the event organizer. You will be notified when your registration has been processed. If this is a free event, then no billing will occur.',
748
+										'event_espresso'
749
+									)
750
+								),
751
+							]
752
+						),
753
+					]
754
+				),
755
+			]
756
+		);
757
+	}
758
+
759
+
760
+	/**
761
+	 * _no_payment_required
762
+	 *
763
+	 * @param EE_Event[] $registrations_for_free_events
764
+	 * @return EE_Form_Section_Proper
765
+	 * @throws EE_Error
766
+	 */
767
+	private function _no_payment_required($registrations_for_free_events = [])
768
+	{
769
+		// set some defaults
770
+		$this->checkout->selected_method_of_payment = 'no_payment_required';
771
+		// generate no_payment_required form
772
+		return new EE_Form_Section_Proper(
773
+			[
774
+				'layout_strategy' => new EE_Template_Layout(
775
+					[
776
+						'layout_template_file' => SPCO_REG_STEPS_PATH
777
+												  . $this->_slug
778
+												  . '/no_payment_required.template.php', // layout_template
779
+						'template_args'        => apply_filters(
780
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___no_payment_required__template_args',
781
+							[
782
+								'revisit'                       => $this->checkout->revisit,
783
+								'registrations'                 => [],
784
+								'ticket_count'                  => [],
785
+								'registrations_for_free_events' => $registrations_for_free_events,
786
+								'no_payment_required_msg'       => EEH_HTML::p(
787
+									esc_html__('This is a free event, so no billing will occur.', 'event_espresso')
788
+								),
789
+							]
790
+						),
791
+					]
792
+				),
793
+			]
794
+		);
795
+	}
796
+
797
+
798
+	/**
799
+	 * _display_payment_options
800
+	 *
801
+	 * @param string $transaction_details
802
+	 * @return EE_Form_Section_Proper
803
+	 * @throws EE_Error
804
+	 * @throws InvalidArgumentException
805
+	 * @throws InvalidDataTypeException
806
+	 * @throws InvalidInterfaceException
807
+	 */
808
+	private function _display_payment_options($transaction_details = '')
809
+	{
810
+		// has method_of_payment been set by no-js user?
811
+		$this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment();
812
+		// build payment options form
813
+		return apply_filters(
814
+			'FHEE__EE_SPCO_Reg_Step_Payment_Options___display_payment_options__payment_options_form',
815
+			new EE_Form_Section_Proper(
816
+				[
817
+					'subsections'     => [
818
+						'before_payment_options' => apply_filters(
819
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___display_payment_options__before_payment_options',
820
+							new EE_Form_Section_Proper(
821
+								['layout_strategy' => new EE_Div_Per_Section_Layout()]
822
+							)
823
+						),
824
+						'payment_options'        => $this->_setup_payment_options(),
825
+						'after_payment_options'  => apply_filters(
826
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___display_payment_options__after_payment_options',
827
+							new EE_Form_Section_Proper(
828
+								['layout_strategy' => new EE_Div_Per_Section_Layout()]
829
+							)
830
+						),
831
+					],
832
+					'layout_strategy' => new EE_Template_Layout(
833
+						[
834
+							'layout_template_file' => $this->_template,
835
+							'template_args'        => apply_filters(
836
+								'FHEE__EE_SPCO_Reg_Step_Payment_Options___display_payment_options__template_args',
837
+								[
838
+									'reg_count'                 => $this->line_item_display->total_items(),
839
+									'transaction_details'       => $transaction_details,
840
+									'available_payment_methods' => [],
841
+								]
842
+							),
843
+						]
844
+					),
845
+				]
846
+			)
847
+		);
848
+	}
849
+
850
+
851
+	/**
852
+	 * _extra_hidden_inputs
853
+	 *
854
+	 * @param bool $no_payment_required
855
+	 * @return EE_Form_Section_Proper
856
+	 * @throws EE_Error
857
+	 * @throws ReflectionException
858
+	 */
859
+	private function _extra_hidden_inputs($no_payment_required = true)
860
+	{
861
+		return new EE_Form_Section_Proper(
862
+			[
863
+				'html_id'         => 'ee-' . $this->slug() . '-extra-hidden-inputs',
864
+				'layout_strategy' => new EE_Div_Per_Section_Layout(),
865
+				'subsections'     => [
866
+					'spco_no_payment_required' => new EE_Hidden_Input(
867
+						[
868
+							'normalization_strategy' => new EE_Boolean_Normalization(),
869
+							'html_name'              => 'spco_no_payment_required',
870
+							'html_id'                => 'spco-no-payment-required-payment_options',
871
+							'default'                => $no_payment_required,
872
+						]
873
+					),
874
+					'spco_transaction_id'      => new EE_Fixed_Hidden_Input(
875
+						[
876
+							'normalization_strategy' => new EE_Int_Normalization(),
877
+							'html_name'              => 'spco_transaction_id',
878
+							'html_id'                => 'spco-transaction-id',
879
+							'default'                => $this->checkout->transaction->ID(),
880
+						]
881
+					),
882
+				],
883
+			]
884
+		);
885
+	}
886
+
887
+
888
+	/**
889
+	 *    _apply_registration_payments_to_amount_owing
890
+	 *
891
+	 * @param array $registrations
892
+	 * @throws EE_Error
893
+	 */
894
+	protected function _apply_registration_payments_to_amount_owing(array $registrations)
895
+	{
896
+		$payments = [];
897
+		foreach ($registrations as $registration) {
898
+			if ($registration instanceof EE_Registration && $registration->owes_monies_and_can_pay()) {
899
+				$payments += $registration->registration_payments();
900
+			}
901
+		}
902
+		if (! empty($payments)) {
903
+			foreach ($payments as $payment) {
904
+				if ($payment instanceof EE_Registration_Payment) {
905
+					$this->checkout->amount_owing -= $payment->amount();
906
+				}
907
+			}
908
+		}
909
+	}
910
+
911
+
912
+	/**
913
+	 *    _reset_selected_method_of_payment
914
+	 *
915
+	 * @access    private
916
+	 * @param bool $force_reset
917
+	 * @return void
918
+	 * @throws InvalidArgumentException
919
+	 * @throws InvalidDataTypeException
920
+	 * @throws InvalidInterfaceException
921
+	 */
922
+	private function _reset_selected_method_of_payment($force_reset = false)
923
+	{
924
+		/** @var RequestInterface $request */
925
+		$request              = LoaderFactory::getLoader()->getShared(RequestInterface::class);
926
+		$reset_payment_method = $request->getRequestParam('reset_payment_method', $force_reset, 'bool');
927
+		if ($reset_payment_method) {
928
+			$this->checkout->selected_method_of_payment = null;
929
+			$this->checkout->payment_method             = null;
930
+			$this->checkout->billing_form               = null;
931
+			$this->_save_selected_method_of_payment();
932
+		}
933
+	}
934
+
935
+
936
+	/**
937
+	 * _save_selected_method_of_payment
938
+	 * stores the selected_method_of_payment in the session
939
+	 * so that it's available for all subsequent requests including AJAX
940
+	 *
941
+	 * @access        private
942
+	 * @param string $selected_method_of_payment
943
+	 * @return void
944
+	 * @throws InvalidArgumentException
945
+	 * @throws InvalidDataTypeException
946
+	 * @throws InvalidInterfaceException
947
+	 */
948
+	private function _save_selected_method_of_payment($selected_method_of_payment = '')
949
+	{
950
+		$selected_method_of_payment = ! empty($selected_method_of_payment)
951
+			? $selected_method_of_payment
952
+			: $this->checkout->selected_method_of_payment;
953
+		EE_Registry::instance()->SSN->set_session_data(
954
+			['selected_method_of_payment' => $selected_method_of_payment]
955
+		);
956
+	}
957
+
958
+
959
+	/**
960
+	 * _setup_payment_options
961
+	 *
962
+	 * @return EE_Form_Section_Proper
963
+	 * @throws EE_Error
964
+	 * @throws InvalidArgumentException
965
+	 * @throws InvalidDataTypeException
966
+	 * @throws InvalidInterfaceException
967
+	 */
968
+	public function _setup_payment_options()
969
+	{
970
+		// load payment method classes
971
+		$this->checkout->available_payment_methods = $this->_get_available_payment_methods();
972
+		if (empty($this->checkout->available_payment_methods)) {
973
+			EE_Error::add_error(
974
+				apply_filters(
975
+					'FHEE__EE_SPCO_Reg_Step_Payment_Options___setup_payment_options__error_message_no_payment_methods',
976
+					sprintf(
977
+						esc_html__(
978
+							'Sorry, you cannot complete your purchase because a payment method is not active.%1$s Please contact %2$s for assistance and provide a description of the problem.',
979
+							'event_espresso'
980
+						),
981
+						'<br>',
982
+						EE_Registry::instance()->CFG->organization->get_pretty('email')
983
+					)
984
+				),
985
+				__FILE__,
986
+				__FUNCTION__,
987
+				__LINE__
988
+			);
989
+		}
990
+		// switch up header depending on number of available payment methods
991
+		$payment_method_header     = count($this->checkout->available_payment_methods) > 1
992
+			? apply_filters(
993
+				'FHEE__registration_page_payment_options__method_of_payment_hdr',
994
+				esc_html__('Please Select Your Method of Payment', 'event_espresso')
995
+			)
996
+			: apply_filters(
997
+				'FHEE__registration_page_payment_options__method_of_payment_hdr',
998
+				esc_html__('Method of Payment', 'event_espresso')
999
+			);
1000
+		$available_payment_methods = [
1001
+			// display the "Payment Method" header
1002
+			'payment_method_header' => new EE_Form_Section_HTML(
1003
+				apply_filters(
1004
+					'FHEE__EE_SPCO_Reg_Step_Payment_Options___setup_payment_options__payment_method_header',
1005
+					EEH_HTML::h4($payment_method_header, 'method-of-payment-hdr'),
1006
+					$payment_method_header
1007
+				)
1008
+			),
1009
+		];
1010
+		// the list of actual payment methods ( invoice, paypal, etc ) in a  ( slug => HTML )  format
1011
+		$available_payment_method_options = [];
1012
+		$default_payment_method_option    = [];
1013
+		// additional instructions to be displayed and hidden below payment methods (adding a clearing div to start)
1014
+		$payment_methods_billing_info = [
1015
+			new EE_Form_Section_HTML(
1016
+				EEH_HTML::div('<br />', '', '', 'clear:both;')
1017
+			),
1018
+		];
1019
+		// loop through payment methods
1020
+		foreach ($this->checkout->available_payment_methods as $payment_method) {
1021
+			if ($payment_method instanceof EE_Payment_Method) {
1022
+				$payment_method_button = EEH_HTML::img(
1023
+					$payment_method->button_url(),
1024
+					$payment_method->name(),
1025
+					'spco-payment-method-' . $payment_method->slug() . '-btn-img',
1026
+					'spco-payment-method-btn-img'
1027
+				);
1028
+				// check if any payment methods are set as default
1029
+				// if payment method is already selected OR nothing is selected and this payment method should be
1030
+				// open_by_default
1031
+				if (($this->checkout->selected_method_of_payment === $payment_method->slug())
1032
+					|| (! $this->checkout->selected_method_of_payment && $payment_method->open_by_default())
1033
+				) {
1034
+					$this->checkout->selected_method_of_payment = $payment_method->slug();
1035
+					$this->_save_selected_method_of_payment();
1036
+					$default_payment_method_option[ $payment_method->slug() ] = $payment_method_button;
1037
+				} else {
1038
+					$available_payment_method_options[ $payment_method->slug() ] = $payment_method_button;
1039
+				}
1040
+				$payment_methods_billing_info[ $payment_method->slug() . '-info' ] =
1041
+					$this->_payment_method_billing_info(
1042
+						$payment_method
1043
+					);
1044
+			}
1045
+		}
1046
+		// prepend available_payment_method_options with default_payment_method_option so that it appears first in list
1047
+		// of PMs
1048
+		$available_payment_method_options = $default_payment_method_option + $available_payment_method_options;
1049
+		// now generate the actual form  inputs
1050
+		$available_payment_methods['available_payment_methods'] = $this->_available_payment_method_inputs(
1051
+			$available_payment_method_options
1052
+		);
1053
+		$available_payment_methods                              += $payment_methods_billing_info;
1054
+		// build the available payment methods form
1055
+		return new EE_Form_Section_Proper(
1056
+			[
1057
+				'html_id'         => 'spco-available-methods-of-payment-dv',
1058
+				'subsections'     => $available_payment_methods,
1059
+				'layout_strategy' => new EE_Div_Per_Section_Layout(),
1060
+			]
1061
+		);
1062
+	}
1063
+
1064
+
1065
+	/**
1066
+	 * _get_available_payment_methods
1067
+	 *
1068
+	 * @return EE_Payment_Method[]
1069
+	 * @throws EE_Error
1070
+	 * @throws InvalidArgumentException
1071
+	 * @throws InvalidDataTypeException
1072
+	 * @throws InvalidInterfaceException
1073
+	 */
1074
+	protected function _get_available_payment_methods()
1075
+	{
1076
+		if (! empty($this->checkout->available_payment_methods)) {
1077
+			return $this->checkout->available_payment_methods;
1078
+		}
1079
+		$available_payment_methods = [];
1080
+		$EEM_Payment_Method        = EEM_Payment_Method::instance();
1081
+		// get all active payment methods
1082
+		$payment_methods = $EEM_Payment_Method->get_all_for_transaction(
1083
+			$this->checkout->transaction,
1084
+			EEM_Payment_Method::scope_cart
1085
+		);
1086
+		foreach ($payment_methods as $payment_method) {
1087
+			if ($payment_method instanceof EE_Payment_Method) {
1088
+				$available_payment_methods[ $payment_method->slug() ] = $payment_method;
1089
+			}
1090
+		}
1091
+		return $available_payment_methods;
1092
+	}
1093
+
1094
+
1095
+	/**
1096
+	 *    _available_payment_method_inputs
1097
+	 *
1098
+	 * @access    private
1099
+	 * @param array $available_payment_method_options
1100
+	 * @return    EE_Form_Section_Proper
1101
+	 * @throws EE_Error
1102
+	 * @throws EE_Error
1103
+	 */
1104
+	private function _available_payment_method_inputs($available_payment_method_options = [])
1105
+	{
1106
+		// generate inputs
1107
+		return new EE_Form_Section_Proper(
1108
+			[
1109
+				'html_id'         => 'ee-available-payment-method-inputs',
1110
+				'layout_strategy' => new EE_Div_Per_Section_Layout(),
1111
+				'subsections'     => [
1112
+					'' => new EE_Radio_Button_Input(
1113
+						$available_payment_method_options,
1114
+						[
1115
+							'html_name'          => 'selected_method_of_payment',
1116
+							'html_class'         => 'spco-payment-method',
1117
+							'default'            => $this->checkout->selected_method_of_payment,
1118
+							'label_size'         => 11,
1119
+							'enforce_label_size' => true,
1120
+						]
1121
+					),
1122
+				],
1123
+			]
1124
+		);
1125
+	}
1126
+
1127
+
1128
+	/**
1129
+	 *    _payment_method_billing_info
1130
+	 *
1131
+	 * @access    private
1132
+	 * @param EE_Payment_Method $payment_method
1133
+	 * @return EE_Form_Section_Proper
1134
+	 * @throws EE_Error
1135
+	 * @throws InvalidArgumentException
1136
+	 * @throws InvalidDataTypeException
1137
+	 * @throws InvalidInterfaceException
1138
+	 */
1139
+	private function _payment_method_billing_info(EE_Payment_Method $payment_method)
1140
+	{
1141
+		$currently_selected = $this->checkout->selected_method_of_payment === $payment_method->slug();
1142
+		// generate the billing form for payment method
1143
+		$billing_form                 = $currently_selected
1144
+			? $this->_get_billing_form_for_payment_method($payment_method)
1145
+			: new EE_Form_Section_HTML();
1146
+		$this->checkout->billing_form = $currently_selected
1147
+			? $billing_form
1148
+			: $this->checkout->billing_form;
1149
+		// it's all in the details
1150
+		$info_html = EEH_HTML::h3(
1151
+			esc_html__('Important information regarding your payment', 'event_espresso'),
1152
+			'',
1153
+			'spco-payment-method-hdr'
1154
+		);
1155
+		// add some info regarding the step, either from what's saved in the admin,
1156
+		// or a default string depending on whether the PM has a billing form or not
1157
+		if ($payment_method->description()) {
1158
+			$payment_method_info = $payment_method->description();
1159
+		} elseif ($billing_form instanceof EE_Billing_Info_Form) {
1160
+			$payment_method_info = sprintf(
1161
+				esc_html__(
1162
+					'Please provide the following billing information, then click the "%1$s" button below in order to proceed.',
1163
+					'event_espresso'
1164
+				),
1165
+				$this->submit_button_text()
1166
+			);
1167
+		} else {
1168
+			$payment_method_info = sprintf(
1169
+				esc_html__('Please click the "%1$s" button below in order to proceed.', 'event_espresso'),
1170
+				$this->submit_button_text()
1171
+			);
1172
+		}
1173
+		$info_html .= EEH_HTML::div(
1174
+			apply_filters(
1175
+				'FHEE__EE_SPCO_Reg_Step_Payment_Options___payment_method_billing_info__payment_method_info',
1176
+				$payment_method_info
1177
+			),
1178
+			'',
1179
+			'spco-payment-method-desc ee-attention'
1180
+		);
1181
+		return new EE_Form_Section_Proper(
1182
+			[
1183
+				'html_id'         => 'spco-payment-method-info-' . $payment_method->slug(),
1184
+				'html_class'      => 'spco-payment-method-info-dv',
1185
+				// only display the selected or default PM
1186
+				'html_style'      => $currently_selected ? '' : 'display:none;',
1187
+				'layout_strategy' => new EE_Div_Per_Section_Layout(),
1188
+				'subsections'     => [
1189
+					'info'         => new EE_Form_Section_HTML($info_html),
1190
+					'billing_form' => $currently_selected ? $billing_form : new EE_Form_Section_HTML(),
1191
+				],
1192
+			]
1193
+		);
1194
+	}
1195
+
1196
+
1197
+	/**
1198
+	 * get_billing_form_html_for_payment_method
1199
+	 *
1200
+	 * @return bool
1201
+	 * @throws EE_Error
1202
+	 * @throws InvalidArgumentException
1203
+	 * @throws ReflectionException
1204
+	 * @throws InvalidDataTypeException
1205
+	 * @throws InvalidInterfaceException
1206
+	 */
1207
+	public function get_billing_form_html_for_payment_method()
1208
+	{
1209
+		// how have they chosen to pay?
1210
+		$this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment(true);
1211
+		$this->checkout->payment_method             = $this->_get_payment_method_for_selected_method_of_payment();
1212
+		if (! $this->checkout->payment_method instanceof EE_Payment_Method) {
1213
+			return false;
1214
+		}
1215
+		if (apply_filters(
1216
+			'FHEE__EE_SPCO_Reg_Step_Payment_Options__registration_checkout__selected_payment_method__display_success',
1217
+			false
1218
+		)) {
1219
+			EE_Error::add_success(
1220
+				apply_filters(
1221
+					'FHEE__Single_Page_Checkout__registration_checkout__selected_payment_method',
1222
+					sprintf(
1223
+						esc_html__(
1224
+							'You have selected "%s" as your method of payment. Please note the important payment information below.',
1225
+							'event_espresso'
1226
+						),
1227
+						$this->checkout->payment_method->name()
1228
+					)
1229
+				)
1230
+			);
1231
+		}
1232
+		// now generate billing form for selected method of payment
1233
+		$payment_method_billing_form = $this->_get_billing_form_for_payment_method($this->checkout->payment_method);
1234
+		// fill form with attendee info if applicable
1235
+		if ($payment_method_billing_form instanceof EE_Billing_Attendee_Info_Form
1236
+			&& $this->checkout->transaction_has_primary_registrant()
1237
+		) {
1238
+			$payment_method_billing_form->populate_from_attendee(
1239
+				$this->checkout->transaction->primary_registration()->attendee()
1240
+			);
1241
+		}
1242
+		// and debug content
1243
+		if ($payment_method_billing_form instanceof EE_Billing_Info_Form
1244
+			&& $this->checkout->payment_method->type_obj() instanceof EE_PMT_Base
1245
+		) {
1246
+			$payment_method_billing_form =
1247
+				$this->checkout->payment_method->type_obj()->apply_billing_form_debug_settings(
1248
+					$payment_method_billing_form
1249
+				);
1250
+		}
1251
+		$billing_info = $payment_method_billing_form instanceof EE_Form_Section_Proper
1252
+			? $payment_method_billing_form->get_html()
1253
+			: '';
1254
+		$this->checkout->json_response->set_return_data(['payment_method_info' => $billing_info]);
1255
+		// localize validation rules for main form
1256
+		$this->checkout->current_step->reg_form->localize_validation_rules();
1257
+		$this->checkout->json_response->add_validation_rules(EE_Form_Section_Proper::js_localization());
1258
+		return true;
1259
+	}
1260
+
1261
+
1262
+	/**
1263
+	 * _get_billing_form_for_payment_method
1264
+	 *
1265
+	 * @param EE_Payment_Method $payment_method
1266
+	 * @return EE_Billing_Info_Form|EE_Form_Section_HTML
1267
+	 * @throws EE_Error
1268
+	 * @throws InvalidArgumentException
1269
+	 * @throws InvalidDataTypeException
1270
+	 * @throws InvalidInterfaceException
1271
+	 */
1272
+	private function _get_billing_form_for_payment_method(EE_Payment_Method $payment_method)
1273
+	{
1274
+		$billing_form = $payment_method->type_obj()->billing_form(
1275
+			$this->checkout->transaction,
1276
+			['amount_owing' => $this->checkout->amount_owing]
1277
+		);
1278
+		if ($billing_form instanceof EE_Billing_Info_Form) {
1279
+			if (apply_filters(
1280
+					'FHEE__EE_SPCO_Reg_Step_Payment_Options__registration_checkout__selected_payment_method__display_success',
1281
+					false
1282
+				)
1283
+				&& $this->request->requestParamIsSet('payment_method')
1284
+			) {
1285
+				EE_Error::add_success(
1286
+					apply_filters(
1287
+						'FHEE__Single_Page_Checkout__registration_checkout__selected_payment_method',
1288
+						sprintf(
1289
+							esc_html__(
1290
+								'You have selected "%s" as your method of payment. Please note the important payment information below.',
1291
+								'event_espresso'
1292
+							),
1293
+							$payment_method->name()
1294
+						)
1295
+					)
1296
+				);
1297
+			}
1298
+			return apply_filters(
1299
+				'FHEE__EE_SPCO_Reg_Step_Payment_Options___get_billing_form_for_payment_method__billing_form',
1300
+				$billing_form,
1301
+				$payment_method
1302
+			);
1303
+		}
1304
+		// no actual billing form, so return empty HTML form section
1305
+		return new EE_Form_Section_HTML();
1306
+	}
1307
+
1308
+
1309
+	/**
1310
+	 * _get_selected_method_of_payment
1311
+	 *
1312
+	 * @param boolean $required whether to throw an error if the "selected_method_of_payment"
1313
+	 *                          is not found in the incoming request
1314
+	 * @param string  $request_param
1315
+	 * @return NULL|string
1316
+	 * @throws EE_Error
1317
+	 * @throws InvalidArgumentException
1318
+	 * @throws InvalidDataTypeException
1319
+	 * @throws InvalidInterfaceException
1320
+	 */
1321
+	private function _get_selected_method_of_payment(
1322
+		$required = false,
1323
+		$request_param = 'selected_method_of_payment'
1324
+	) {
1325
+		// is selected_method_of_payment set in the request ?
1326
+		$selected_method_of_payment = $this->request->getRequestParam($request_param);
1327
+		if ($selected_method_of_payment) {
1328
+			// sanitize it
1329
+			$selected_method_of_payment = is_array($selected_method_of_payment)
1330
+				? array_shift($selected_method_of_payment)
1331
+				: $selected_method_of_payment;
1332
+			$selected_method_of_payment = sanitize_text_field($selected_method_of_payment);
1333
+			// store it in the session so that it's available for all subsequent requests including AJAX
1334
+			$this->_save_selected_method_of_payment($selected_method_of_payment);
1335
+		} else {
1336
+			// or is is set in the session ?
1337
+			$selected_method_of_payment = EE_Registry::instance()->SSN->get_session_data(
1338
+				'selected_method_of_payment'
1339
+			);
1340
+		}
1341
+		// do ya really really gotta have it?
1342
+		if (empty($selected_method_of_payment) && $required) {
1343
+			EE_Error::add_error(
1344
+				sprintf(
1345
+					esc_html__(
1346
+						'The selected method of payment could not be determined.%sPlease ensure that you have selected one before proceeding.%sIf you continue to experience difficulties, then refresh your browser and try again, or contact %s for assistance.',
1347
+						'event_espresso'
1348
+					),
1349
+					'<br/>',
1350
+					'<br/>',
1351
+					EE_Registry::instance()->CFG->organization->get_pretty('email')
1352
+				),
1353
+				__FILE__,
1354
+				__FUNCTION__,
1355
+				__LINE__
1356
+			);
1357
+			return null;
1358
+		}
1359
+		return $selected_method_of_payment;
1360
+	}
1361
+
1362
+
1363
+
1364
+
1365
+
1366
+
1367
+	/********************************************************************************************************/
1368
+	/***********************************  SWITCH PAYMENT METHOD  ************************************/
1369
+	/********************************************************************************************************/
1370
+	/**
1371
+	 * switch_payment_method
1372
+	 *
1373
+	 * @return bool
1374
+	 * @throws EE_Error
1375
+	 * @throws InvalidArgumentException
1376
+	 * @throws InvalidDataTypeException
1377
+	 * @throws InvalidInterfaceException
1378
+	 * @throws ReflectionException
1379
+	 */
1380
+	public function switch_payment_method()
1381
+	{
1382
+		if (! $this->_verify_payment_method_is_set()) {
1383
+			return false;
1384
+		}
1385
+		if (apply_filters(
1386
+			'FHEE__EE_SPCO_Reg_Step_Payment_Options__registration_checkout__selected_payment_method__display_success',
1387
+			false
1388
+		)) {
1389
+			EE_Error::add_success(
1390
+				apply_filters(
1391
+					'FHEE__Single_Page_Checkout__registration_checkout__selected_payment_method',
1392
+					sprintf(
1393
+						esc_html__(
1394
+							'You have selected "%s" as your method of payment. Please note the important payment information below.',
1395
+							'event_espresso'
1396
+						),
1397
+						$this->checkout->payment_method->name()
1398
+					)
1399
+				)
1400
+			);
1401
+		}
1402
+		// generate billing form for selected method of payment if it hasn't been done already
1403
+		if ($this->checkout->payment_method->type_obj()->has_billing_form()) {
1404
+			$this->checkout->billing_form = $this->_get_billing_form_for_payment_method(
1405
+				$this->checkout->payment_method
1406
+			);
1407
+		}
1408
+		// fill form with attendee info if applicable
1409
+		if (apply_filters(
1410
+			'FHEE__populate_billing_form_fields_from_attendee',
1411
+			(
1412
+				$this->checkout->billing_form instanceof EE_Billing_Attendee_Info_Form
1413
+				&& $this->checkout->transaction_has_primary_registrant()
1414
+			),
1415
+			$this->checkout->billing_form,
1416
+			$this->checkout->transaction
1417
+		)
1418
+		) {
1419
+			$this->checkout->billing_form->populate_from_attendee(
1420
+				$this->checkout->transaction->primary_registration()->attendee()
1421
+			);
1422
+		}
1423
+		// and debug content
1424
+		if ($this->checkout->billing_form instanceof EE_Billing_Info_Form
1425
+			&& $this->checkout->payment_method->type_obj() instanceof EE_PMT_Base
1426
+		) {
1427
+			$this->checkout->billing_form =
1428
+				$this->checkout->payment_method->type_obj()->apply_billing_form_debug_settings(
1429
+					$this->checkout->billing_form
1430
+				);
1431
+		}
1432
+		// get html and validation rules for form
1433
+		if ($this->checkout->billing_form instanceof EE_Form_Section_Proper) {
1434
+			$this->checkout->json_response->set_return_data(
1435
+				['payment_method_info' => $this->checkout->billing_form->get_html()]
1436
+			);
1437
+			// localize validation rules for main form
1438
+			$this->checkout->billing_form->localize_validation_rules(true);
1439
+			$this->checkout->json_response->add_validation_rules(EE_Form_Section_Proper::js_localization());
1440
+		} else {
1441
+			$this->checkout->json_response->set_return_data(['payment_method_info' => '']);
1442
+		}
1443
+		// prevents advancement to next step
1444
+		$this->checkout->continue_reg = false;
1445
+		return true;
1446
+	}
1447
+
1448
+
1449
+	/**
1450
+	 * _verify_payment_method_is_set
1451
+	 *
1452
+	 * @return bool
1453
+	 * @throws EE_Error
1454
+	 * @throws InvalidArgumentException
1455
+	 * @throws ReflectionException
1456
+	 * @throws InvalidDataTypeException
1457
+	 * @throws InvalidInterfaceException
1458
+	 */
1459
+	protected function _verify_payment_method_is_set()
1460
+	{
1461
+		// generate billing form for selected method of payment if it hasn't been done already
1462
+		if (empty($this->checkout->selected_method_of_payment)) {
1463
+			// how have they chosen to pay?
1464
+			$this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment(true);
1465
+		} else {
1466
+			// choose your own adventure based on method_of_payment
1467
+			switch ($this->checkout->selected_method_of_payment) {
1468
+				case 'events_sold_out':
1469
+					EE_Error::add_attention(
1470
+						apply_filters(
1471
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___verify_payment_method_is_set__sold_out_events_msg',
1472
+							esc_html__(
1473
+								'It appears that the event you were about to make a payment for has sold out since this form first loaded. Please contact the event administrator if you believe this is an error.',
1474
+								'event_espresso'
1475
+							)
1476
+						),
1477
+						__FILE__,
1478
+						__FUNCTION__,
1479
+						__LINE__
1480
+					);
1481
+					return false;
1482
+				case 'payments_closed':
1483
+					EE_Error::add_attention(
1484
+						apply_filters(
1485
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___verify_payment_method_is_set__payments_closed_msg',
1486
+							esc_html__(
1487
+								'It appears that the event you were about to make a payment for is not accepting payments at this time. Please contact the event administrator if you believe this is an error.',
1488
+								'event_espresso'
1489
+							)
1490
+						),
1491
+						__FILE__,
1492
+						__FUNCTION__,
1493
+						__LINE__
1494
+					);
1495
+					return false;
1496
+				case 'no_payment_required':
1497
+					EE_Error::add_attention(
1498
+						apply_filters(
1499
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___verify_payment_method_is_set__no_payment_required_msg',
1500
+							esc_html__(
1501
+								'It appears that the event you were about to make a payment for does not require payment. Please contact the event administrator if you believe this is an error.',
1502
+								'event_espresso'
1503
+							)
1504
+						),
1505
+						__FILE__,
1506
+						__FUNCTION__,
1507
+						__LINE__
1508
+					);
1509
+					return false;
1510
+				default:
1511
+			}
1512
+		}
1513
+		// verify payment method
1514
+		if (! $this->checkout->payment_method instanceof EE_Payment_Method) {
1515
+			// get payment method for selected method of payment
1516
+			$this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment();
1517
+		}
1518
+		return $this->checkout->payment_method instanceof EE_Payment_Method;
1519
+	}
1520
+
1521
+
1522
+
1523
+	/********************************************************************************************************/
1524
+	/***************************************  SAVE PAYER DETAILS  ****************************************/
1525
+	/********************************************************************************************************/
1526
+	/**
1527
+	 * save_payer_details_via_ajax
1528
+	 *
1529
+	 * @return void
1530
+	 * @throws EE_Error
1531
+	 * @throws InvalidArgumentException
1532
+	 * @throws ReflectionException
1533
+	 * @throws RuntimeException
1534
+	 * @throws InvalidDataTypeException
1535
+	 * @throws InvalidInterfaceException
1536
+	 */
1537
+	public function save_payer_details_via_ajax()
1538
+	{
1539
+		if (! $this->_verify_payment_method_is_set()) {
1540
+			return;
1541
+		}
1542
+		// generate billing form for selected method of payment if it hasn't been done already
1543
+		if ($this->checkout->payment_method->type_obj()->has_billing_form()) {
1544
+			$this->checkout->billing_form = $this->_get_billing_form_for_payment_method(
1545
+				$this->checkout->payment_method
1546
+			);
1547
+		}
1548
+		// generate primary attendee from payer info if applicable
1549
+		if (! $this->checkout->transaction_has_primary_registrant()) {
1550
+			$attendee = $this->_create_attendee_from_request_data();
1551
+			if ($attendee instanceof EE_Attendee) {
1552
+				foreach ($this->checkout->transaction->registrations() as $registration) {
1553
+					if ($registration->is_primary_registrant()) {
1554
+						$this->checkout->primary_attendee_obj = $attendee;
1555
+						$registration->_add_relation_to($attendee, 'Attendee');
1556
+						$registration->set_attendee_id($attendee->ID());
1557
+						$registration->update_cache_after_object_save('Attendee', $attendee);
1558
+					}
1559
+				}
1560
+			}
1561
+		}
1562
+	}
1563
+
1564
+
1565
+	/**
1566
+	 * create_attendee_from_request_data
1567
+	 * uses info from alternate GET or POST data (such as AJAX) to create a new attendee
1568
+	 *
1569
+	 * @return EE_Attendee
1570
+	 * @throws EE_Error
1571
+	 * @throws InvalidArgumentException
1572
+	 * @throws ReflectionException
1573
+	 * @throws InvalidDataTypeException
1574
+	 * @throws InvalidInterfaceException
1575
+	 */
1576
+	protected function _create_attendee_from_request_data()
1577
+	{
1578
+		// get State ID
1579
+		$STA_ID = $this->request->getRequestParam('state');
1580
+		if (! empty($STA_ID)) {
1581
+			// can we get state object from name ?
1582
+			EE_Registry::instance()->load_model('State');
1583
+			$state  = EEM_State::instance()->get_col([['STA_name' => $STA_ID], 'limit' => 1], 'STA_ID');
1584
+			$STA_ID = is_array($state) && ! empty($state) ? reset($state) : $STA_ID;
1585
+		}
1586
+		// get Country ISO
1587
+		$CNT_ISO = $this->request->getRequestParam('country');
1588
+		if (! empty($CNT_ISO)) {
1589
+			// can we get country object from name ?
1590
+			EE_Registry::instance()->load_model('Country');
1591
+			$country = EEM_Country::instance()->get_col(
1592
+				[['CNT_name' => $CNT_ISO], 'limit' => 1],
1593
+				'CNT_ISO'
1594
+			);
1595
+			$CNT_ISO = is_array($country) && ! empty($country) ? reset($country) : $CNT_ISO;
1596
+		}
1597
+		// grab attendee data
1598
+		$attendee_data = [
1599
+			'ATT_fname'    => $this->request->getRequestParam('first_name'),
1600
+			'ATT_lname'    => $this->request->getRequestParam('last_name'),
1601
+			'ATT_email'    => $this->request->getRequestParam('email'),
1602
+			'ATT_address'  => $this->request->getRequestParam('address'),
1603
+			'ATT_address2' => $this->request->getRequestParam('address2'),
1604
+			'ATT_city'     => $this->request->getRequestParam('city'),
1605
+			'STA_ID'       => $STA_ID,
1606
+			'CNT_ISO'      => $CNT_ISO,
1607
+			'ATT_zip'      => $this->request->getRequestParam('zip'),
1608
+			'ATT_phone'    => $this->request->getRequestParam('phone'),
1609
+		];
1610
+		// validate the email address since it is the most important piece of info
1611
+		if (empty($attendee_data['ATT_email'])) {
1612
+			EE_Error::add_error(
1613
+				esc_html__('An invalid email address was submitted.', 'event_espresso'),
1614
+				__FILE__,
1615
+				__FUNCTION__,
1616
+				__LINE__
1617
+			);
1618
+		}
1619
+		// does this attendee already exist in the db ? we're searching using a combination of first name, last name,
1620
+		// AND email address
1621
+		if (! empty($attendee_data['ATT_fname'])
1622
+			&& ! empty($attendee_data['ATT_lname'])
1623
+			&& ! empty($attendee_data['ATT_email'])
1624
+		) {
1625
+			$existing_attendee = EEM_Attendee::instance()->find_existing_attendee(
1626
+				[
1627
+					'ATT_fname' => $attendee_data['ATT_fname'],
1628
+					'ATT_lname' => $attendee_data['ATT_lname'],
1629
+					'ATT_email' => $attendee_data['ATT_email'],
1630
+				]
1631
+			);
1632
+			if ($existing_attendee instanceof EE_Attendee) {
1633
+				return $existing_attendee;
1634
+			}
1635
+		}
1636
+		// no existing attendee? kk let's create a new one
1637
+		// kinda lame, but we need a first and last name to create an attendee, so use the email address if those
1638
+		// don't exist
1639
+		$attendee_data['ATT_fname'] = ! empty($attendee_data['ATT_fname'])
1640
+			? $attendee_data['ATT_fname']
1641
+			: $attendee_data['ATT_email'];
1642
+		$attendee_data['ATT_lname'] = ! empty($attendee_data['ATT_lname'])
1643
+			? $attendee_data['ATT_lname']
1644
+			: $attendee_data['ATT_email'];
1645
+		return EE_Attendee::new_instance($attendee_data);
1646
+	}
1647
+
1648
+
1649
+
1650
+	/********************************************************************************************************/
1651
+	/****************************************  PROCESS REG STEP  *****************************************/
1652
+	/********************************************************************************************************/
1653
+	/**
1654
+	 * process_reg_step
1655
+	 *
1656
+	 * @return bool
1657
+	 * @throws EE_Error
1658
+	 * @throws InvalidArgumentException
1659
+	 * @throws ReflectionException
1660
+	 * @throws EntityNotFoundException
1661
+	 * @throws InvalidDataTypeException
1662
+	 * @throws InvalidInterfaceException
1663
+	 * @throws InvalidStatusException
1664
+	 */
1665
+	public function process_reg_step()
1666
+	{
1667
+		// how have they chosen to pay?
1668
+		$this->checkout->selected_method_of_payment = $this->checkout->transaction->is_free()
1669
+			? 'no_payment_required'
1670
+			: $this->_get_selected_method_of_payment(true);
1671
+		// choose your own adventure based on method_of_payment
1672
+		switch ($this->checkout->selected_method_of_payment) {
1673
+			case 'events_sold_out':
1674
+				$this->checkout->redirect     = true;
1675
+				$this->checkout->redirect_url = $this->checkout->cancel_page_url;
1676
+				$this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
1677
+				// mark this reg step as completed
1678
+				$this->set_completed();
1679
+				return false;
1680
+
1681
+			case 'payments_closed':
1682
+				if (apply_filters(
1683
+					'FHEE__EE_SPCO_Reg_Step_Payment_Options__process_reg_step__payments_closed__display_success',
1684
+					false
1685
+				)) {
1686
+					EE_Error::add_success(
1687
+						esc_html__('no payment required at this time.', 'event_espresso'),
1688
+						__FILE__,
1689
+						__FUNCTION__,
1690
+						__LINE__
1691
+					);
1692
+				}
1693
+				// mark this reg step as completed
1694
+				$this->set_completed();
1695
+				return true;
1696
+
1697
+			case 'no_payment_required':
1698
+				if (apply_filters(
1699
+					'FHEE__EE_SPCO_Reg_Step_Payment_Options__process_reg_step__no_payment_required__display_success',
1700
+					false
1701
+				)) {
1702
+					EE_Error::add_success(
1703
+						esc_html__('no payment required.', 'event_espresso'),
1704
+						__FILE__,
1705
+						__FUNCTION__,
1706
+						__LINE__
1707
+					);
1708
+				}
1709
+				// mark this reg step as completed
1710
+				$this->set_completed();
1711
+				return true;
1712
+
1713
+			default:
1714
+				$registrations         = EE_Registry::instance()->SSN->checkout()->transaction->registrations(
1715
+					EE_Registry::instance()->SSN->checkout()->reg_cache_where_params
1716
+				);
1717
+				$ejected_registrations = EE_SPCO_Reg_Step_Payment_Options::find_registrations_that_lost_their_space(
1718
+					$registrations,
1719
+					EE_Registry::instance()->SSN->checkout()->revisit
1720
+				);
1721
+				// calculate difference between the two arrays
1722
+				$registrations = array_diff($registrations, $ejected_registrations);
1723
+				if (empty($registrations)) {
1724
+					$this->_redirect_because_event_sold_out();
1725
+					return false;
1726
+				}
1727
+				$payment_successful = $this->_process_payment();
1728
+				if ($payment_successful) {
1729
+					$this->checkout->continue_reg = true;
1730
+					$this->_maybe_set_completed($this->checkout->payment_method);
1731
+				} else {
1732
+					$this->checkout->continue_reg = false;
1733
+				}
1734
+				return $payment_successful;
1735
+		}
1736
+	}
1737
+
1738
+
1739
+	/**
1740
+	 * _redirect_because_event_sold_out
1741
+	 *
1742
+	 * @return void
1743
+	 */
1744
+	protected function _redirect_because_event_sold_out()
1745
+	{
1746
+		$this->checkout->continue_reg = false;
1747
+		// set redirect URL
1748
+		$this->checkout->redirect_url = add_query_arg(
1749
+			['e_reg_url_link' => $this->checkout->reg_url_link],
1750
+			$this->checkout->current_step->reg_step_url()
1751
+		);
1752
+		$this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
1753
+	}
1754
+
1755
+
1756
+	/**
1757
+	 * _maybe_set_completed
1758
+	 *
1759
+	 * @param EE_Payment_Method $payment_method
1760
+	 * @return void
1761
+	 * @throws EE_Error
1762
+	 */
1763
+	protected function _maybe_set_completed(EE_Payment_Method $payment_method)
1764
+	{
1765
+		switch ($payment_method->type_obj()->payment_occurs()) {
1766
+			case EE_PMT_Base::offsite:
1767
+				break;
1768
+			case EE_PMT_Base::onsite:
1769
+			case EE_PMT_Base::offline:
1770
+				// mark this reg step as completed
1771
+				$this->set_completed();
1772
+				break;
1773
+		}
1774
+	}
1775
+
1776
+
1777
+	/**
1778
+	 *    update_reg_step
1779
+	 *    this is the final step after a user  revisits the site to retry a payment
1780
+	 *
1781
+	 * @return bool
1782
+	 * @throws EE_Error
1783
+	 * @throws InvalidArgumentException
1784
+	 * @throws ReflectionException
1785
+	 * @throws EntityNotFoundException
1786
+	 * @throws InvalidDataTypeException
1787
+	 * @throws InvalidInterfaceException
1788
+	 * @throws InvalidStatusException
1789
+	 */
1790
+	public function update_reg_step()
1791
+	{
1792
+		$success = true;
1793
+		// if payment required
1794
+		if ($this->checkout->transaction->total() > 0) {
1795
+			do_action(
1796
+				'AHEE__EE_Single_Page_Checkout__process_finalize_registration__before_gateway',
1797
+				$this->checkout->transaction
1798
+			);
1799
+			// attempt payment via payment method
1800
+			$success = $this->process_reg_step();
1801
+		}
1802
+		if ($success && ! $this->checkout->redirect) {
1803
+			$this->checkout->cart->get_grand_total()->save_this_and_descendants_to_txn(
1804
+				$this->checkout->transaction->ID()
1805
+			);
1806
+			// set return URL
1807
+			$this->checkout->redirect_url = add_query_arg(
1808
+				['e_reg_url_link' => $this->checkout->reg_url_link],
1809
+				$this->checkout->thank_you_page_url
1810
+			);
1811
+		}
1812
+		return $success;
1813
+	}
1814
+
1815
+
1816
+	/**
1817
+	 *    _process_payment
1818
+	 *
1819
+	 * @return bool
1820
+	 * @throws EE_Error
1821
+	 * @throws InvalidArgumentException
1822
+	 * @throws ReflectionException
1823
+	 * @throws RuntimeException
1824
+	 * @throws InvalidDataTypeException
1825
+	 * @throws InvalidInterfaceException
1826
+	 */
1827
+	private function _process_payment()
1828
+	{
1829
+		// basically confirm that the event hasn't sold out since they hit the page
1830
+		if (! $this->_last_second_ticket_verifications()) {
1831
+			return false;
1832
+		}
1833
+		// ya gotta make a choice man
1834
+		if (empty($this->checkout->selected_method_of_payment)) {
1835
+			$this->checkout->json_response->set_plz_select_method_of_payment(
1836
+				esc_html__('Please select a method of payment before proceeding.', 'event_espresso')
1837
+			);
1838
+			return false;
1839
+		}
1840
+		// get EE_Payment_Method object
1841
+		if (! $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment()) {
1842
+			return false;
1843
+		}
1844
+		// setup billing form
1845
+		if ($this->checkout->payment_method->is_on_site()) {
1846
+			$this->checkout->billing_form = $this->_get_billing_form_for_payment_method(
1847
+				$this->checkout->payment_method
1848
+			);
1849
+			// bad billing form ?
1850
+			if (! $this->_billing_form_is_valid()) {
1851
+				return false;
1852
+			}
1853
+		}
1854
+		// ensure primary registrant has been fully processed
1855
+		if (! $this->_setup_primary_registrant_prior_to_payment()) {
1856
+			return false;
1857
+		}
1858
+		// if session is close to expiring (under 10 minutes by default)
1859
+		if ((time() - EE_Registry::instance()->SSN->expiration()) < EE_Registry::instance()->SSN->extension()) {
1860
+			// add some time to session expiration so that payment can be completed
1861
+			EE_Registry::instance()->SSN->extend_expiration();
1862
+		}
1863
+		/** @type EE_Transaction_Processor $transaction_processor */
1864
+		// $transaction_processor = EE_Registry::instance()->load_class( 'Transaction_Processor' );
1865
+		// in case a registrant leaves to an Off-Site Gateway and never returns, we want to approve any registrations
1866
+		// for events with a default reg status of Approved
1867
+		// $transaction_processor->toggle_registration_statuses_for_default_approved_events(
1868
+		//      $this->checkout->transaction, $this->checkout->reg_cache_where_params
1869
+		// );
1870
+		// attempt payment
1871
+		$payment = $this->_attempt_payment($this->checkout->payment_method);
1872
+		// process results
1873
+		$payment = $this->_validate_payment($payment);
1874
+		$payment = $this->_post_payment_processing($payment);
1875
+		// verify payment
1876
+		if ($payment instanceof EE_Payment) {
1877
+			// store that for later
1878
+			$this->checkout->payment = $payment;
1879
+			// we can also consider the TXN to not have been failed, so temporarily upgrade it's status to abandoned
1880
+			$this->checkout->transaction->toggle_failed_transaction_status();
1881
+			$payment_status = $payment->status();
1882
+			return $payment_status === EEM_Payment::status_id_approved
1883
+				   || $payment_status === EEM_Payment::status_id_pending;
1884
+		}
1885
+		if ($payment === true) {
1886
+			// please note that offline payment methods will NOT make a payment,
1887
+			// but instead just mark themselves as the PMD_ID on the transaction, and return true
1888
+			$this->checkout->payment = $payment;
1889
+			return true;
1890
+		}
1891
+		// where's my money?
1892
+		return false;
1893
+	}
1894
+
1895
+
1896
+	/**
1897
+	 * _last_second_ticket_verifications
1898
+	 *
1899
+	 * @return bool
1900
+	 * @throws EE_Error
1901
+	 * @throws ReflectionException
1902
+	 */
1903
+	protected function _last_second_ticket_verifications()
1904
+	{
1905
+		// don't bother re-validating if not a return visit
1906
+		if (! $this->checkout->revisit) {
1907
+			return true;
1908
+		}
1909
+		$registrations = $this->checkout->transaction->registrations();
1910
+		if (empty($registrations)) {
1911
+			return false;
1912
+		}
1913
+		foreach ($registrations as $registration) {
1914
+			if ($registration instanceof EE_Registration && ! $registration->is_approved()) {
1915
+				$event = $registration->event_obj();
1916
+				if ($event instanceof EE_Event && $event->is_sold_out(true)) {
1917
+					EE_Error::add_error(
1918
+						apply_filters(
1919
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___last_second_ticket_verifications__sold_out_events_msg',
1920
+							sprintf(
1921
+								esc_html__(
1922
+									'It appears that the %1$s event that you were about to make a payment for has sold out since you first registered and/or arrived at this page. Please refresh the page and try again. If you have already made a partial payment towards this event, please contact the event administrator for a refund.',
1923
+									'event_espresso'
1924
+								),
1925
+								$event->name()
1926
+							)
1927
+						),
1928
+						__FILE__,
1929
+						__FUNCTION__,
1930
+						__LINE__
1931
+					);
1932
+					return false;
1933
+				}
1934
+			}
1935
+		}
1936
+		return true;
1937
+	}
1938
+
1939
+
1940
+	/**
1941
+	 * redirect_form
1942
+	 *
1943
+	 * @return bool
1944
+	 * @throws EE_Error
1945
+	 * @throws InvalidArgumentException
1946
+	 * @throws ReflectionException
1947
+	 * @throws InvalidDataTypeException
1948
+	 * @throws InvalidInterfaceException
1949
+	 */
1950
+	public function redirect_form()
1951
+	{
1952
+		$payment_method_billing_info = $this->_payment_method_billing_info(
1953
+			$this->_get_payment_method_for_selected_method_of_payment()
1954
+		);
1955
+		$html                        = $payment_method_billing_info->get_html();
1956
+		$html                        .= $this->checkout->redirect_form;
1957
+		/** @var ResponseInterface $response */
1958
+		$response = LoaderFactory::getLoader()->getShared(ResponseInterface::class);
1959
+		$response->addOutput($html);
1960
+		return true;
1961
+	}
1962
+
1963
+
1964
+	/**
1965
+	 * _billing_form_is_valid
1966
+	 *
1967
+	 * @return bool
1968
+	 * @throws EE_Error
1969
+	 */
1970
+	private function _billing_form_is_valid()
1971
+	{
1972
+		if (! $this->checkout->payment_method->type_obj()->has_billing_form()) {
1973
+			return true;
1974
+		}
1975
+		if ($this->checkout->billing_form instanceof EE_Billing_Info_Form) {
1976
+			if ($this->checkout->billing_form->was_submitted()) {
1977
+				$this->checkout->billing_form->receive_form_submission();
1978
+				if ($this->checkout->billing_form->is_valid()) {
1979
+					return true;
1980
+				}
1981
+				$validation_errors = $this->checkout->billing_form->get_validation_errors_accumulated();
1982
+				$error_strings     = [];
1983
+				foreach ($validation_errors as $validation_error) {
1984
+					if ($validation_error instanceof EE_Validation_Error) {
1985
+						$form_section = $validation_error->get_form_section();
1986
+						if ($form_section instanceof EE_Form_Input_Base) {
1987
+							$label = $form_section->html_label_text();
1988
+						} elseif ($form_section instanceof EE_Form_Section_Base) {
1989
+							$label = $form_section->name();
1990
+						} else {
1991
+							$label = esc_html__('Validation Error', 'event_espresso');
1992
+						}
1993
+						$error_strings[] = sprintf('%1$s: %2$s', $label, $validation_error->getMessage());
1994
+					}
1995
+				}
1996
+				EE_Error::add_error(
1997
+					sprintf(
1998
+						esc_html__(
1999
+							'One or more billing form inputs are invalid and require correction before proceeding. %1$s %2$s',
2000
+							'event_espresso'
2001
+						),
2002
+						'<br/>',
2003
+						implode('<br/>', $error_strings)
2004
+					),
2005
+					__FILE__,
2006
+					__FUNCTION__,
2007
+					__LINE__
2008
+				);
2009
+			} else {
2010
+				EE_Error::add_error(
2011
+					esc_html__(
2012
+						'The billing form was not submitted or something prevented it\'s submission.',
2013
+						'event_espresso'
2014
+					),
2015
+					__FILE__,
2016
+					__FUNCTION__,
2017
+					__LINE__
2018
+				);
2019
+			}
2020
+		} else {
2021
+			EE_Error::add_error(
2022
+				esc_html__(
2023
+					'The submitted billing form is invalid possibly due to a technical reason.',
2024
+					'event_espresso'
2025
+				),
2026
+				__FILE__,
2027
+				__FUNCTION__,
2028
+				__LINE__
2029
+			);
2030
+		}
2031
+		return false;
2032
+	}
2033
+
2034
+
2035
+	/**
2036
+	 * _setup_primary_registrant_prior_to_payment
2037
+	 * ensures that the primary registrant has a valid attendee object created with the critical details populated
2038
+	 * (first & last name & email) and that both the transaction object and primary registration object have been saved
2039
+	 * plz note that any other registrations will NOT be saved at this point (because they may not have any details
2040
+	 * yet)
2041
+	 *
2042
+	 * @return bool
2043
+	 * @throws EE_Error
2044
+	 * @throws InvalidArgumentException
2045
+	 * @throws ReflectionException
2046
+	 * @throws RuntimeException
2047
+	 * @throws InvalidDataTypeException
2048
+	 * @throws InvalidInterfaceException
2049
+	 */
2050
+	private function _setup_primary_registrant_prior_to_payment()
2051
+	{
2052
+		// check if transaction has a primary registrant and that it has a related Attendee object
2053
+		// if not, then we need to at least gather some primary registrant data before attempting payment
2054
+		if ($this->checkout->billing_form instanceof EE_Billing_Attendee_Info_Form
2055
+			&& ! $this->checkout->transaction_has_primary_registrant()
2056
+			&& ! $this->_capture_primary_registration_data_from_billing_form()
2057
+		) {
2058
+			return false;
2059
+		}
2060
+		// because saving an object clears it's cache, we need to do the chevy shuffle
2061
+		// grab the primary_registration object
2062
+		$primary_registration = $this->checkout->transaction->primary_registration();
2063
+		// at this point we'll consider a TXN to not have been failed
2064
+		$this->checkout->transaction->toggle_failed_transaction_status();
2065
+		// save the TXN ( which clears cached copy of primary_registration)
2066
+		$this->checkout->transaction->save();
2067
+		// grab TXN ID and save it to the primary_registration
2068
+		$primary_registration->set_transaction_id($this->checkout->transaction->ID());
2069
+		// save what we have so far
2070
+		$primary_registration->save();
2071
+		return true;
2072
+	}
2073
+
2074
+
2075
+	/**
2076
+	 * _capture_primary_registration_data_from_billing_form
2077
+	 *
2078
+	 * @return bool
2079
+	 * @throws EE_Error
2080
+	 * @throws InvalidArgumentException
2081
+	 * @throws ReflectionException
2082
+	 * @throws InvalidDataTypeException
2083
+	 * @throws InvalidInterfaceException
2084
+	 */
2085
+	private function _capture_primary_registration_data_from_billing_form()
2086
+	{
2087
+		// convert billing form data into an attendee
2088
+		$this->checkout->primary_attendee_obj = $this->checkout->billing_form->create_attendee_from_billing_form_data();
2089
+		if (! $this->checkout->primary_attendee_obj instanceof EE_Attendee) {
2090
+			EE_Error::add_error(
2091
+				sprintf(
2092
+					esc_html__(
2093
+						'The billing form details could not be used for attendee details due to a technical issue.%sPlease try again or contact %s for assistance.',
2094
+						'event_espresso'
2095
+					),
2096
+					'<br/>',
2097
+					EE_Registry::instance()->CFG->organization->get_pretty('email')
2098
+				),
2099
+				__FILE__,
2100
+				__FUNCTION__,
2101
+				__LINE__
2102
+			);
2103
+			return false;
2104
+		}
2105
+		$primary_registration = $this->checkout->transaction->primary_registration();
2106
+		if (! $primary_registration instanceof EE_Registration) {
2107
+			EE_Error::add_error(
2108
+				sprintf(
2109
+					esc_html__(
2110
+						'The primary registrant for this transaction could not be determined due to a technical issue.%sPlease try again or contact %s for assistance.',
2111
+						'event_espresso'
2112
+					),
2113
+					'<br/>',
2114
+					EE_Registry::instance()->CFG->organization->get_pretty('email')
2115
+				),
2116
+				__FILE__,
2117
+				__FUNCTION__,
2118
+				__LINE__
2119
+			);
2120
+			return false;
2121
+		}
2122
+		if (! $primary_registration->_add_relation_to($this->checkout->primary_attendee_obj, 'Attendee')
2123
+			  instanceof
2124
+			  EE_Attendee
2125
+		) {
2126
+			EE_Error::add_error(
2127
+				sprintf(
2128
+					esc_html__(
2129
+						'The primary registrant could not be associated with this transaction due to a technical issue.%sPlease try again or contact %s for assistance.',
2130
+						'event_espresso'
2131
+					),
2132
+					'<br/>',
2133
+					EE_Registry::instance()->CFG->organization->get_pretty('email')
2134
+				),
2135
+				__FILE__,
2136
+				__FUNCTION__,
2137
+				__LINE__
2138
+			);
2139
+			return false;
2140
+		}
2141
+		/** @type EE_Registration_Processor $registration_processor */
2142
+		$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
2143
+		// at this point, we should have enough details about the registrant to consider the registration NOT incomplete
2144
+		$registration_processor->toggle_incomplete_registration_status_to_default($primary_registration);
2145
+		return true;
2146
+	}
2147
+
2148
+
2149
+	/**
2150
+	 * _get_payment_method_for_selected_method_of_payment
2151
+	 * retrieves a valid payment method
2152
+	 *
2153
+	 * @return EE_Payment_Method
2154
+	 * @throws EE_Error
2155
+	 * @throws InvalidArgumentException
2156
+	 * @throws ReflectionException
2157
+	 * @throws InvalidDataTypeException
2158
+	 * @throws InvalidInterfaceException
2159
+	 */
2160
+	private function _get_payment_method_for_selected_method_of_payment()
2161
+	{
2162
+		if ($this->checkout->selected_method_of_payment === 'events_sold_out') {
2163
+			$this->_redirect_because_event_sold_out();
2164
+			return null;
2165
+		}
2166
+		// get EE_Payment_Method object
2167
+		if (isset($this->checkout->available_payment_methods[ $this->checkout->selected_method_of_payment ])) {
2168
+			$payment_method = $this->checkout->available_payment_methods[ $this->checkout->selected_method_of_payment ];
2169
+		} else {
2170
+			// load EEM_Payment_Method
2171
+			EE_Registry::instance()->load_model('Payment_Method');
2172
+			$EEM_Payment_Method = EEM_Payment_Method::instance();
2173
+			$payment_method     = $EEM_Payment_Method->get_one_by_slug($this->checkout->selected_method_of_payment);
2174
+		}
2175
+		// verify $payment_method
2176
+		if (! $payment_method instanceof EE_Payment_Method) {
2177
+			// not a payment
2178
+			EE_Error::add_error(
2179
+				sprintf(
2180
+					esc_html__(
2181
+						'The selected method of payment could not be determined due to a technical issue.%sPlease try again or contact %s for assistance.',
2182
+						'event_espresso'
2183
+					),
2184
+					'<br/>',
2185
+					EE_Registry::instance()->CFG->organization->get_pretty('email')
2186
+				),
2187
+				__FILE__,
2188
+				__FUNCTION__,
2189
+				__LINE__
2190
+			);
2191
+			return null;
2192
+		}
2193
+		// and verify it has a valid Payment_Method Type object
2194
+		if (! $payment_method->type_obj() instanceof EE_PMT_Base) {
2195
+			// not a payment
2196
+			EE_Error::add_error(
2197
+				sprintf(
2198
+					esc_html__(
2199
+						'A valid payment method could not be determined due to a technical issue.%sPlease try again or contact %s for assistance.',
2200
+						'event_espresso'
2201
+					),
2202
+					'<br/>',
2203
+					EE_Registry::instance()->CFG->organization->get_pretty('email')
2204
+				),
2205
+				__FILE__,
2206
+				__FUNCTION__,
2207
+				__LINE__
2208
+			);
2209
+			return null;
2210
+		}
2211
+		return $payment_method;
2212
+	}
2213
+
2214
+
2215
+	/**
2216
+	 *    _attempt_payment
2217
+	 *
2218
+	 * @access    private
2219
+	 * @type    EE_Payment_Method $payment_method
2220
+	 * @return mixed EE_Payment | boolean
2221
+	 * @throws EE_Error
2222
+	 * @throws InvalidArgumentException
2223
+	 * @throws ReflectionException
2224
+	 * @throws InvalidDataTypeException
2225
+	 * @throws InvalidInterfaceException
2226
+	 */
2227
+	private function _attempt_payment(EE_Payment_Method $payment_method)
2228
+	{
2229
+		$payment = null;
2230
+		$this->checkout->transaction->save();
2231
+		$payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
2232
+		if (! $payment_processor instanceof EE_Payment_Processor) {
2233
+			return false;
2234
+		}
2235
+		try {
2236
+			$payment_processor->set_revisit($this->checkout->revisit);
2237
+			// generate payment object
2238
+			$payment = $payment_processor->process_payment(
2239
+				$payment_method,
2240
+				$this->checkout->transaction,
2241
+				$this->checkout->amount_owing,
2242
+				$this->checkout->billing_form,
2243
+				$this->_get_return_url($payment_method),
2244
+				'CART',
2245
+				$this->checkout->admin_request,
2246
+				true,
2247
+				$this->reg_step_url()
2248
+			);
2249
+		} catch (Exception $e) {
2250
+			$this->_handle_payment_processor_exception($e);
2251
+		}
2252
+		return $payment;
2253
+	}
2254
+
2255
+
2256
+	/**
2257
+	 * _handle_payment_processor_exception
2258
+	 *
2259
+	 * @param Exception $e
2260
+	 * @return void
2261
+	 * @throws EE_Error
2262
+	 * @throws InvalidArgumentException
2263
+	 * @throws InvalidDataTypeException
2264
+	 * @throws InvalidInterfaceException
2265
+	 */
2266
+	protected function _handle_payment_processor_exception(Exception $e)
2267
+	{
2268
+		EE_Error::add_error(
2269
+			sprintf(
2270
+				esc_html__(
2271
+					'The payment could not br processed due to a technical issue.%1$sPlease try again or contact %2$s for assistance.||The following Exception was thrown in %4$s on line %5$s:%1$s%3$s',
2272
+					'event_espresso'
2273
+				),
2274
+				'<br/>',
2275
+				EE_Registry::instance()->CFG->organization->get_pretty('email'),
2276
+				$e->getMessage(),
2277
+				$e->getFile(),
2278
+				$e->getLine()
2279
+			),
2280
+			__FILE__,
2281
+			__FUNCTION__,
2282
+			__LINE__
2283
+		);
2284
+	}
2285
+
2286
+
2287
+	/**
2288
+	 * _get_return_url
2289
+	 *
2290
+	 * @param EE_Payment_Method $payment_method
2291
+	 * @return string
2292
+	 * @throws EE_Error
2293
+	 * @throws ReflectionException
2294
+	 */
2295
+	protected function _get_return_url(EE_Payment_Method $payment_method)
2296
+	{
2297
+		$return_url = '';
2298
+		switch ($payment_method->type_obj()->payment_occurs()) {
2299
+			case EE_PMT_Base::offsite:
2300
+				$return_url = add_query_arg(
2301
+					[
2302
+						'action'                     => 'process_gateway_response',
2303
+						'selected_method_of_payment' => $this->checkout->selected_method_of_payment,
2304
+						'spco_txn'                   => $this->checkout->transaction->ID(),
2305
+					],
2306
+					$this->reg_step_url()
2307
+				);
2308
+				break;
2309
+			case EE_PMT_Base::onsite:
2310
+			case EE_PMT_Base::offline:
2311
+				$return_url = $this->checkout->next_step->reg_step_url();
2312
+				break;
2313
+		}
2314
+		return $return_url;
2315
+	}
2316
+
2317
+
2318
+	/**
2319
+	 * _validate_payment
2320
+	 *
2321
+	 * @param EE_Payment $payment
2322
+	 * @return EE_Payment|FALSE
2323
+	 * @throws EE_Error
2324
+	 * @throws InvalidArgumentException
2325
+	 * @throws InvalidDataTypeException
2326
+	 * @throws InvalidInterfaceException
2327
+	 */
2328
+	private function _validate_payment($payment = null)
2329
+	{
2330
+		if ($this->checkout->payment_method->is_off_line()) {
2331
+			return true;
2332
+		}
2333
+		// verify payment object
2334
+		if (! $payment instanceof EE_Payment) {
2335
+			// not a payment
2336
+			EE_Error::add_error(
2337
+				sprintf(
2338
+					esc_html__(
2339
+						'A valid payment was not generated due to a technical issue.%1$sPlease try again or contact %2$s for assistance.',
2340
+						'event_espresso'
2341
+					),
2342
+					'<br/>',
2343
+					EE_Registry::instance()->CFG->organization->get_pretty('email')
2344
+				),
2345
+				__FILE__,
2346
+				__FUNCTION__,
2347
+				__LINE__
2348
+			);
2349
+			return false;
2350
+		}
2351
+		return $payment;
2352
+	}
2353
+
2354
+
2355
+	/**
2356
+	 * _post_payment_processing
2357
+	 *
2358
+	 * @param EE_Payment|bool $payment
2359
+	 * @return bool
2360
+	 * @throws EE_Error
2361
+	 * @throws InvalidArgumentException
2362
+	 * @throws InvalidDataTypeException
2363
+	 * @throws InvalidInterfaceException
2364
+	 * @throws ReflectionException
2365
+	 */
2366
+	private function _post_payment_processing($payment = null)
2367
+	{
2368
+		// Off-Line payment?
2369
+		if ($payment === true) {
2370
+			// $this->_setup_redirect_for_next_step();
2371
+			return true;
2372
+			// On-Site payment?
2373
+		} elseif ($this->checkout->payment_method->is_on_site()) {
2374
+			if (! $this->_process_payment_status($payment, EE_PMT_Base::onsite)) {
2375
+				// $this->_setup_redirect_for_next_step();
2376
+				$this->checkout->continue_reg = false;
2377
+			}
2378
+			// Off-Site payment?
2379
+		} elseif ($this->checkout->payment_method->is_off_site()) {
2380
+			// if a payment object was made and it specifies a redirect url, then we'll setup that redirect info
2381
+			if ($payment instanceof EE_Payment && $payment->redirect_url()) {
2382
+				do_action('AHEE_log', __CLASS__, __FUNCTION__, $payment->redirect_url(), '$payment->redirect_url()');
2383
+				$this->checkout->redirect      = true;
2384
+				$this->checkout->redirect_form = $payment->redirect_form();
2385
+				$this->checkout->redirect_url  = $this->reg_step_url('redirect_form');
2386
+				// set JSON response
2387
+				$this->checkout->json_response->set_redirect_form($this->checkout->redirect_form);
2388
+				// and lastly, let's bump the payment status to pending
2389
+				$payment->set_status(EEM_Payment::status_id_pending);
2390
+				$payment->save();
2391
+			} else {
2392
+				// we couldn't redirect the user. Let's tell them why.
2393
+				$error_message = sprintf(
2394
+					esc_html__(
2395
+						'It appears the Off Site Payment Method was not configured properly.%sPlease try again or contact %s for assistance.',
2396
+						'event_espresso'
2397
+					),
2398
+					'<br/>',
2399
+					EE_Registry::instance()->CFG->organization->get_pretty('email')
2400
+				);
2401
+				if ($payment instanceof EE_Payment && $payment->gateway_response()) {
2402
+					$error_message = $error_message . '<br/>' . $payment->gateway_response();
2403
+				}
2404
+				$this->checkout->continue_reg = false;
2405
+				EE_Error::add_error(
2406
+					$error_message,
2407
+					__FILE__,
2408
+					__FUNCTION__,
2409
+					__LINE__
2410
+				);
2411
+			}
2412
+		} else {
2413
+			// ummm ya... not Off-Line, not On-Site, not off-Site ????
2414
+			$this->checkout->continue_reg = false;
2415
+			return false;
2416
+		}
2417
+		return $payment;
2418
+	}
2419
+
2420
+
2421
+	/**
2422
+	 *    _process_payment_status
2423
+	 *
2424
+	 * @type    EE_Payment $payment
2425
+	 * @param string       $payment_occurs
2426
+	 * @return bool
2427
+	 * @throws EE_Error
2428
+	 * @throws InvalidArgumentException
2429
+	 * @throws InvalidDataTypeException
2430
+	 * @throws InvalidInterfaceException
2431
+	 */
2432
+	private function _process_payment_status($payment, $payment_occurs = EE_PMT_Base::offline)
2433
+	{
2434
+		// off-line payment? carry on
2435
+		if ($payment_occurs === EE_PMT_Base::offline) {
2436
+			return true;
2437
+		}
2438
+		// verify payment validity
2439
+		if ($payment instanceof EE_Payment) {
2440
+			do_action('AHEE_log', __CLASS__, __FUNCTION__, $payment->status(), '$payment->status()');
2441
+			$msg = $payment->gateway_response();
2442
+			// check results
2443
+			switch ($payment->status()) {
2444
+				// good payment
2445
+				case EEM_Payment::status_id_approved:
2446
+					EE_Error::add_success(
2447
+						esc_html__('Your payment was processed successfully.', 'event_espresso'),
2448
+						__FILE__,
2449
+						__FUNCTION__,
2450
+						__LINE__
2451
+					);
2452
+					return true;
2453
+				// slow payment
2454
+				case EEM_Payment::status_id_pending:
2455
+					if (empty($msg)) {
2456
+						$msg = esc_html__(
2457
+							'Your payment appears to have been processed successfully, but the Instant Payment Notification has not yet been received. It should arrive shortly.',
2458
+							'event_espresso'
2459
+						);
2460
+					}
2461
+					EE_Error::add_success($msg, __FILE__, __FUNCTION__, __LINE__);
2462
+					return true;
2463
+				// don't wanna payment
2464
+				case EEM_Payment::status_id_cancelled:
2465
+					if (empty($msg)) {
2466
+						$msg = _n(
2467
+							'Payment cancelled. Please try again.',
2468
+							'Payment cancelled. Please try again or select another method of payment.',
2469
+							count($this->checkout->available_payment_methods),
2470
+							'event_espresso'
2471
+						);
2472
+					}
2473
+					EE_Error::add_attention($msg, __FILE__, __FUNCTION__, __LINE__);
2474
+					return false;
2475
+				// not enough payment
2476
+				case EEM_Payment::status_id_declined:
2477
+					if (empty($msg)) {
2478
+						$msg = _n(
2479
+							'We\'re sorry but your payment was declined. Please try again.',
2480
+							'We\'re sorry but your payment was declined. Please try again or select another method of payment.',
2481
+							count($this->checkout->available_payment_methods),
2482
+							'event_espresso'
2483
+						);
2484
+					}
2485
+					EE_Error::add_attention($msg, __FILE__, __FUNCTION__, __LINE__);
2486
+					return false;
2487
+				// bad payment
2488
+				case EEM_Payment::status_id_failed:
2489
+					if (! empty($msg)) {
2490
+						EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2491
+						return false;
2492
+					}
2493
+					// default to error below
2494
+					break;
2495
+			}
2496
+		}
2497
+		// off-site payment gateway responses are too unreliable, so let's just assume that
2498
+		// the payment processing is just running slower than the registrant's request
2499
+		if ($payment_occurs === EE_PMT_Base::offsite) {
2500
+			return true;
2501
+		}
2502
+		EE_Error::add_error(
2503
+			sprintf(
2504
+				esc_html__(
2505
+					'Your payment could not be processed successfully due to a technical issue.%sPlease try again or contact %s for assistance.',
2506
+					'event_espresso'
2507
+				),
2508
+				'<br/>',
2509
+				EE_Registry::instance()->CFG->organization->get_pretty('email')
2510
+			),
2511
+			__FILE__,
2512
+			__FUNCTION__,
2513
+			__LINE__
2514
+		);
2515
+		return false;
2516
+	}
2517
+
2518
+
2519
+
2520
+
2521
+
2522
+
2523
+	/********************************************************************************************************/
2524
+	/**********************************  PROCESS GATEWAY RESPONSE  **********************************/
2525
+	/********************************************************************************************************/
2526
+	/**
2527
+	 * process_gateway_response
2528
+	 * this is the return point for Off-Site Payment Methods
2529
+	 * It will attempt to "handle the IPN" if it appears that this has not already occurred,
2530
+	 * otherwise, it will load up the last payment made for the TXN.
2531
+	 * If the payment retrieved looks good, it will then either:
2532
+	 *    complete the current step and allow advancement to the next reg step
2533
+	 *        or present the payment options again
2534
+	 *
2535
+	 * @return bool
2536
+	 * @throws EE_Error
2537
+	 * @throws InvalidArgumentException
2538
+	 * @throws ReflectionException
2539
+	 * @throws InvalidDataTypeException
2540
+	 * @throws InvalidInterfaceException
2541
+	 */
2542
+	public function process_gateway_response()
2543
+	{
2544
+		// how have they chosen to pay?
2545
+		$this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment(true);
2546
+		// get EE_Payment_Method object
2547
+		if (! $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment()) {
2548
+			$this->checkout->continue_reg = false;
2549
+			return false;
2550
+		}
2551
+		if (! $this->checkout->payment_method->is_off_site()) {
2552
+			return false;
2553
+		}
2554
+		$this->_validate_offsite_return();
2555
+		// verify TXN
2556
+		if ($this->checkout->transaction instanceof EE_Transaction) {
2557
+			$gateway = $this->checkout->payment_method->type_obj()->get_gateway();
2558
+			if (! $gateway instanceof EE_Offsite_Gateway) {
2559
+				$this->checkout->continue_reg = false;
2560
+				return false;
2561
+			}
2562
+			$payment = $this->_process_off_site_payment($gateway);
2563
+			$payment = $this->_process_cancelled_payments($payment);
2564
+			$payment = $this->_validate_payment($payment);
2565
+			// if payment was not declined by the payment gateway or cancelled by the registrant
2566
+			if ($this->_process_payment_status($payment, EE_PMT_Base::offsite)) {
2567
+				// $this->_setup_redirect_for_next_step();
2568
+				// store that for later
2569
+				$this->checkout->payment = $payment;
2570
+				// mark this reg step as completed, as long as gateway doesn't use a separate IPN request,
2571
+				// because we will complete this step during the IPN processing then
2572
+				if (! $this->handle_IPN_in_this_request()) {
2573
+					$this->set_completed();
2574
+				}
2575
+				return true;
2576
+			}
2577
+		}
2578
+		// DEBUG LOG
2579
+		// $this->checkout->log(
2580
+		//     __CLASS__,
2581
+		//     __FUNCTION__,
2582
+		//     __LINE__,
2583
+		//     array('payment' => $payment)
2584
+		// );
2585
+		$this->checkout->continue_reg = false;
2586
+		return false;
2587
+	}
2588
+
2589
+
2590
+	/**
2591
+	 * _validate_return
2592
+	 *
2593
+	 * @return void
2594
+	 * @throws EE_Error
2595
+	 * @throws InvalidArgumentException
2596
+	 * @throws InvalidDataTypeException
2597
+	 * @throws InvalidInterfaceException
2598
+	 * @throws ReflectionException
2599
+	 */
2600
+	private function _validate_offsite_return()
2601
+	{
2602
+		$TXN_ID = $this->request->getRequestParam('spco_txn', 0, 'int');
2603
+		if ($TXN_ID !== $this->checkout->transaction->ID()) {
2604
+			// Houston... we might have a problem
2605
+			$invalid_TXN = false;
2606
+			// first gather some info
2607
+			$valid_TXN          = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
2608
+			$primary_registrant = $valid_TXN instanceof EE_Transaction
2609
+				? $valid_TXN->primary_registration()
2610
+				: null;
2611
+			// let's start by retrieving the cart for this TXN
2612
+			$cart = $this->checkout->get_cart_for_transaction($this->checkout->transaction);
2613
+			if ($cart instanceof EE_Cart) {
2614
+				// verify that the current cart has tickets
2615
+				$tickets = $cart->get_tickets();
2616
+				if (empty($tickets)) {
2617
+					$invalid_TXN = true;
2618
+				}
2619
+			} else {
2620
+				$invalid_TXN = true;
2621
+			}
2622
+			$valid_TXN_SID = $primary_registrant instanceof EE_Registration
2623
+				? $primary_registrant->session_ID()
2624
+				: null;
2625
+			// validate current Session ID and compare against valid TXN session ID
2626
+			if ($invalid_TXN // if this is already true, then skip other checks
2627
+				|| EE_Session::instance()->id() === null
2628
+				|| (
2629
+					// WARNING !!!
2630
+					// this could be PayPal sending back duplicate requests (ya they do that)
2631
+					// or it **could** mean someone is simply registering AGAIN after having just done so
2632
+					// so now we need to determine if this current TXN looks valid or not
2633
+					// and whether this reg step has even been started ?
2634
+					EE_Session::instance()->id() === $valid_TXN_SID
2635
+					// really? you're half way through this reg step, but you never started it ?
2636
+					&& $this->checkout->transaction->reg_step_completed($this->slug()) === false
2637
+				)
2638
+			) {
2639
+				$invalid_TXN = true;
2640
+			}
2641
+			if ($invalid_TXN) {
2642
+				// is the valid TXN completed ?
2643
+				if ($valid_TXN instanceof EE_Transaction) {
2644
+					// has this step even been started ?
2645
+					$reg_step_completed = $valid_TXN->reg_step_completed($this->slug());
2646
+					if ($reg_step_completed !== false && $reg_step_completed !== true) {
2647
+						// so it **looks** like this is a double request from PayPal
2648
+						// so let's try to pick up where we left off
2649
+						$this->checkout->transaction = $valid_TXN;
2650
+						$this->checkout->refresh_all_entities(true);
2651
+						return;
2652
+					}
2653
+				}
2654
+				// you appear to be lost?
2655
+				$this->_redirect_wayward_request($primary_registrant);
2656
+			}
2657
+		}
2658
+	}
2659
+
2660
+
2661
+	/**
2662
+	 * _redirect_wayward_request
2663
+	 *
2664
+	 * @param EE_Registration|null $primary_registrant
2665
+	 * @return void
2666
+	 * @throws EE_Error
2667
+	 * @throws InvalidArgumentException
2668
+	 * @throws InvalidDataTypeException
2669
+	 * @throws InvalidInterfaceException
2670
+	 * @throws ReflectionException
2671
+	 */
2672
+	private function _redirect_wayward_request(EE_Registration $primary_registrant)
2673
+	{
2674
+		if (! $primary_registrant instanceof EE_Registration) {
2675
+			// try redirecting based on the current TXN
2676
+			$primary_registrant = $this->checkout->transaction instanceof EE_Transaction
2677
+				? $this->checkout->transaction->primary_registration()
2678
+				: null;
2679
+		}
2680
+		if (! $primary_registrant instanceof EE_Registration) {
2681
+			EE_Error::add_error(
2682
+				sprintf(
2683
+					esc_html__(
2684
+						'Invalid information was received from the Off-Site Payment Processor and your Transaction details could not be retrieved from the database.%1$sPlease try again or contact %2$s for assistance.',
2685
+						'event_espresso'
2686
+					),
2687
+					'<br/>',
2688
+					EE_Registry::instance()->CFG->organization->get_pretty('email')
2689
+				),
2690
+				__FILE__,
2691
+				__FUNCTION__,
2692
+				__LINE__
2693
+			);
2694
+			return;
2695
+		}
2696
+		// make sure transaction is not locked
2697
+		$this->checkout->transaction->unlock();
2698
+		wp_safe_redirect(
2699
+			add_query_arg(
2700
+				[
2701
+					'e_reg_url_link' => $primary_registrant->reg_url_link(),
2702
+				],
2703
+				$this->checkout->thank_you_page_url
2704
+			)
2705
+		);
2706
+		exit();
2707
+	}
2708
+
2709
+
2710
+	/**
2711
+	 * _process_off_site_payment
2712
+	 *
2713
+	 * @param EE_Offsite_Gateway $gateway
2714
+	 * @return EE_Payment
2715
+	 * @throws EE_Error
2716
+	 * @throws InvalidArgumentException
2717
+	 * @throws InvalidDataTypeException
2718
+	 * @throws InvalidInterfaceException
2719
+	 * @throws ReflectionException
2720
+	 */
2721
+	private function _process_off_site_payment(EE_Offsite_Gateway $gateway)
2722
+	{
2723
+		try {
2724
+			$request      = LoaderFactory::getLoader()->getShared(RequestInterface::class);
2725
+			$request_data = $request->requestParams();
2726
+			// if gateway uses_separate_IPN_request, then we don't have to process the IPN manually
2727
+			$this->set_handle_IPN_in_this_request(
2728
+				$gateway->handle_IPN_in_this_request($request_data, false)
2729
+			);
2730
+			if ($this->handle_IPN_in_this_request()) {
2731
+				// get payment details and process results
2732
+				/** @type EE_Payment_Processor $payment_processor */
2733
+				$payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
2734
+				$payment           = $payment_processor->process_ipn(
2735
+					$request_data,
2736
+					$this->checkout->transaction,
2737
+					$this->checkout->payment_method,
2738
+					true,
2739
+					false
2740
+				);
2741
+				// $payment_source = 'process_ipn';
2742
+			} else {
2743
+				$payment = $this->checkout->transaction->last_payment();
2744
+				// $payment_source = 'last_payment';
2745
+			}
2746
+		} catch (Exception $e) {
2747
+			// let's just eat the exception and try to move on using any previously set payment info
2748
+			$payment = $this->checkout->transaction->last_payment();
2749
+			// $payment_source = 'last_payment after Exception';
2750
+			// but if we STILL don't have a payment object
2751
+			if (! $payment instanceof EE_Payment) {
2752
+				// then we'll object ! ( not object like a thing... but object like what a lawyer says ! )
2753
+				$this->_handle_payment_processor_exception($e);
2754
+			}
2755
+		}
2756
+		return $payment;
2757
+	}
2758
+
2759
+
2760
+	/**
2761
+	 * _process_cancelled_payments
2762
+	 * just makes sure that the payment status gets updated correctly
2763
+	 * so tha tan error isn't generated during payment validation
2764
+	 *
2765
+	 * @param EE_Payment $payment
2766
+	 * @return EE_Payment|null
2767
+	 * @throws EE_Error
2768
+	 */
2769
+	private function _process_cancelled_payments($payment = null)
2770
+	{
2771
+		if ($payment instanceof EE_Payment
2772
+			&& $this->request->requestParamIsSet('ee_cancel_payment')
2773
+			&& $payment->status() === EEM_Payment::status_id_failed
2774
+		) {
2775
+			$payment->set_status(EEM_Payment::status_id_cancelled);
2776
+		}
2777
+		return $payment;
2778
+	}
2779
+
2780
+
2781
+	/**
2782
+	 *    get_transaction_details_for_gateways
2783
+	 *
2784
+	 * @access    public
2785
+	 * @return void
2786
+	 * @throws EE_Error
2787
+	 * @throws InvalidArgumentException
2788
+	 * @throws ReflectionException
2789
+	 * @throws InvalidDataTypeException
2790
+	 * @throws InvalidInterfaceException
2791
+	 */
2792
+	public function get_transaction_details_for_gateways()
2793
+	{
2794
+		$txn_details = [];
2795
+		// ya gotta make a choice man
2796
+		if (empty($this->checkout->selected_method_of_payment)) {
2797
+			$txn_details = [
2798
+				'error' => esc_html__('Please select a method of payment before proceeding.', 'event_espresso'),
2799
+			];
2800
+		}
2801
+		// get EE_Payment_Method object
2802
+		if (empty($txn_details)
2803
+			&& ! $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment()
2804
+		) {
2805
+			$txn_details = [
2806
+				'selected_method_of_payment' => $this->checkout->selected_method_of_payment,
2807
+				'error'                      => esc_html__(
2808
+					'A valid Payment Method could not be determined.',
2809
+					'event_espresso'
2810
+				),
2811
+			];
2812
+		}
2813
+		if (empty($txn_details) && $this->checkout->transaction instanceof EE_Transaction) {
2814
+			$return_url  = $this->_get_return_url($this->checkout->payment_method);
2815
+			$txn_details = [
2816
+				'TXN_ID'         => $this->checkout->transaction->ID(),
2817
+				'TXN_timestamp'  => $this->checkout->transaction->datetime(),
2818
+				'TXN_total'      => $this->checkout->transaction->total(),
2819
+				'TXN_paid'       => $this->checkout->transaction->paid(),
2820
+				'TXN_reg_steps'  => $this->checkout->transaction->reg_steps(),
2821
+				'STS_ID'         => $this->checkout->transaction->status_ID(),
2822
+				'PMD_ID'         => $this->checkout->transaction->payment_method_ID(),
2823
+				'payment_amount' => $this->checkout->amount_owing,
2824
+				'return_url'     => $return_url,
2825
+				'cancel_url'     => add_query_arg(['ee_cancel_payment' => true], $return_url),
2826
+				'notify_url'     => EE_Config::instance()->core->txn_page_url(
2827
+					[
2828
+						'e_reg_url_link'    => $this->checkout->transaction->primary_registration()->reg_url_link(),
2829
+						'ee_payment_method' => $this->checkout->payment_method->slug(),
2830
+					]
2831
+				),
2832
+			];
2833
+		}
2834
+		echo wp_json_encode($txn_details);
2835
+		exit();
2836
+	}
2837
+
2838
+
2839
+	/**
2840
+	 *    __sleep
2841
+	 * to conserve db space, let's remove the reg_form and the EE_Checkout object from EE_SPCO_Reg_Step objects upon
2842
+	 * serialization EE_Checkout will handle the reimplementation of itself upon waking, but we won't bother with the
2843
+	 * reg form, because if needed, it will be regenerated anyways
2844
+	 *
2845
+	 * @return array
2846
+	 */
2847
+	public function __sleep()
2848
+	{
2849
+		// remove the reg form and the checkout
2850
+		return array_diff(array_keys(get_object_vars($this)), ['reg_form', 'checkout', 'line_item_display']);
2851
+	}
2852 2852
 }
Please login to merge, or discard this patch.
Spacing   +83 added lines, -83 removed lines patch added patch discarded remove patch
@@ -133,7 +133,7 @@  discard block
 block discarded – undo
133 133
         $this->request   = EED_Single_Page_Checkout::getRequest();
134 134
         $this->_slug     = 'payment_options';
135 135
         $this->_name     = esc_html__('Payment Options', 'event_espresso');
136
-        $this->_template = SPCO_REG_STEPS_PATH . $this->_slug . '/payment_options_main.template.php';
136
+        $this->_template = SPCO_REG_STEPS_PATH.$this->_slug.'/payment_options_main.template.php';
137 137
         $this->checkout  = $checkout;
138 138
         $this->_reset_success_message();
139 139
         $this->set_instructions(
@@ -188,7 +188,7 @@  discard block
 block discarded – undo
188 188
      */
189 189
     public function translate_js_strings()
190 190
     {
191
-        EE_Registry::$i18n_js_strings['no_payment_method']      = esc_html__(
191
+        EE_Registry::$i18n_js_strings['no_payment_method'] = esc_html__(
192 192
             'Please select a method of payment in order to continue.',
193 193
             'event_espresso'
194 194
         );
@@ -196,7 +196,7 @@  discard block
 block discarded – undo
196 196
             'A valid method of payment could not be determined. Please refresh the page and try again.',
197 197
             'event_espresso'
198 198
         );
199
-        EE_Registry::$i18n_js_strings['forwarding_to_offsite']  = esc_html__(
199
+        EE_Registry::$i18n_js_strings['forwarding_to_offsite'] = esc_html__(
200 200
             'Forwarding to Secure Payment Provider.',
201 201
             'event_espresso'
202 202
         );
@@ -217,7 +217,7 @@  discard block
 block discarded – undo
217 217
     {
218 218
         $transaction = $this->checkout->transaction;
219 219
         // if the transaction isn't set or nothing is owed on it, don't enqueue any JS
220
-        if (! $transaction instanceof EE_Transaction || EEH_Money::compare_floats($transaction->remaining(), 0)) {
220
+        if ( ! $transaction instanceof EE_Transaction || EEH_Money::compare_floats($transaction->remaining(), 0)) {
221 221
             return;
222 222
         }
223 223
         foreach (EEM_Payment_Method::instance()->get_all_for_transaction(
@@ -309,18 +309,18 @@  discard block
 block discarded – undo
309 309
         foreach ($registrations as $REG_ID => $registration) {
310 310
             /** @var $registration EE_Registration */
311 311
             // has this registration lost it's space ?
312
-            if (isset($ejected_registrations[ $REG_ID ])) {
312
+            if (isset($ejected_registrations[$REG_ID])) {
313 313
                 if ($registration->event()->is_sold_out() || $registration->event()->is_sold_out(true)) {
314
-                    $sold_out_events[ $registration->event()->ID() ] = $registration->event();
314
+                    $sold_out_events[$registration->event()->ID()] = $registration->event();
315 315
                 } else {
316
-                    $insufficient_spaces_available[ $registration->event()->ID() ] = $registration->event();
316
+                    $insufficient_spaces_available[$registration->event()->ID()] = $registration->event();
317 317
                 }
318 318
                 continue;
319 319
             }
320 320
             // event requires admin approval
321 321
             if ($registration->status_ID() === EEM_Registration::status_id_not_approved) {
322 322
                 // add event to list of events with pre-approval reg status
323
-                $registrations_requiring_pre_approval[ $REG_ID ] = $registration;
323
+                $registrations_requiring_pre_approval[$REG_ID] = $registration;
324 324
                 do_action(
325 325
                     'AHEE__EE_SPCO_Reg_Step_Payment_Options__generate_reg_form__event_requires_pre_approval',
326 326
                     $registration->event(),
@@ -336,7 +336,7 @@  discard block
 block discarded – undo
336 336
                 )
337 337
             ) {
338 338
                 // add event to list of events that are sold out
339
-                $sold_out_events[ $registration->event()->ID() ] = $registration->event();
339
+                $sold_out_events[$registration->event()->ID()] = $registration->event();
340 340
                 do_action(
341 341
                     'AHEE__EE_SPCO_Reg_Step_Payment_Options__generate_reg_form__sold_out_event',
342 342
                     $registration->event(),
@@ -346,38 +346,38 @@  discard block
 block discarded – undo
346 346
             }
347 347
             // are they allowed to pay now and is there monies owing?
348 348
             if ($registration->owes_monies_and_can_pay()) {
349
-                $registrations_requiring_payment[ $REG_ID ] = $registration;
349
+                $registrations_requiring_payment[$REG_ID] = $registration;
350 350
                 do_action(
351 351
                     'AHEE__EE_SPCO_Reg_Step_Payment_Options__generate_reg_form__event_requires_payment',
352 352
                     $registration->event(),
353 353
                     $this
354 354
                 );
355
-            } elseif (! $this->checkout->revisit
355
+            } elseif ( ! $this->checkout->revisit
356 356
                       && $registration->status_ID() !== EEM_Registration::status_id_not_approved
357 357
                       && $registration->ticket()->is_free()
358 358
             ) {
359
-                $registrations_for_free_events[ $registration->ticket()->ID() ] = $registration;
359
+                $registrations_for_free_events[$registration->ticket()->ID()] = $registration;
360 360
             }
361 361
         }
362 362
         $subsections = [];
363 363
         // now decide which template to load
364
-        if (! empty($sold_out_events)) {
364
+        if ( ! empty($sold_out_events)) {
365 365
             $subsections['sold_out_events'] = $this->_sold_out_events($sold_out_events);
366 366
         }
367
-        if (! empty($insufficient_spaces_available)) {
367
+        if ( ! empty($insufficient_spaces_available)) {
368 368
             $subsections['insufficient_space'] = $this->_insufficient_spaces_available(
369 369
                 $insufficient_spaces_available
370 370
             );
371 371
         }
372
-        if (! empty($registrations_requiring_pre_approval)) {
372
+        if ( ! empty($registrations_requiring_pre_approval)) {
373 373
             $subsections['registrations_requiring_pre_approval'] = $this->_registrations_requiring_pre_approval(
374 374
                 $registrations_requiring_pre_approval
375 375
             );
376 376
         }
377
-        if (! empty($registrations_for_free_events)) {
377
+        if ( ! empty($registrations_for_free_events)) {
378 378
             $subsections['no_payment_required'] = $this->_no_payment_required($registrations_for_free_events);
379 379
         }
380
-        if (! empty($registrations_requiring_payment)) {
380
+        if ( ! empty($registrations_requiring_payment)) {
381 381
             if ($this->checkout->amount_owing > 0) {
382 382
                 // autoload Line_Item_Display classes
383 383
                 EEH_Autoloader::register_line_item_filter_autoloaders();
@@ -398,7 +398,7 @@  discard block
 block discarded – undo
398 398
                         ['registrations' => $registrations]
399 399
                     )
400 400
                 );
401
-                $this->checkout->amount_owing   = $filtered_line_item_tree->total();
401
+                $this->checkout->amount_owing = $filtered_line_item_tree->total();
402 402
                 $this->_apply_registration_payments_to_amount_owing($registrations);
403 403
             }
404 404
             $no_payment_required = false;
@@ -442,13 +442,13 @@  discard block
 block discarded – undo
442 442
      */
443 443
     public static function add_spco_line_item_filters(EE_Line_Item_Filter_Collection $line_item_filter_collection)
444 444
     {
445
-        if (! EE_Registry::instance()->SSN instanceof EE_Session) {
445
+        if ( ! EE_Registry::instance()->SSN instanceof EE_Session) {
446 446
             return $line_item_filter_collection;
447 447
         }
448
-        if (! EE_Registry::instance()->SSN->checkout() instanceof EE_Checkout) {
448
+        if ( ! EE_Registry::instance()->SSN->checkout() instanceof EE_Checkout) {
449 449
             return $line_item_filter_collection;
450 450
         }
451
-        if (! EE_Registry::instance()->SSN->checkout()->transaction instanceof EE_Transaction) {
451
+        if ( ! EE_Registry::instance()->SSN->checkout()->transaction instanceof EE_Transaction) {
452 452
             return $line_item_filter_collection;
453 453
         }
454 454
         $line_item_filter_collection->add(
@@ -488,8 +488,8 @@  discard block
 block discarded – undo
488 488
         );
489 489
         foreach ($registrations as $REG_ID => $registration) {
490 490
             // has this registration lost it's space ?
491
-            if (isset($ejected_registrations[ $REG_ID ])) {
492
-                unset($registrations[ $REG_ID ]);
491
+            if (isset($ejected_registrations[$REG_ID])) {
492
+                unset($registrations[$REG_ID]);
493 493
             }
494 494
         }
495 495
         return $registrations;
@@ -538,24 +538,24 @@  discard block
 block discarded – undo
538 538
             }
539 539
             $EVT_ID = $registration->event_ID();
540 540
             $ticket = $registration->ticket();
541
-            if (! isset($tickets_remaining[ $ticket->ID() ])) {
542
-                $tickets_remaining[ $ticket->ID() ] = $ticket->remaining();
541
+            if ( ! isset($tickets_remaining[$ticket->ID()])) {
542
+                $tickets_remaining[$ticket->ID()] = $ticket->remaining();
543 543
             }
544
-            if ($tickets_remaining[ $ticket->ID() ] > 0) {
545
-                if (! isset($event_reg_count[ $EVT_ID ])) {
546
-                    $event_reg_count[ $EVT_ID ] = 0;
544
+            if ($tickets_remaining[$ticket->ID()] > 0) {
545
+                if ( ! isset($event_reg_count[$EVT_ID])) {
546
+                    $event_reg_count[$EVT_ID] = 0;
547 547
                 }
548
-                $event_reg_count[ $EVT_ID ]++;
549
-                if (! isset($event_spaces_remaining[ $EVT_ID ])) {
550
-                    $event_spaces_remaining[ $EVT_ID ] = $registration->event()->spaces_remaining_for_sale();
548
+                $event_reg_count[$EVT_ID]++;
549
+                if ( ! isset($event_spaces_remaining[$EVT_ID])) {
550
+                    $event_spaces_remaining[$EVT_ID] = $registration->event()->spaces_remaining_for_sale();
551 551
                 }
552 552
             }
553 553
             if ($revisit
554
-                && ($tickets_remaining[ $ticket->ID() ] === 0
555
-                    || $event_reg_count[ $EVT_ID ] > $event_spaces_remaining[ $EVT_ID ]
554
+                && ($tickets_remaining[$ticket->ID()] === 0
555
+                    || $event_reg_count[$EVT_ID] > $event_spaces_remaining[$EVT_ID]
556 556
                 )
557 557
             ) {
558
-                $ejected_registrations[ $REG_ID ] = $registration->event();
558
+                $ejected_registrations[$REG_ID] = $registration->event();
559 559
                 if ($registration->status_ID() !== EEM_Registration::status_id_wait_list) {
560 560
                     /** @type EE_Registration_Processor $registration_processor */
561 561
                     $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
@@ -615,7 +615,7 @@  discard block
 block discarded – undo
615 615
         foreach ($sold_out_events_array as $sold_out_event) {
616 616
             $sold_out_events .= EEH_HTML::li(
617 617
                 EEH_HTML::span(
618
-                    '  ' . $sold_out_event->name(),
618
+                    '  '.$sold_out_event->name(),
619 619
                     '',
620 620
                     'dashicons dashicons-marker ee-icon-size-16 pink-text'
621 621
                 )
@@ -671,7 +671,7 @@  discard block
 block discarded – undo
671 671
         foreach ($insufficient_spaces_events_array as $event) {
672 672
             if ($event instanceof EE_Event) {
673 673
                 $insufficient_space_events .= EEH_HTML::li(
674
-                    EEH_HTML::span(' ' . $event->name(), '', 'dashicons dashicons-marker ee-icon-size-16 pink-text')
674
+                    EEH_HTML::span(' '.$event->name(), '', 'dashicons dashicons-marker ee-icon-size-16 pink-text')
675 675
                 );
676 676
             }
677 677
         }
@@ -720,7 +720,7 @@  discard block
 block discarded – undo
720 720
         $events_requiring_pre_approval = [];
721 721
         foreach ($registrations_requiring_pre_approval as $registration) {
722 722
             if ($registration instanceof EE_Registration && $registration->event() instanceof EE_Event) {
723
-                $events_requiring_pre_approval[ $registration->event()->ID() ] = EEH_HTML::li(
723
+                $events_requiring_pre_approval[$registration->event()->ID()] = EEH_HTML::li(
724 724
                     EEH_HTML::span(
725 725
                         '',
726 726
                         '',
@@ -860,7 +860,7 @@  discard block
 block discarded – undo
860 860
     {
861 861
         return new EE_Form_Section_Proper(
862 862
             [
863
-                'html_id'         => 'ee-' . $this->slug() . '-extra-hidden-inputs',
863
+                'html_id'         => 'ee-'.$this->slug().'-extra-hidden-inputs',
864 864
                 'layout_strategy' => new EE_Div_Per_Section_Layout(),
865 865
                 'subsections'     => [
866 866
                     'spco_no_payment_required' => new EE_Hidden_Input(
@@ -899,7 +899,7 @@  discard block
 block discarded – undo
899 899
                 $payments += $registration->registration_payments();
900 900
             }
901 901
         }
902
-        if (! empty($payments)) {
902
+        if ( ! empty($payments)) {
903 903
             foreach ($payments as $payment) {
904 904
                 if ($payment instanceof EE_Registration_Payment) {
905 905
                     $this->checkout->amount_owing -= $payment->amount();
@@ -988,7 +988,7 @@  discard block
 block discarded – undo
988 988
             );
989 989
         }
990 990
         // switch up header depending on number of available payment methods
991
-        $payment_method_header     = count($this->checkout->available_payment_methods) > 1
991
+        $payment_method_header = count($this->checkout->available_payment_methods) > 1
992 992
             ? apply_filters(
993 993
                 'FHEE__registration_page_payment_options__method_of_payment_hdr',
994 994
                 esc_html__('Please Select Your Method of Payment', 'event_espresso')
@@ -1022,22 +1022,22 @@  discard block
 block discarded – undo
1022 1022
                 $payment_method_button = EEH_HTML::img(
1023 1023
                     $payment_method->button_url(),
1024 1024
                     $payment_method->name(),
1025
-                    'spco-payment-method-' . $payment_method->slug() . '-btn-img',
1025
+                    'spco-payment-method-'.$payment_method->slug().'-btn-img',
1026 1026
                     'spco-payment-method-btn-img'
1027 1027
                 );
1028 1028
                 // check if any payment methods are set as default
1029 1029
                 // if payment method is already selected OR nothing is selected and this payment method should be
1030 1030
                 // open_by_default
1031 1031
                 if (($this->checkout->selected_method_of_payment === $payment_method->slug())
1032
-                    || (! $this->checkout->selected_method_of_payment && $payment_method->open_by_default())
1032
+                    || ( ! $this->checkout->selected_method_of_payment && $payment_method->open_by_default())
1033 1033
                 ) {
1034 1034
                     $this->checkout->selected_method_of_payment = $payment_method->slug();
1035 1035
                     $this->_save_selected_method_of_payment();
1036
-                    $default_payment_method_option[ $payment_method->slug() ] = $payment_method_button;
1036
+                    $default_payment_method_option[$payment_method->slug()] = $payment_method_button;
1037 1037
                 } else {
1038
-                    $available_payment_method_options[ $payment_method->slug() ] = $payment_method_button;
1038
+                    $available_payment_method_options[$payment_method->slug()] = $payment_method_button;
1039 1039
                 }
1040
-                $payment_methods_billing_info[ $payment_method->slug() . '-info' ] =
1040
+                $payment_methods_billing_info[$payment_method->slug().'-info'] =
1041 1041
                     $this->_payment_method_billing_info(
1042 1042
                         $payment_method
1043 1043
                     );
@@ -1050,7 +1050,7 @@  discard block
 block discarded – undo
1050 1050
         $available_payment_methods['available_payment_methods'] = $this->_available_payment_method_inputs(
1051 1051
             $available_payment_method_options
1052 1052
         );
1053
-        $available_payment_methods                              += $payment_methods_billing_info;
1053
+        $available_payment_methods += $payment_methods_billing_info;
1054 1054
         // build the available payment methods form
1055 1055
         return new EE_Form_Section_Proper(
1056 1056
             [
@@ -1073,7 +1073,7 @@  discard block
 block discarded – undo
1073 1073
      */
1074 1074
     protected function _get_available_payment_methods()
1075 1075
     {
1076
-        if (! empty($this->checkout->available_payment_methods)) {
1076
+        if ( ! empty($this->checkout->available_payment_methods)) {
1077 1077
             return $this->checkout->available_payment_methods;
1078 1078
         }
1079 1079
         $available_payment_methods = [];
@@ -1085,7 +1085,7 @@  discard block
 block discarded – undo
1085 1085
         );
1086 1086
         foreach ($payment_methods as $payment_method) {
1087 1087
             if ($payment_method instanceof EE_Payment_Method) {
1088
-                $available_payment_methods[ $payment_method->slug() ] = $payment_method;
1088
+                $available_payment_methods[$payment_method->slug()] = $payment_method;
1089 1089
             }
1090 1090
         }
1091 1091
         return $available_payment_methods;
@@ -1180,7 +1180,7 @@  discard block
 block discarded – undo
1180 1180
         );
1181 1181
         return new EE_Form_Section_Proper(
1182 1182
             [
1183
-                'html_id'         => 'spco-payment-method-info-' . $payment_method->slug(),
1183
+                'html_id'         => 'spco-payment-method-info-'.$payment_method->slug(),
1184 1184
                 'html_class'      => 'spco-payment-method-info-dv',
1185 1185
                 // only display the selected or default PM
1186 1186
                 'html_style'      => $currently_selected ? '' : 'display:none;',
@@ -1209,7 +1209,7 @@  discard block
 block discarded – undo
1209 1209
         // how have they chosen to pay?
1210 1210
         $this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment(true);
1211 1211
         $this->checkout->payment_method             = $this->_get_payment_method_for_selected_method_of_payment();
1212
-        if (! $this->checkout->payment_method instanceof EE_Payment_Method) {
1212
+        if ( ! $this->checkout->payment_method instanceof EE_Payment_Method) {
1213 1213
             return false;
1214 1214
         }
1215 1215
         if (apply_filters(
@@ -1379,7 +1379,7 @@  discard block
 block discarded – undo
1379 1379
      */
1380 1380
     public function switch_payment_method()
1381 1381
     {
1382
-        if (! $this->_verify_payment_method_is_set()) {
1382
+        if ( ! $this->_verify_payment_method_is_set()) {
1383 1383
             return false;
1384 1384
         }
1385 1385
         if (apply_filters(
@@ -1511,7 +1511,7 @@  discard block
 block discarded – undo
1511 1511
             }
1512 1512
         }
1513 1513
         // verify payment method
1514
-        if (! $this->checkout->payment_method instanceof EE_Payment_Method) {
1514
+        if ( ! $this->checkout->payment_method instanceof EE_Payment_Method) {
1515 1515
             // get payment method for selected method of payment
1516 1516
             $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment();
1517 1517
         }
@@ -1536,7 +1536,7 @@  discard block
 block discarded – undo
1536 1536
      */
1537 1537
     public function save_payer_details_via_ajax()
1538 1538
     {
1539
-        if (! $this->_verify_payment_method_is_set()) {
1539
+        if ( ! $this->_verify_payment_method_is_set()) {
1540 1540
             return;
1541 1541
         }
1542 1542
         // generate billing form for selected method of payment if it hasn't been done already
@@ -1546,7 +1546,7 @@  discard block
 block discarded – undo
1546 1546
             );
1547 1547
         }
1548 1548
         // generate primary attendee from payer info if applicable
1549
-        if (! $this->checkout->transaction_has_primary_registrant()) {
1549
+        if ( ! $this->checkout->transaction_has_primary_registrant()) {
1550 1550
             $attendee = $this->_create_attendee_from_request_data();
1551 1551
             if ($attendee instanceof EE_Attendee) {
1552 1552
                 foreach ($this->checkout->transaction->registrations() as $registration) {
@@ -1577,7 +1577,7 @@  discard block
 block discarded – undo
1577 1577
     {
1578 1578
         // get State ID
1579 1579
         $STA_ID = $this->request->getRequestParam('state');
1580
-        if (! empty($STA_ID)) {
1580
+        if ( ! empty($STA_ID)) {
1581 1581
             // can we get state object from name ?
1582 1582
             EE_Registry::instance()->load_model('State');
1583 1583
             $state  = EEM_State::instance()->get_col([['STA_name' => $STA_ID], 'limit' => 1], 'STA_ID');
@@ -1585,7 +1585,7 @@  discard block
 block discarded – undo
1585 1585
         }
1586 1586
         // get Country ISO
1587 1587
         $CNT_ISO = $this->request->getRequestParam('country');
1588
-        if (! empty($CNT_ISO)) {
1588
+        if ( ! empty($CNT_ISO)) {
1589 1589
             // can we get country object from name ?
1590 1590
             EE_Registry::instance()->load_model('Country');
1591 1591
             $country = EEM_Country::instance()->get_col(
@@ -1618,7 +1618,7 @@  discard block
 block discarded – undo
1618 1618
         }
1619 1619
         // does this attendee already exist in the db ? we're searching using a combination of first name, last name,
1620 1620
         // AND email address
1621
-        if (! empty($attendee_data['ATT_fname'])
1621
+        if ( ! empty($attendee_data['ATT_fname'])
1622 1622
             && ! empty($attendee_data['ATT_lname'])
1623 1623
             && ! empty($attendee_data['ATT_email'])
1624 1624
         ) {
@@ -1827,7 +1827,7 @@  discard block
 block discarded – undo
1827 1827
     private function _process_payment()
1828 1828
     {
1829 1829
         // basically confirm that the event hasn't sold out since they hit the page
1830
-        if (! $this->_last_second_ticket_verifications()) {
1830
+        if ( ! $this->_last_second_ticket_verifications()) {
1831 1831
             return false;
1832 1832
         }
1833 1833
         // ya gotta make a choice man
@@ -1838,7 +1838,7 @@  discard block
 block discarded – undo
1838 1838
             return false;
1839 1839
         }
1840 1840
         // get EE_Payment_Method object
1841
-        if (! $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment()) {
1841
+        if ( ! $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment()) {
1842 1842
             return false;
1843 1843
         }
1844 1844
         // setup billing form
@@ -1847,12 +1847,12 @@  discard block
 block discarded – undo
1847 1847
                 $this->checkout->payment_method
1848 1848
             );
1849 1849
             // bad billing form ?
1850
-            if (! $this->_billing_form_is_valid()) {
1850
+            if ( ! $this->_billing_form_is_valid()) {
1851 1851
                 return false;
1852 1852
             }
1853 1853
         }
1854 1854
         // ensure primary registrant has been fully processed
1855
-        if (! $this->_setup_primary_registrant_prior_to_payment()) {
1855
+        if ( ! $this->_setup_primary_registrant_prior_to_payment()) {
1856 1856
             return false;
1857 1857
         }
1858 1858
         // if session is close to expiring (under 10 minutes by default)
@@ -1903,7 +1903,7 @@  discard block
 block discarded – undo
1903 1903
     protected function _last_second_ticket_verifications()
1904 1904
     {
1905 1905
         // don't bother re-validating if not a return visit
1906
-        if (! $this->checkout->revisit) {
1906
+        if ( ! $this->checkout->revisit) {
1907 1907
             return true;
1908 1908
         }
1909 1909
         $registrations = $this->checkout->transaction->registrations();
@@ -1953,7 +1953,7 @@  discard block
 block discarded – undo
1953 1953
             $this->_get_payment_method_for_selected_method_of_payment()
1954 1954
         );
1955 1955
         $html                        = $payment_method_billing_info->get_html();
1956
-        $html                        .= $this->checkout->redirect_form;
1956
+        $html .= $this->checkout->redirect_form;
1957 1957
         /** @var ResponseInterface $response */
1958 1958
         $response = LoaderFactory::getLoader()->getShared(ResponseInterface::class);
1959 1959
         $response->addOutput($html);
@@ -1969,7 +1969,7 @@  discard block
 block discarded – undo
1969 1969
      */
1970 1970
     private function _billing_form_is_valid()
1971 1971
     {
1972
-        if (! $this->checkout->payment_method->type_obj()->has_billing_form()) {
1972
+        if ( ! $this->checkout->payment_method->type_obj()->has_billing_form()) {
1973 1973
             return true;
1974 1974
         }
1975 1975
         if ($this->checkout->billing_form instanceof EE_Billing_Info_Form) {
@@ -2086,7 +2086,7 @@  discard block
 block discarded – undo
2086 2086
     {
2087 2087
         // convert billing form data into an attendee
2088 2088
         $this->checkout->primary_attendee_obj = $this->checkout->billing_form->create_attendee_from_billing_form_data();
2089
-        if (! $this->checkout->primary_attendee_obj instanceof EE_Attendee) {
2089
+        if ( ! $this->checkout->primary_attendee_obj instanceof EE_Attendee) {
2090 2090
             EE_Error::add_error(
2091 2091
                 sprintf(
2092 2092
                     esc_html__(
@@ -2103,7 +2103,7 @@  discard block
 block discarded – undo
2103 2103
             return false;
2104 2104
         }
2105 2105
         $primary_registration = $this->checkout->transaction->primary_registration();
2106
-        if (! $primary_registration instanceof EE_Registration) {
2106
+        if ( ! $primary_registration instanceof EE_Registration) {
2107 2107
             EE_Error::add_error(
2108 2108
                 sprintf(
2109 2109
                     esc_html__(
@@ -2119,7 +2119,7 @@  discard block
 block discarded – undo
2119 2119
             );
2120 2120
             return false;
2121 2121
         }
2122
-        if (! $primary_registration->_add_relation_to($this->checkout->primary_attendee_obj, 'Attendee')
2122
+        if ( ! $primary_registration->_add_relation_to($this->checkout->primary_attendee_obj, 'Attendee')
2123 2123
               instanceof
2124 2124
               EE_Attendee
2125 2125
         ) {
@@ -2164,8 +2164,8 @@  discard block
 block discarded – undo
2164 2164
             return null;
2165 2165
         }
2166 2166
         // get EE_Payment_Method object
2167
-        if (isset($this->checkout->available_payment_methods[ $this->checkout->selected_method_of_payment ])) {
2168
-            $payment_method = $this->checkout->available_payment_methods[ $this->checkout->selected_method_of_payment ];
2167
+        if (isset($this->checkout->available_payment_methods[$this->checkout->selected_method_of_payment])) {
2168
+            $payment_method = $this->checkout->available_payment_methods[$this->checkout->selected_method_of_payment];
2169 2169
         } else {
2170 2170
             // load EEM_Payment_Method
2171 2171
             EE_Registry::instance()->load_model('Payment_Method');
@@ -2173,7 +2173,7 @@  discard block
 block discarded – undo
2173 2173
             $payment_method     = $EEM_Payment_Method->get_one_by_slug($this->checkout->selected_method_of_payment);
2174 2174
         }
2175 2175
         // verify $payment_method
2176
-        if (! $payment_method instanceof EE_Payment_Method) {
2176
+        if ( ! $payment_method instanceof EE_Payment_Method) {
2177 2177
             // not a payment
2178 2178
             EE_Error::add_error(
2179 2179
                 sprintf(
@@ -2191,7 +2191,7 @@  discard block
 block discarded – undo
2191 2191
             return null;
2192 2192
         }
2193 2193
         // and verify it has a valid Payment_Method Type object
2194
-        if (! $payment_method->type_obj() instanceof EE_PMT_Base) {
2194
+        if ( ! $payment_method->type_obj() instanceof EE_PMT_Base) {
2195 2195
             // not a payment
2196 2196
             EE_Error::add_error(
2197 2197
                 sprintf(
@@ -2229,7 +2229,7 @@  discard block
 block discarded – undo
2229 2229
         $payment = null;
2230 2230
         $this->checkout->transaction->save();
2231 2231
         $payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
2232
-        if (! $payment_processor instanceof EE_Payment_Processor) {
2232
+        if ( ! $payment_processor instanceof EE_Payment_Processor) {
2233 2233
             return false;
2234 2234
         }
2235 2235
         try {
@@ -2331,7 +2331,7 @@  discard block
 block discarded – undo
2331 2331
             return true;
2332 2332
         }
2333 2333
         // verify payment object
2334
-        if (! $payment instanceof EE_Payment) {
2334
+        if ( ! $payment instanceof EE_Payment) {
2335 2335
             // not a payment
2336 2336
             EE_Error::add_error(
2337 2337
                 sprintf(
@@ -2371,7 +2371,7 @@  discard block
 block discarded – undo
2371 2371
             return true;
2372 2372
             // On-Site payment?
2373 2373
         } elseif ($this->checkout->payment_method->is_on_site()) {
2374
-            if (! $this->_process_payment_status($payment, EE_PMT_Base::onsite)) {
2374
+            if ( ! $this->_process_payment_status($payment, EE_PMT_Base::onsite)) {
2375 2375
                 // $this->_setup_redirect_for_next_step();
2376 2376
                 $this->checkout->continue_reg = false;
2377 2377
             }
@@ -2399,7 +2399,7 @@  discard block
 block discarded – undo
2399 2399
                     EE_Registry::instance()->CFG->organization->get_pretty('email')
2400 2400
                 );
2401 2401
                 if ($payment instanceof EE_Payment && $payment->gateway_response()) {
2402
-                    $error_message = $error_message . '<br/>' . $payment->gateway_response();
2402
+                    $error_message = $error_message.'<br/>'.$payment->gateway_response();
2403 2403
                 }
2404 2404
                 $this->checkout->continue_reg = false;
2405 2405
                 EE_Error::add_error(
@@ -2486,7 +2486,7 @@  discard block
 block discarded – undo
2486 2486
                     return false;
2487 2487
                 // bad payment
2488 2488
                 case EEM_Payment::status_id_failed:
2489
-                    if (! empty($msg)) {
2489
+                    if ( ! empty($msg)) {
2490 2490
                         EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2491 2491
                         return false;
2492 2492
                     }
@@ -2544,18 +2544,18 @@  discard block
 block discarded – undo
2544 2544
         // how have they chosen to pay?
2545 2545
         $this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment(true);
2546 2546
         // get EE_Payment_Method object
2547
-        if (! $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment()) {
2547
+        if ( ! $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment()) {
2548 2548
             $this->checkout->continue_reg = false;
2549 2549
             return false;
2550 2550
         }
2551
-        if (! $this->checkout->payment_method->is_off_site()) {
2551
+        if ( ! $this->checkout->payment_method->is_off_site()) {
2552 2552
             return false;
2553 2553
         }
2554 2554
         $this->_validate_offsite_return();
2555 2555
         // verify TXN
2556 2556
         if ($this->checkout->transaction instanceof EE_Transaction) {
2557 2557
             $gateway = $this->checkout->payment_method->type_obj()->get_gateway();
2558
-            if (! $gateway instanceof EE_Offsite_Gateway) {
2558
+            if ( ! $gateway instanceof EE_Offsite_Gateway) {
2559 2559
                 $this->checkout->continue_reg = false;
2560 2560
                 return false;
2561 2561
             }
@@ -2569,7 +2569,7 @@  discard block
 block discarded – undo
2569 2569
                 $this->checkout->payment = $payment;
2570 2570
                 // mark this reg step as completed, as long as gateway doesn't use a separate IPN request,
2571 2571
                 // because we will complete this step during the IPN processing then
2572
-                if (! $this->handle_IPN_in_this_request()) {
2572
+                if ( ! $this->handle_IPN_in_this_request()) {
2573 2573
                     $this->set_completed();
2574 2574
                 }
2575 2575
                 return true;
@@ -2671,13 +2671,13 @@  discard block
 block discarded – undo
2671 2671
      */
2672 2672
     private function _redirect_wayward_request(EE_Registration $primary_registrant)
2673 2673
     {
2674
-        if (! $primary_registrant instanceof EE_Registration) {
2674
+        if ( ! $primary_registrant instanceof EE_Registration) {
2675 2675
             // try redirecting based on the current TXN
2676 2676
             $primary_registrant = $this->checkout->transaction instanceof EE_Transaction
2677 2677
                 ? $this->checkout->transaction->primary_registration()
2678 2678
                 : null;
2679 2679
         }
2680
-        if (! $primary_registrant instanceof EE_Registration) {
2680
+        if ( ! $primary_registrant instanceof EE_Registration) {
2681 2681
             EE_Error::add_error(
2682 2682
                 sprintf(
2683 2683
                     esc_html__(
@@ -2748,7 +2748,7 @@  discard block
 block discarded – undo
2748 2748
             $payment = $this->checkout->transaction->last_payment();
2749 2749
             // $payment_source = 'last_payment after Exception';
2750 2750
             // but if we STILL don't have a payment object
2751
-            if (! $payment instanceof EE_Payment) {
2751
+            if ( ! $payment instanceof EE_Payment) {
2752 2752
                 // then we'll object ! ( not object like a thing... but object like what a lawyer says ! )
2753 2753
                 $this->_handle_payment_processor_exception($e);
2754 2754
             }
Please login to merge, or discard this patch.
attendee_information/EE_SPCO_Reg_Step_Attendee_Information.class.php 2 patches
Indentation   +1436 added lines, -1436 removed lines patch added patch discarded remove patch
@@ -18,1443 +18,1443 @@
 block discarded – undo
18 18
 class EE_SPCO_Reg_Step_Attendee_Information extends EE_SPCO_Reg_Step
19 19
 {
20 20
 
21
-    /**
22
-     * @type bool $_print_copy_info
23
-     */
24
-    private $_print_copy_info = false;
25
-
26
-    /**
27
-     * @type array $_attendee_data
28
-     */
29
-    private $_attendee_data = [];
30
-
31
-    /**
32
-     * @type array $_required_questions
33
-     */
34
-    private $_required_questions = [];
35
-
36
-    /**
37
-     * @type array $_registration_answers
38
-     */
39
-    private $_registration_answers = [];
40
-
41
-    /**
42
-     * @type int $reg_form_count
43
-     */
44
-    protected $reg_form_count = 0;
45
-
46
-
47
-    /**
48
-     *    class constructor
49
-     *
50
-     * @access    public
51
-     * @param EE_Checkout $checkout
52
-     */
53
-    public function __construct(EE_Checkout $checkout)
54
-    {
55
-        $this->request  = EED_Single_Page_Checkout::getRequest();
56
-        $this->_slug    = 'attendee_information';
57
-        $this->_name    = esc_html__('Attendee Information', 'event_espresso');
58
-        $this->checkout = $checkout;
59
-        $this->_reset_success_message();
60
-        $this->set_instructions(
61
-            esc_html__('Please answer the following registration questions before proceeding.', 'event_espresso')
62
-        );
63
-    }
64
-
65
-
66
-    public function translate_js_strings()
67
-    {
68
-        EE_Registry::$i18n_js_strings['required_field']            = esc_html__(
69
-            ' is a required question.',
70
-            'event_espresso'
71
-        );
72
-        EE_Registry::$i18n_js_strings['required_multi_field']      = esc_html__(
73
-            ' is a required question. Please enter a value for at least one of the options.',
74
-            'event_espresso'
75
-        );
76
-        EE_Registry::$i18n_js_strings['answer_required_questions'] = esc_html__(
77
-            'Please answer all required questions correctly before proceeding.',
78
-            'event_espresso'
79
-        );
80
-        EE_Registry::$i18n_js_strings['attendee_info_copied']      = sprintf(
81
-            esc_html_x(
82
-                'The attendee information was successfully copied.%sPlease ensure the rest of the registration form is completed before proceeding.',
83
-                'The attendee information was successfully copied.(line break)Please ensure the rest of the registration form is completed before proceeding.',
84
-                'event_espresso'
85
-            ),
86
-            '<br/>'
87
-        );
88
-        EE_Registry::$i18n_js_strings['attendee_info_copy_error']  = esc_html__(
89
-            'An unknown error occurred on the server while attempting to copy the attendee information. Please refresh the page and try again.',
90
-            'event_espresso'
91
-        );
92
-        EE_Registry::$i18n_js_strings['enter_valid_email']         = esc_html__(
93
-            'You must enter a valid email address.',
94
-            'event_espresso'
95
-        );
96
-        EE_Registry::$i18n_js_strings['valid_email_and_questions'] = esc_html__(
97
-            'You must enter a valid email address and answer all other required questions before you can proceed.',
98
-            'event_espresso'
99
-        );
100
-    }
101
-
102
-
103
-    public function enqueue_styles_and_scripts()
104
-    {
105
-    }
106
-
107
-
108
-    /**
109
-     * @return boolean
110
-     */
111
-    public function initialize_reg_step()
112
-    {
113
-        return true;
114
-    }
115
-
116
-
117
-    /**
118
-     * @return EE_Form_Section_Proper
119
-     * @throws DomainException
120
-     * @throws EE_Error
121
-     * @throws InvalidArgumentException
122
-     * @throws ReflectionException
123
-     * @throws EntityNotFoundException
124
-     * @throws InvalidDataTypeException
125
-     * @throws InvalidInterfaceException
126
-     */
127
-    public function generate_reg_form()
128
-    {
129
-        /**
130
-         * @var $reg_config EE_Registration_Config
131
-         */
132
-        $reg_config = LoaderFactory::getLoader()->getShared('EE_Registration_Config');
133
-
134
-        $this->_print_copy_info = $reg_config->copyAttendeeInfo();
135
-
136
-        // Init reg forms count.
137
-        $this->reg_form_count = 0;
138
-
139
-        $primary_registrant = null;
140
-        // autoload Line_Item_Display classes
141
-        EEH_Autoloader::register_line_item_display_autoloaders();
142
-        $Line_Item_Display = new EE_Line_Item_Display();
143
-        // calculate taxes
144
-        $Line_Item_Display->display_line_item(
145
-            $this->checkout->cart->get_grand_total(),
146
-            ['set_tax_rate' => true]
147
-        );
148
-        /** @var $subsections EE_Form_Section_Proper[] */
149
-        $extra_inputs_section = $this->reg_step_hidden_inputs();
150
-        $subsections          = [
151
-            'default_hidden_inputs' => $extra_inputs_section,
152
-        ];
153
-
154
-        // if this isn't a revisit, and they have the privacy consent box enabled, add it
155
-        if (! $this->checkout->revisit && $reg_config->isConsentCheckboxEnabled()) {
156
-            $extra_inputs_section->add_subsections(
157
-                [
158
-                    'consent_box' => new EE_Form_Section_Proper(
159
-                        [
160
-                            'layout_strategy' =>
161
-                                new EE_Template_Layout(
162
-                                    [
163
-                                        'input_template_file' => SPCO_REG_STEPS_PATH
164
-                                                                 . $this->_slug
165
-                                                                 . '/privacy_consent.template.php',
166
-                                    ]
167
-                                ),
168
-                            'subsections'     => [
169
-                                'consent' => new EE_Checkbox_Multi_Input(
170
-                                    [
171
-                                        'consent' => $reg_config->getConsentCheckboxLabelText(),
172
-                                    ],
173
-                                    [
174
-                                        'required'                          => true,
175
-                                        'required_validation_error_message' => esc_html__(
176
-                                            'You must consent to these terms in order to register.',
177
-                                            'event_espresso'
178
-                                        ),
179
-                                        'html_label_text'                   => '',
180
-                                    ]
181
-                                ),
182
-                            ],
183
-                        ]
184
-                    ),
185
-                ],
186
-                null,
187
-                false
188
-            );
189
-        }
190
-        $template_args = [
191
-            'revisit'       => $this->checkout->revisit,
192
-            'registrations' => [],
193
-            'ticket_count'  => [],
194
-        ];
195
-        // grab the saved registrations from the transaction
196
-        $registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
197
-        if ($registrations) {
198
-            foreach ($registrations as $registration) {
199
-                // can this registration be processed during this visit ?
200
-                if ($registration instanceof EE_Registration
201
-                    && $this->checkout->visit_allows_processing_of_this_registration($registration)
202
-                ) {
203
-                    $subsections[ $registration->reg_url_link() ]                       =
204
-                        $this->_registrations_reg_form($registration);
205
-                    $template_args['registrations'][ $registration->reg_url_link() ]    = $registration;
206
-                    $template_args['ticket_count'][ $registration->ticket()->ID() ]     = isset(
207
-                        $template_args['ticket_count'][ $registration->ticket()->ID() ]
208
-                    )
209
-                        ? $template_args['ticket_count'][ $registration->ticket()->ID() ] + 1
210
-                        : 1;
211
-                    $ticket_line_item                                                   =
212
-                        EEH_Line_Item::get_line_items_by_object_type_and_IDs(
213
-                            $this->checkout->cart->get_grand_total(),
214
-                            'Ticket',
215
-                            [$registration->ticket()->ID()]
216
-                        );
217
-                    $ticket_line_item                                                   = is_array($ticket_line_item)
218
-                        ? reset($ticket_line_item)
219
-                        : $ticket_line_item;
220
-                    $template_args['ticket_line_item'][ $registration->ticket()->ID() ] =
221
-                        $Line_Item_Display->display_line_item($ticket_line_item);
222
-                    if ($registration->is_primary_registrant()) {
223
-                        $primary_registrant = $registration->reg_url_link();
224
-                    }
225
-                }
226
-            }
227
-
228
-            if ($primary_registrant && count($registrations) > 1) {
229
-                $copy_options['spco_copy_attendee_chk'] = $this->_print_copy_info
230
-                    ? $this->_copy_attendee_info_form()
231
-                    : $this->_auto_copy_attendee_info();
232
-                // generate hidden input
233
-                if (isset($subsections[ $primary_registrant ])
234
-                    && $subsections[ $primary_registrant ] instanceof EE_Form_Section_Proper
235
-                ) {
236
-                    $subsections[ $primary_registrant ]->add_subsections(
237
-                        $copy_options,
238
-                        'primary_registrant',
239
-                        false
240
-                    );
241
-                }
242
-            }
243
-        }
244
-
245
-        // Set the registration form template (default: one form per ticket details table).
246
-        // We decide the template to used based on the number of forms.
247
-        $this->_template = $this->reg_form_count > 1
248
-            ? SPCO_REG_STEPS_PATH . $this->_slug . '/attendee_info_main.template.php'
249
-            : SPCO_REG_STEPS_PATH . $this->_slug . '/attendee_info_single.template.php';
250
-
251
-        return new EE_Form_Section_Proper(
252
-            [
253
-                'name'            => $this->reg_form_name(),
254
-                'html_id'         => $this->reg_form_name(),
255
-                'subsections'     => $subsections,
256
-                'layout_strategy' => new EE_Template_Layout(
257
-                    [
258
-                        'layout_template_file' => $this->_template, // layout_template
259
-                        'template_args'        => $template_args,
260
-                    ]
261
-                ),
262
-            ]
263
-        );
264
-    }
265
-
266
-
267
-    /**
268
-     * @param EE_Registration $registration
269
-     * @return EE_Form_Section_Base
270
-     * @throws EE_Error
271
-     * @throws InvalidArgumentException
272
-     * @throws EntityNotFoundException
273
-     * @throws InvalidDataTypeException
274
-     * @throws InvalidInterfaceException
275
-     * @throws ReflectionException
276
-     */
277
-    private function _registrations_reg_form(EE_Registration $registration)
278
-    {
279
-        static $attendee_nmbr = 1;
280
-        $form_args = [];
281
-        // verify that registration has valid event
282
-        if ($registration->event() instanceof EE_Event) {
283
-            $field_name      = 'Event_Question_Group.'
284
-                               . EEM_Event_Question_Group::instance()->fieldNameForContext(
285
-                    $registration->is_primary_registrant()
286
-                );
287
-            $question_groups = $registration->event()->question_groups(
288
-                apply_filters(
289
-                // @codingStandardsIgnoreStart
290
-                    'FHEE__EE_SPCO_Reg_Step_Attendee_Information___registrations_reg_form__question_groups_query_parameters',
291
-                    // @codingStandardsIgnoreEnd
292
-                    [
293
-                        [
294
-                            'Event.EVT_ID' => $registration->event()->ID(),
295
-                            $field_name    => true,
296
-                        ],
297
-                        'order_by' => ['QSG_order' => 'ASC'],
298
-                    ],
299
-                    $registration,
300
-                    $this
301
-                )
302
-            );
303
-            if ($question_groups) {
304
-                // array of params to pass to parent constructor
305
-                $form_args = [
306
-                    'html_id'         => 'ee-registration-' . $registration->reg_url_link(),
307
-                    'html_class'      => 'ee-reg-form-attendee-dv',
308
-                    'html_style'      => $this->checkout->admin_request
309
-                        ? 'padding:0em 2em 1em; margin:3em 0 0; border:1px solid #ddd;'
310
-                        : '',
311
-                    'subsections'     => [],
312
-                    'layout_strategy' => new EE_Fieldset_Section_Layout(
313
-                        [
314
-                            'legend_class' => 'spco-attendee-lgnd smaller-text lt-grey-text',
315
-                            'legend_text'  => sprintf(
316
-                                esc_html_x(
317
-                                    'Attendee %d',
318
-                                    'Attendee 123',
319
-                                    'event_espresso'
320
-                                ),
321
-                                $attendee_nmbr
322
-                            ),
323
-                        ]
324
-                    ),
325
-                ];
326
-                foreach ($question_groups as $question_group) {
327
-                    if ($question_group instanceof EE_Question_Group) {
328
-                        $form_args['subsections'][ $question_group->identifier() ] = $this->_question_group_reg_form(
329
-                            $registration,
330
-                            $question_group
331
-                        );
332
-                    }
333
-                }
334
-                // add hidden input
335
-                $form_args['subsections']['additional_attendee_reg_info'] = $this->_additional_attendee_reg_info_input(
336
-                    $registration
337
-                );
338
-
339
-                /**
340
-                 * @var $reg_config EE_Registration_Config
341
-                 */
342
-                $reg_config = LoaderFactory::getLoader()->getShared('EE_Registration_Config');
343
-
344
-                // If we have question groups for additional attendees, then display the copy options
345
-                $this->_print_copy_info = apply_filters(
346
-                    'FHEE__EE_SPCO_Reg_Step_Attendee_Information___registrations_reg_form___printCopyInfo',
347
-                    $attendee_nmbr > 1 && $reg_config->copyAttendeeInfo(),
348
-                    $attendee_nmbr
349
-                );
350
-
351
-                if ($registration->is_primary_registrant()) {
352
-                    // generate hidden input
353
-                    $form_args['subsections']['primary_registrant'] = $this->_additional_primary_registrant_inputs(
354
-                        $registration
355
-                    );
356
-                }
357
-            }
358
-        }
359
-        $attendee_nmbr++;
360
-
361
-        // Increment the reg forms number if form is valid.
362
-        if (! empty($form_args)) {
363
-            $this->reg_form_count++;
364
-        }
365
-
366
-        return ! empty($form_args)
367
-            ? new EE_Form_Section_Proper($form_args)
368
-            : new EE_Form_Section_HTML();
369
-    }
370
-
371
-
372
-    /**
373
-     * @param EE_Registration $registration
374
-     * @param bool            $additional_attendee_reg_info
375
-     * @return EE_Form_Input_Base
376
-     * @throws EE_Error
377
-     */
378
-    private function _additional_attendee_reg_info_input(
379
-        EE_Registration $registration,
380
-        $additional_attendee_reg_info = true
381
-    ) {
382
-        // generate hidden input
383
-        return new EE_Hidden_Input(
384
-            [
385
-                'html_id' => 'additional-attendee-reg-info-' . $registration->reg_url_link(),
386
-                'default' => $additional_attendee_reg_info,
387
-            ]
388
-        );
389
-    }
390
-
391
-
392
-    /**
393
-     * @param EE_Registration   $registration
394
-     * @param EE_Question_Group $question_group
395
-     * @return EE_Form_Section_Proper
396
-     * @throws EE_Error
397
-     * @throws InvalidArgumentException
398
-     * @throws InvalidDataTypeException
399
-     * @throws InvalidInterfaceException
400
-     * @throws ReflectionException
401
-     */
402
-    private function _question_group_reg_form(EE_Registration $registration, EE_Question_Group $question_group)
403
-    {
404
-        // array of params to pass to parent constructor
405
-        $form_args = [
406
-            'html_id'         => 'ee-reg-form-qstn-grp-' . $question_group->identifier() . '-' . $registration->ID(),
407
-            'html_class'      => $this->checkout->admin_request
408
-                ? 'form-table ee-reg-form-qstn-grp-dv'
409
-                : 'ee-reg-form-qstn-grp-dv',
410
-            'html_label_id'   => 'ee-reg-form-qstn-grp-' . $question_group->identifier() . '-'
411
-                                 . $registration->ID() . '-lbl',
412
-            'subsections'     => [
413
-                'reg_form_qstn_grp_hdr' => $this->_question_group_header($question_group),
414
-            ],
415
-            'layout_strategy' => $this->checkout->admin_request
416
-                ? new EE_Admin_Two_Column_Layout()
417
-                : new EE_Div_Per_Section_Layout(),
418
-        ];
419
-        // where params
420
-        $query_params = ['QST_deleted' => 0];
421
-        // don't load admin only questions on the frontend
422
-        if (! $this->checkout->admin_request) {
423
-            $query_params['QST_admin_only'] = ['!=', true];
424
-        }
425
-        $questions = $question_group->get_many_related(
426
-            'Question',
427
-            apply_filters(
428
-                'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__related_questions_query_params',
429
-                [
430
-                    $query_params,
431
-                    'order_by' => [
432
-                        'Question_Group_Question.QGQ_order' => 'ASC',
433
-                    ],
434
-                ],
435
-                $question_group,
436
-                $registration,
437
-                $this
438
-            )
439
-        );
440
-        // filter for additional content before questions
441
-        $form_args['subsections']['reg_form_questions_before'] = new EE_Form_Section_HTML(
442
-            apply_filters(
443
-                'FHEE__EEH_Form_Fields__generate_question_groups_html__before_question_group_questions',
444
-                '',
445
-                $registration,
446
-                $question_group,
447
-                $this
448
-            )
449
-        );
450
-        // loop thru questions
451
-        foreach ($questions as $question) {
452
-            if ($question instanceof EE_Question) {
453
-                $identifier                              = $question->is_system_question()
454
-                    ? $question->system_ID()
455
-                    : $question->ID();
456
-                $form_args['subsections'][ $identifier ] = $this->reg_form_question($registration, $question);
457
-            }
458
-        }
459
-        $form_args['subsections'] = apply_filters(
460
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information__question_group_reg_form__subsections_array',
461
-            $form_args['subsections'],
462
-            $registration,
463
-            $question_group,
464
-            $this
465
-        );
466
-        // filter for additional content after questions
467
-        $form_args['subsections']['reg_form_questions_after'] = new EE_Form_Section_HTML(
468
-            apply_filters(
469
-                'FHEE__EEH_Form_Fields__generate_question_groups_html__after_question_group_questions',
470
-                '',
471
-                $registration,
472
-                $question_group,
473
-                $this
474
-            )
475
-        );
476
-        // d($form_args);
477
-        $question_group_reg_form = new EE_Form_Section_Proper($form_args);
478
-        return apply_filters(
479
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__question_group_reg_form',
480
-            $question_group_reg_form,
481
-            $registration,
482
-            $question_group,
483
-            $this
484
-        );
485
-    }
486
-
487
-
488
-    /**
489
-     * @param EE_Question_Group $question_group
490
-     * @return    EE_Form_Section_HTML
491
-     */
492
-    private function _question_group_header(EE_Question_Group $question_group)
493
-    {
494
-        $html = '';
495
-        // group_name
496
-        if ($question_group->show_group_name() && $question_group->name() !== '') {
497
-            if ($this->checkout->admin_request) {
498
-                $html .= EEH_HTML::br();
499
-                $html .= EEH_HTML::h3(
500
-                    $question_group->name(),
501
-                    '',
502
-                    'ee-reg-form-qstn-grp-title title',
503
-                    'font-size: 1.3em; padding-left:0;'
504
-                );
505
-            } else {
506
-                $html .= EEH_HTML::h4(
507
-                    $question_group->name(),
508
-                    '',
509
-                    'ee-reg-form-qstn-grp-title section-title'
510
-                );
511
-            }
512
-        }
513
-        // group_desc
514
-        if ($question_group->show_group_desc() && $question_group->desc() !== '') {
515
-            $html .= EEH_HTML::p(
516
-                $question_group->desc(),
517
-                '',
518
-                $this->checkout->admin_request
519
-                    ? 'ee-reg-form-qstn-grp-desc-pg'
520
-                    : 'ee-reg-form-qstn-grp-desc-pg small-text lt-grey-text'
521
-            );
522
-        }
523
-        return new EE_Form_Section_HTML($html);
524
-    }
525
-
526
-
527
-    /**
528
-     * @return    EE_Form_Section_Proper
529
-     * @throws EE_Error
530
-     * @throws InvalidArgumentException
531
-     * @throws ReflectionException
532
-     * @throws InvalidDataTypeException
533
-     * @throws InvalidInterfaceException
534
-     */
535
-    private function _copy_attendee_info_form()
536
-    {
537
-        // array of params to pass to parent constructor
538
-        return new EE_Form_Section_Proper(
539
-            [
540
-                'subsections'     => $this->_copy_attendee_info_inputs(),
541
-                'layout_strategy' => new EE_Template_Layout(
542
-                    [
543
-                        'layout_template_file'     => SPCO_REG_STEPS_PATH
544
-                                                      . $this->_slug
545
-                                                      . '/copy_attendee_info.template.php',
546
-                        'begin_template_file'      => null,
547
-                        'input_template_file'      => null,
548
-                        'subsection_template_file' => null,
549
-                        'end_template_file'        => null,
550
-                    ]
551
-                ),
552
-            ]
553
-        );
554
-    }
555
-
556
-
557
-    /**
558
-     * @return EE_Form_Section_HTML
559
-     * @throws DomainException
560
-     * @throws InvalidArgumentException
561
-     * @throws InvalidDataTypeException
562
-     * @throws InvalidInterfaceException
563
-     */
564
-    private function _auto_copy_attendee_info()
565
-    {
566
-        return new EE_Form_Section_HTML(
567
-            EEH_Template::locate_template(
568
-                SPCO_REG_STEPS_PATH . $this->_slug . '/_auto_copy_attendee_info.template.php',
569
-                apply_filters(
570
-                    'FHEE__EE_SPCO_Reg_Step_Attendee_Information__auto_copy_attendee_info__template_args',
571
-                    []
572
-                )
573
-            )
574
-        );
575
-    }
576
-
577
-
578
-    /**
579
-     * @return array
580
-     * @throws EE_Error
581
-     * @throws InvalidArgumentException
582
-     * @throws ReflectionException
583
-     * @throws InvalidDataTypeException
584
-     * @throws InvalidInterfaceException
585
-     */
586
-    private function _copy_attendee_info_inputs()
587
-    {
588
-        $copy_attendee_info_inputs = [];
589
-        $prev_ticket               = null;
590
-        // grab the saved registrations from the transaction
591
-        $registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
592
-        foreach ($registrations as $registration) {
593
-            // for all  attendees other than the primary attendee
594
-            if ($registration instanceof EE_Registration && ! $registration->is_primary_registrant()) {
595
-                // if this is a new ticket OR if this is the very first additional attendee after the primary attendee
596
-                if ($registration->ticket()->ID() !== $prev_ticket) {
597
-                    $item_name                          = $registration->ticket()->name();
598
-                    $item_name                          .= $registration->ticket()->description() !== ''
599
-                        ? ' - ' . $registration->ticket()->description()
600
-                        : '';
601
-                    $copy_attendee_info_inputs[ 'spco_copy_attendee_chk[ticket-'
602
-                                                . $registration->ticket()->ID()
603
-                                                . ']' ] =
604
-                        new EE_Form_Section_HTML(
605
-                            '<h6 class="spco-copy-attendee-event-hdr">' . $item_name . '</h6>'
606
-                        );
607
-                    $prev_ticket                        = $registration->ticket()->ID();
608
-                }
609
-
610
-                $copy_attendee_info_inputs[ 'spco_copy_attendee_chk[' . $registration->ID() . ']' ] =
611
-                    new EE_Checkbox_Multi_Input(
612
-                        [
613
-                            $registration->ID() => sprintf(
614
-                                esc_html_x('Attendee #%s', 'Attendee #123', 'event_espresso'),
615
-                                $registration->count()
616
-                            ),
617
-                        ],
618
-                        [
619
-                            'html_id'                 => 'spco-copy-attendee-chk-' . $registration->reg_url_link(),
620
-                            'html_class'              => 'spco-copy-attendee-chk ee-do-not-validate',
621
-                            'display_html_label_text' => false,
622
-                        ]
623
-                    );
624
-            }
625
-        }
626
-        return $copy_attendee_info_inputs;
627
-    }
628
-
629
-
630
-    /**
631
-     * @param EE_Registration $registration
632
-     * @return    EE_Form_Input_Base
633
-     * @throws EE_Error
634
-     */
635
-    private function _additional_primary_registrant_inputs(EE_Registration $registration)
636
-    {
637
-        // generate hidden input
638
-        return new EE_Hidden_Input(
639
-            [
640
-                'html_id' => 'primary_registrant',
641
-                'default' => $registration->reg_url_link(),
642
-            ]
643
-        );
644
-    }
645
-
646
-
647
-    /**
648
-     * @param EE_Registration $registration
649
-     * @param EE_Question     $question
650
-     * @return EE_Form_Input_Base
651
-     * @throws EE_Error
652
-     * @throws InvalidArgumentException
653
-     * @throws InvalidDataTypeException
654
-     * @throws InvalidInterfaceException
655
-     * @throws ReflectionException
656
-     */
657
-    public function reg_form_question(EE_Registration $registration, EE_Question $question)
658
-    {
659
-
660
-        // if this question was for an attendee detail, then check for that answer
661
-        $answer_value = EEM_Answer::instance()->get_attendee_property_answer_value(
662
-            $registration,
663
-            $question->system_ID()
664
-        );
665
-        $answer       = $answer_value === null
666
-            ? EEM_Answer::instance()->get_one(
667
-                [['QST_ID' => $question->ID(), 'REG_ID' => $registration->ID()]]
668
-            )
669
-            : null;
670
-        // if NOT returning to edit an existing registration
671
-        // OR if this question is for an attendee property
672
-        // OR we still don't have an EE_Answer object
673
-        if ($answer_value || ! $answer instanceof EE_Answer || ! $registration->reg_url_link()) {
674
-            // create an EE_Answer object for storing everything in
675
-            $answer = EE_Answer::new_instance(
676
-                [
677
-                    'QST_ID' => $question->ID(),
678
-                    'REG_ID' => $registration->ID(),
679
-                ]
680
-            );
681
-        }
682
-        // verify instance
683
-        if ($answer instanceof EE_Answer) {
684
-            if (! empty($answer_value)) {
685
-                $answer->set('ANS_value', $answer_value);
686
-            }
687
-            $answer->cache('Question', $question);
688
-            // remember system ID had a bug where sometimes it could be null
689
-            $answer_cache_id = $question->is_system_question()
690
-                ? $question->system_ID() . '-' . $registration->reg_url_link()
691
-                : $question->ID() . '-' . $registration->reg_url_link();
692
-            $registration->cache('Answer', $answer, $answer_cache_id);
693
-        }
694
-        return $this->_generate_question_input($registration, $question, $answer);
695
-    }
696
-
697
-
698
-    /**
699
-     * @param EE_Registration $registration
700
-     * @param EE_Question     $question
701
-     * @param                 $answer
702
-     * @return EE_Form_Input_Base
703
-     * @throws EE_Error
704
-     * @throws InvalidArgumentException
705
-     * @throws ReflectionException
706
-     * @throws InvalidDataTypeException
707
-     * @throws InvalidInterfaceException
708
-     */
709
-    private function _generate_question_input(EE_Registration $registration, EE_Question $question, $answer)
710
-    {
711
-        $identifier                               = $question->is_system_question()
712
-            ? $question->system_ID()
713
-            : $question->ID();
714
-        $this->_required_questions[ $identifier ] = $question->required();
715
-        add_filter(
716
-            'FHEE__EE_Question__generate_form_input__country_options',
717
-            [$this, 'use_cached_countries_for_form_input'],
718
-            10,
719
-            4
720
-        );
721
-        add_filter(
722
-            'FHEE__EE_Question__generate_form_input__state_options',
723
-            [$this, 'use_cached_states_for_form_input'],
724
-            10,
725
-            4
726
-        );
727
-        $input_constructor_args                  = [
728
-            'html_name'        => 'ee_reg_qstn[' . $registration->ID() . '][' . $identifier . ']',
729
-            'html_id'          => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
730
-            'html_class'       => 'ee-reg-qstn ee-reg-qstn-' . $identifier,
731
-            'html_label_id'    => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
732
-            'html_label_class' => 'ee-reg-qstn',
733
-        ];
734
-        $input_constructor_args['html_label_id'] .= '-lbl';
735
-        if ($answer instanceof EE_Answer && $answer->ID()) {
736
-            $input_constructor_args['html_name']     .= '[' . $answer->ID() . ']';
737
-            $input_constructor_args['html_id']       .= '-' . $answer->ID();
738
-            $input_constructor_args['html_label_id'] .= '-' . $answer->ID();
739
-        }
740
-        $form_input = $question->generate_form_input(
741
-            $registration,
742
-            $answer,
743
-            $input_constructor_args
744
-        );
745
-        remove_filter(
746
-            'FHEE__EE_Question__generate_form_input__country_options',
747
-            [$this, 'use_cached_countries_for_form_input']
748
-        );
749
-        remove_filter(
750
-            'FHEE__EE_Question__generate_form_input__state_options',
751
-            [$this, 'use_cached_states_for_form_input']
752
-        );
753
-        return $form_input;
754
-    }
755
-
756
-
757
-    /**
758
-     * Gets the list of countries for the form input
759
-     *
760
-     * @param array|null      $countries_list
761
-     * @param EE_Question     $question
762
-     * @param EE_Registration $registration
763
-     * @param EE_Answer       $answer
764
-     * @return array 2d keys are country IDs, values are their names
765
-     * @throws EE_Error
766
-     * @throws InvalidArgumentException
767
-     * @throws InvalidDataTypeException
768
-     * @throws InvalidInterfaceException
769
-     * @throws ReflectionException
770
-     */
771
-    public function use_cached_countries_for_form_input(
772
-        $countries_list,
773
-        EE_Question $question = null,
774
-        EE_Registration $registration = null,
775
-        EE_Answer $answer = null
776
-    ) {
777
-        $country_options = ['' => ''];
778
-        // get possibly cached list of countries
779
-        $countries = $this->checkout->action === 'process_reg_step'
780
-            ? EEM_Country::instance()->get_all_countries()
781
-            : EEM_Country::instance()->get_all_active_countries();
782
-        if (! empty($countries)) {
783
-            foreach ($countries as $country) {
784
-                if ($country instanceof EE_Country) {
785
-                    $country_options[ $country->ID() ] = $country->name();
786
-                }
787
-            }
788
-        }
789
-        if ($question instanceof EE_Question && $registration instanceof EE_Registration) {
790
-            $answer = EEM_Answer::instance()->get_one(
791
-                [['QST_ID' => $question->ID(), 'REG_ID' => $registration->ID()]]
792
-            );
793
-        } else {
794
-            $answer = EE_Answer::new_instance();
795
-        }
796
-        return apply_filters(
797
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__country_options',
798
-            $country_options,
799
-            $this,
800
-            $registration,
801
-            $question,
802
-            $answer
803
-        );
804
-    }
805
-
806
-
807
-    /**
808
-     * Gets the list of states for the form input
809
-     *
810
-     * @param array|null      $states_list
811
-     * @param EE_Question     $question
812
-     * @param EE_Registration $registration
813
-     * @param EE_Answer       $answer
814
-     * @return array 2d keys are state IDs, values are their names
815
-     * @throws EE_Error
816
-     * @throws InvalidArgumentException
817
-     * @throws InvalidDataTypeException
818
-     * @throws InvalidInterfaceException
819
-     * @throws ReflectionException
820
-     */
821
-    public function use_cached_states_for_form_input(
822
-        $states_list,
823
-        EE_Question $question = null,
824
-        EE_Registration $registration = null,
825
-        EE_Answer $answer = null
826
-    ) {
827
-        $state_options = ['' => ['' => '']];
828
-        $states        = $this->checkout->action === 'process_reg_step'
829
-            ? EEM_State::instance()->get_all_states()
830
-            : EEM_State::instance()->get_all_active_states();
831
-        if (! empty($states)) {
832
-            foreach ($states as $state) {
833
-                if ($state instanceof EE_State) {
834
-                    $state_options[ $state->country()->name() ][ $state->ID() ] = $state->name();
835
-                }
836
-            }
837
-        }
838
-        return apply_filters(
839
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__state_options',
840
-            $state_options,
841
-            $this,
842
-            $registration,
843
-            $question,
844
-            $answer
845
-        );
846
-    }
847
-
848
-
849
-    /********************************************************************************************************/
850
-    /****************************************  PROCESS REG STEP  ****************************************/
851
-    /********************************************************************************************************/
852
-
853
-
854
-    /**
855
-     * @return bool
856
-     * @throws EE_Error
857
-     * @throws InvalidArgumentException
858
-     * @throws ReflectionException
859
-     * @throws RuntimeException
860
-     * @throws InvalidDataTypeException
861
-     * @throws InvalidInterfaceException
862
-     */
863
-    public function process_reg_step()
864
-    {
865
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
866
-        // grab validated data from form
867
-        $valid_data = $this->checkout->current_step->valid_data();
868
-        // if we don't have any $valid_data then something went TERRIBLY WRONG !!!
869
-        if (empty($valid_data)) {
870
-            EE_Error::add_error(
871
-                esc_html__('No valid question responses were received.', 'event_espresso'),
872
-                __FILE__,
873
-                __FUNCTION__,
874
-                __LINE__
875
-            );
876
-            return false;
877
-        }
878
-        if (! $this->checkout->transaction instanceof EE_Transaction || ! $this->checkout->continue_reg) {
879
-            EE_Error::add_error(
880
-                esc_html__(
881
-                    'A valid transaction could not be initiated for processing your registrations.',
882
-                    'event_espresso'
883
-                ),
884
-                __FILE__,
885
-                __FUNCTION__,
886
-                __LINE__
887
-            );
888
-            return false;
889
-        }
890
-        // get cached registrations
891
-        $registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
892
-        // verify we got the goods
893
-        if (empty($registrations)) {
894
-            // combine the old translated string with a new one, in order to not break translations
895
-            $error_message = esc_html__(
896
-                'Your form data could not be applied to any valid registrations.',
897
-                'event_espresso'
898
-            )
899
-            . sprintf(
900
-                esc_html_x(
901
-                    '%3$sThis can sometimes happen if too much time has been taken to complete the registration process.%3$sPlease return to the %1$sEvent List%2$s and reselect your tickets. If the problem continues, please contact the site administrator.',
902
-                    '(line break)This can sometimes happen if too much time has been taken to complete the registration process.(line break)Please return to the (link)Event List(end link) and reselect your tickets. If the problem continues, please contact the site administrator.',
903
-                    'event_espresso'
904
-                ),
905
-                '<a href="' . get_post_type_archive_link('espresso_events') . '" >',
906
-                '</a>',
907
-                '<br />'
908
-            );
909
-            EE_Error::add_error(
910
-                $error_message,
911
-                __FILE__,
912
-                __FUNCTION__,
913
-                __LINE__
914
-            );
915
-            return false;
916
-        }
917
-        // extract attendee info from form data and save to model objects
918
-        $registrations_processed = $this->_process_registrations($registrations, $valid_data);
919
-        // if first pass thru SPCO,
920
-        // then let's check processed registrations against the total number of tickets in the cart
921
-        if ($registrations_processed === false) {
922
-            // but return immediately if the previous step exited early due to errors
923
-            return false;
924
-        }
925
-        if (! $this->checkout->revisit && $registrations_processed !== $this->checkout->total_ticket_count) {
926
-            // generate a correctly translated string for all possible singular/plural combinations
927
-            if ($this->checkout->total_ticket_count === 1 && $registrations_processed !== 1) {
928
-                $error_msg = sprintf(
929
-                    esc_html_x(
930
-                        'There was %1$d ticket in the Event Queue, but %2$ds registrations were processed',
931
-                        'There was 1 ticket in the Event Queue, but 2 registrations were processed',
932
-                        'event_espresso'
933
-                    ),
934
-                    $this->checkout->total_ticket_count,
935
-                    $registrations_processed
936
-                );
937
-            } elseif ($this->checkout->total_ticket_count !== 1 && $registrations_processed === 1) {
938
-                $error_msg = sprintf(
939
-                    esc_html_x(
940
-                        'There was a total of %1$d tickets in the Event Queue, but only %2$ds registration was processed',
941
-                        'There was a total of 2 tickets in the Event Queue, but only 1 registration was processed',
942
-                        'event_espresso'
943
-                    ),
944
-                    $this->checkout->total_ticket_count,
945
-                    $registrations_processed
946
-                );
947
-            } else {
948
-                $error_msg = sprintf(
949
-                    esc_html__(
950
-                        'There was a total of 2 tickets in the Event Queue, but 2 registrations were processed',
951
-                        'event_espresso'
952
-                    ),
953
-                    $this->checkout->total_ticket_count,
954
-                    $registrations_processed
955
-                );
956
-            }
957
-            EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
958
-            return false;
959
-        }
960
-        // mark this reg step as completed
961
-        $this->set_completed();
962
-        $this->_set_success_message(
963
-            esc_html__('The Attendee Information Step has been successfully completed.', 'event_espresso')
964
-        );
965
-        // do action in case a plugin wants to do something with the data submitted in step 1.
966
-        // passes EE_Single_Page_Checkout, and it's posted data
967
-        do_action('AHEE__EE_Single_Page_Checkout__process_attendee_information__end', $this, $valid_data);
968
-        return true;
969
-    }
970
-
971
-
972
-    /**
973
-     *    _process_registrations
974
-     *
975
-     * @param EE_Registration[] $registrations
976
-     * @param array[][]         $valid_data
977
-     * @return bool|int
978
-     * @throws EntityNotFoundException
979
-     * @throws EE_Error
980
-     * @throws InvalidArgumentException
981
-     * @throws ReflectionException
982
-     * @throws RuntimeException
983
-     * @throws InvalidDataTypeException
984
-     * @throws InvalidInterfaceException
985
-     */
986
-    private function _process_registrations($registrations = [], $valid_data = [])
987
-    {
988
-        // load resources and set some defaults
989
-        EE_Registry::instance()->load_model('Attendee');
990
-        // holder for primary registrant attendee object
991
-        $this->checkout->primary_attendee_obj = null;
992
-        // array for tracking reg form data for the primary registrant
993
-        $primary_registrant = [
994
-            'line_item_id' => null,
995
-        ];
996
-        $copy_primary       = false;
997
-        // reg form sections that do not contain inputs
998
-        $non_input_form_sections = [
999
-            'primary_registrant',
1000
-            'additional_attendee_reg_info',
1001
-            'spco_copy_attendee_chk',
1002
-        ];
1003
-        // attendee counter
1004
-        $att_nmbr = 0;
1005
-        // grab the saved registrations from the transaction
1006
-        foreach ($registrations as $registration) {
1007
-            // verify EE_Registration object
1008
-            if (! $registration instanceof EE_Registration) {
1009
-                EE_Error::add_error(
1010
-                    esc_html__(
1011
-                        'An invalid Registration object was discovered when attempting to process your registration information.',
1012
-                        'event_espresso'
1013
-                    ),
1014
-                    __FILE__,
1015
-                    __FUNCTION__,
1016
-                    __LINE__
1017
-                );
1018
-                return false;
1019
-            }
1020
-            $reg_url_link = $registration->reg_url_link();
1021
-            // reg_url_link exists ?
1022
-            if (! empty($reg_url_link)) {
1023
-                // should this registration be processed during this visit ?
1024
-                if ($this->checkout->visit_allows_processing_of_this_registration($registration)) {
1025
-                    // if NOT revisiting, then let's save the registration now,
1026
-                    // so that we have a REG_ID to use when generating other objects
1027
-                    if (! $this->checkout->revisit) {
1028
-                        $registration->save();
1029
-                    }
1030
-                    /**
1031
-                     * This allows plugins to trigger a fail on processing of a
1032
-                     * registration for any conditions they may have for it to pass.
1033
-                     *
1034
-                     * @var bool   if true is returned by the plugin then the
1035
-                     *            registration processing is halted.
1036
-                     */
1037
-                    if (apply_filters(
1038
-                        'FHEE__EE_SPCO_Reg_Step_Attendee_Information___process_registrations__pre_registration_process',
1039
-                        false,
1040
-                        $att_nmbr,
1041
-                        $registration,
1042
-                        $registrations,
1043
-                        $valid_data,
1044
-                        $this
1045
-                    )) {
1046
-                        return false;
1047
-                    }
1048
-
1049
-                    // Houston, we have a registration!
1050
-                    $att_nmbr++;
1051
-                    $this->_attendee_data[ $reg_url_link ] = [];
1052
-                    // grab any existing related answer objects
1053
-                    $this->_registration_answers = $registration->answers();
1054
-                    // unset( $valid_data[ $reg_url_link ]['additional_attendee_reg_info'] );
1055
-                    if (isset($valid_data[ $reg_url_link ])) {
1056
-                        // do we need to copy basic info from primary attendee ?
1057
-                        $copy_primary = isset($valid_data[ $reg_url_link ]['additional_attendee_reg_info'])
1058
-                                        && absint($valid_data[ $reg_url_link ]['additional_attendee_reg_info']) === 0;
1059
-                        // filter form input data for this registration
1060
-                        $valid_data[ $reg_url_link ] = (array) apply_filters(
1061
-                            'FHEE__EE_Single_Page_Checkout__process_attendee_information__valid_data_line_item',
1062
-                            $valid_data[ $reg_url_link ]
1063
-                        );
1064
-                        if (isset($valid_data['primary_attendee'])) {
1065
-                            $primary_registrant['line_item_id'] = ! empty($valid_data['primary_attendee'])
1066
-                                ? $valid_data['primary_attendee']
1067
-                                : false;
1068
-                            unset($valid_data['primary_attendee']);
1069
-                        }
1070
-                        // now loop through our array of valid post data && process attendee reg forms
1071
-                        foreach ($valid_data[ $reg_url_link ] as $form_section => $form_inputs) {
1072
-                            if (! in_array($form_section, $non_input_form_sections, true)) {
1073
-                                foreach ($form_inputs as $form_input => $input_value) {
1074
-                                    // check for critical inputs
1075
-                                    if (! $this->_verify_critical_attendee_details_are_set_and_validate_email(
1076
-                                        $form_input,
1077
-                                        $input_value
1078
-                                    )
1079
-                                    ) {
1080
-                                        return false;
1081
-                                    }
1082
-                                    // store a bit of data about the primary attendee
1083
-                                    if ($att_nmbr === 1
1084
-                                        && ! empty($input_value)
1085
-                                        && $reg_url_link === $primary_registrant['line_item_id']
1086
-                                    ) {
1087
-                                        $primary_registrant[ $form_input ] = $input_value;
1088
-                                    } elseif ($copy_primary
1089
-                                              && $input_value === null
1090
-                                              && isset($primary_registrant[ $form_input ])
1091
-                                    ) {
1092
-                                        $input_value = $primary_registrant[ $form_input ];
1093
-                                    }
1094
-                                    // now attempt to save the input data
1095
-                                    if (! $this->_save_registration_form_input(
1096
-                                        $registration,
1097
-                                        $form_input,
1098
-                                        $input_value
1099
-                                    )
1100
-                                    ) {
1101
-                                        EE_Error::add_error(
1102
-                                            sprintf(
1103
-                                                esc_html_x(
1104
-                                                    'Unable to save registration form data for the form input: "%1$s" with the submitted value: "%2$s"',
1105
-                                                    'Unable to save registration form data for the form input: "form input name" with the submitted value: "form input value"',
1106
-                                                    'event_espresso'
1107
-                                                ),
1108
-                                                $form_input,
1109
-                                                $input_value
1110
-                                            ),
1111
-                                            __FILE__,
1112
-                                            __FUNCTION__,
1113
-                                            __LINE__
1114
-                                        );
1115
-                                        return false;
1116
-                                    }
1117
-                                }
1118
-                            }
1119
-                        }  // end of foreach ( $valid_data[ $reg_url_link ] as $form_section => $form_inputs )
1120
-                    }
1121
-                    // this registration does not require additional attendee information ?
1122
-                    if ($copy_primary
1123
-                        && $att_nmbr > 1
1124
-                        && $this->checkout->primary_attendee_obj instanceof EE_Attendee
1125
-                    ) {
1126
-                        // just copy the primary registrant
1127
-                        $attendee = $this->checkout->primary_attendee_obj;
1128
-                    } else {
1129
-                        // ensure critical details are set for additional attendees
1130
-                        $this->_attendee_data[ $reg_url_link ] = $att_nmbr > 1
1131
-                            ? $this->_copy_critical_attendee_details_from_primary_registrant(
1132
-                                $this->_attendee_data[ $reg_url_link ]
1133
-                            )
1134
-                            : $this->_attendee_data[ $reg_url_link ];
1135
-                        // execute create attendee command (which may return an existing attendee)
1136
-                        $attendee = EE_Registry::instance()->BUS->execute(
1137
-                            new CreateAttendeeCommand(
1138
-                                $this->_attendee_data[ $reg_url_link ],
1139
-                                $registration
1140
-                            )
1141
-                        );
1142
-                        // who's #1 ?
1143
-                        if ($att_nmbr === 1) {
1144
-                            $this->checkout->primary_attendee_obj = $attendee;
1145
-                        }
1146
-                    }
1147
-                    // add relation to registration, set attendee ID, and cache attendee
1148
-                    $this->_associate_attendee_with_registration($registration, $attendee);
1149
-                    if (! $registration->attendee() instanceof EE_Attendee) {
1150
-                        EE_Error::add_error(
1151
-                            sprintf(
1152
-                                esc_html_x(
1153
-                                    'Registration %s has an invalid or missing Attendee object.',
1154
-                                    'Registration 123-456-789 has an invalid or missing Attendee object.',
1155
-                                    'event_espresso'
1156
-                                ),
1157
-                                $reg_url_link
1158
-                            ),
1159
-                            __FILE__,
1160
-                            __FUNCTION__,
1161
-                            __LINE__
1162
-                        );
1163
-                        return false;
1164
-                    }
1165
-                    /** @type EE_Registration_Processor $registration_processor */
1166
-                    $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
1167
-                    // at this point, we should have enough details about the registrant to consider the registration
1168
-                    // NOT incomplete
1169
-                    $registration_processor->toggle_incomplete_registration_status_to_default(
1170
-                        $registration,
1171
-                        false,
1172
-                        new Context(
1173
-                            'spco_reg_step_attendee_information_process_registrations',
1174
-                            esc_html__(
1175
-                                'Finished populating registration with details from the registration form after submitting the Attendee Information Reg Step.',
1176
-                                'event_espresso'
1177
-                            )
1178
-                        )
1179
-                    );
1180
-                    // we can also consider the TXN to not have been failed, so temporarily upgrade it's status to
1181
-                    // abandoned
1182
-                    $this->checkout->transaction->toggle_failed_transaction_status();
1183
-                    // if we've gotten this far, then let's save what we have
1184
-                    $registration->save();
1185
-                    // add relation between TXN and registration
1186
-                    $this->_associate_registration_with_transaction($registration);
1187
-                }
1188
-            } else {
1189
-                EE_Error::add_error(
1190
-                    esc_html__(
1191
-                        'An invalid or missing line item ID was encountered while attempting to process the registration form.',
1192
-                        'event_espresso'
1193
-                    ),
1194
-                    __FILE__,
1195
-                    __FUNCTION__,
1196
-                    __LINE__
1197
-                );
1198
-                // remove malformed data
1199
-                unset($valid_data[ $reg_url_link ]);
1200
-                return false;
1201
-            }
1202
-        } // end of foreach ( $this->checkout->transaction->registrations()  as $registration )
1203
-        return $att_nmbr;
1204
-    }
1205
-
1206
-
1207
-    /**
1208
-     *    _save_registration_form_input
1209
-     *
1210
-     * @param EE_Registration $registration
1211
-     * @param string          $form_input
1212
-     * @param string          $input_value
1213
-     * @return bool
1214
-     * @throws EE_Error
1215
-     * @throws InvalidArgumentException
1216
-     * @throws InvalidDataTypeException
1217
-     * @throws InvalidInterfaceException
1218
-     * @throws ReflectionException
1219
-     */
1220
-    private function _save_registration_form_input(
1221
-        EE_Registration $registration,
1222
-        $form_input = '',
1223
-        $input_value = ''
1224
-    ) {
1225
-        // If email_confirm is sent it's not saved
1226
-        if ((string) $form_input === 'email_confirm') {
1227
-            return true;
1228
-        }
1229
-
1230
-        // allow for plugins to hook in and do their own processing of the form input.
1231
-        // For plugins to bypass normal processing here, they just need to return a boolean value.
1232
-        if (apply_filters(
1233
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___save_registration_form_input',
1234
-            false,
1235
-            $registration,
1236
-            $form_input,
1237
-            $input_value,
1238
-            $this
1239
-        )) {
1240
-            return true;
1241
-        }
1242
-        /*
21
+	/**
22
+	 * @type bool $_print_copy_info
23
+	 */
24
+	private $_print_copy_info = false;
25
+
26
+	/**
27
+	 * @type array $_attendee_data
28
+	 */
29
+	private $_attendee_data = [];
30
+
31
+	/**
32
+	 * @type array $_required_questions
33
+	 */
34
+	private $_required_questions = [];
35
+
36
+	/**
37
+	 * @type array $_registration_answers
38
+	 */
39
+	private $_registration_answers = [];
40
+
41
+	/**
42
+	 * @type int $reg_form_count
43
+	 */
44
+	protected $reg_form_count = 0;
45
+
46
+
47
+	/**
48
+	 *    class constructor
49
+	 *
50
+	 * @access    public
51
+	 * @param EE_Checkout $checkout
52
+	 */
53
+	public function __construct(EE_Checkout $checkout)
54
+	{
55
+		$this->request  = EED_Single_Page_Checkout::getRequest();
56
+		$this->_slug    = 'attendee_information';
57
+		$this->_name    = esc_html__('Attendee Information', 'event_espresso');
58
+		$this->checkout = $checkout;
59
+		$this->_reset_success_message();
60
+		$this->set_instructions(
61
+			esc_html__('Please answer the following registration questions before proceeding.', 'event_espresso')
62
+		);
63
+	}
64
+
65
+
66
+	public function translate_js_strings()
67
+	{
68
+		EE_Registry::$i18n_js_strings['required_field']            = esc_html__(
69
+			' is a required question.',
70
+			'event_espresso'
71
+		);
72
+		EE_Registry::$i18n_js_strings['required_multi_field']      = esc_html__(
73
+			' is a required question. Please enter a value for at least one of the options.',
74
+			'event_espresso'
75
+		);
76
+		EE_Registry::$i18n_js_strings['answer_required_questions'] = esc_html__(
77
+			'Please answer all required questions correctly before proceeding.',
78
+			'event_espresso'
79
+		);
80
+		EE_Registry::$i18n_js_strings['attendee_info_copied']      = sprintf(
81
+			esc_html_x(
82
+				'The attendee information was successfully copied.%sPlease ensure the rest of the registration form is completed before proceeding.',
83
+				'The attendee information was successfully copied.(line break)Please ensure the rest of the registration form is completed before proceeding.',
84
+				'event_espresso'
85
+			),
86
+			'<br/>'
87
+		);
88
+		EE_Registry::$i18n_js_strings['attendee_info_copy_error']  = esc_html__(
89
+			'An unknown error occurred on the server while attempting to copy the attendee information. Please refresh the page and try again.',
90
+			'event_espresso'
91
+		);
92
+		EE_Registry::$i18n_js_strings['enter_valid_email']         = esc_html__(
93
+			'You must enter a valid email address.',
94
+			'event_espresso'
95
+		);
96
+		EE_Registry::$i18n_js_strings['valid_email_and_questions'] = esc_html__(
97
+			'You must enter a valid email address and answer all other required questions before you can proceed.',
98
+			'event_espresso'
99
+		);
100
+	}
101
+
102
+
103
+	public function enqueue_styles_and_scripts()
104
+	{
105
+	}
106
+
107
+
108
+	/**
109
+	 * @return boolean
110
+	 */
111
+	public function initialize_reg_step()
112
+	{
113
+		return true;
114
+	}
115
+
116
+
117
+	/**
118
+	 * @return EE_Form_Section_Proper
119
+	 * @throws DomainException
120
+	 * @throws EE_Error
121
+	 * @throws InvalidArgumentException
122
+	 * @throws ReflectionException
123
+	 * @throws EntityNotFoundException
124
+	 * @throws InvalidDataTypeException
125
+	 * @throws InvalidInterfaceException
126
+	 */
127
+	public function generate_reg_form()
128
+	{
129
+		/**
130
+		 * @var $reg_config EE_Registration_Config
131
+		 */
132
+		$reg_config = LoaderFactory::getLoader()->getShared('EE_Registration_Config');
133
+
134
+		$this->_print_copy_info = $reg_config->copyAttendeeInfo();
135
+
136
+		// Init reg forms count.
137
+		$this->reg_form_count = 0;
138
+
139
+		$primary_registrant = null;
140
+		// autoload Line_Item_Display classes
141
+		EEH_Autoloader::register_line_item_display_autoloaders();
142
+		$Line_Item_Display = new EE_Line_Item_Display();
143
+		// calculate taxes
144
+		$Line_Item_Display->display_line_item(
145
+			$this->checkout->cart->get_grand_total(),
146
+			['set_tax_rate' => true]
147
+		);
148
+		/** @var $subsections EE_Form_Section_Proper[] */
149
+		$extra_inputs_section = $this->reg_step_hidden_inputs();
150
+		$subsections          = [
151
+			'default_hidden_inputs' => $extra_inputs_section,
152
+		];
153
+
154
+		// if this isn't a revisit, and they have the privacy consent box enabled, add it
155
+		if (! $this->checkout->revisit && $reg_config->isConsentCheckboxEnabled()) {
156
+			$extra_inputs_section->add_subsections(
157
+				[
158
+					'consent_box' => new EE_Form_Section_Proper(
159
+						[
160
+							'layout_strategy' =>
161
+								new EE_Template_Layout(
162
+									[
163
+										'input_template_file' => SPCO_REG_STEPS_PATH
164
+																 . $this->_slug
165
+																 . '/privacy_consent.template.php',
166
+									]
167
+								),
168
+							'subsections'     => [
169
+								'consent' => new EE_Checkbox_Multi_Input(
170
+									[
171
+										'consent' => $reg_config->getConsentCheckboxLabelText(),
172
+									],
173
+									[
174
+										'required'                          => true,
175
+										'required_validation_error_message' => esc_html__(
176
+											'You must consent to these terms in order to register.',
177
+											'event_espresso'
178
+										),
179
+										'html_label_text'                   => '',
180
+									]
181
+								),
182
+							],
183
+						]
184
+					),
185
+				],
186
+				null,
187
+				false
188
+			);
189
+		}
190
+		$template_args = [
191
+			'revisit'       => $this->checkout->revisit,
192
+			'registrations' => [],
193
+			'ticket_count'  => [],
194
+		];
195
+		// grab the saved registrations from the transaction
196
+		$registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
197
+		if ($registrations) {
198
+			foreach ($registrations as $registration) {
199
+				// can this registration be processed during this visit ?
200
+				if ($registration instanceof EE_Registration
201
+					&& $this->checkout->visit_allows_processing_of_this_registration($registration)
202
+				) {
203
+					$subsections[ $registration->reg_url_link() ]                       =
204
+						$this->_registrations_reg_form($registration);
205
+					$template_args['registrations'][ $registration->reg_url_link() ]    = $registration;
206
+					$template_args['ticket_count'][ $registration->ticket()->ID() ]     = isset(
207
+						$template_args['ticket_count'][ $registration->ticket()->ID() ]
208
+					)
209
+						? $template_args['ticket_count'][ $registration->ticket()->ID() ] + 1
210
+						: 1;
211
+					$ticket_line_item                                                   =
212
+						EEH_Line_Item::get_line_items_by_object_type_and_IDs(
213
+							$this->checkout->cart->get_grand_total(),
214
+							'Ticket',
215
+							[$registration->ticket()->ID()]
216
+						);
217
+					$ticket_line_item                                                   = is_array($ticket_line_item)
218
+						? reset($ticket_line_item)
219
+						: $ticket_line_item;
220
+					$template_args['ticket_line_item'][ $registration->ticket()->ID() ] =
221
+						$Line_Item_Display->display_line_item($ticket_line_item);
222
+					if ($registration->is_primary_registrant()) {
223
+						$primary_registrant = $registration->reg_url_link();
224
+					}
225
+				}
226
+			}
227
+
228
+			if ($primary_registrant && count($registrations) > 1) {
229
+				$copy_options['spco_copy_attendee_chk'] = $this->_print_copy_info
230
+					? $this->_copy_attendee_info_form()
231
+					: $this->_auto_copy_attendee_info();
232
+				// generate hidden input
233
+				if (isset($subsections[ $primary_registrant ])
234
+					&& $subsections[ $primary_registrant ] instanceof EE_Form_Section_Proper
235
+				) {
236
+					$subsections[ $primary_registrant ]->add_subsections(
237
+						$copy_options,
238
+						'primary_registrant',
239
+						false
240
+					);
241
+				}
242
+			}
243
+		}
244
+
245
+		// Set the registration form template (default: one form per ticket details table).
246
+		// We decide the template to used based on the number of forms.
247
+		$this->_template = $this->reg_form_count > 1
248
+			? SPCO_REG_STEPS_PATH . $this->_slug . '/attendee_info_main.template.php'
249
+			: SPCO_REG_STEPS_PATH . $this->_slug . '/attendee_info_single.template.php';
250
+
251
+		return new EE_Form_Section_Proper(
252
+			[
253
+				'name'            => $this->reg_form_name(),
254
+				'html_id'         => $this->reg_form_name(),
255
+				'subsections'     => $subsections,
256
+				'layout_strategy' => new EE_Template_Layout(
257
+					[
258
+						'layout_template_file' => $this->_template, // layout_template
259
+						'template_args'        => $template_args,
260
+					]
261
+				),
262
+			]
263
+		);
264
+	}
265
+
266
+
267
+	/**
268
+	 * @param EE_Registration $registration
269
+	 * @return EE_Form_Section_Base
270
+	 * @throws EE_Error
271
+	 * @throws InvalidArgumentException
272
+	 * @throws EntityNotFoundException
273
+	 * @throws InvalidDataTypeException
274
+	 * @throws InvalidInterfaceException
275
+	 * @throws ReflectionException
276
+	 */
277
+	private function _registrations_reg_form(EE_Registration $registration)
278
+	{
279
+		static $attendee_nmbr = 1;
280
+		$form_args = [];
281
+		// verify that registration has valid event
282
+		if ($registration->event() instanceof EE_Event) {
283
+			$field_name      = 'Event_Question_Group.'
284
+							   . EEM_Event_Question_Group::instance()->fieldNameForContext(
285
+					$registration->is_primary_registrant()
286
+				);
287
+			$question_groups = $registration->event()->question_groups(
288
+				apply_filters(
289
+				// @codingStandardsIgnoreStart
290
+					'FHEE__EE_SPCO_Reg_Step_Attendee_Information___registrations_reg_form__question_groups_query_parameters',
291
+					// @codingStandardsIgnoreEnd
292
+					[
293
+						[
294
+							'Event.EVT_ID' => $registration->event()->ID(),
295
+							$field_name    => true,
296
+						],
297
+						'order_by' => ['QSG_order' => 'ASC'],
298
+					],
299
+					$registration,
300
+					$this
301
+				)
302
+			);
303
+			if ($question_groups) {
304
+				// array of params to pass to parent constructor
305
+				$form_args = [
306
+					'html_id'         => 'ee-registration-' . $registration->reg_url_link(),
307
+					'html_class'      => 'ee-reg-form-attendee-dv',
308
+					'html_style'      => $this->checkout->admin_request
309
+						? 'padding:0em 2em 1em; margin:3em 0 0; border:1px solid #ddd;'
310
+						: '',
311
+					'subsections'     => [],
312
+					'layout_strategy' => new EE_Fieldset_Section_Layout(
313
+						[
314
+							'legend_class' => 'spco-attendee-lgnd smaller-text lt-grey-text',
315
+							'legend_text'  => sprintf(
316
+								esc_html_x(
317
+									'Attendee %d',
318
+									'Attendee 123',
319
+									'event_espresso'
320
+								),
321
+								$attendee_nmbr
322
+							),
323
+						]
324
+					),
325
+				];
326
+				foreach ($question_groups as $question_group) {
327
+					if ($question_group instanceof EE_Question_Group) {
328
+						$form_args['subsections'][ $question_group->identifier() ] = $this->_question_group_reg_form(
329
+							$registration,
330
+							$question_group
331
+						);
332
+					}
333
+				}
334
+				// add hidden input
335
+				$form_args['subsections']['additional_attendee_reg_info'] = $this->_additional_attendee_reg_info_input(
336
+					$registration
337
+				);
338
+
339
+				/**
340
+				 * @var $reg_config EE_Registration_Config
341
+				 */
342
+				$reg_config = LoaderFactory::getLoader()->getShared('EE_Registration_Config');
343
+
344
+				// If we have question groups for additional attendees, then display the copy options
345
+				$this->_print_copy_info = apply_filters(
346
+					'FHEE__EE_SPCO_Reg_Step_Attendee_Information___registrations_reg_form___printCopyInfo',
347
+					$attendee_nmbr > 1 && $reg_config->copyAttendeeInfo(),
348
+					$attendee_nmbr
349
+				);
350
+
351
+				if ($registration->is_primary_registrant()) {
352
+					// generate hidden input
353
+					$form_args['subsections']['primary_registrant'] = $this->_additional_primary_registrant_inputs(
354
+						$registration
355
+					);
356
+				}
357
+			}
358
+		}
359
+		$attendee_nmbr++;
360
+
361
+		// Increment the reg forms number if form is valid.
362
+		if (! empty($form_args)) {
363
+			$this->reg_form_count++;
364
+		}
365
+
366
+		return ! empty($form_args)
367
+			? new EE_Form_Section_Proper($form_args)
368
+			: new EE_Form_Section_HTML();
369
+	}
370
+
371
+
372
+	/**
373
+	 * @param EE_Registration $registration
374
+	 * @param bool            $additional_attendee_reg_info
375
+	 * @return EE_Form_Input_Base
376
+	 * @throws EE_Error
377
+	 */
378
+	private function _additional_attendee_reg_info_input(
379
+		EE_Registration $registration,
380
+		$additional_attendee_reg_info = true
381
+	) {
382
+		// generate hidden input
383
+		return new EE_Hidden_Input(
384
+			[
385
+				'html_id' => 'additional-attendee-reg-info-' . $registration->reg_url_link(),
386
+				'default' => $additional_attendee_reg_info,
387
+			]
388
+		);
389
+	}
390
+
391
+
392
+	/**
393
+	 * @param EE_Registration   $registration
394
+	 * @param EE_Question_Group $question_group
395
+	 * @return EE_Form_Section_Proper
396
+	 * @throws EE_Error
397
+	 * @throws InvalidArgumentException
398
+	 * @throws InvalidDataTypeException
399
+	 * @throws InvalidInterfaceException
400
+	 * @throws ReflectionException
401
+	 */
402
+	private function _question_group_reg_form(EE_Registration $registration, EE_Question_Group $question_group)
403
+	{
404
+		// array of params to pass to parent constructor
405
+		$form_args = [
406
+			'html_id'         => 'ee-reg-form-qstn-grp-' . $question_group->identifier() . '-' . $registration->ID(),
407
+			'html_class'      => $this->checkout->admin_request
408
+				? 'form-table ee-reg-form-qstn-grp-dv'
409
+				: 'ee-reg-form-qstn-grp-dv',
410
+			'html_label_id'   => 'ee-reg-form-qstn-grp-' . $question_group->identifier() . '-'
411
+								 . $registration->ID() . '-lbl',
412
+			'subsections'     => [
413
+				'reg_form_qstn_grp_hdr' => $this->_question_group_header($question_group),
414
+			],
415
+			'layout_strategy' => $this->checkout->admin_request
416
+				? new EE_Admin_Two_Column_Layout()
417
+				: new EE_Div_Per_Section_Layout(),
418
+		];
419
+		// where params
420
+		$query_params = ['QST_deleted' => 0];
421
+		// don't load admin only questions on the frontend
422
+		if (! $this->checkout->admin_request) {
423
+			$query_params['QST_admin_only'] = ['!=', true];
424
+		}
425
+		$questions = $question_group->get_many_related(
426
+			'Question',
427
+			apply_filters(
428
+				'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__related_questions_query_params',
429
+				[
430
+					$query_params,
431
+					'order_by' => [
432
+						'Question_Group_Question.QGQ_order' => 'ASC',
433
+					],
434
+				],
435
+				$question_group,
436
+				$registration,
437
+				$this
438
+			)
439
+		);
440
+		// filter for additional content before questions
441
+		$form_args['subsections']['reg_form_questions_before'] = new EE_Form_Section_HTML(
442
+			apply_filters(
443
+				'FHEE__EEH_Form_Fields__generate_question_groups_html__before_question_group_questions',
444
+				'',
445
+				$registration,
446
+				$question_group,
447
+				$this
448
+			)
449
+		);
450
+		// loop thru questions
451
+		foreach ($questions as $question) {
452
+			if ($question instanceof EE_Question) {
453
+				$identifier                              = $question->is_system_question()
454
+					? $question->system_ID()
455
+					: $question->ID();
456
+				$form_args['subsections'][ $identifier ] = $this->reg_form_question($registration, $question);
457
+			}
458
+		}
459
+		$form_args['subsections'] = apply_filters(
460
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information__question_group_reg_form__subsections_array',
461
+			$form_args['subsections'],
462
+			$registration,
463
+			$question_group,
464
+			$this
465
+		);
466
+		// filter for additional content after questions
467
+		$form_args['subsections']['reg_form_questions_after'] = new EE_Form_Section_HTML(
468
+			apply_filters(
469
+				'FHEE__EEH_Form_Fields__generate_question_groups_html__after_question_group_questions',
470
+				'',
471
+				$registration,
472
+				$question_group,
473
+				$this
474
+			)
475
+		);
476
+		// d($form_args);
477
+		$question_group_reg_form = new EE_Form_Section_Proper($form_args);
478
+		return apply_filters(
479
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__question_group_reg_form',
480
+			$question_group_reg_form,
481
+			$registration,
482
+			$question_group,
483
+			$this
484
+		);
485
+	}
486
+
487
+
488
+	/**
489
+	 * @param EE_Question_Group $question_group
490
+	 * @return    EE_Form_Section_HTML
491
+	 */
492
+	private function _question_group_header(EE_Question_Group $question_group)
493
+	{
494
+		$html = '';
495
+		// group_name
496
+		if ($question_group->show_group_name() && $question_group->name() !== '') {
497
+			if ($this->checkout->admin_request) {
498
+				$html .= EEH_HTML::br();
499
+				$html .= EEH_HTML::h3(
500
+					$question_group->name(),
501
+					'',
502
+					'ee-reg-form-qstn-grp-title title',
503
+					'font-size: 1.3em; padding-left:0;'
504
+				);
505
+			} else {
506
+				$html .= EEH_HTML::h4(
507
+					$question_group->name(),
508
+					'',
509
+					'ee-reg-form-qstn-grp-title section-title'
510
+				);
511
+			}
512
+		}
513
+		// group_desc
514
+		if ($question_group->show_group_desc() && $question_group->desc() !== '') {
515
+			$html .= EEH_HTML::p(
516
+				$question_group->desc(),
517
+				'',
518
+				$this->checkout->admin_request
519
+					? 'ee-reg-form-qstn-grp-desc-pg'
520
+					: 'ee-reg-form-qstn-grp-desc-pg small-text lt-grey-text'
521
+			);
522
+		}
523
+		return new EE_Form_Section_HTML($html);
524
+	}
525
+
526
+
527
+	/**
528
+	 * @return    EE_Form_Section_Proper
529
+	 * @throws EE_Error
530
+	 * @throws InvalidArgumentException
531
+	 * @throws ReflectionException
532
+	 * @throws InvalidDataTypeException
533
+	 * @throws InvalidInterfaceException
534
+	 */
535
+	private function _copy_attendee_info_form()
536
+	{
537
+		// array of params to pass to parent constructor
538
+		return new EE_Form_Section_Proper(
539
+			[
540
+				'subsections'     => $this->_copy_attendee_info_inputs(),
541
+				'layout_strategy' => new EE_Template_Layout(
542
+					[
543
+						'layout_template_file'     => SPCO_REG_STEPS_PATH
544
+													  . $this->_slug
545
+													  . '/copy_attendee_info.template.php',
546
+						'begin_template_file'      => null,
547
+						'input_template_file'      => null,
548
+						'subsection_template_file' => null,
549
+						'end_template_file'        => null,
550
+					]
551
+				),
552
+			]
553
+		);
554
+	}
555
+
556
+
557
+	/**
558
+	 * @return EE_Form_Section_HTML
559
+	 * @throws DomainException
560
+	 * @throws InvalidArgumentException
561
+	 * @throws InvalidDataTypeException
562
+	 * @throws InvalidInterfaceException
563
+	 */
564
+	private function _auto_copy_attendee_info()
565
+	{
566
+		return new EE_Form_Section_HTML(
567
+			EEH_Template::locate_template(
568
+				SPCO_REG_STEPS_PATH . $this->_slug . '/_auto_copy_attendee_info.template.php',
569
+				apply_filters(
570
+					'FHEE__EE_SPCO_Reg_Step_Attendee_Information__auto_copy_attendee_info__template_args',
571
+					[]
572
+				)
573
+			)
574
+		);
575
+	}
576
+
577
+
578
+	/**
579
+	 * @return array
580
+	 * @throws EE_Error
581
+	 * @throws InvalidArgumentException
582
+	 * @throws ReflectionException
583
+	 * @throws InvalidDataTypeException
584
+	 * @throws InvalidInterfaceException
585
+	 */
586
+	private function _copy_attendee_info_inputs()
587
+	{
588
+		$copy_attendee_info_inputs = [];
589
+		$prev_ticket               = null;
590
+		// grab the saved registrations from the transaction
591
+		$registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
592
+		foreach ($registrations as $registration) {
593
+			// for all  attendees other than the primary attendee
594
+			if ($registration instanceof EE_Registration && ! $registration->is_primary_registrant()) {
595
+				// if this is a new ticket OR if this is the very first additional attendee after the primary attendee
596
+				if ($registration->ticket()->ID() !== $prev_ticket) {
597
+					$item_name                          = $registration->ticket()->name();
598
+					$item_name                          .= $registration->ticket()->description() !== ''
599
+						? ' - ' . $registration->ticket()->description()
600
+						: '';
601
+					$copy_attendee_info_inputs[ 'spco_copy_attendee_chk[ticket-'
602
+												. $registration->ticket()->ID()
603
+												. ']' ] =
604
+						new EE_Form_Section_HTML(
605
+							'<h6 class="spco-copy-attendee-event-hdr">' . $item_name . '</h6>'
606
+						);
607
+					$prev_ticket                        = $registration->ticket()->ID();
608
+				}
609
+
610
+				$copy_attendee_info_inputs[ 'spco_copy_attendee_chk[' . $registration->ID() . ']' ] =
611
+					new EE_Checkbox_Multi_Input(
612
+						[
613
+							$registration->ID() => sprintf(
614
+								esc_html_x('Attendee #%s', 'Attendee #123', 'event_espresso'),
615
+								$registration->count()
616
+							),
617
+						],
618
+						[
619
+							'html_id'                 => 'spco-copy-attendee-chk-' . $registration->reg_url_link(),
620
+							'html_class'              => 'spco-copy-attendee-chk ee-do-not-validate',
621
+							'display_html_label_text' => false,
622
+						]
623
+					);
624
+			}
625
+		}
626
+		return $copy_attendee_info_inputs;
627
+	}
628
+
629
+
630
+	/**
631
+	 * @param EE_Registration $registration
632
+	 * @return    EE_Form_Input_Base
633
+	 * @throws EE_Error
634
+	 */
635
+	private function _additional_primary_registrant_inputs(EE_Registration $registration)
636
+	{
637
+		// generate hidden input
638
+		return new EE_Hidden_Input(
639
+			[
640
+				'html_id' => 'primary_registrant',
641
+				'default' => $registration->reg_url_link(),
642
+			]
643
+		);
644
+	}
645
+
646
+
647
+	/**
648
+	 * @param EE_Registration $registration
649
+	 * @param EE_Question     $question
650
+	 * @return EE_Form_Input_Base
651
+	 * @throws EE_Error
652
+	 * @throws InvalidArgumentException
653
+	 * @throws InvalidDataTypeException
654
+	 * @throws InvalidInterfaceException
655
+	 * @throws ReflectionException
656
+	 */
657
+	public function reg_form_question(EE_Registration $registration, EE_Question $question)
658
+	{
659
+
660
+		// if this question was for an attendee detail, then check for that answer
661
+		$answer_value = EEM_Answer::instance()->get_attendee_property_answer_value(
662
+			$registration,
663
+			$question->system_ID()
664
+		);
665
+		$answer       = $answer_value === null
666
+			? EEM_Answer::instance()->get_one(
667
+				[['QST_ID' => $question->ID(), 'REG_ID' => $registration->ID()]]
668
+			)
669
+			: null;
670
+		// if NOT returning to edit an existing registration
671
+		// OR if this question is for an attendee property
672
+		// OR we still don't have an EE_Answer object
673
+		if ($answer_value || ! $answer instanceof EE_Answer || ! $registration->reg_url_link()) {
674
+			// create an EE_Answer object for storing everything in
675
+			$answer = EE_Answer::new_instance(
676
+				[
677
+					'QST_ID' => $question->ID(),
678
+					'REG_ID' => $registration->ID(),
679
+				]
680
+			);
681
+		}
682
+		// verify instance
683
+		if ($answer instanceof EE_Answer) {
684
+			if (! empty($answer_value)) {
685
+				$answer->set('ANS_value', $answer_value);
686
+			}
687
+			$answer->cache('Question', $question);
688
+			// remember system ID had a bug where sometimes it could be null
689
+			$answer_cache_id = $question->is_system_question()
690
+				? $question->system_ID() . '-' . $registration->reg_url_link()
691
+				: $question->ID() . '-' . $registration->reg_url_link();
692
+			$registration->cache('Answer', $answer, $answer_cache_id);
693
+		}
694
+		return $this->_generate_question_input($registration, $question, $answer);
695
+	}
696
+
697
+
698
+	/**
699
+	 * @param EE_Registration $registration
700
+	 * @param EE_Question     $question
701
+	 * @param                 $answer
702
+	 * @return EE_Form_Input_Base
703
+	 * @throws EE_Error
704
+	 * @throws InvalidArgumentException
705
+	 * @throws ReflectionException
706
+	 * @throws InvalidDataTypeException
707
+	 * @throws InvalidInterfaceException
708
+	 */
709
+	private function _generate_question_input(EE_Registration $registration, EE_Question $question, $answer)
710
+	{
711
+		$identifier                               = $question->is_system_question()
712
+			? $question->system_ID()
713
+			: $question->ID();
714
+		$this->_required_questions[ $identifier ] = $question->required();
715
+		add_filter(
716
+			'FHEE__EE_Question__generate_form_input__country_options',
717
+			[$this, 'use_cached_countries_for_form_input'],
718
+			10,
719
+			4
720
+		);
721
+		add_filter(
722
+			'FHEE__EE_Question__generate_form_input__state_options',
723
+			[$this, 'use_cached_states_for_form_input'],
724
+			10,
725
+			4
726
+		);
727
+		$input_constructor_args                  = [
728
+			'html_name'        => 'ee_reg_qstn[' . $registration->ID() . '][' . $identifier . ']',
729
+			'html_id'          => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
730
+			'html_class'       => 'ee-reg-qstn ee-reg-qstn-' . $identifier,
731
+			'html_label_id'    => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
732
+			'html_label_class' => 'ee-reg-qstn',
733
+		];
734
+		$input_constructor_args['html_label_id'] .= '-lbl';
735
+		if ($answer instanceof EE_Answer && $answer->ID()) {
736
+			$input_constructor_args['html_name']     .= '[' . $answer->ID() . ']';
737
+			$input_constructor_args['html_id']       .= '-' . $answer->ID();
738
+			$input_constructor_args['html_label_id'] .= '-' . $answer->ID();
739
+		}
740
+		$form_input = $question->generate_form_input(
741
+			$registration,
742
+			$answer,
743
+			$input_constructor_args
744
+		);
745
+		remove_filter(
746
+			'FHEE__EE_Question__generate_form_input__country_options',
747
+			[$this, 'use_cached_countries_for_form_input']
748
+		);
749
+		remove_filter(
750
+			'FHEE__EE_Question__generate_form_input__state_options',
751
+			[$this, 'use_cached_states_for_form_input']
752
+		);
753
+		return $form_input;
754
+	}
755
+
756
+
757
+	/**
758
+	 * Gets the list of countries for the form input
759
+	 *
760
+	 * @param array|null      $countries_list
761
+	 * @param EE_Question     $question
762
+	 * @param EE_Registration $registration
763
+	 * @param EE_Answer       $answer
764
+	 * @return array 2d keys are country IDs, values are their names
765
+	 * @throws EE_Error
766
+	 * @throws InvalidArgumentException
767
+	 * @throws InvalidDataTypeException
768
+	 * @throws InvalidInterfaceException
769
+	 * @throws ReflectionException
770
+	 */
771
+	public function use_cached_countries_for_form_input(
772
+		$countries_list,
773
+		EE_Question $question = null,
774
+		EE_Registration $registration = null,
775
+		EE_Answer $answer = null
776
+	) {
777
+		$country_options = ['' => ''];
778
+		// get possibly cached list of countries
779
+		$countries = $this->checkout->action === 'process_reg_step'
780
+			? EEM_Country::instance()->get_all_countries()
781
+			: EEM_Country::instance()->get_all_active_countries();
782
+		if (! empty($countries)) {
783
+			foreach ($countries as $country) {
784
+				if ($country instanceof EE_Country) {
785
+					$country_options[ $country->ID() ] = $country->name();
786
+				}
787
+			}
788
+		}
789
+		if ($question instanceof EE_Question && $registration instanceof EE_Registration) {
790
+			$answer = EEM_Answer::instance()->get_one(
791
+				[['QST_ID' => $question->ID(), 'REG_ID' => $registration->ID()]]
792
+			);
793
+		} else {
794
+			$answer = EE_Answer::new_instance();
795
+		}
796
+		return apply_filters(
797
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__country_options',
798
+			$country_options,
799
+			$this,
800
+			$registration,
801
+			$question,
802
+			$answer
803
+		);
804
+	}
805
+
806
+
807
+	/**
808
+	 * Gets the list of states for the form input
809
+	 *
810
+	 * @param array|null      $states_list
811
+	 * @param EE_Question     $question
812
+	 * @param EE_Registration $registration
813
+	 * @param EE_Answer       $answer
814
+	 * @return array 2d keys are state IDs, values are their names
815
+	 * @throws EE_Error
816
+	 * @throws InvalidArgumentException
817
+	 * @throws InvalidDataTypeException
818
+	 * @throws InvalidInterfaceException
819
+	 * @throws ReflectionException
820
+	 */
821
+	public function use_cached_states_for_form_input(
822
+		$states_list,
823
+		EE_Question $question = null,
824
+		EE_Registration $registration = null,
825
+		EE_Answer $answer = null
826
+	) {
827
+		$state_options = ['' => ['' => '']];
828
+		$states        = $this->checkout->action === 'process_reg_step'
829
+			? EEM_State::instance()->get_all_states()
830
+			: EEM_State::instance()->get_all_active_states();
831
+		if (! empty($states)) {
832
+			foreach ($states as $state) {
833
+				if ($state instanceof EE_State) {
834
+					$state_options[ $state->country()->name() ][ $state->ID() ] = $state->name();
835
+				}
836
+			}
837
+		}
838
+		return apply_filters(
839
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__state_options',
840
+			$state_options,
841
+			$this,
842
+			$registration,
843
+			$question,
844
+			$answer
845
+		);
846
+	}
847
+
848
+
849
+	/********************************************************************************************************/
850
+	/****************************************  PROCESS REG STEP  ****************************************/
851
+	/********************************************************************************************************/
852
+
853
+
854
+	/**
855
+	 * @return bool
856
+	 * @throws EE_Error
857
+	 * @throws InvalidArgumentException
858
+	 * @throws ReflectionException
859
+	 * @throws RuntimeException
860
+	 * @throws InvalidDataTypeException
861
+	 * @throws InvalidInterfaceException
862
+	 */
863
+	public function process_reg_step()
864
+	{
865
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
866
+		// grab validated data from form
867
+		$valid_data = $this->checkout->current_step->valid_data();
868
+		// if we don't have any $valid_data then something went TERRIBLY WRONG !!!
869
+		if (empty($valid_data)) {
870
+			EE_Error::add_error(
871
+				esc_html__('No valid question responses were received.', 'event_espresso'),
872
+				__FILE__,
873
+				__FUNCTION__,
874
+				__LINE__
875
+			);
876
+			return false;
877
+		}
878
+		if (! $this->checkout->transaction instanceof EE_Transaction || ! $this->checkout->continue_reg) {
879
+			EE_Error::add_error(
880
+				esc_html__(
881
+					'A valid transaction could not be initiated for processing your registrations.',
882
+					'event_espresso'
883
+				),
884
+				__FILE__,
885
+				__FUNCTION__,
886
+				__LINE__
887
+			);
888
+			return false;
889
+		}
890
+		// get cached registrations
891
+		$registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
892
+		// verify we got the goods
893
+		if (empty($registrations)) {
894
+			// combine the old translated string with a new one, in order to not break translations
895
+			$error_message = esc_html__(
896
+				'Your form data could not be applied to any valid registrations.',
897
+				'event_espresso'
898
+			)
899
+			. sprintf(
900
+				esc_html_x(
901
+					'%3$sThis can sometimes happen if too much time has been taken to complete the registration process.%3$sPlease return to the %1$sEvent List%2$s and reselect your tickets. If the problem continues, please contact the site administrator.',
902
+					'(line break)This can sometimes happen if too much time has been taken to complete the registration process.(line break)Please return to the (link)Event List(end link) and reselect your tickets. If the problem continues, please contact the site administrator.',
903
+					'event_espresso'
904
+				),
905
+				'<a href="' . get_post_type_archive_link('espresso_events') . '" >',
906
+				'</a>',
907
+				'<br />'
908
+			);
909
+			EE_Error::add_error(
910
+				$error_message,
911
+				__FILE__,
912
+				__FUNCTION__,
913
+				__LINE__
914
+			);
915
+			return false;
916
+		}
917
+		// extract attendee info from form data and save to model objects
918
+		$registrations_processed = $this->_process_registrations($registrations, $valid_data);
919
+		// if first pass thru SPCO,
920
+		// then let's check processed registrations against the total number of tickets in the cart
921
+		if ($registrations_processed === false) {
922
+			// but return immediately if the previous step exited early due to errors
923
+			return false;
924
+		}
925
+		if (! $this->checkout->revisit && $registrations_processed !== $this->checkout->total_ticket_count) {
926
+			// generate a correctly translated string for all possible singular/plural combinations
927
+			if ($this->checkout->total_ticket_count === 1 && $registrations_processed !== 1) {
928
+				$error_msg = sprintf(
929
+					esc_html_x(
930
+						'There was %1$d ticket in the Event Queue, but %2$ds registrations were processed',
931
+						'There was 1 ticket in the Event Queue, but 2 registrations were processed',
932
+						'event_espresso'
933
+					),
934
+					$this->checkout->total_ticket_count,
935
+					$registrations_processed
936
+				);
937
+			} elseif ($this->checkout->total_ticket_count !== 1 && $registrations_processed === 1) {
938
+				$error_msg = sprintf(
939
+					esc_html_x(
940
+						'There was a total of %1$d tickets in the Event Queue, but only %2$ds registration was processed',
941
+						'There was a total of 2 tickets in the Event Queue, but only 1 registration was processed',
942
+						'event_espresso'
943
+					),
944
+					$this->checkout->total_ticket_count,
945
+					$registrations_processed
946
+				);
947
+			} else {
948
+				$error_msg = sprintf(
949
+					esc_html__(
950
+						'There was a total of 2 tickets in the Event Queue, but 2 registrations were processed',
951
+						'event_espresso'
952
+					),
953
+					$this->checkout->total_ticket_count,
954
+					$registrations_processed
955
+				);
956
+			}
957
+			EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
958
+			return false;
959
+		}
960
+		// mark this reg step as completed
961
+		$this->set_completed();
962
+		$this->_set_success_message(
963
+			esc_html__('The Attendee Information Step has been successfully completed.', 'event_espresso')
964
+		);
965
+		// do action in case a plugin wants to do something with the data submitted in step 1.
966
+		// passes EE_Single_Page_Checkout, and it's posted data
967
+		do_action('AHEE__EE_Single_Page_Checkout__process_attendee_information__end', $this, $valid_data);
968
+		return true;
969
+	}
970
+
971
+
972
+	/**
973
+	 *    _process_registrations
974
+	 *
975
+	 * @param EE_Registration[] $registrations
976
+	 * @param array[][]         $valid_data
977
+	 * @return bool|int
978
+	 * @throws EntityNotFoundException
979
+	 * @throws EE_Error
980
+	 * @throws InvalidArgumentException
981
+	 * @throws ReflectionException
982
+	 * @throws RuntimeException
983
+	 * @throws InvalidDataTypeException
984
+	 * @throws InvalidInterfaceException
985
+	 */
986
+	private function _process_registrations($registrations = [], $valid_data = [])
987
+	{
988
+		// load resources and set some defaults
989
+		EE_Registry::instance()->load_model('Attendee');
990
+		// holder for primary registrant attendee object
991
+		$this->checkout->primary_attendee_obj = null;
992
+		// array for tracking reg form data for the primary registrant
993
+		$primary_registrant = [
994
+			'line_item_id' => null,
995
+		];
996
+		$copy_primary       = false;
997
+		// reg form sections that do not contain inputs
998
+		$non_input_form_sections = [
999
+			'primary_registrant',
1000
+			'additional_attendee_reg_info',
1001
+			'spco_copy_attendee_chk',
1002
+		];
1003
+		// attendee counter
1004
+		$att_nmbr = 0;
1005
+		// grab the saved registrations from the transaction
1006
+		foreach ($registrations as $registration) {
1007
+			// verify EE_Registration object
1008
+			if (! $registration instanceof EE_Registration) {
1009
+				EE_Error::add_error(
1010
+					esc_html__(
1011
+						'An invalid Registration object was discovered when attempting to process your registration information.',
1012
+						'event_espresso'
1013
+					),
1014
+					__FILE__,
1015
+					__FUNCTION__,
1016
+					__LINE__
1017
+				);
1018
+				return false;
1019
+			}
1020
+			$reg_url_link = $registration->reg_url_link();
1021
+			// reg_url_link exists ?
1022
+			if (! empty($reg_url_link)) {
1023
+				// should this registration be processed during this visit ?
1024
+				if ($this->checkout->visit_allows_processing_of_this_registration($registration)) {
1025
+					// if NOT revisiting, then let's save the registration now,
1026
+					// so that we have a REG_ID to use when generating other objects
1027
+					if (! $this->checkout->revisit) {
1028
+						$registration->save();
1029
+					}
1030
+					/**
1031
+					 * This allows plugins to trigger a fail on processing of a
1032
+					 * registration for any conditions they may have for it to pass.
1033
+					 *
1034
+					 * @var bool   if true is returned by the plugin then the
1035
+					 *            registration processing is halted.
1036
+					 */
1037
+					if (apply_filters(
1038
+						'FHEE__EE_SPCO_Reg_Step_Attendee_Information___process_registrations__pre_registration_process',
1039
+						false,
1040
+						$att_nmbr,
1041
+						$registration,
1042
+						$registrations,
1043
+						$valid_data,
1044
+						$this
1045
+					)) {
1046
+						return false;
1047
+					}
1048
+
1049
+					// Houston, we have a registration!
1050
+					$att_nmbr++;
1051
+					$this->_attendee_data[ $reg_url_link ] = [];
1052
+					// grab any existing related answer objects
1053
+					$this->_registration_answers = $registration->answers();
1054
+					// unset( $valid_data[ $reg_url_link ]['additional_attendee_reg_info'] );
1055
+					if (isset($valid_data[ $reg_url_link ])) {
1056
+						// do we need to copy basic info from primary attendee ?
1057
+						$copy_primary = isset($valid_data[ $reg_url_link ]['additional_attendee_reg_info'])
1058
+										&& absint($valid_data[ $reg_url_link ]['additional_attendee_reg_info']) === 0;
1059
+						// filter form input data for this registration
1060
+						$valid_data[ $reg_url_link ] = (array) apply_filters(
1061
+							'FHEE__EE_Single_Page_Checkout__process_attendee_information__valid_data_line_item',
1062
+							$valid_data[ $reg_url_link ]
1063
+						);
1064
+						if (isset($valid_data['primary_attendee'])) {
1065
+							$primary_registrant['line_item_id'] = ! empty($valid_data['primary_attendee'])
1066
+								? $valid_data['primary_attendee']
1067
+								: false;
1068
+							unset($valid_data['primary_attendee']);
1069
+						}
1070
+						// now loop through our array of valid post data && process attendee reg forms
1071
+						foreach ($valid_data[ $reg_url_link ] as $form_section => $form_inputs) {
1072
+							if (! in_array($form_section, $non_input_form_sections, true)) {
1073
+								foreach ($form_inputs as $form_input => $input_value) {
1074
+									// check for critical inputs
1075
+									if (! $this->_verify_critical_attendee_details_are_set_and_validate_email(
1076
+										$form_input,
1077
+										$input_value
1078
+									)
1079
+									) {
1080
+										return false;
1081
+									}
1082
+									// store a bit of data about the primary attendee
1083
+									if ($att_nmbr === 1
1084
+										&& ! empty($input_value)
1085
+										&& $reg_url_link === $primary_registrant['line_item_id']
1086
+									) {
1087
+										$primary_registrant[ $form_input ] = $input_value;
1088
+									} elseif ($copy_primary
1089
+											  && $input_value === null
1090
+											  && isset($primary_registrant[ $form_input ])
1091
+									) {
1092
+										$input_value = $primary_registrant[ $form_input ];
1093
+									}
1094
+									// now attempt to save the input data
1095
+									if (! $this->_save_registration_form_input(
1096
+										$registration,
1097
+										$form_input,
1098
+										$input_value
1099
+									)
1100
+									) {
1101
+										EE_Error::add_error(
1102
+											sprintf(
1103
+												esc_html_x(
1104
+													'Unable to save registration form data for the form input: "%1$s" with the submitted value: "%2$s"',
1105
+													'Unable to save registration form data for the form input: "form input name" with the submitted value: "form input value"',
1106
+													'event_espresso'
1107
+												),
1108
+												$form_input,
1109
+												$input_value
1110
+											),
1111
+											__FILE__,
1112
+											__FUNCTION__,
1113
+											__LINE__
1114
+										);
1115
+										return false;
1116
+									}
1117
+								}
1118
+							}
1119
+						}  // end of foreach ( $valid_data[ $reg_url_link ] as $form_section => $form_inputs )
1120
+					}
1121
+					// this registration does not require additional attendee information ?
1122
+					if ($copy_primary
1123
+						&& $att_nmbr > 1
1124
+						&& $this->checkout->primary_attendee_obj instanceof EE_Attendee
1125
+					) {
1126
+						// just copy the primary registrant
1127
+						$attendee = $this->checkout->primary_attendee_obj;
1128
+					} else {
1129
+						// ensure critical details are set for additional attendees
1130
+						$this->_attendee_data[ $reg_url_link ] = $att_nmbr > 1
1131
+							? $this->_copy_critical_attendee_details_from_primary_registrant(
1132
+								$this->_attendee_data[ $reg_url_link ]
1133
+							)
1134
+							: $this->_attendee_data[ $reg_url_link ];
1135
+						// execute create attendee command (which may return an existing attendee)
1136
+						$attendee = EE_Registry::instance()->BUS->execute(
1137
+							new CreateAttendeeCommand(
1138
+								$this->_attendee_data[ $reg_url_link ],
1139
+								$registration
1140
+							)
1141
+						);
1142
+						// who's #1 ?
1143
+						if ($att_nmbr === 1) {
1144
+							$this->checkout->primary_attendee_obj = $attendee;
1145
+						}
1146
+					}
1147
+					// add relation to registration, set attendee ID, and cache attendee
1148
+					$this->_associate_attendee_with_registration($registration, $attendee);
1149
+					if (! $registration->attendee() instanceof EE_Attendee) {
1150
+						EE_Error::add_error(
1151
+							sprintf(
1152
+								esc_html_x(
1153
+									'Registration %s has an invalid or missing Attendee object.',
1154
+									'Registration 123-456-789 has an invalid or missing Attendee object.',
1155
+									'event_espresso'
1156
+								),
1157
+								$reg_url_link
1158
+							),
1159
+							__FILE__,
1160
+							__FUNCTION__,
1161
+							__LINE__
1162
+						);
1163
+						return false;
1164
+					}
1165
+					/** @type EE_Registration_Processor $registration_processor */
1166
+					$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
1167
+					// at this point, we should have enough details about the registrant to consider the registration
1168
+					// NOT incomplete
1169
+					$registration_processor->toggle_incomplete_registration_status_to_default(
1170
+						$registration,
1171
+						false,
1172
+						new Context(
1173
+							'spco_reg_step_attendee_information_process_registrations',
1174
+							esc_html__(
1175
+								'Finished populating registration with details from the registration form after submitting the Attendee Information Reg Step.',
1176
+								'event_espresso'
1177
+							)
1178
+						)
1179
+					);
1180
+					// we can also consider the TXN to not have been failed, so temporarily upgrade it's status to
1181
+					// abandoned
1182
+					$this->checkout->transaction->toggle_failed_transaction_status();
1183
+					// if we've gotten this far, then let's save what we have
1184
+					$registration->save();
1185
+					// add relation between TXN and registration
1186
+					$this->_associate_registration_with_transaction($registration);
1187
+				}
1188
+			} else {
1189
+				EE_Error::add_error(
1190
+					esc_html__(
1191
+						'An invalid or missing line item ID was encountered while attempting to process the registration form.',
1192
+						'event_espresso'
1193
+					),
1194
+					__FILE__,
1195
+					__FUNCTION__,
1196
+					__LINE__
1197
+				);
1198
+				// remove malformed data
1199
+				unset($valid_data[ $reg_url_link ]);
1200
+				return false;
1201
+			}
1202
+		} // end of foreach ( $this->checkout->transaction->registrations()  as $registration )
1203
+		return $att_nmbr;
1204
+	}
1205
+
1206
+
1207
+	/**
1208
+	 *    _save_registration_form_input
1209
+	 *
1210
+	 * @param EE_Registration $registration
1211
+	 * @param string          $form_input
1212
+	 * @param string          $input_value
1213
+	 * @return bool
1214
+	 * @throws EE_Error
1215
+	 * @throws InvalidArgumentException
1216
+	 * @throws InvalidDataTypeException
1217
+	 * @throws InvalidInterfaceException
1218
+	 * @throws ReflectionException
1219
+	 */
1220
+	private function _save_registration_form_input(
1221
+		EE_Registration $registration,
1222
+		$form_input = '',
1223
+		$input_value = ''
1224
+	) {
1225
+		// If email_confirm is sent it's not saved
1226
+		if ((string) $form_input === 'email_confirm') {
1227
+			return true;
1228
+		}
1229
+
1230
+		// allow for plugins to hook in and do their own processing of the form input.
1231
+		// For plugins to bypass normal processing here, they just need to return a boolean value.
1232
+		if (apply_filters(
1233
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___save_registration_form_input',
1234
+			false,
1235
+			$registration,
1236
+			$form_input,
1237
+			$input_value,
1238
+			$this
1239
+		)) {
1240
+			return true;
1241
+		}
1242
+		/*
1243 1243
          * $answer_cache_id is the key used to find the EE_Answer we want
1244 1244
          * @see https://events.codebasehq.com/projects/event-espresso/tickets/10477
1245 1245
          */
1246
-        $answer_cache_id = $this->checkout->reg_url_link
1247
-            ? $form_input . '-' . $registration->reg_url_link()
1248
-            : $form_input;
1249
-        $answer_is_obj   = isset($this->_registration_answers[ $answer_cache_id ])
1250
-                           && $this->_registration_answers[ $answer_cache_id ] instanceof EE_Answer;
1251
-        // rename form_inputs if they are EE_Attendee properties
1252
-        switch ((string) $form_input) {
1253
-            case 'state':
1254
-            case 'STA_ID':
1255
-                $attendee_property = true;
1256
-                $form_input        = 'STA_ID';
1257
-                break;
1258
-
1259
-            case 'country':
1260
-            case 'CNT_ISO':
1261
-                $attendee_property = true;
1262
-                $form_input        = 'CNT_ISO';
1263
-                break;
1264
-
1265
-            default:
1266
-                $ATT_input = 'ATT_' . $form_input;
1267
-                $attendee_property = EEM_Attendee::instance()->has_field($ATT_input);
1268
-                $form_input        = $attendee_property ? 'ATT_' . $form_input : $form_input;
1269
-        }
1270
-        // if this form input has a corresponding attendee property
1271
-        if ($attendee_property) {
1272
-            $this->_attendee_data[ $registration->reg_url_link() ][ $form_input ] = $input_value;
1273
-            if ($answer_is_obj) {
1274
-                // and delete the corresponding answer since we won't be storing this data in that object
1275
-                $registration->_remove_relation_to($this->_registration_answers[ $answer_cache_id ], 'Answer');
1276
-                $this->_registration_answers[ $answer_cache_id ]->delete_permanently();
1277
-            }
1278
-            return true;
1279
-        }
1280
-        if ($answer_is_obj) {
1281
-            // save this data to the answer object
1282
-            $this->_registration_answers[ $answer_cache_id ]->set_value($input_value);
1283
-            $result = $this->_registration_answers[ $answer_cache_id ]->save();
1284
-            return $result !== false;
1285
-        }
1286
-        foreach ($this->_registration_answers as $answer) {
1287
-            if ($answer instanceof EE_Answer && (string) $answer->question_ID() === $answer_cache_id) {
1288
-                $answer->set_value($input_value);
1289
-                $result = $answer->save();
1290
-                return $result !== false;
1291
-            }
1292
-        }
1293
-        return false;
1294
-    }
1295
-
1296
-
1297
-    /**
1298
-     *    _verify_critical_attendee_details_are_set
1299
-     *
1300
-     * @param string $form_input
1301
-     * @param string $input_value
1302
-     * @return boolean
1303
-     */
1304
-    private function _verify_critical_attendee_details_are_set_and_validate_email(
1305
-        $form_input = '',
1306
-        $input_value = ''
1307
-    ) {
1308
-        if (empty($input_value)) {
1309
-            // if the form input isn't marked as being required, then just return
1310
-            if (! isset($this->_required_questions[ $form_input ]) || ! $this->_required_questions[ $form_input ]) {
1311
-                return true;
1312
-            }
1313
-            switch ($form_input) {
1314
-                case 'fname':
1315
-                    EE_Error::add_error(
1316
-                        esc_html__('First Name is a required value.', 'event_espresso'),
1317
-                        __FILE__,
1318
-                        __FUNCTION__,
1319
-                        __LINE__
1320
-                    );
1321
-                    return false;
1322
-                case 'lname':
1323
-                    EE_Error::add_error(
1324
-                        esc_html__('Last Name is a required value.', 'event_espresso'),
1325
-                        __FILE__,
1326
-                        __FUNCTION__,
1327
-                        __LINE__
1328
-                    );
1329
-                    return false;
1330
-                case 'email':
1331
-                    EE_Error::add_error(
1332
-                        esc_html__('Please enter a valid email address.', 'event_espresso'),
1333
-                        __FILE__,
1334
-                        __FUNCTION__,
1335
-                        __LINE__
1336
-                    );
1337
-                    return false;
1338
-            }
1339
-        }
1340
-        return true;
1341
-    }
1342
-
1343
-
1344
-    /**
1345
-     *    _associate_attendee_with_registration
1346
-     *
1347
-     * @param EE_Registration $registration
1348
-     * @param EE_Attendee     $attendee
1349
-     * @return void
1350
-     * @throws EE_Error
1351
-     * @throws InvalidArgumentException
1352
-     * @throws ReflectionException
1353
-     * @throws RuntimeException
1354
-     * @throws InvalidDataTypeException
1355
-     * @throws InvalidInterfaceException
1356
-     */
1357
-    private function _associate_attendee_with_registration(EE_Registration $registration, EE_Attendee $attendee)
1358
-    {
1359
-        // add relation to attendee
1360
-        $registration->_add_relation_to($attendee, 'Attendee');
1361
-        $registration->set_attendee_id($attendee->ID());
1362
-        $registration->update_cache_after_object_save('Attendee', $attendee);
1363
-    }
1364
-
1365
-
1366
-    /**
1367
-     *    _associate_registration_with_transaction
1368
-     *
1369
-     * @param EE_Registration $registration
1370
-     * @return void
1371
-     * @throws EE_Error
1372
-     * @throws InvalidArgumentException
1373
-     * @throws ReflectionException
1374
-     * @throws InvalidDataTypeException
1375
-     * @throws InvalidInterfaceException
1376
-     */
1377
-    private function _associate_registration_with_transaction(EE_Registration $registration)
1378
-    {
1379
-        // add relation to registration
1380
-        $this->checkout->transaction->_add_relation_to($registration, 'Registration');
1381
-        $this->checkout->transaction->update_cache_after_object_save('Registration', $registration);
1382
-    }
1383
-
1384
-
1385
-    /**
1386
-     *    _copy_critical_attendee_details_from_primary_registrant
1387
-     *    ensures that all attendees at least have data for first name, last name, and email address
1388
-     *
1389
-     * @param array $attendee_data
1390
-     * @return array
1391
-     * @throws EE_Error
1392
-     * @throws InvalidArgumentException
1393
-     * @throws ReflectionException
1394
-     * @throws InvalidDataTypeException
1395
-     * @throws InvalidInterfaceException
1396
-     */
1397
-    private function _copy_critical_attendee_details_from_primary_registrant($attendee_data = [])
1398
-    {
1399
-        // bare minimum critical details include first name, last name, email address
1400
-        $critical_attendee_details = ['ATT_fname', 'ATT_lname', 'ATT_email'];
1401
-        // add address info to critical details?
1402
-        if (apply_filters(
1403
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information__merge_address_details_with_critical_attendee_details',
1404
-            false
1405
-        )) {
1406
-            $address_details           = [
1407
-                'ATT_address',
1408
-                'ATT_address2',
1409
-                'ATT_city',
1410
-                'STA_ID',
1411
-                'CNT_ISO',
1412
-                'ATT_zip',
1413
-                'ATT_phone',
1414
-            ];
1415
-            $critical_attendee_details = array_merge($critical_attendee_details, $address_details);
1416
-        }
1417
-        foreach ($critical_attendee_details as $critical_attendee_detail) {
1418
-            if (! isset($attendee_data[ $critical_attendee_detail ])
1419
-                || empty($attendee_data[ $critical_attendee_detail ])
1420
-            ) {
1421
-                $attendee_data[ $critical_attendee_detail ] = $this->checkout->primary_attendee_obj->get(
1422
-                    $critical_attendee_detail
1423
-                );
1424
-            }
1425
-        }
1426
-        return $attendee_data;
1427
-    }
1428
-
1429
-
1430
-    /**
1431
-     *    update_reg_step
1432
-     *    this is the final step after a user  revisits the site to edit their attendee information
1433
-     *    this gets called AFTER the process_reg_step() method above
1434
-     *
1435
-     * @return bool
1436
-     * @throws EE_Error
1437
-     * @throws InvalidArgumentException
1438
-     * @throws ReflectionException
1439
-     * @throws RuntimeException
1440
-     * @throws InvalidDataTypeException
1441
-     * @throws InvalidInterfaceException
1442
-     */
1443
-    public function update_reg_step()
1444
-    {
1445
-        // save everything
1446
-        if ($this->process_reg_step()) {
1447
-            $this->checkout->redirect     = true;
1448
-            $this->checkout->redirect_url = add_query_arg(
1449
-                [
1450
-                    'e_reg_url_link' => $this->checkout->reg_url_link,
1451
-                    'revisit'        => true,
1452
-                ],
1453
-                $this->checkout->thank_you_page_url
1454
-            );
1455
-            $this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
1456
-            return true;
1457
-        }
1458
-        return false;
1459
-    }
1246
+		$answer_cache_id = $this->checkout->reg_url_link
1247
+			? $form_input . '-' . $registration->reg_url_link()
1248
+			: $form_input;
1249
+		$answer_is_obj   = isset($this->_registration_answers[ $answer_cache_id ])
1250
+						   && $this->_registration_answers[ $answer_cache_id ] instanceof EE_Answer;
1251
+		// rename form_inputs if they are EE_Attendee properties
1252
+		switch ((string) $form_input) {
1253
+			case 'state':
1254
+			case 'STA_ID':
1255
+				$attendee_property = true;
1256
+				$form_input        = 'STA_ID';
1257
+				break;
1258
+
1259
+			case 'country':
1260
+			case 'CNT_ISO':
1261
+				$attendee_property = true;
1262
+				$form_input        = 'CNT_ISO';
1263
+				break;
1264
+
1265
+			default:
1266
+				$ATT_input = 'ATT_' . $form_input;
1267
+				$attendee_property = EEM_Attendee::instance()->has_field($ATT_input);
1268
+				$form_input        = $attendee_property ? 'ATT_' . $form_input : $form_input;
1269
+		}
1270
+		// if this form input has a corresponding attendee property
1271
+		if ($attendee_property) {
1272
+			$this->_attendee_data[ $registration->reg_url_link() ][ $form_input ] = $input_value;
1273
+			if ($answer_is_obj) {
1274
+				// and delete the corresponding answer since we won't be storing this data in that object
1275
+				$registration->_remove_relation_to($this->_registration_answers[ $answer_cache_id ], 'Answer');
1276
+				$this->_registration_answers[ $answer_cache_id ]->delete_permanently();
1277
+			}
1278
+			return true;
1279
+		}
1280
+		if ($answer_is_obj) {
1281
+			// save this data to the answer object
1282
+			$this->_registration_answers[ $answer_cache_id ]->set_value($input_value);
1283
+			$result = $this->_registration_answers[ $answer_cache_id ]->save();
1284
+			return $result !== false;
1285
+		}
1286
+		foreach ($this->_registration_answers as $answer) {
1287
+			if ($answer instanceof EE_Answer && (string) $answer->question_ID() === $answer_cache_id) {
1288
+				$answer->set_value($input_value);
1289
+				$result = $answer->save();
1290
+				return $result !== false;
1291
+			}
1292
+		}
1293
+		return false;
1294
+	}
1295
+
1296
+
1297
+	/**
1298
+	 *    _verify_critical_attendee_details_are_set
1299
+	 *
1300
+	 * @param string $form_input
1301
+	 * @param string $input_value
1302
+	 * @return boolean
1303
+	 */
1304
+	private function _verify_critical_attendee_details_are_set_and_validate_email(
1305
+		$form_input = '',
1306
+		$input_value = ''
1307
+	) {
1308
+		if (empty($input_value)) {
1309
+			// if the form input isn't marked as being required, then just return
1310
+			if (! isset($this->_required_questions[ $form_input ]) || ! $this->_required_questions[ $form_input ]) {
1311
+				return true;
1312
+			}
1313
+			switch ($form_input) {
1314
+				case 'fname':
1315
+					EE_Error::add_error(
1316
+						esc_html__('First Name is a required value.', 'event_espresso'),
1317
+						__FILE__,
1318
+						__FUNCTION__,
1319
+						__LINE__
1320
+					);
1321
+					return false;
1322
+				case 'lname':
1323
+					EE_Error::add_error(
1324
+						esc_html__('Last Name is a required value.', 'event_espresso'),
1325
+						__FILE__,
1326
+						__FUNCTION__,
1327
+						__LINE__
1328
+					);
1329
+					return false;
1330
+				case 'email':
1331
+					EE_Error::add_error(
1332
+						esc_html__('Please enter a valid email address.', 'event_espresso'),
1333
+						__FILE__,
1334
+						__FUNCTION__,
1335
+						__LINE__
1336
+					);
1337
+					return false;
1338
+			}
1339
+		}
1340
+		return true;
1341
+	}
1342
+
1343
+
1344
+	/**
1345
+	 *    _associate_attendee_with_registration
1346
+	 *
1347
+	 * @param EE_Registration $registration
1348
+	 * @param EE_Attendee     $attendee
1349
+	 * @return void
1350
+	 * @throws EE_Error
1351
+	 * @throws InvalidArgumentException
1352
+	 * @throws ReflectionException
1353
+	 * @throws RuntimeException
1354
+	 * @throws InvalidDataTypeException
1355
+	 * @throws InvalidInterfaceException
1356
+	 */
1357
+	private function _associate_attendee_with_registration(EE_Registration $registration, EE_Attendee $attendee)
1358
+	{
1359
+		// add relation to attendee
1360
+		$registration->_add_relation_to($attendee, 'Attendee');
1361
+		$registration->set_attendee_id($attendee->ID());
1362
+		$registration->update_cache_after_object_save('Attendee', $attendee);
1363
+	}
1364
+
1365
+
1366
+	/**
1367
+	 *    _associate_registration_with_transaction
1368
+	 *
1369
+	 * @param EE_Registration $registration
1370
+	 * @return void
1371
+	 * @throws EE_Error
1372
+	 * @throws InvalidArgumentException
1373
+	 * @throws ReflectionException
1374
+	 * @throws InvalidDataTypeException
1375
+	 * @throws InvalidInterfaceException
1376
+	 */
1377
+	private function _associate_registration_with_transaction(EE_Registration $registration)
1378
+	{
1379
+		// add relation to registration
1380
+		$this->checkout->transaction->_add_relation_to($registration, 'Registration');
1381
+		$this->checkout->transaction->update_cache_after_object_save('Registration', $registration);
1382
+	}
1383
+
1384
+
1385
+	/**
1386
+	 *    _copy_critical_attendee_details_from_primary_registrant
1387
+	 *    ensures that all attendees at least have data for first name, last name, and email address
1388
+	 *
1389
+	 * @param array $attendee_data
1390
+	 * @return array
1391
+	 * @throws EE_Error
1392
+	 * @throws InvalidArgumentException
1393
+	 * @throws ReflectionException
1394
+	 * @throws InvalidDataTypeException
1395
+	 * @throws InvalidInterfaceException
1396
+	 */
1397
+	private function _copy_critical_attendee_details_from_primary_registrant($attendee_data = [])
1398
+	{
1399
+		// bare minimum critical details include first name, last name, email address
1400
+		$critical_attendee_details = ['ATT_fname', 'ATT_lname', 'ATT_email'];
1401
+		// add address info to critical details?
1402
+		if (apply_filters(
1403
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information__merge_address_details_with_critical_attendee_details',
1404
+			false
1405
+		)) {
1406
+			$address_details           = [
1407
+				'ATT_address',
1408
+				'ATT_address2',
1409
+				'ATT_city',
1410
+				'STA_ID',
1411
+				'CNT_ISO',
1412
+				'ATT_zip',
1413
+				'ATT_phone',
1414
+			];
1415
+			$critical_attendee_details = array_merge($critical_attendee_details, $address_details);
1416
+		}
1417
+		foreach ($critical_attendee_details as $critical_attendee_detail) {
1418
+			if (! isset($attendee_data[ $critical_attendee_detail ])
1419
+				|| empty($attendee_data[ $critical_attendee_detail ])
1420
+			) {
1421
+				$attendee_data[ $critical_attendee_detail ] = $this->checkout->primary_attendee_obj->get(
1422
+					$critical_attendee_detail
1423
+				);
1424
+			}
1425
+		}
1426
+		return $attendee_data;
1427
+	}
1428
+
1429
+
1430
+	/**
1431
+	 *    update_reg_step
1432
+	 *    this is the final step after a user  revisits the site to edit their attendee information
1433
+	 *    this gets called AFTER the process_reg_step() method above
1434
+	 *
1435
+	 * @return bool
1436
+	 * @throws EE_Error
1437
+	 * @throws InvalidArgumentException
1438
+	 * @throws ReflectionException
1439
+	 * @throws RuntimeException
1440
+	 * @throws InvalidDataTypeException
1441
+	 * @throws InvalidInterfaceException
1442
+	 */
1443
+	public function update_reg_step()
1444
+	{
1445
+		// save everything
1446
+		if ($this->process_reg_step()) {
1447
+			$this->checkout->redirect     = true;
1448
+			$this->checkout->redirect_url = add_query_arg(
1449
+				[
1450
+					'e_reg_url_link' => $this->checkout->reg_url_link,
1451
+					'revisit'        => true,
1452
+				],
1453
+				$this->checkout->thank_you_page_url
1454
+			);
1455
+			$this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
1456
+			return true;
1457
+		}
1458
+		return false;
1459
+	}
1460 1460
 }
Please login to merge, or discard this patch.
Spacing   +95 added lines, -95 removed lines patch added patch discarded remove patch
@@ -65,11 +65,11 @@  discard block
 block discarded – undo
65 65
 
66 66
     public function translate_js_strings()
67 67
     {
68
-        EE_Registry::$i18n_js_strings['required_field']            = esc_html__(
68
+        EE_Registry::$i18n_js_strings['required_field'] = esc_html__(
69 69
             ' is a required question.',
70 70
             'event_espresso'
71 71
         );
72
-        EE_Registry::$i18n_js_strings['required_multi_field']      = esc_html__(
72
+        EE_Registry::$i18n_js_strings['required_multi_field'] = esc_html__(
73 73
             ' is a required question. Please enter a value for at least one of the options.',
74 74
             'event_espresso'
75 75
         );
@@ -77,7 +77,7 @@  discard block
 block discarded – undo
77 77
             'Please answer all required questions correctly before proceeding.',
78 78
             'event_espresso'
79 79
         );
80
-        EE_Registry::$i18n_js_strings['attendee_info_copied']      = sprintf(
80
+        EE_Registry::$i18n_js_strings['attendee_info_copied'] = sprintf(
81 81
             esc_html_x(
82 82
                 'The attendee information was successfully copied.%sPlease ensure the rest of the registration form is completed before proceeding.',
83 83
                 'The attendee information was successfully copied.(line break)Please ensure the rest of the registration form is completed before proceeding.',
@@ -85,11 +85,11 @@  discard block
 block discarded – undo
85 85
             ),
86 86
             '<br/>'
87 87
         );
88
-        EE_Registry::$i18n_js_strings['attendee_info_copy_error']  = esc_html__(
88
+        EE_Registry::$i18n_js_strings['attendee_info_copy_error'] = esc_html__(
89 89
             'An unknown error occurred on the server while attempting to copy the attendee information. Please refresh the page and try again.',
90 90
             'event_espresso'
91 91
         );
92
-        EE_Registry::$i18n_js_strings['enter_valid_email']         = esc_html__(
92
+        EE_Registry::$i18n_js_strings['enter_valid_email'] = esc_html__(
93 93
             'You must enter a valid email address.',
94 94
             'event_espresso'
95 95
         );
@@ -152,7 +152,7 @@  discard block
 block discarded – undo
152 152
         ];
153 153
 
154 154
         // if this isn't a revisit, and they have the privacy consent box enabled, add it
155
-        if (! $this->checkout->revisit && $reg_config->isConsentCheckboxEnabled()) {
155
+        if ( ! $this->checkout->revisit && $reg_config->isConsentCheckboxEnabled()) {
156 156
             $extra_inputs_section->add_subsections(
157 157
                 [
158 158
                     'consent_box' => new EE_Form_Section_Proper(
@@ -200,15 +200,15 @@  discard block
 block discarded – undo
200 200
                 if ($registration instanceof EE_Registration
201 201
                     && $this->checkout->visit_allows_processing_of_this_registration($registration)
202 202
                 ) {
203
-                    $subsections[ $registration->reg_url_link() ]                       =
203
+                    $subsections[$registration->reg_url_link()]                       =
204 204
                         $this->_registrations_reg_form($registration);
205
-                    $template_args['registrations'][ $registration->reg_url_link() ]    = $registration;
206
-                    $template_args['ticket_count'][ $registration->ticket()->ID() ]     = isset(
207
-                        $template_args['ticket_count'][ $registration->ticket()->ID() ]
205
+                    $template_args['registrations'][$registration->reg_url_link()]    = $registration;
206
+                    $template_args['ticket_count'][$registration->ticket()->ID()]     = isset(
207
+                        $template_args['ticket_count'][$registration->ticket()->ID()]
208 208
                     )
209
-                        ? $template_args['ticket_count'][ $registration->ticket()->ID() ] + 1
209
+                        ? $template_args['ticket_count'][$registration->ticket()->ID()] + 1
210 210
                         : 1;
211
-                    $ticket_line_item                                                   =
211
+                    $ticket_line_item =
212 212
                         EEH_Line_Item::get_line_items_by_object_type_and_IDs(
213 213
                             $this->checkout->cart->get_grand_total(),
214 214
                             'Ticket',
@@ -217,7 +217,7 @@  discard block
 block discarded – undo
217 217
                     $ticket_line_item                                                   = is_array($ticket_line_item)
218 218
                         ? reset($ticket_line_item)
219 219
                         : $ticket_line_item;
220
-                    $template_args['ticket_line_item'][ $registration->ticket()->ID() ] =
220
+                    $template_args['ticket_line_item'][$registration->ticket()->ID()] =
221 221
                         $Line_Item_Display->display_line_item($ticket_line_item);
222 222
                     if ($registration->is_primary_registrant()) {
223 223
                         $primary_registrant = $registration->reg_url_link();
@@ -230,10 +230,10 @@  discard block
 block discarded – undo
230 230
                     ? $this->_copy_attendee_info_form()
231 231
                     : $this->_auto_copy_attendee_info();
232 232
                 // generate hidden input
233
-                if (isset($subsections[ $primary_registrant ])
234
-                    && $subsections[ $primary_registrant ] instanceof EE_Form_Section_Proper
233
+                if (isset($subsections[$primary_registrant])
234
+                    && $subsections[$primary_registrant] instanceof EE_Form_Section_Proper
235 235
                 ) {
236
-                    $subsections[ $primary_registrant ]->add_subsections(
236
+                    $subsections[$primary_registrant]->add_subsections(
237 237
                         $copy_options,
238 238
                         'primary_registrant',
239 239
                         false
@@ -245,8 +245,8 @@  discard block
 block discarded – undo
245 245
         // Set the registration form template (default: one form per ticket details table).
246 246
         // We decide the template to used based on the number of forms.
247 247
         $this->_template = $this->reg_form_count > 1
248
-            ? SPCO_REG_STEPS_PATH . $this->_slug . '/attendee_info_main.template.php'
249
-            : SPCO_REG_STEPS_PATH . $this->_slug . '/attendee_info_single.template.php';
248
+            ? SPCO_REG_STEPS_PATH . $this->_slug.'/attendee_info_main.template.php'
249
+            : SPCO_REG_STEPS_PATH.$this->_slug.'/attendee_info_single.template.php';
250 250
 
251 251
         return new EE_Form_Section_Proper(
252 252
             [
@@ -280,7 +280,7 @@  discard block
 block discarded – undo
280 280
         $form_args = [];
281 281
         // verify that registration has valid event
282 282
         if ($registration->event() instanceof EE_Event) {
283
-            $field_name      = 'Event_Question_Group.'
283
+            $field_name = 'Event_Question_Group.'
284 284
                                . EEM_Event_Question_Group::instance()->fieldNameForContext(
285 285
                     $registration->is_primary_registrant()
286 286
                 );
@@ -303,7 +303,7 @@  discard block
 block discarded – undo
303 303
             if ($question_groups) {
304 304
                 // array of params to pass to parent constructor
305 305
                 $form_args = [
306
-                    'html_id'         => 'ee-registration-' . $registration->reg_url_link(),
306
+                    'html_id'         => 'ee-registration-'.$registration->reg_url_link(),
307 307
                     'html_class'      => 'ee-reg-form-attendee-dv',
308 308
                     'html_style'      => $this->checkout->admin_request
309 309
                         ? 'padding:0em 2em 1em; margin:3em 0 0; border:1px solid #ddd;'
@@ -325,7 +325,7 @@  discard block
 block discarded – undo
325 325
                 ];
326 326
                 foreach ($question_groups as $question_group) {
327 327
                     if ($question_group instanceof EE_Question_Group) {
328
-                        $form_args['subsections'][ $question_group->identifier() ] = $this->_question_group_reg_form(
328
+                        $form_args['subsections'][$question_group->identifier()] = $this->_question_group_reg_form(
329 329
                             $registration,
330 330
                             $question_group
331 331
                         );
@@ -359,7 +359,7 @@  discard block
 block discarded – undo
359 359
         $attendee_nmbr++;
360 360
 
361 361
         // Increment the reg forms number if form is valid.
362
-        if (! empty($form_args)) {
362
+        if ( ! empty($form_args)) {
363 363
             $this->reg_form_count++;
364 364
         }
365 365
 
@@ -382,7 +382,7 @@  discard block
 block discarded – undo
382 382
         // generate hidden input
383 383
         return new EE_Hidden_Input(
384 384
             [
385
-                'html_id' => 'additional-attendee-reg-info-' . $registration->reg_url_link(),
385
+                'html_id' => 'additional-attendee-reg-info-'.$registration->reg_url_link(),
386 386
                 'default' => $additional_attendee_reg_info,
387 387
             ]
388 388
         );
@@ -403,12 +403,12 @@  discard block
 block discarded – undo
403 403
     {
404 404
         // array of params to pass to parent constructor
405 405
         $form_args = [
406
-            'html_id'         => 'ee-reg-form-qstn-grp-' . $question_group->identifier() . '-' . $registration->ID(),
406
+            'html_id'         => 'ee-reg-form-qstn-grp-'.$question_group->identifier().'-'.$registration->ID(),
407 407
             'html_class'      => $this->checkout->admin_request
408 408
                 ? 'form-table ee-reg-form-qstn-grp-dv'
409 409
                 : 'ee-reg-form-qstn-grp-dv',
410
-            'html_label_id'   => 'ee-reg-form-qstn-grp-' . $question_group->identifier() . '-'
411
-                                 . $registration->ID() . '-lbl',
410
+            'html_label_id'   => 'ee-reg-form-qstn-grp-'.$question_group->identifier().'-'
411
+                                 . $registration->ID().'-lbl',
412 412
             'subsections'     => [
413 413
                 'reg_form_qstn_grp_hdr' => $this->_question_group_header($question_group),
414 414
             ],
@@ -419,7 +419,7 @@  discard block
 block discarded – undo
419 419
         // where params
420 420
         $query_params = ['QST_deleted' => 0];
421 421
         // don't load admin only questions on the frontend
422
-        if (! $this->checkout->admin_request) {
422
+        if ( ! $this->checkout->admin_request) {
423 423
             $query_params['QST_admin_only'] = ['!=', true];
424 424
         }
425 425
         $questions = $question_group->get_many_related(
@@ -453,7 +453,7 @@  discard block
 block discarded – undo
453 453
                 $identifier                              = $question->is_system_question()
454 454
                     ? $question->system_ID()
455 455
                     : $question->ID();
456
-                $form_args['subsections'][ $identifier ] = $this->reg_form_question($registration, $question);
456
+                $form_args['subsections'][$identifier] = $this->reg_form_question($registration, $question);
457 457
             }
458 458
         }
459 459
         $form_args['subsections'] = apply_filters(
@@ -565,7 +565,7 @@  discard block
 block discarded – undo
565 565
     {
566 566
         return new EE_Form_Section_HTML(
567 567
             EEH_Template::locate_template(
568
-                SPCO_REG_STEPS_PATH . $this->_slug . '/_auto_copy_attendee_info.template.php',
568
+                SPCO_REG_STEPS_PATH.$this->_slug.'/_auto_copy_attendee_info.template.php',
569 569
                 apply_filters(
570 570
                     'FHEE__EE_SPCO_Reg_Step_Attendee_Information__auto_copy_attendee_info__template_args',
571 571
                     []
@@ -594,20 +594,20 @@  discard block
 block discarded – undo
594 594
             if ($registration instanceof EE_Registration && ! $registration->is_primary_registrant()) {
595 595
                 // if this is a new ticket OR if this is the very first additional attendee after the primary attendee
596 596
                 if ($registration->ticket()->ID() !== $prev_ticket) {
597
-                    $item_name                          = $registration->ticket()->name();
598
-                    $item_name                          .= $registration->ticket()->description() !== ''
599
-                        ? ' - ' . $registration->ticket()->description()
597
+                    $item_name = $registration->ticket()->name();
598
+                    $item_name .= $registration->ticket()->description() !== ''
599
+                        ? ' - '.$registration->ticket()->description()
600 600
                         : '';
601
-                    $copy_attendee_info_inputs[ 'spco_copy_attendee_chk[ticket-'
601
+                    $copy_attendee_info_inputs['spco_copy_attendee_chk[ticket-'
602 602
                                                 . $registration->ticket()->ID()
603
-                                                . ']' ] =
603
+                                                . ']'] =
604 604
                         new EE_Form_Section_HTML(
605
-                            '<h6 class="spco-copy-attendee-event-hdr">' . $item_name . '</h6>'
605
+                            '<h6 class="spco-copy-attendee-event-hdr">'.$item_name.'</h6>'
606 606
                         );
607
-                    $prev_ticket                        = $registration->ticket()->ID();
607
+                    $prev_ticket = $registration->ticket()->ID();
608 608
                 }
609 609
 
610
-                $copy_attendee_info_inputs[ 'spco_copy_attendee_chk[' . $registration->ID() . ']' ] =
610
+                $copy_attendee_info_inputs['spco_copy_attendee_chk['.$registration->ID().']'] =
611 611
                     new EE_Checkbox_Multi_Input(
612 612
                         [
613 613
                             $registration->ID() => sprintf(
@@ -616,7 +616,7 @@  discard block
 block discarded – undo
616 616
                             ),
617 617
                         ],
618 618
                         [
619
-                            'html_id'                 => 'spco-copy-attendee-chk-' . $registration->reg_url_link(),
619
+                            'html_id'                 => 'spco-copy-attendee-chk-'.$registration->reg_url_link(),
620 620
                             'html_class'              => 'spco-copy-attendee-chk ee-do-not-validate',
621 621
                             'display_html_label_text' => false,
622 622
                         ]
@@ -662,7 +662,7 @@  discard block
 block discarded – undo
662 662
             $registration,
663 663
             $question->system_ID()
664 664
         );
665
-        $answer       = $answer_value === null
665
+        $answer = $answer_value === null
666 666
             ? EEM_Answer::instance()->get_one(
667 667
                 [['QST_ID' => $question->ID(), 'REG_ID' => $registration->ID()]]
668 668
             )
@@ -681,14 +681,14 @@  discard block
 block discarded – undo
681 681
         }
682 682
         // verify instance
683 683
         if ($answer instanceof EE_Answer) {
684
-            if (! empty($answer_value)) {
684
+            if ( ! empty($answer_value)) {
685 685
                 $answer->set('ANS_value', $answer_value);
686 686
             }
687 687
             $answer->cache('Question', $question);
688 688
             // remember system ID had a bug where sometimes it could be null
689 689
             $answer_cache_id = $question->is_system_question()
690
-                ? $question->system_ID() . '-' . $registration->reg_url_link()
691
-                : $question->ID() . '-' . $registration->reg_url_link();
690
+                ? $question->system_ID().'-'.$registration->reg_url_link()
691
+                : $question->ID().'-'.$registration->reg_url_link();
692 692
             $registration->cache('Answer', $answer, $answer_cache_id);
693 693
         }
694 694
         return $this->_generate_question_input($registration, $question, $answer);
@@ -711,7 +711,7 @@  discard block
 block discarded – undo
711 711
         $identifier                               = $question->is_system_question()
712 712
             ? $question->system_ID()
713 713
             : $question->ID();
714
-        $this->_required_questions[ $identifier ] = $question->required();
714
+        $this->_required_questions[$identifier] = $question->required();
715 715
         add_filter(
716 716
             'FHEE__EE_Question__generate_form_input__country_options',
717 717
             [$this, 'use_cached_countries_for_form_input'],
@@ -724,18 +724,18 @@  discard block
 block discarded – undo
724 724
             10,
725 725
             4
726 726
         );
727
-        $input_constructor_args                  = [
728
-            'html_name'        => 'ee_reg_qstn[' . $registration->ID() . '][' . $identifier . ']',
729
-            'html_id'          => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
730
-            'html_class'       => 'ee-reg-qstn ee-reg-qstn-' . $identifier,
731
-            'html_label_id'    => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
727
+        $input_constructor_args = [
728
+            'html_name'        => 'ee_reg_qstn['.$registration->ID().']['.$identifier.']',
729
+            'html_id'          => 'ee_reg_qstn-'.$registration->ID().'-'.$identifier,
730
+            'html_class'       => 'ee-reg-qstn ee-reg-qstn-'.$identifier,
731
+            'html_label_id'    => 'ee_reg_qstn-'.$registration->ID().'-'.$identifier,
732 732
             'html_label_class' => 'ee-reg-qstn',
733 733
         ];
734 734
         $input_constructor_args['html_label_id'] .= '-lbl';
735 735
         if ($answer instanceof EE_Answer && $answer->ID()) {
736
-            $input_constructor_args['html_name']     .= '[' . $answer->ID() . ']';
737
-            $input_constructor_args['html_id']       .= '-' . $answer->ID();
738
-            $input_constructor_args['html_label_id'] .= '-' . $answer->ID();
736
+            $input_constructor_args['html_name']     .= '['.$answer->ID().']';
737
+            $input_constructor_args['html_id']       .= '-'.$answer->ID();
738
+            $input_constructor_args['html_label_id'] .= '-'.$answer->ID();
739 739
         }
740 740
         $form_input = $question->generate_form_input(
741 741
             $registration,
@@ -779,10 +779,10 @@  discard block
 block discarded – undo
779 779
         $countries = $this->checkout->action === 'process_reg_step'
780 780
             ? EEM_Country::instance()->get_all_countries()
781 781
             : EEM_Country::instance()->get_all_active_countries();
782
-        if (! empty($countries)) {
782
+        if ( ! empty($countries)) {
783 783
             foreach ($countries as $country) {
784 784
                 if ($country instanceof EE_Country) {
785
-                    $country_options[ $country->ID() ] = $country->name();
785
+                    $country_options[$country->ID()] = $country->name();
786 786
                 }
787 787
             }
788 788
         }
@@ -828,10 +828,10 @@  discard block
 block discarded – undo
828 828
         $states        = $this->checkout->action === 'process_reg_step'
829 829
             ? EEM_State::instance()->get_all_states()
830 830
             : EEM_State::instance()->get_all_active_states();
831
-        if (! empty($states)) {
831
+        if ( ! empty($states)) {
832 832
             foreach ($states as $state) {
833 833
                 if ($state instanceof EE_State) {
834
-                    $state_options[ $state->country()->name() ][ $state->ID() ] = $state->name();
834
+                    $state_options[$state->country()->name()][$state->ID()] = $state->name();
835 835
                 }
836 836
             }
837 837
         }
@@ -875,7 +875,7 @@  discard block
 block discarded – undo
875 875
             );
876 876
             return false;
877 877
         }
878
-        if (! $this->checkout->transaction instanceof EE_Transaction || ! $this->checkout->continue_reg) {
878
+        if ( ! $this->checkout->transaction instanceof EE_Transaction || ! $this->checkout->continue_reg) {
879 879
             EE_Error::add_error(
880 880
                 esc_html__(
881 881
                     'A valid transaction could not be initiated for processing your registrations.',
@@ -902,7 +902,7 @@  discard block
 block discarded – undo
902 902
                     '(line break)This can sometimes happen if too much time has been taken to complete the registration process.(line break)Please return to the (link)Event List(end link) and reselect your tickets. If the problem continues, please contact the site administrator.',
903 903
                     'event_espresso'
904 904
                 ),
905
-                '<a href="' . get_post_type_archive_link('espresso_events') . '" >',
905
+                '<a href="'.get_post_type_archive_link('espresso_events').'" >',
906 906
                 '</a>',
907 907
                 '<br />'
908 908
             );
@@ -922,7 +922,7 @@  discard block
 block discarded – undo
922 922
             // but return immediately if the previous step exited early due to errors
923 923
             return false;
924 924
         }
925
-        if (! $this->checkout->revisit && $registrations_processed !== $this->checkout->total_ticket_count) {
925
+        if ( ! $this->checkout->revisit && $registrations_processed !== $this->checkout->total_ticket_count) {
926 926
             // generate a correctly translated string for all possible singular/plural combinations
927 927
             if ($this->checkout->total_ticket_count === 1 && $registrations_processed !== 1) {
928 928
                 $error_msg = sprintf(
@@ -1005,7 +1005,7 @@  discard block
 block discarded – undo
1005 1005
         // grab the saved registrations from the transaction
1006 1006
         foreach ($registrations as $registration) {
1007 1007
             // verify EE_Registration object
1008
-            if (! $registration instanceof EE_Registration) {
1008
+            if ( ! $registration instanceof EE_Registration) {
1009 1009
                 EE_Error::add_error(
1010 1010
                     esc_html__(
1011 1011
                         'An invalid Registration object was discovered when attempting to process your registration information.',
@@ -1019,12 +1019,12 @@  discard block
 block discarded – undo
1019 1019
             }
1020 1020
             $reg_url_link = $registration->reg_url_link();
1021 1021
             // reg_url_link exists ?
1022
-            if (! empty($reg_url_link)) {
1022
+            if ( ! empty($reg_url_link)) {
1023 1023
                 // should this registration be processed during this visit ?
1024 1024
                 if ($this->checkout->visit_allows_processing_of_this_registration($registration)) {
1025 1025
                     // if NOT revisiting, then let's save the registration now,
1026 1026
                     // so that we have a REG_ID to use when generating other objects
1027
-                    if (! $this->checkout->revisit) {
1027
+                    if ( ! $this->checkout->revisit) {
1028 1028
                         $registration->save();
1029 1029
                     }
1030 1030
                     /**
@@ -1048,18 +1048,18 @@  discard block
 block discarded – undo
1048 1048
 
1049 1049
                     // Houston, we have a registration!
1050 1050
                     $att_nmbr++;
1051
-                    $this->_attendee_data[ $reg_url_link ] = [];
1051
+                    $this->_attendee_data[$reg_url_link] = [];
1052 1052
                     // grab any existing related answer objects
1053 1053
                     $this->_registration_answers = $registration->answers();
1054 1054
                     // unset( $valid_data[ $reg_url_link ]['additional_attendee_reg_info'] );
1055
-                    if (isset($valid_data[ $reg_url_link ])) {
1055
+                    if (isset($valid_data[$reg_url_link])) {
1056 1056
                         // do we need to copy basic info from primary attendee ?
1057
-                        $copy_primary = isset($valid_data[ $reg_url_link ]['additional_attendee_reg_info'])
1058
-                                        && absint($valid_data[ $reg_url_link ]['additional_attendee_reg_info']) === 0;
1057
+                        $copy_primary = isset($valid_data[$reg_url_link]['additional_attendee_reg_info'])
1058
+                                        && absint($valid_data[$reg_url_link]['additional_attendee_reg_info']) === 0;
1059 1059
                         // filter form input data for this registration
1060
-                        $valid_data[ $reg_url_link ] = (array) apply_filters(
1060
+                        $valid_data[$reg_url_link] = (array) apply_filters(
1061 1061
                             'FHEE__EE_Single_Page_Checkout__process_attendee_information__valid_data_line_item',
1062
-                            $valid_data[ $reg_url_link ]
1062
+                            $valid_data[$reg_url_link]
1063 1063
                         );
1064 1064
                         if (isset($valid_data['primary_attendee'])) {
1065 1065
                             $primary_registrant['line_item_id'] = ! empty($valid_data['primary_attendee'])
@@ -1068,11 +1068,11 @@  discard block
 block discarded – undo
1068 1068
                             unset($valid_data['primary_attendee']);
1069 1069
                         }
1070 1070
                         // now loop through our array of valid post data && process attendee reg forms
1071
-                        foreach ($valid_data[ $reg_url_link ] as $form_section => $form_inputs) {
1072
-                            if (! in_array($form_section, $non_input_form_sections, true)) {
1071
+                        foreach ($valid_data[$reg_url_link] as $form_section => $form_inputs) {
1072
+                            if ( ! in_array($form_section, $non_input_form_sections, true)) {
1073 1073
                                 foreach ($form_inputs as $form_input => $input_value) {
1074 1074
                                     // check for critical inputs
1075
-                                    if (! $this->_verify_critical_attendee_details_are_set_and_validate_email(
1075
+                                    if ( ! $this->_verify_critical_attendee_details_are_set_and_validate_email(
1076 1076
                                         $form_input,
1077 1077
                                         $input_value
1078 1078
                                     )
@@ -1084,15 +1084,15 @@  discard block
 block discarded – undo
1084 1084
                                         && ! empty($input_value)
1085 1085
                                         && $reg_url_link === $primary_registrant['line_item_id']
1086 1086
                                     ) {
1087
-                                        $primary_registrant[ $form_input ] = $input_value;
1087
+                                        $primary_registrant[$form_input] = $input_value;
1088 1088
                                     } elseif ($copy_primary
1089 1089
                                               && $input_value === null
1090
-                                              && isset($primary_registrant[ $form_input ])
1090
+                                              && isset($primary_registrant[$form_input])
1091 1091
                                     ) {
1092
-                                        $input_value = $primary_registrant[ $form_input ];
1092
+                                        $input_value = $primary_registrant[$form_input];
1093 1093
                                     }
1094 1094
                                     // now attempt to save the input data
1095
-                                    if (! $this->_save_registration_form_input(
1095
+                                    if ( ! $this->_save_registration_form_input(
1096 1096
                                         $registration,
1097 1097
                                         $form_input,
1098 1098
                                         $input_value
@@ -1127,15 +1127,15 @@  discard block
 block discarded – undo
1127 1127
                         $attendee = $this->checkout->primary_attendee_obj;
1128 1128
                     } else {
1129 1129
                         // ensure critical details are set for additional attendees
1130
-                        $this->_attendee_data[ $reg_url_link ] = $att_nmbr > 1
1130
+                        $this->_attendee_data[$reg_url_link] = $att_nmbr > 1
1131 1131
                             ? $this->_copy_critical_attendee_details_from_primary_registrant(
1132
-                                $this->_attendee_data[ $reg_url_link ]
1132
+                                $this->_attendee_data[$reg_url_link]
1133 1133
                             )
1134
-                            : $this->_attendee_data[ $reg_url_link ];
1134
+                            : $this->_attendee_data[$reg_url_link];
1135 1135
                         // execute create attendee command (which may return an existing attendee)
1136 1136
                         $attendee = EE_Registry::instance()->BUS->execute(
1137 1137
                             new CreateAttendeeCommand(
1138
-                                $this->_attendee_data[ $reg_url_link ],
1138
+                                $this->_attendee_data[$reg_url_link],
1139 1139
                                 $registration
1140 1140
                             )
1141 1141
                         );
@@ -1146,7 +1146,7 @@  discard block
 block discarded – undo
1146 1146
                     }
1147 1147
                     // add relation to registration, set attendee ID, and cache attendee
1148 1148
                     $this->_associate_attendee_with_registration($registration, $attendee);
1149
-                    if (! $registration->attendee() instanceof EE_Attendee) {
1149
+                    if ( ! $registration->attendee() instanceof EE_Attendee) {
1150 1150
                         EE_Error::add_error(
1151 1151
                             sprintf(
1152 1152
                                 esc_html_x(
@@ -1196,7 +1196,7 @@  discard block
 block discarded – undo
1196 1196
                     __LINE__
1197 1197
                 );
1198 1198
                 // remove malformed data
1199
-                unset($valid_data[ $reg_url_link ]);
1199
+                unset($valid_data[$reg_url_link]);
1200 1200
                 return false;
1201 1201
             }
1202 1202
         } // end of foreach ( $this->checkout->transaction->registrations()  as $registration )
@@ -1244,10 +1244,10 @@  discard block
 block discarded – undo
1244 1244
          * @see https://events.codebasehq.com/projects/event-espresso/tickets/10477
1245 1245
          */
1246 1246
         $answer_cache_id = $this->checkout->reg_url_link
1247
-            ? $form_input . '-' . $registration->reg_url_link()
1247
+            ? $form_input.'-'.$registration->reg_url_link()
1248 1248
             : $form_input;
1249
-        $answer_is_obj   = isset($this->_registration_answers[ $answer_cache_id ])
1250
-                           && $this->_registration_answers[ $answer_cache_id ] instanceof EE_Answer;
1249
+        $answer_is_obj   = isset($this->_registration_answers[$answer_cache_id])
1250
+                           && $this->_registration_answers[$answer_cache_id] instanceof EE_Answer;
1251 1251
         // rename form_inputs if they are EE_Attendee properties
1252 1252
         switch ((string) $form_input) {
1253 1253
             case 'state':
@@ -1263,24 +1263,24 @@  discard block
 block discarded – undo
1263 1263
                 break;
1264 1264
 
1265 1265
             default:
1266
-                $ATT_input = 'ATT_' . $form_input;
1266
+                $ATT_input = 'ATT_'.$form_input;
1267 1267
                 $attendee_property = EEM_Attendee::instance()->has_field($ATT_input);
1268
-                $form_input        = $attendee_property ? 'ATT_' . $form_input : $form_input;
1268
+                $form_input        = $attendee_property ? 'ATT_'.$form_input : $form_input;
1269 1269
         }
1270 1270
         // if this form input has a corresponding attendee property
1271 1271
         if ($attendee_property) {
1272
-            $this->_attendee_data[ $registration->reg_url_link() ][ $form_input ] = $input_value;
1272
+            $this->_attendee_data[$registration->reg_url_link()][$form_input] = $input_value;
1273 1273
             if ($answer_is_obj) {
1274 1274
                 // and delete the corresponding answer since we won't be storing this data in that object
1275
-                $registration->_remove_relation_to($this->_registration_answers[ $answer_cache_id ], 'Answer');
1276
-                $this->_registration_answers[ $answer_cache_id ]->delete_permanently();
1275
+                $registration->_remove_relation_to($this->_registration_answers[$answer_cache_id], 'Answer');
1276
+                $this->_registration_answers[$answer_cache_id]->delete_permanently();
1277 1277
             }
1278 1278
             return true;
1279 1279
         }
1280 1280
         if ($answer_is_obj) {
1281 1281
             // save this data to the answer object
1282
-            $this->_registration_answers[ $answer_cache_id ]->set_value($input_value);
1283
-            $result = $this->_registration_answers[ $answer_cache_id ]->save();
1282
+            $this->_registration_answers[$answer_cache_id]->set_value($input_value);
1283
+            $result = $this->_registration_answers[$answer_cache_id]->save();
1284 1284
             return $result !== false;
1285 1285
         }
1286 1286
         foreach ($this->_registration_answers as $answer) {
@@ -1307,7 +1307,7 @@  discard block
 block discarded – undo
1307 1307
     ) {
1308 1308
         if (empty($input_value)) {
1309 1309
             // if the form input isn't marked as being required, then just return
1310
-            if (! isset($this->_required_questions[ $form_input ]) || ! $this->_required_questions[ $form_input ]) {
1310
+            if ( ! isset($this->_required_questions[$form_input]) || ! $this->_required_questions[$form_input]) {
1311 1311
                 return true;
1312 1312
             }
1313 1313
             switch ($form_input) {
@@ -1403,7 +1403,7 @@  discard block
 block discarded – undo
1403 1403
             'FHEE__EE_SPCO_Reg_Step_Attendee_Information__merge_address_details_with_critical_attendee_details',
1404 1404
             false
1405 1405
         )) {
1406
-            $address_details           = [
1406
+            $address_details = [
1407 1407
                 'ATT_address',
1408 1408
                 'ATT_address2',
1409 1409
                 'ATT_city',
@@ -1415,10 +1415,10 @@  discard block
 block discarded – undo
1415 1415
             $critical_attendee_details = array_merge($critical_attendee_details, $address_details);
1416 1416
         }
1417 1417
         foreach ($critical_attendee_details as $critical_attendee_detail) {
1418
-            if (! isset($attendee_data[ $critical_attendee_detail ])
1419
-                || empty($attendee_data[ $critical_attendee_detail ])
1418
+            if ( ! isset($attendee_data[$critical_attendee_detail])
1419
+                || empty($attendee_data[$critical_attendee_detail])
1420 1420
             ) {
1421
-                $attendee_data[ $critical_attendee_detail ] = $this->checkout->primary_attendee_obj->get(
1421
+                $attendee_data[$critical_attendee_detail] = $this->checkout->primary_attendee_obj->get(
1422 1422
                     $critical_attendee_detail
1423 1423
                 );
1424 1424
             }
Please login to merge, or discard this patch.
finalize_registration/EE_SPCO_Reg_Step_Finalize_Registration.class.php 2 patches
Indentation   +225 added lines, -225 removed lines patch added patch discarded remove patch
@@ -15,248 +15,248 @@
 block discarded – undo
15 15
 class EE_SPCO_Reg_Step_Finalize_Registration extends EE_SPCO_Reg_Step
16 16
 {
17 17
 
18
-    /**
19
-     *    class constructor
20
-     *
21
-     * @access    public
22
-     * @param EE_Checkout $checkout
23
-     */
24
-    public function __construct(EE_Checkout $checkout)
25
-    {
26
-        $this->request             = EED_Single_Page_Checkout::getRequest();
27
-        $this->_slug               = 'finalize_registration';
28
-        $this->_name               = __('Finalize Registration', 'event_espresso');
29
-        $this->_submit_button_text = $this->_name;
30
-        $this->_template           = '';
31
-        $this->checkout            = $checkout;
32
-    }
18
+	/**
19
+	 *    class constructor
20
+	 *
21
+	 * @access    public
22
+	 * @param EE_Checkout $checkout
23
+	 */
24
+	public function __construct(EE_Checkout $checkout)
25
+	{
26
+		$this->request             = EED_Single_Page_Checkout::getRequest();
27
+		$this->_slug               = 'finalize_registration';
28
+		$this->_name               = __('Finalize Registration', 'event_espresso');
29
+		$this->_submit_button_text = $this->_name;
30
+		$this->_template           = '';
31
+		$this->checkout            = $checkout;
32
+	}
33 33
 
34 34
 
35
-    public function translate_js_strings()
36
-    {
37
-    }
35
+	public function translate_js_strings()
36
+	{
37
+	}
38 38
 
39 39
 
40
-    public function enqueue_styles_and_scripts()
41
-    {
42
-    }
40
+	public function enqueue_styles_and_scripts()
41
+	{
42
+	}
43 43
 
44 44
 
45
-    /**
46
-     * @return boolean
47
-     */
48
-    public function initialize_reg_step()
49
-    {
50
-        // there's actually no reg form to process if this is the final step
51
-        if ($this->is_current_step()) {
52
-            $this->checkout->step              = $this->slug();
53
-            $this->checkout->action            = 'process_reg_step';
54
-            $this->checkout->generate_reg_form = false;
55
-            $this->request->setRequestParam('step', $this->checkout->step);
56
-            $this->request->setRequestParam('action', $this->checkout->action);
57
-        }
58
-        return true;
59
-    }
45
+	/**
46
+	 * @return boolean
47
+	 */
48
+	public function initialize_reg_step()
49
+	{
50
+		// there's actually no reg form to process if this is the final step
51
+		if ($this->is_current_step()) {
52
+			$this->checkout->step              = $this->slug();
53
+			$this->checkout->action            = 'process_reg_step';
54
+			$this->checkout->generate_reg_form = false;
55
+			$this->request->setRequestParam('step', $this->checkout->step);
56
+			$this->request->setRequestParam('action', $this->checkout->action);
57
+		}
58
+		return true;
59
+	}
60 60
 
61 61
 
62
-    /**
63
-     * @return string
64
-     */
65
-    public function generate_reg_form()
66
-    {
67
-        // create empty form so that things don't break
68
-        $this->reg_form = new EE_Form_Section_Proper();
69
-        return '';
70
-    }
62
+	/**
63
+	 * @return string
64
+	 */
65
+	public function generate_reg_form()
66
+	{
67
+		// create empty form so that things don't break
68
+		$this->reg_form = new EE_Form_Section_Proper();
69
+		return '';
70
+	}
71 71
 
72 72
 
73
-    /**
74
-     * @return boolean
75
-     * @throws RuntimeException
76
-     * @throws EE_Error
77
-     * @throws ReflectionException
78
-     */
79
-    public function process_reg_step()
80
-    {
81
-        // ensure all data gets refreshed from the db
82
-        $this->checkout->refresh_all_entities(true);
83
-        // ensures that all details and statuses for transaction, registration, and payments are updated
84
-        $txn_update_params = $this->_finalize_transaction();
85
-        // maybe send messages
86
-        $this->_set_notification_triggers();
87
-        // send messages
88
-        /** @type EE_Registration_Processor $registration_processor */
89
-        $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
90
-        $registration_processor->trigger_registration_update_notifications(
91
-            $this->checkout->transaction->primary_registration(),
92
-            $txn_update_params
93
-        );
94
-        // set a hook point
95
-        do_action(
96
-            'AHEE__EE_SPCO_Reg_Step_Finalize_Registration__process_reg_step__completed',
97
-            $this->checkout,
98
-            $txn_update_params
99
-        );
100
-        // check if transaction has a primary registrant and that it has a related Attendee object
101
-        if (! $this->_validate_primary_registrant()) {
102
-            return false;
103
-        }
104
-        // you don't have to go home but you can't stay here !
105
-        $this->checkout->redirect     = true;
106
-        $this->checkout->continue_reg = true;
107
-        $this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
108
-        if (! (
109
-            $this->checkout->payment_method instanceof EE_Payment_Method
110
-            && $this->checkout->payment_method->is_off_site()
111
-        )) {
112
-            // mark this reg step as completed
113
-            $this->set_completed();
114
-        }
115
-        $this->checkout->set_exit_spco();
116
-        return true;
117
-    }
73
+	/**
74
+	 * @return boolean
75
+	 * @throws RuntimeException
76
+	 * @throws EE_Error
77
+	 * @throws ReflectionException
78
+	 */
79
+	public function process_reg_step()
80
+	{
81
+		// ensure all data gets refreshed from the db
82
+		$this->checkout->refresh_all_entities(true);
83
+		// ensures that all details and statuses for transaction, registration, and payments are updated
84
+		$txn_update_params = $this->_finalize_transaction();
85
+		// maybe send messages
86
+		$this->_set_notification_triggers();
87
+		// send messages
88
+		/** @type EE_Registration_Processor $registration_processor */
89
+		$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
90
+		$registration_processor->trigger_registration_update_notifications(
91
+			$this->checkout->transaction->primary_registration(),
92
+			$txn_update_params
93
+		);
94
+		// set a hook point
95
+		do_action(
96
+			'AHEE__EE_SPCO_Reg_Step_Finalize_Registration__process_reg_step__completed',
97
+			$this->checkout,
98
+			$txn_update_params
99
+		);
100
+		// check if transaction has a primary registrant and that it has a related Attendee object
101
+		if (! $this->_validate_primary_registrant()) {
102
+			return false;
103
+		}
104
+		// you don't have to go home but you can't stay here !
105
+		$this->checkout->redirect     = true;
106
+		$this->checkout->continue_reg = true;
107
+		$this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
108
+		if (! (
109
+			$this->checkout->payment_method instanceof EE_Payment_Method
110
+			&& $this->checkout->payment_method->is_off_site()
111
+		)) {
112
+			// mark this reg step as completed
113
+			$this->set_completed();
114
+		}
115
+		$this->checkout->set_exit_spco();
116
+		return true;
117
+	}
118 118
 
119 119
 
120
-    /**
121
-     * _finalize_transaction
122
-     * ensures that all details and statuses for transaction, registration, and payments are updated
123
-     *
124
-     * @return array
125
-     * @throws RuntimeException
126
-     * @throws EE_Error
127
-     * @throws ReflectionException
128
-     */
129
-    protected function _finalize_transaction()
130
-    {
131
-        /** @type EE_Transaction_Processor $transaction_processor */
132
-        $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
133
-        // set revisit flag in txn processor
134
-        $transaction_processor->set_revisit($this->checkout->revisit);
135
-        // at this point we'll consider a TXN to not have been abandoned
136
-        $this->checkout->transaction->toggle_abandoned_transaction_status();
137
-        if ($this->checkout->cart instanceof EE_Cart) {
138
-            // save TXN data to the cart
139
-            $this->checkout->cart->get_grand_total()->save_this_and_descendants_to_txn(
140
-                $this->checkout->transaction->ID()
141
-            );
142
-        }
143
-        // maybe update status, but don't save transaction just yet
144
-        $this->checkout->transaction->update_status_based_on_total_paid(false);
145
-        // this will result in the base session properties getting saved to the TXN_Session_data field
146
-        $session_data = EE_Registry::instance()->SSN->get_session_data(null, true);
147
-        // anonymize the last part of the IP address, now that the transaction is complete (we won't be using the IP address
148
-        // for spam or bot detection now)
149
-        if (function_exists('wp_privacy_anonymize_ip') && isset($session_data['ip_address'])) {
150
-            $session_data['ip_address'] = wp_privacy_anonymize_ip($session_data['ip_address']);
151
-        }
152
-        $this->checkout->transaction->set_txn_session_data($session_data);
153
-        // update the TXN if payment conditions have changed, but do NOT trigger notifications,
154
-        // because we will do that in process_reg_step() after setting some more triggers
155
-        return $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment(
156
-            $this->checkout->transaction,
157
-            $this->checkout->payment,
158
-            $this->checkout->reg_cache_where_params,
159
-            false
160
-        );
161
-    }
120
+	/**
121
+	 * _finalize_transaction
122
+	 * ensures that all details and statuses for transaction, registration, and payments are updated
123
+	 *
124
+	 * @return array
125
+	 * @throws RuntimeException
126
+	 * @throws EE_Error
127
+	 * @throws ReflectionException
128
+	 */
129
+	protected function _finalize_transaction()
130
+	{
131
+		/** @type EE_Transaction_Processor $transaction_processor */
132
+		$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
133
+		// set revisit flag in txn processor
134
+		$transaction_processor->set_revisit($this->checkout->revisit);
135
+		// at this point we'll consider a TXN to not have been abandoned
136
+		$this->checkout->transaction->toggle_abandoned_transaction_status();
137
+		if ($this->checkout->cart instanceof EE_Cart) {
138
+			// save TXN data to the cart
139
+			$this->checkout->cart->get_grand_total()->save_this_and_descendants_to_txn(
140
+				$this->checkout->transaction->ID()
141
+			);
142
+		}
143
+		// maybe update status, but don't save transaction just yet
144
+		$this->checkout->transaction->update_status_based_on_total_paid(false);
145
+		// this will result in the base session properties getting saved to the TXN_Session_data field
146
+		$session_data = EE_Registry::instance()->SSN->get_session_data(null, true);
147
+		// anonymize the last part of the IP address, now that the transaction is complete (we won't be using the IP address
148
+		// for spam or bot detection now)
149
+		if (function_exists('wp_privacy_anonymize_ip') && isset($session_data['ip_address'])) {
150
+			$session_data['ip_address'] = wp_privacy_anonymize_ip($session_data['ip_address']);
151
+		}
152
+		$this->checkout->transaction->set_txn_session_data($session_data);
153
+		// update the TXN if payment conditions have changed, but do NOT trigger notifications,
154
+		// because we will do that in process_reg_step() after setting some more triggers
155
+		return $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment(
156
+			$this->checkout->transaction,
157
+			$this->checkout->payment,
158
+			$this->checkout->reg_cache_where_params,
159
+			false
160
+		);
161
+	}
162 162
 
163 163
 
164
-    /**
165
-     * If request is not a revisit, and an Off-Site gateway using IPNs has NOT been selected...
166
-     * OR
167
-     * if it IS a revisit and the TXN and/or one or more REG statuses have changed...
168
-     * then trigger notifications
169
-     *
170
-     * @return void
171
-     * @throws EE_Error
172
-     * @throws ReflectionException
173
-     */
174
-    protected function _set_notification_triggers()
175
-    {
164
+	/**
165
+	 * If request is not a revisit, and an Off-Site gateway using IPNs has NOT been selected...
166
+	 * OR
167
+	 * if it IS a revisit and the TXN and/or one or more REG statuses have changed...
168
+	 * then trigger notifications
169
+	 *
170
+	 * @return void
171
+	 * @throws EE_Error
172
+	 * @throws ReflectionException
173
+	 */
174
+	protected function _set_notification_triggers()
175
+	{
176 176
 
177
-        if ($this->checkout->payment_method instanceof EE_Payment_Method) {
178
-            // let's start with the assumption that we need to trigger notifications
179
-            // then toggle this to false for conditions where we know we don't need to
180
-            $deliver_notifications = true;
181
-            if (// if SPCO revisit
182
-                filter_var($this->checkout->revisit, FILTER_VALIDATE_BOOLEAN)
183
-                // and TXN or REG statuses have NOT changed due to a payment
184
-                && ! (
185
-                    $this->checkout->transaction->txn_status_updated()
186
-                    || $this->checkout->any_reg_status_updated()
187
-                )
188
-            ) {
189
-                $deliver_notifications = false;
190
-            }
191
-            if ($this->checkout->payment_method->is_off_site()) {
192
-                /** @var EE_Gateway $gateway */
193
-                $gateway = $this->checkout->payment_method->type_obj()->get_gateway();
194
-                // and the gateway uses a separate request to process the IPN
195
-                /** @var RequestInterface $request */
196
-                $request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
197
-                if ($gateway instanceof EE_Offsite_Gateway
198
-                    && $gateway->handle_IPN_in_this_request($request->requestParams(), true)
199
-                ) {
200
-                    // IPN request will handle triggering notifications
201
-                    $deliver_notifications = false;
202
-                    // no really... don't send any notices in this request
203
-                    remove_all_filters('FHEE__EED_Messages___maybe_registration__deliver_notifications');
204
-                    add_filter(
205
-                        'FHEE__EED_Messages___maybe_registration__deliver_notifications',
206
-                        '__return_false',
207
-                        15
208
-                    );
209
-                }
210
-            }
211
-            if ($deliver_notifications) {
212
-                // send out notifications
213
-                add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true', 10);
214
-            }
215
-        }
216
-    }
177
+		if ($this->checkout->payment_method instanceof EE_Payment_Method) {
178
+			// let's start with the assumption that we need to trigger notifications
179
+			// then toggle this to false for conditions where we know we don't need to
180
+			$deliver_notifications = true;
181
+			if (// if SPCO revisit
182
+				filter_var($this->checkout->revisit, FILTER_VALIDATE_BOOLEAN)
183
+				// and TXN or REG statuses have NOT changed due to a payment
184
+				&& ! (
185
+					$this->checkout->transaction->txn_status_updated()
186
+					|| $this->checkout->any_reg_status_updated()
187
+				)
188
+			) {
189
+				$deliver_notifications = false;
190
+			}
191
+			if ($this->checkout->payment_method->is_off_site()) {
192
+				/** @var EE_Gateway $gateway */
193
+				$gateway = $this->checkout->payment_method->type_obj()->get_gateway();
194
+				// and the gateway uses a separate request to process the IPN
195
+				/** @var RequestInterface $request */
196
+				$request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
197
+				if ($gateway instanceof EE_Offsite_Gateway
198
+					&& $gateway->handle_IPN_in_this_request($request->requestParams(), true)
199
+				) {
200
+					// IPN request will handle triggering notifications
201
+					$deliver_notifications = false;
202
+					// no really... don't send any notices in this request
203
+					remove_all_filters('FHEE__EED_Messages___maybe_registration__deliver_notifications');
204
+					add_filter(
205
+						'FHEE__EED_Messages___maybe_registration__deliver_notifications',
206
+						'__return_false',
207
+						15
208
+					);
209
+				}
210
+			}
211
+			if ($deliver_notifications) {
212
+				// send out notifications
213
+				add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true', 10);
214
+			}
215
+		}
216
+	}
217 217
 
218 218
 
219
-    /**
220
-     * check if transaction has a primary registrant and that it has a related Attendee object
221
-     *
222
-     * @return boolean
223
-     * @throws EE_Error
224
-     * @throws ReflectionException
225
-     */
226
-    protected function _validate_primary_registrant()
227
-    {
228
-        if (! $this->checkout->transaction_has_primary_registrant()) {
229
-            EE_Error::add_error(
230
-                __('A valid Primary Registration for this Transaction could not be found.', 'event_espresso'),
231
-                __FILE__,
232
-                __FUNCTION__,
233
-                __LINE__
234
-            );
235
-            $this->checkout->redirect     = false;
236
-            $this->checkout->continue_reg = false;
237
-            return false;
238
-        }
239
-        // setup URL for redirect
240
-        $this->checkout->redirect_url = add_query_arg(
241
-            ['e_reg_url_link' => $this->checkout->transaction->primary_registration()->reg_url_link()],
242
-            $this->checkout->thank_you_page_url
243
-        );
244
-        return true;
245
-    }
219
+	/**
220
+	 * check if transaction has a primary registrant and that it has a related Attendee object
221
+	 *
222
+	 * @return boolean
223
+	 * @throws EE_Error
224
+	 * @throws ReflectionException
225
+	 */
226
+	protected function _validate_primary_registrant()
227
+	{
228
+		if (! $this->checkout->transaction_has_primary_registrant()) {
229
+			EE_Error::add_error(
230
+				__('A valid Primary Registration for this Transaction could not be found.', 'event_espresso'),
231
+				__FILE__,
232
+				__FUNCTION__,
233
+				__LINE__
234
+			);
235
+			$this->checkout->redirect     = false;
236
+			$this->checkout->continue_reg = false;
237
+			return false;
238
+		}
239
+		// setup URL for redirect
240
+		$this->checkout->redirect_url = add_query_arg(
241
+			['e_reg_url_link' => $this->checkout->transaction->primary_registration()->reg_url_link()],
242
+			$this->checkout->thank_you_page_url
243
+		);
244
+		return true;
245
+	}
246 246
 
247 247
 
248
-    /**
249
-     * @return void
250
-     */
251
-    public function update_reg_step()
252
-    {
253
-        EE_Error::doing_it_wrong(
254
-            __CLASS__ . '::' . __FILE__,
255
-            __(
256
-                'Can not call update_reg_step() on the Finalize Registration reg step.',
257
-                'event_espresso'
258
-            ),
259
-            '4.6.0'
260
-        );
261
-    }
248
+	/**
249
+	 * @return void
250
+	 */
251
+	public function update_reg_step()
252
+	{
253
+		EE_Error::doing_it_wrong(
254
+			__CLASS__ . '::' . __FILE__,
255
+			__(
256
+				'Can not call update_reg_step() on the Finalize Registration reg step.',
257
+				'event_espresso'
258
+			),
259
+			'4.6.0'
260
+		);
261
+	}
262 262
 }
Please login to merge, or discard this patch.
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -98,14 +98,14 @@  discard block
 block discarded – undo
98 98
             $txn_update_params
99 99
         );
100 100
         // check if transaction has a primary registrant and that it has a related Attendee object
101
-        if (! $this->_validate_primary_registrant()) {
101
+        if ( ! $this->_validate_primary_registrant()) {
102 102
             return false;
103 103
         }
104 104
         // you don't have to go home but you can't stay here !
105 105
         $this->checkout->redirect     = true;
106 106
         $this->checkout->continue_reg = true;
107 107
         $this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
108
-        if (! (
108
+        if ( ! (
109 109
             $this->checkout->payment_method instanceof EE_Payment_Method
110 110
             && $this->checkout->payment_method->is_off_site()
111 111
         )) {
@@ -225,7 +225,7 @@  discard block
 block discarded – undo
225 225
      */
226 226
     protected function _validate_primary_registrant()
227 227
     {
228
-        if (! $this->checkout->transaction_has_primary_registrant()) {
228
+        if ( ! $this->checkout->transaction_has_primary_registrant()) {
229 229
             EE_Error::add_error(
230 230
                 __('A valid Primary Registration for this Transaction could not be found.', 'event_espresso'),
231 231
                 __FILE__,
@@ -251,7 +251,7 @@  discard block
 block discarded – undo
251 251
     public function update_reg_step()
252 252
     {
253 253
         EE_Error::doing_it_wrong(
254
-            __CLASS__ . '::' . __FILE__,
254
+            __CLASS__.'::'.__FILE__,
255 255
             __(
256 256
                 'Can not call update_reg_step() on the Finalize Registration reg step.',
257 257
                 'event_espresso'
Please login to merge, or discard this patch.