Completed
Branch FET/Gutenberg/11467/espresso-c... (b0019e)
by
unknown
80:52 queued 67:02
created
admin_pages/transactions/templates/txn_admin_details_header.template.php 1 patch
Spacing   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -1,17 +1,17 @@
 block discarded – undo
1 1
 
2
-		<h3 class="txn-navigation-strip"><?php echo $previous_transaction . '&nbsp;'; echo __( 'Transaction # ', 'event_espresso' ) . $txn_nmbr['value']; echo '&nbsp;' . $next_transaction; ?></h3>
3
-		<h2 id="txn-date-h2" class="txn-date-h2"><?php echo $txn_datetime['value'];?></h2>
2
+		<h3 class="txn-navigation-strip"><?php echo $previous_transaction.'&nbsp;'; echo __('Transaction # ', 'event_espresso').$txn_nmbr['value']; echo '&nbsp;'.$next_transaction; ?></h3>
3
+		<h2 id="txn-date-h2" class="txn-date-h2"><?php echo $txn_datetime['value']; ?></h2>
4 4
 		<h2 id="txn-status-h2" class="txn-status-h2">
5
-			<?php echo __( 'Transaction Status: ', 'event_espresso' );?><span id="txn-status" class="<?php echo $txn_status['class'];?>"><?php echo $txn_status['value'];?></span>
5
+			<?php echo __('Transaction Status: ', 'event_espresso'); ?><span id="txn-status" class="<?php echo $txn_status['class']; ?>"><?php echo $txn_status['value']; ?></span>
6 6
 		</h2>
7 7
 
8 8
 	<?php $attributes = $amount_due ? 'class="txn-amount-due-h2"' : 'class="txn-amount-due-h2 hidden"'; ?>
9 9
 		<h2 id="txn-amount-due-h2" <?php echo $attributes; ?>>
10
-			<?php echo __( 'Total Amount Due: ', 'event_espresso' );?><span id="txn-admin-total-amount-due" class="<?php echo $amount_due_class;?>"><?php echo $amount_due;?></span>
10
+			<?php echo __('Total Amount Due: ', 'event_espresso'); ?><span id="txn-admin-total-amount-due" class="<?php echo $amount_due_class; ?>"><?php echo $amount_due; ?></span>
11 11
 		</h2>
12 12
 
13 13
 		<h3 id="txn-selected-method-of-payment-h3" class="txn-selected-method-of-payment-h3">
14
-			<?php echo __( 'Last Method of Payment: ', 'event_espresso' );?><?php echo $method_of_payment_name;?>
14
+			<?php echo __('Last Method of Payment: ', 'event_espresso'); ?><?php echo $method_of_payment_name; ?>
15 15
 		</h3>
16 16
 
17 17
 
Please login to merge, or discard this patch.
core/helpers/EEH_Activation.helper.php 2 patches
Spacing   +28 added lines, -28 removed lines patch added patch discarded remove patch
@@ -57,7 +57,7 @@  discard block
 block discarded – undo
57 57
      */
58 58
     public static function getTableAnalysis()
59 59
     {
60
-        if (! self::$table_analysis instanceof \EventEspresso\core\services\database\TableAnalysis) {
60
+        if ( ! self::$table_analysis instanceof \EventEspresso\core\services\database\TableAnalysis) {
61 61
             self::$table_analysis = EE_Registry::instance()->create('TableAnalysis', array(), true);
62 62
         }
63 63
         return self::$table_analysis;
@@ -69,7 +69,7 @@  discard block
 block discarded – undo
69 69
      */
70 70
     public static function getTableManager()
71 71
     {
72
-        if (! self::$table_manager instanceof \EventEspresso\core\services\database\TableManager) {
72
+        if ( ! self::$table_manager instanceof \EventEspresso\core\services\database\TableManager) {
73 73
             self::$table_manager = EE_Registry::instance()->create('TableManager', array(), true);
74 74
         }
75 75
         return self::$table_manager;
@@ -183,7 +183,7 @@  discard block
 block discarded – undo
183 183
         if ($which_to_include === 'old') {
184 184
             $cron_tasks = array_filter(
185 185
                 $cron_tasks,
186
-                function ($value) {
186
+                function($value) {
187 187
                     return $value === EEH_Activation::cron_task_no_longer_in_use;
188 188
                 }
189 189
             );
@@ -213,7 +213,7 @@  discard block
 block discarded – undo
213 213
     {
214 214
 
215 215
         foreach (EEH_Activation::get_cron_tasks('current') as $hook_name => $frequency) {
216
-            if (! wp_next_scheduled($hook_name)) {
216
+            if ( ! wp_next_scheduled($hook_name)) {
217 217
                 /**
218 218
                  * This allows client code to define the initial start timestamp for this schedule.
219 219
                  */
@@ -318,7 +318,7 @@  discard block
 block discarded – undo
318 318
             3
319 319
         );
320 320
         //EE_Config::reset();
321
-        if (! EE_Config::logging_enabled()) {
321
+        if ( ! EE_Config::logging_enabled()) {
322 322
             delete_option(EE_Config::LOG_NAME);
323 323
         }
324 324
     }
@@ -333,7 +333,7 @@  discard block
 block discarded – undo
333 333
     public static function load_calendar_config()
334 334
     {
335 335
         // grab array of all plugin folders and loop thru it
336
-        $plugins = glob(WP_PLUGIN_DIR . DS . '*', GLOB_ONLYDIR);
336
+        $plugins = glob(WP_PLUGIN_DIR.DS.'*', GLOB_ONLYDIR);
337 337
         if (empty($plugins)) {
338 338
             return;
339 339
         }
@@ -350,7 +350,7 @@  discard block
 block discarded – undo
350 350
                 || strpos($plugin, 'calendar') !== false
351 351
             ) {
352 352
                 // this is what we are looking for
353
-                $calendar_config = $plugin_path . DS . 'EE_Calendar_Config.php';
353
+                $calendar_config = $plugin_path.DS.'EE_Calendar_Config.php';
354 354
                 // does it exist in this folder ?
355 355
                 if (is_readable($calendar_config)) {
356 356
                     // YEAH! let's load it
@@ -478,7 +478,7 @@  discard block
 block discarded – undo
478 478
             ) {
479 479
                 //update Config with post ID
480 480
                 $EE_Core_Config->{$critical_page['id']} = $critical_page['post']->ID;
481
-                if (! EE_Config::instance()->update_espresso_config(false, false)) {
481
+                if ( ! EE_Config::instance()->update_espresso_config(false, false)) {
482 482
                     $msg = __(
483 483
                         'The Event Espresso critical page configuration settings could not be updated.',
484 484
                         'event_espresso'
@@ -501,7 +501,7 @@  discard block
 block discarded – undo
501 501
                         'A potential issue has been detected with one or more of your Event Espresso pages. Go to %s to view your Event Espresso pages.',
502 502
                         'event_espresso'
503 503
                     ),
504
-                    '<a href="' . admin_url('admin.php?page=espresso_general_settings&action=critical_pages') . '">'
504
+                    '<a href="'.admin_url('admin.php?page=espresso_general_settings&action=critical_pages').'">'
505 505
                     . __('Event Espresso Critical Pages Settings', 'event_espresso')
506 506
                     . '</a>'
507 507
                 )
@@ -527,7 +527,7 @@  discard block
 block discarded – undo
527 527
     public static function get_page_by_ee_shortcode($ee_shortcode)
528 528
     {
529 529
         global $wpdb;
530
-        $shortcode_and_opening_bracket = '[' . $ee_shortcode;
530
+        $shortcode_and_opening_bracket = '['.$ee_shortcode;
531 531
         $post_id = $wpdb->get_var("SELECT ID FROM {$wpdb->posts} WHERE post_content LIKE '%$shortcode_and_opening_bracket%' LIMIT 1");
532 532
         if ($post_id) {
533 533
             return get_post($post_id);
@@ -553,11 +553,11 @@  discard block
 block discarded – undo
553 553
             'post_status'    => 'publish',
554 554
             'post_type'      => 'page',
555 555
             'comment_status' => 'closed',
556
-            'post_content'   => '[' . $critical_page['code'] . ']',
556
+            'post_content'   => '['.$critical_page['code'].']',
557 557
         );
558 558
 
559 559
         $post_id = wp_insert_post($post_args);
560
-        if (! $post_id) {
560
+        if ( ! $post_id) {
561 561
             $msg = sprintf(
562 562
                 __('The Event Espresso  critical page entitled "%s" could not be created.', 'event_espresso'),
563 563
                 $critical_page['name']
@@ -566,7 +566,7 @@  discard block
 block discarded – undo
566 566
             return $critical_page;
567 567
         }
568 568
         // get newly created post's details
569
-        if (! $critical_page['post'] = get_post($post_id)) {
569
+        if ( ! $critical_page['post'] = get_post($post_id)) {
570 570
             $msg = sprintf(
571 571
                 __('The Event Espresso critical page entitled "%s" could not be retrieved.', 'event_espresso'),
572 572
                 $critical_page['name']
@@ -603,17 +603,17 @@  discard block
 block discarded – undo
603 603
             $role_to_check
604 604
         );
605 605
         if ($pre_filtered_id !== false) {
606
-            return (int)$pre_filtered_id;
606
+            return (int) $pre_filtered_id;
607 607
         }
608 608
         $capabilities_key = \EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix('capabilities');
609 609
         $query = $wpdb->prepare(
610 610
             "SELECT user_id FROM $wpdb->usermeta WHERE meta_key = '$capabilities_key' AND meta_value LIKE %s ORDER BY user_id ASC LIMIT 0,1",
611
-            '%' . $role_to_check . '%'
611
+            '%'.$role_to_check.'%'
612 612
         );
613 613
         $user_id = $wpdb->get_var($query);
614 614
         $user_id = apply_filters('FHEE__EEH_Activation_Helper__get_default_creator_id__user_id', $user_id);
615
-        if ($user_id && (int)$user_id) {
616
-            self::$_default_creator_id = (int)$user_id;
615
+        if ($user_id && (int) $user_id) {
616
+            self::$_default_creator_id = (int) $user_id;
617 617
             return self::$_default_creator_id;
618 618
         } else {
619 619
             return null;
@@ -648,7 +648,7 @@  discard block
 block discarded – undo
648 648
         }
649 649
         do_action('AHEE_log', __FILE__, __FUNCTION__, '');
650 650
         if ( ! function_exists('dbDelta')) {
651
-            require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
651
+            require_once(ABSPATH.'wp-admin/includes/upgrade.php');
652 652
         }
653 653
         $tableAnalysis = \EEH_Activation::getTableAnalysis();
654 654
         $wp_table_name = $tableAnalysis->ensureTableNameHasPrefix($table_name);
@@ -859,13 +859,13 @@  discard block
 block discarded – undo
859 859
             // reset values array
860 860
             $QSG_values = array();
861 861
             // if we don't have what we should have (but use $QST_system as as string because that's what we got from the db)
862
-            if (! in_array("$QSG_system", $question_groups)) {
862
+            if ( ! in_array("$QSG_system", $question_groups)) {
863 863
                 // add it
864 864
                 switch ($QSG_system) {
865 865
                     case 1:
866 866
                         $QSG_values = array(
867 867
                             'QSG_name'            => __('Personal Information', 'event_espresso'),
868
-                            'QSG_identifier'      => 'personal-information-' . time(),
868
+                            'QSG_identifier'      => 'personal-information-'.time(),
869 869
                             'QSG_desc'            => '',
870 870
                             'QSG_order'           => 1,
871 871
                             'QSG_show_group_name' => 1,
@@ -877,7 +877,7 @@  discard block
 block discarded – undo
877 877
                     case 2:
878 878
                         $QSG_values = array(
879 879
                             'QSG_name'            => __('Address Information', 'event_espresso'),
880
-                            'QSG_identifier'      => 'address-information-' . time(),
880
+                            'QSG_identifier'      => 'address-information-'.time(),
881 881
                             'QSG_desc'            => '',
882 882
                             'QSG_order'           => 2,
883 883
                             'QSG_show_group_name' => 1,
@@ -888,7 +888,7 @@  discard block
 block discarded – undo
888 888
                         break;
889 889
                 }
890 890
                 // make sure we have some values before inserting them
891
-                if (! empty($QSG_values)) {
891
+                if ( ! empty($QSG_values)) {
892 892
                     // insert system question
893 893
                     $wpdb->insert(
894 894
                         $table_name,
@@ -925,7 +925,7 @@  discard block
 block discarded – undo
925 925
             // reset values array
926 926
             $QST_values = array();
927 927
             // if we don't have what we should have
928
-            if (! in_array($QST_system, $questions)) {
928
+            if ( ! in_array($QST_system, $questions)) {
929 929
                 // add it
930 930
                 switch ($QST_system) {
931 931
                     case 'fname':
@@ -1077,7 +1077,7 @@  discard block
 block discarded – undo
1077 1077
                         );
1078 1078
                         break;
1079 1079
                 }
1080
-                if (! empty($QST_values)) {
1080
+                if ( ! empty($QST_values)) {
1081 1081
                     // insert system question
1082 1082
                     $wpdb->insert(
1083 1083
                         $table_name,
@@ -1138,7 +1138,7 @@  discard block
 block discarded – undo
1138 1138
      */
1139 1139
     public static function insert_default_payment_methods()
1140 1140
     {
1141
-        if (! EEM_Payment_Method::instance()->count_active(EEM_Payment_Method::scope_cart)) {
1141
+        if ( ! EEM_Payment_Method::instance()->count_active(EEM_Payment_Method::scope_cart)) {
1142 1142
             EE_Registry::instance()->load_lib('Payment_Method_Manager');
1143 1143
             EE_Payment_Method_Manager::instance()->activate_a_payment_method_of_type('Invoice');
1144 1144
         } else {
@@ -1427,7 +1427,7 @@  discard block
 block discarded – undo
1427 1427
         // this creates an array for tracking events that have no active ticket prices created
1428 1428
         // this allows us to warn admins of the situation so that it can be corrected
1429 1429
         $espresso_no_ticket_prices = get_option('ee_no_ticket_prices', false);
1430
-        if (! $espresso_no_ticket_prices) {
1430
+        if ( ! $espresso_no_ticket_prices) {
1431 1431
             add_option('ee_no_ticket_prices', array(), '', false);
1432 1432
         }
1433 1433
     }
@@ -1466,7 +1466,7 @@  discard block
 block discarded – undo
1466 1466
             }
1467 1467
         }
1468 1468
         //get all our CPTs
1469
-        $query   = "SELECT ID FROM {$wpdb->posts} WHERE post_type IN (" . implode(",", $ee_post_types) . ")";
1469
+        $query   = "SELECT ID FROM {$wpdb->posts} WHERE post_type IN (".implode(",", $ee_post_types).")";
1470 1470
         $cpt_ids = $wpdb->get_col($query);
1471 1471
         //delete each post meta and term relations too
1472 1472
         foreach ($cpt_ids as $post_id) {
@@ -1606,7 +1606,7 @@  discard block
 block discarded – undo
1606 1606
         if ($remove_all && $espresso_db_update = get_option('espresso_db_update')) {
1607 1607
             $db_update_sans_ee4 = array();
1608 1608
             foreach ($espresso_db_update as $version => $times_activated) {
1609
-                if ((string)$version[0] === '3') {//if its NON EE4
1609
+                if ((string) $version[0] === '3') {//if its NON EE4
1610 1610
                     $db_update_sans_ee4[$version] = $times_activated;
1611 1611
                 }
1612 1612
             }
Please login to merge, or discard this patch.
Indentation   +1581 added lines, -1581 removed lines patch added patch discarded remove patch
@@ -19,233 +19,233 @@  discard block
 block discarded – undo
19 19
 class EEH_Activation implements ResettableInterface
20 20
 {
21 21
 
22
-    /**
23
-     * constant used to indicate a cron task is no longer in use
24
-     */
25
-    const cron_task_no_longer_in_use = 'no_longer_in_use';
26
-
27
-    /**
28
-     * WP_User->ID
29
-     *
30
-     * @var int
31
-     */
32
-    private static $_default_creator_id;
33
-
34
-    /**
35
-     * indicates whether or not we've already verified core's default data during this request,
36
-     * because after migrations are done, any addons activated while in maintenance mode
37
-     * will want to setup their own default data, and they might hook into core's default data
38
-     * and trigger core to setup its default data. In which case they might all ask for core to init its default data.
39
-     * This prevents doing that for EVERY single addon.
40
-     *
41
-     * @var boolean
42
-     */
43
-    protected static $_initialized_db_content_already_in_this_request = false;
44
-
45
-    /**
46
-     * @var \EventEspresso\core\services\database\TableAnalysis $table_analysis
47
-     */
48
-    private static $table_analysis;
49
-
50
-    /**
51
-     * @var \EventEspresso\core\services\database\TableManager $table_manager
52
-     */
53
-    private static $table_manager;
54
-
55
-
56
-    /**
57
-     * @return \EventEspresso\core\services\database\TableAnalysis
58
-     */
59
-    public static function getTableAnalysis()
60
-    {
61
-        if (! self::$table_analysis instanceof \EventEspresso\core\services\database\TableAnalysis) {
62
-            self::$table_analysis = EE_Registry::instance()->create('TableAnalysis', array(), true);
63
-        }
64
-        return self::$table_analysis;
65
-    }
66
-
67
-
68
-    /**
69
-     * @return \EventEspresso\core\services\database\TableManager
70
-     */
71
-    public static function getTableManager()
72
-    {
73
-        if (! self::$table_manager instanceof \EventEspresso\core\services\database\TableManager) {
74
-            self::$table_manager = EE_Registry::instance()->create('TableManager', array(), true);
75
-        }
76
-        return self::$table_manager;
77
-    }
78
-
79
-
80
-    /**
81
-     *    _ensure_table_name_has_prefix
82
-     *
83
-     * @deprecated instead use TableAnalysis::ensureTableNameHasPrefix()
84
-     * @access     public
85
-     * @static
86
-     * @param $table_name
87
-     * @return string
88
-     */
89
-    public static function ensure_table_name_has_prefix($table_name)
90
-    {
91
-        return \EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix($table_name);
92
-    }
93
-
94
-
95
-    /**
96
-     *    system_initialization
97
-     *    ensures the EE configuration settings are loaded with at least default options set
98
-     *    and that all critical EE pages have been generated with the appropriate shortcodes in place
99
-     *
100
-     * @access public
101
-     * @static
102
-     * @return void
103
-     */
104
-    public static function system_initialization()
105
-    {
106
-        EEH_Activation::reset_and_update_config();
107
-        //which is fired BEFORE activation of plugin anyways
108
-        EEH_Activation::verify_default_pages_exist();
109
-    }
110
-
111
-
112
-    /**
113
-     * Sets the database schema and creates folders. This should
114
-     * be called on plugin activation and reactivation
115
-     *
116
-     * @return boolean success, whether the database and folders are setup properly
117
-     * @throws \EE_Error
118
-     */
119
-    public static function initialize_db_and_folders()
120
-    {
121
-        return EEH_Activation::create_database_tables();
122
-    }
123
-
124
-
125
-    /**
126
-     * assuming we have an up-to-date database schema, this will populate it
127
-     * with default and initial data. This should be called
128
-     * upon activation of a new plugin, reactivation, and at the end
129
-     * of running migration scripts
130
-     *
131
-     * @throws \EE_Error
132
-     */
133
-    public static function initialize_db_content()
134
-    {
135
-        //let's avoid doing all this logic repeatedly, especially when addons are requesting it
136
-        if (EEH_Activation::$_initialized_db_content_already_in_this_request) {
137
-            return;
138
-        }
139
-        EEH_Activation::$_initialized_db_content_already_in_this_request = true;
140
-
141
-        EEH_Activation::initialize_system_questions();
142
-        EEH_Activation::insert_default_status_codes();
143
-        EEH_Activation::generate_default_message_templates();
144
-        EEH_Activation::create_no_ticket_prices_array();
145
-
146
-        EEH_Activation::validate_messages_system();
147
-        EEH_Activation::insert_default_payment_methods();
148
-        //in case we've
149
-        EEH_Activation::remove_cron_tasks();
150
-        EEH_Activation::create_cron_tasks();
151
-        // remove all TXN locks since that is being done via extra meta now
152
-        delete_option('ee_locked_transactions');
153
-        //also, check for CAF default db content
154
-        do_action('AHEE__EEH_Activation__initialize_db_content');
155
-        //also: EEM_Gateways::load_all_gateways() outputs a lot of success messages
156
-        //which users really won't care about on initial activation
157
-        EE_Error::overwrite_success();
158
-    }
159
-
160
-
161
-    /**
162
-     * Returns an array of cron tasks. Array values are the actions fired by the cron tasks (the "hooks"),
163
-     * values are the frequency (the "recurrence"). See http://codex.wordpress.org/Function_Reference/wp_schedule_event
164
-     * If the cron task should NO longer be used, it should have a value of EEH_Activation::cron_task_no_longer_in_use
165
-     * (null)
166
-     *
167
-     * @param string $which_to_include can be 'current' (ones that are currently in use),
168
-     *                                 'old' (only returns ones that should no longer be used),or 'all',
169
-     * @return array
170
-     * @throws \EE_Error
171
-     */
172
-    public static function get_cron_tasks($which_to_include)
173
-    {
174
-        $cron_tasks = apply_filters(
175
-            'FHEE__EEH_Activation__get_cron_tasks',
176
-            array(
177
-                'AHEE__EE_Cron_Tasks__clean_up_junk_transactions'      => 'hourly',
22
+	/**
23
+	 * constant used to indicate a cron task is no longer in use
24
+	 */
25
+	const cron_task_no_longer_in_use = 'no_longer_in_use';
26
+
27
+	/**
28
+	 * WP_User->ID
29
+	 *
30
+	 * @var int
31
+	 */
32
+	private static $_default_creator_id;
33
+
34
+	/**
35
+	 * indicates whether or not we've already verified core's default data during this request,
36
+	 * because after migrations are done, any addons activated while in maintenance mode
37
+	 * will want to setup their own default data, and they might hook into core's default data
38
+	 * and trigger core to setup its default data. In which case they might all ask for core to init its default data.
39
+	 * This prevents doing that for EVERY single addon.
40
+	 *
41
+	 * @var boolean
42
+	 */
43
+	protected static $_initialized_db_content_already_in_this_request = false;
44
+
45
+	/**
46
+	 * @var \EventEspresso\core\services\database\TableAnalysis $table_analysis
47
+	 */
48
+	private static $table_analysis;
49
+
50
+	/**
51
+	 * @var \EventEspresso\core\services\database\TableManager $table_manager
52
+	 */
53
+	private static $table_manager;
54
+
55
+
56
+	/**
57
+	 * @return \EventEspresso\core\services\database\TableAnalysis
58
+	 */
59
+	public static function getTableAnalysis()
60
+	{
61
+		if (! self::$table_analysis instanceof \EventEspresso\core\services\database\TableAnalysis) {
62
+			self::$table_analysis = EE_Registry::instance()->create('TableAnalysis', array(), true);
63
+		}
64
+		return self::$table_analysis;
65
+	}
66
+
67
+
68
+	/**
69
+	 * @return \EventEspresso\core\services\database\TableManager
70
+	 */
71
+	public static function getTableManager()
72
+	{
73
+		if (! self::$table_manager instanceof \EventEspresso\core\services\database\TableManager) {
74
+			self::$table_manager = EE_Registry::instance()->create('TableManager', array(), true);
75
+		}
76
+		return self::$table_manager;
77
+	}
78
+
79
+
80
+	/**
81
+	 *    _ensure_table_name_has_prefix
82
+	 *
83
+	 * @deprecated instead use TableAnalysis::ensureTableNameHasPrefix()
84
+	 * @access     public
85
+	 * @static
86
+	 * @param $table_name
87
+	 * @return string
88
+	 */
89
+	public static function ensure_table_name_has_prefix($table_name)
90
+	{
91
+		return \EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix($table_name);
92
+	}
93
+
94
+
95
+	/**
96
+	 *    system_initialization
97
+	 *    ensures the EE configuration settings are loaded with at least default options set
98
+	 *    and that all critical EE pages have been generated with the appropriate shortcodes in place
99
+	 *
100
+	 * @access public
101
+	 * @static
102
+	 * @return void
103
+	 */
104
+	public static function system_initialization()
105
+	{
106
+		EEH_Activation::reset_and_update_config();
107
+		//which is fired BEFORE activation of plugin anyways
108
+		EEH_Activation::verify_default_pages_exist();
109
+	}
110
+
111
+
112
+	/**
113
+	 * Sets the database schema and creates folders. This should
114
+	 * be called on plugin activation and reactivation
115
+	 *
116
+	 * @return boolean success, whether the database and folders are setup properly
117
+	 * @throws \EE_Error
118
+	 */
119
+	public static function initialize_db_and_folders()
120
+	{
121
+		return EEH_Activation::create_database_tables();
122
+	}
123
+
124
+
125
+	/**
126
+	 * assuming we have an up-to-date database schema, this will populate it
127
+	 * with default and initial data. This should be called
128
+	 * upon activation of a new plugin, reactivation, and at the end
129
+	 * of running migration scripts
130
+	 *
131
+	 * @throws \EE_Error
132
+	 */
133
+	public static function initialize_db_content()
134
+	{
135
+		//let's avoid doing all this logic repeatedly, especially when addons are requesting it
136
+		if (EEH_Activation::$_initialized_db_content_already_in_this_request) {
137
+			return;
138
+		}
139
+		EEH_Activation::$_initialized_db_content_already_in_this_request = true;
140
+
141
+		EEH_Activation::initialize_system_questions();
142
+		EEH_Activation::insert_default_status_codes();
143
+		EEH_Activation::generate_default_message_templates();
144
+		EEH_Activation::create_no_ticket_prices_array();
145
+
146
+		EEH_Activation::validate_messages_system();
147
+		EEH_Activation::insert_default_payment_methods();
148
+		//in case we've
149
+		EEH_Activation::remove_cron_tasks();
150
+		EEH_Activation::create_cron_tasks();
151
+		// remove all TXN locks since that is being done via extra meta now
152
+		delete_option('ee_locked_transactions');
153
+		//also, check for CAF default db content
154
+		do_action('AHEE__EEH_Activation__initialize_db_content');
155
+		//also: EEM_Gateways::load_all_gateways() outputs a lot of success messages
156
+		//which users really won't care about on initial activation
157
+		EE_Error::overwrite_success();
158
+	}
159
+
160
+
161
+	/**
162
+	 * Returns an array of cron tasks. Array values are the actions fired by the cron tasks (the "hooks"),
163
+	 * values are the frequency (the "recurrence"). See http://codex.wordpress.org/Function_Reference/wp_schedule_event
164
+	 * If the cron task should NO longer be used, it should have a value of EEH_Activation::cron_task_no_longer_in_use
165
+	 * (null)
166
+	 *
167
+	 * @param string $which_to_include can be 'current' (ones that are currently in use),
168
+	 *                                 'old' (only returns ones that should no longer be used),or 'all',
169
+	 * @return array
170
+	 * @throws \EE_Error
171
+	 */
172
+	public static function get_cron_tasks($which_to_include)
173
+	{
174
+		$cron_tasks = apply_filters(
175
+			'FHEE__EEH_Activation__get_cron_tasks',
176
+			array(
177
+				'AHEE__EE_Cron_Tasks__clean_up_junk_transactions'      => 'hourly',
178 178
 //				'AHEE__EE_Cron_Tasks__finalize_abandoned_transactions' => EEH_Activation::cron_task_no_longer_in_use, actually this is still in use
179
-                'AHEE__EE_Cron_Tasks__update_transaction_with_payment' => EEH_Activation::cron_task_no_longer_in_use,
180
-                //there may have been a bug which prevented from these cron tasks from getting unscheduled, so we might want to remove these for a few updates
181
-                'AHEE_EE_Cron_Tasks__clean_out_old_gateway_logs'       => 'daily',
182
-            )
183
-        );
184
-        if ($which_to_include === 'old') {
185
-            $cron_tasks = array_filter(
186
-                $cron_tasks,
187
-                function ($value) {
188
-                    return $value === EEH_Activation::cron_task_no_longer_in_use;
189
-                }
190
-            );
191
-        } elseif ($which_to_include === 'current') {
192
-            $cron_tasks = array_filter($cron_tasks);
193
-        } elseif (WP_DEBUG && $which_to_include !== 'all') {
194
-            throw new EE_Error(
195
-                sprintf(
196
-                    __(
197
-                        'Invalid argument of "%1$s" passed to EEH_Activation::get_cron_tasks. Valid values are "all", "old" and "current".',
198
-                        'event_espresso'
199
-                    ),
200
-                    $which_to_include
201
-                )
202
-            );
203
-        }
204
-        return $cron_tasks;
205
-    }
206
-
207
-
208
-    /**
209
-     * Ensure cron tasks are setup (the removal of crons should be done by remove_crons())
210
-     *
211
-     * @throws \EE_Error
212
-     */
213
-    public static function create_cron_tasks()
214
-    {
215
-
216
-        foreach (EEH_Activation::get_cron_tasks('current') as $hook_name => $frequency) {
217
-            if (! wp_next_scheduled($hook_name)) {
218
-                /**
219
-                 * This allows client code to define the initial start timestamp for this schedule.
220
-                 */
221
-                if (is_array($frequency)
222
-                    && count($frequency) === 2
223
-                    && isset($frequency[0], $frequency[1])
224
-                ) {
225
-                    $start_timestamp = $frequency[0];
226
-                    $frequency = $frequency[1];
227
-                } else {
228
-                    $start_timestamp = time();
229
-                }
230
-                wp_schedule_event($start_timestamp, $frequency, $hook_name);
231
-            }
232
-        }
233
-
234
-    }
235
-
236
-
237
-    /**
238
-     * Remove the currently-existing and now-removed cron tasks.
239
-     *
240
-     * @param boolean $remove_all whether to only remove the old ones, or remove absolutely ALL the EE ones
241
-     * @throws \EE_Error
242
-     */
243
-    public static function remove_cron_tasks($remove_all = true)
244
-    {
245
-        $cron_tasks_to_remove = $remove_all ? 'all' : 'old';
246
-        $crons                = _get_cron_array();
247
-        $crons                = is_array($crons) ? $crons : array();
248
-        /* reminder of what $crons look like:
179
+				'AHEE__EE_Cron_Tasks__update_transaction_with_payment' => EEH_Activation::cron_task_no_longer_in_use,
180
+				//there may have been a bug which prevented from these cron tasks from getting unscheduled, so we might want to remove these for a few updates
181
+				'AHEE_EE_Cron_Tasks__clean_out_old_gateway_logs'       => 'daily',
182
+			)
183
+		);
184
+		if ($which_to_include === 'old') {
185
+			$cron_tasks = array_filter(
186
+				$cron_tasks,
187
+				function ($value) {
188
+					return $value === EEH_Activation::cron_task_no_longer_in_use;
189
+				}
190
+			);
191
+		} elseif ($which_to_include === 'current') {
192
+			$cron_tasks = array_filter($cron_tasks);
193
+		} elseif (WP_DEBUG && $which_to_include !== 'all') {
194
+			throw new EE_Error(
195
+				sprintf(
196
+					__(
197
+						'Invalid argument of "%1$s" passed to EEH_Activation::get_cron_tasks. Valid values are "all", "old" and "current".',
198
+						'event_espresso'
199
+					),
200
+					$which_to_include
201
+				)
202
+			);
203
+		}
204
+		return $cron_tasks;
205
+	}
206
+
207
+
208
+	/**
209
+	 * Ensure cron tasks are setup (the removal of crons should be done by remove_crons())
210
+	 *
211
+	 * @throws \EE_Error
212
+	 */
213
+	public static function create_cron_tasks()
214
+	{
215
+
216
+		foreach (EEH_Activation::get_cron_tasks('current') as $hook_name => $frequency) {
217
+			if (! wp_next_scheduled($hook_name)) {
218
+				/**
219
+				 * This allows client code to define the initial start timestamp for this schedule.
220
+				 */
221
+				if (is_array($frequency)
222
+					&& count($frequency) === 2
223
+					&& isset($frequency[0], $frequency[1])
224
+				) {
225
+					$start_timestamp = $frequency[0];
226
+					$frequency = $frequency[1];
227
+				} else {
228
+					$start_timestamp = time();
229
+				}
230
+				wp_schedule_event($start_timestamp, $frequency, $hook_name);
231
+			}
232
+		}
233
+
234
+	}
235
+
236
+
237
+	/**
238
+	 * Remove the currently-existing and now-removed cron tasks.
239
+	 *
240
+	 * @param boolean $remove_all whether to only remove the old ones, or remove absolutely ALL the EE ones
241
+	 * @throws \EE_Error
242
+	 */
243
+	public static function remove_cron_tasks($remove_all = true)
244
+	{
245
+		$cron_tasks_to_remove = $remove_all ? 'all' : 'old';
246
+		$crons                = _get_cron_array();
247
+		$crons                = is_array($crons) ? $crons : array();
248
+		/* reminder of what $crons look like:
249 249
          * Top-level keys are timestamps, and their values are arrays.
250 250
          * The 2nd level arrays have keys with each of the cron task hook names to run at that time
251 251
          * and their values are arrays.
@@ -262,911 +262,911 @@  discard block
 block discarded – undo
262 262
          *					...
263 263
          *      ...
264 264
          */
265
-        $ee_cron_tasks_to_remove = EEH_Activation::get_cron_tasks($cron_tasks_to_remove);
266
-        foreach ($crons as $timestamp => $hooks_to_fire_at_time) {
267
-            if (is_array($hooks_to_fire_at_time)) {
268
-                foreach ($hooks_to_fire_at_time as $hook_name => $hook_actions) {
269
-                    if (isset($ee_cron_tasks_to_remove[$hook_name])
270
-                        && is_array($ee_cron_tasks_to_remove[$hook_name])
271
-                    ) {
272
-                        unset($crons[$timestamp][$hook_name]);
273
-                    }
274
-                }
275
-                //also take care of any empty cron timestamps.
276
-                if (empty($hooks_to_fire_at_time)) {
277
-                    unset($crons[$timestamp]);
278
-                }
279
-            }
280
-        }
281
-        _set_cron_array($crons);
282
-    }
283
-
284
-
285
-    /**
286
-     *    CPT_initialization
287
-     *    registers all EE CPTs ( Custom Post Types ) then flushes rewrite rules so that all endpoints exist
288
-     *
289
-     * @access public
290
-     * @static
291
-     * @return void
292
-     */
293
-    public static function CPT_initialization()
294
-    {
295
-        // register Custom Post Types
296
-        EE_Registry::instance()->load_core('Register_CPTs');
297
-        flush_rewrite_rules();
298
-    }
299
-
300
-
301
-
302
-    /**
303
-     *    reset_and_update_config
304
-     * The following code was moved over from EE_Config so that it will no longer run on every request.
305
-     * If there is old calendar config data saved, then it will get converted on activation.
306
-     * This was basically a DMS before we had DMS's, and will get removed after a few more versions.
307
-     *
308
-     * @access public
309
-     * @static
310
-     * @return void
311
-     */
312
-    public static function reset_and_update_config()
313
-    {
314
-        do_action('AHEE__EE_Config___load_core_config__start', array('EEH_Activation', 'load_calendar_config'));
315
-        add_filter(
316
-            'FHEE__EE_Config___load_core_config__config_settings',
317
-            array('EEH_Activation', 'migrate_old_config_data'),
318
-            10,
319
-            3
320
-        );
321
-        //EE_Config::reset();
322
-        if (! EE_Config::logging_enabled()) {
323
-            delete_option(EE_Config::LOG_NAME);
324
-        }
325
-    }
326
-
327
-
328
-    /**
329
-     *    load_calendar_config
330
-     *
331
-     * @access    public
332
-     * @return    void
333
-     */
334
-    public static function load_calendar_config()
335
-    {
336
-        // grab array of all plugin folders and loop thru it
337
-        $plugins = glob(WP_PLUGIN_DIR . DS . '*', GLOB_ONLYDIR);
338
-        if (empty($plugins)) {
339
-            return;
340
-        }
341
-        foreach ($plugins as $plugin_path) {
342
-            // grab plugin folder name from path
343
-            $plugin = basename($plugin_path);
344
-            // drill down to Espresso plugins
345
-            // then to calendar related plugins
346
-            if (
347
-                strpos($plugin, 'espresso') !== false
348
-                || strpos($plugin, 'Espresso') !== false
349
-                || strpos($plugin, 'ee4') !== false
350
-                || strpos($plugin, 'EE4') !== false
351
-                || strpos($plugin, 'calendar') !== false
352
-            ) {
353
-                // this is what we are looking for
354
-                $calendar_config = $plugin_path . DS . 'EE_Calendar_Config.php';
355
-                // does it exist in this folder ?
356
-                if (is_readable($calendar_config)) {
357
-                    // YEAH! let's load it
358
-                    require_once($calendar_config);
359
-                }
360
-            }
361
-        }
362
-    }
363
-
364
-
365
-
366
-    /**
367
-     *    _migrate_old_config_data
368
-     *
369
-     * @access    public
370
-     * @param array|stdClass $settings
371
-     * @param string         $config
372
-     * @param \EE_Config     $EE_Config
373
-     * @return \stdClass
374
-     */
375
-    public static function migrate_old_config_data($settings = array(), $config = '', EE_Config $EE_Config)
376
-    {
377
-        $convert_from_array = array('addons');
378
-        // in case old settings were saved as an array
379
-        if (is_array($settings) && in_array($config, $convert_from_array)) {
380
-            // convert existing settings to an object
381
-            $config_array = $settings;
382
-            $settings = new stdClass();
383
-            foreach ($config_array as $key => $value) {
384
-                if ($key === 'calendar' && class_exists('EE_Calendar_Config')) {
385
-                    $EE_Config->set_config('addons', 'EE_Calendar', 'EE_Calendar_Config', $value);
386
-                } else {
387
-                    $settings->{$key} = $value;
388
-                }
389
-            }
390
-            add_filter('FHEE__EE_Config___load_core_config__update_espresso_config', '__return_true');
391
-        }
392
-        return $settings;
393
-    }
394
-
395
-
396
-    /**
397
-     * deactivate_event_espresso
398
-     *
399
-     * @access public
400
-     * @static
401
-     * @return void
402
-     */
403
-    public static function deactivate_event_espresso()
404
-    {
405
-        // check permissions
406
-        if (current_user_can('activate_plugins')) {
407
-            deactivate_plugins(EE_PLUGIN_BASENAME, true);
408
-        }
409
-    }
410
-
411
-
412
-
413
-    /**
414
-     * verify_default_pages_exist
415
-     *
416
-     * @access public
417
-     * @static
418
-     * @return void
419
-     * @throws InvalidDataTypeException
420
-     */
421
-    public static function verify_default_pages_exist()
422
-    {
423
-        $critical_page_problem = false;
424
-        $critical_pages = array(
425
-            array(
426
-                'id'   => 'reg_page_id',
427
-                'name' => __('Registration Checkout', 'event_espresso'),
428
-                'post' => null,
429
-                'code' => 'ESPRESSO_CHECKOUT',
430
-            ),
431
-            array(
432
-                'id'   => 'txn_page_id',
433
-                'name' => __('Transactions', 'event_espresso'),
434
-                'post' => null,
435
-                'code' => 'ESPRESSO_TXN_PAGE',
436
-            ),
437
-            array(
438
-                'id'   => 'thank_you_page_id',
439
-                'name' => __('Thank You', 'event_espresso'),
440
-                'post' => null,
441
-                'code' => 'ESPRESSO_THANK_YOU',
442
-            ),
443
-            array(
444
-                'id'   => 'cancel_page_id',
445
-                'name' => __('Registration Cancelled', 'event_espresso'),
446
-                'post' => null,
447
-                'code' => 'ESPRESSO_CANCELLED',
448
-            ),
449
-        );
450
-        $EE_Core_Config = EE_Registry::instance()->CFG->core;
451
-        foreach ($critical_pages as $critical_page) {
452
-            // is critical page ID set in config ?
453
-            if ($EE_Core_Config->{$critical_page['id']} !== false) {
454
-                // attempt to find post by ID
455
-                $critical_page['post'] = get_post($EE_Core_Config->{$critical_page['id']});
456
-            }
457
-            // no dice?
458
-            if ($critical_page['post'] === null) {
459
-                // attempt to find post by title
460
-                $critical_page['post'] = self::get_page_by_ee_shortcode($critical_page['code']);
461
-                // still nothing?
462
-                if ($critical_page['post'] === null) {
463
-                    $critical_page = EEH_Activation::create_critical_page($critical_page);
464
-                    // REALLY? Still nothing ??!?!?
465
-                    if ($critical_page['post'] === null) {
466
-                        $msg = __(
467
-                            'The Event Espresso critical page configuration settings could not be updated.',
468
-                            'event_espresso'
469
-                        );
470
-                        EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
471
-                        break;
472
-                    }
473
-                }
474
-            }
475
-            // check that Post ID matches critical page ID in config
476
-            if (
477
-                isset($critical_page['post']->ID)
478
-                && $critical_page['post']->ID !== $EE_Core_Config->{$critical_page['id']}
479
-            ) {
480
-                //update Config with post ID
481
-                $EE_Core_Config->{$critical_page['id']} = $critical_page['post']->ID;
482
-                if (! EE_Config::instance()->update_espresso_config(false, false)) {
483
-                    $msg = __(
484
-                        'The Event Espresso critical page configuration settings could not be updated.',
485
-                        'event_espresso'
486
-                    );
487
-                    EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
488
-                }
489
-            }
490
-            $critical_page_problem =
491
-                ! isset($critical_page['post']->post_status)
492
-                || $critical_page['post']->post_status !== 'publish'
493
-                || strpos($critical_page['post']->post_content, $critical_page['code']) === false
494
-                    ? true
495
-                    : $critical_page_problem;
496
-        }
497
-        if ($critical_page_problem) {
498
-            new PersistentAdminNotice(
499
-                'critical_page_problem',
500
-                sprintf(
501
-                    esc_html__(
502
-                        'A potential issue has been detected with one or more of your Event Espresso pages. Go to %s to view your Event Espresso pages.',
503
-                        'event_espresso'
504
-                    ),
505
-                    '<a href="' . admin_url('admin.php?page=espresso_general_settings&action=critical_pages') . '">'
506
-                    . __('Event Espresso Critical Pages Settings', 'event_espresso')
507
-                    . '</a>'
508
-                )
509
-            );
510
-        }
511
-        if (EE_Error::has_notices()) {
512
-            EE_Error::get_notices(false, true, true);
513
-        }
514
-    }
515
-
516
-
517
-
518
-    /**
519
-     * Returns the first post which uses the specified shortcode
520
-     *
521
-     * @param string $ee_shortcode usually one of the critical pages shortcodes, eg
522
-     *                             ESPRESSO_THANK_YOU. So we will search fora post with the content
523
-     *                             "[ESPRESSO_THANK_YOU"
524
-     *                             (we don't search for the closing shortcode bracket because they might have added
525
-     *                             parameter to the shortcode
526
-     * @return WP_Post or NULl
527
-     */
528
-    public static function get_page_by_ee_shortcode($ee_shortcode)
529
-    {
530
-        global $wpdb;
531
-        $shortcode_and_opening_bracket = '[' . $ee_shortcode;
532
-        $post_id = $wpdb->get_var("SELECT ID FROM {$wpdb->posts} WHERE post_content LIKE '%$shortcode_and_opening_bracket%' LIMIT 1");
533
-        if ($post_id) {
534
-            return get_post($post_id);
535
-        } else {
536
-            return null;
537
-        }
538
-    }
539
-
540
-
541
-    /**
542
-     *    This function generates a post for critical espresso pages
543
-     *
544
-     * @access public
545
-     * @static
546
-     * @param array $critical_page
547
-     * @return array
548
-     */
549
-    public static function create_critical_page($critical_page)
550
-    {
551
-
552
-        $post_args = array(
553
-            'post_title'     => $critical_page['name'],
554
-            'post_status'    => 'publish',
555
-            'post_type'      => 'page',
556
-            'comment_status' => 'closed',
557
-            'post_content'   => '[' . $critical_page['code'] . ']',
558
-        );
559
-
560
-        $post_id = wp_insert_post($post_args);
561
-        if (! $post_id) {
562
-            $msg = sprintf(
563
-                __('The Event Espresso  critical page entitled "%s" could not be created.', 'event_espresso'),
564
-                $critical_page['name']
565
-            );
566
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
567
-            return $critical_page;
568
-        }
569
-        // get newly created post's details
570
-        if (! $critical_page['post'] = get_post($post_id)) {
571
-            $msg = sprintf(
572
-                __('The Event Espresso critical page entitled "%s" could not be retrieved.', 'event_espresso'),
573
-                $critical_page['name']
574
-            );
575
-            EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
576
-        }
577
-
578
-        return $critical_page;
579
-
580
-    }
581
-
582
-
583
-
584
-
585
-    /**
586
-     * Tries to find the oldest admin for this site.  If there are no admins for this site then return NULL.
587
-     * The role being used to check is filterable.
588
-     *
589
-     * @since  4.6.0
590
-     * @global WPDB $wpdb
591
-     * @return mixed null|int WP_user ID or NULL
592
-     */
593
-    public static function get_default_creator_id()
594
-    {
595
-        global $wpdb;
596
-        if ( ! empty(self::$_default_creator_id)) {
597
-            return self::$_default_creator_id;
598
-        }/**/
599
-        $role_to_check = apply_filters('FHEE__EEH_Activation__get_default_creator_id__role_to_check', 'administrator');
600
-        //let's allow pre_filtering for early exits by alternative methods for getting id.  We check for truthy result and if so then exit early.
601
-        $pre_filtered_id = apply_filters(
602
-            'FHEE__EEH_Activation__get_default_creator_id__pre_filtered_id',
603
-            false,
604
-            $role_to_check
605
-        );
606
-        if ($pre_filtered_id !== false) {
607
-            return (int)$pre_filtered_id;
608
-        }
609
-        $capabilities_key = \EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix('capabilities');
610
-        $query = $wpdb->prepare(
611
-            "SELECT user_id FROM $wpdb->usermeta WHERE meta_key = '$capabilities_key' AND meta_value LIKE %s ORDER BY user_id ASC LIMIT 0,1",
612
-            '%' . $role_to_check . '%'
613
-        );
614
-        $user_id = $wpdb->get_var($query);
615
-        $user_id = apply_filters('FHEE__EEH_Activation_Helper__get_default_creator_id__user_id', $user_id);
616
-        if ($user_id && (int)$user_id) {
617
-            self::$_default_creator_id = (int)$user_id;
618
-            return self::$_default_creator_id;
619
-        } else {
620
-            return null;
621
-        }
622
-    }
623
-
624
-
625
-
626
-    /**
627
-     * used by EE and EE addons during plugin activation to create tables.
628
-     * Its a wrapper for EventEspresso\core\services\database\TableManager::createTable,
629
-     * but includes extra logic regarding activations.
630
-     *
631
-     * @access public
632
-     * @static
633
-     * @param string  $table_name              without the $wpdb->prefix
634
-     * @param string  $sql                     SQL for creating the table (contents between brackets in an SQL create
635
-     *                                         table query)
636
-     * @param string  $engine                  like 'ENGINE=MyISAM' or 'ENGINE=InnoDB'
637
-     * @param boolean $drop_pre_existing_table set to TRUE when you want to make SURE the table is completely empty
638
-     *                                         and new once this function is done (ie, you really do want to CREATE a
639
-     *                                         table, and expect it to be empty once you're done) leave as FALSE when
640
-     *                                         you just want to verify the table exists and matches this definition
641
-     *                                         (and if it HAS data in it you want to leave it be)
642
-     * @return void
643
-     * @throws EE_Error if there are database errors
644
-     */
645
-    public static function create_table($table_name, $sql, $engine = 'ENGINE=MyISAM ', $drop_pre_existing_table = false)
646
-    {
647
-        if (apply_filters('FHEE__EEH_Activation__create_table__short_circuit', false, $table_name, $sql)) {
648
-            return;
649
-        }
650
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
651
-        if ( ! function_exists('dbDelta')) {
652
-            require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
653
-        }
654
-        $tableAnalysis = \EEH_Activation::getTableAnalysis();
655
-        $wp_table_name = $tableAnalysis->ensureTableNameHasPrefix($table_name);
656
-        // do we need to first delete an existing version of this table ?
657
-        if ($drop_pre_existing_table && $tableAnalysis->tableExists($wp_table_name)) {
658
-            // ok, delete the table... but ONLY if it's empty
659
-            $deleted_safely = EEH_Activation::delete_db_table_if_empty($wp_table_name);
660
-            // table is NOT empty, are you SURE you want to delete this table ???
661
-            if ( ! $deleted_safely && defined('EE_DROP_BAD_TABLES') && EE_DROP_BAD_TABLES) {
662
-                \EEH_Activation::getTableManager()->dropTable($wp_table_name);
663
-            } else if ( ! $deleted_safely) {
664
-                // so we should be more cautious rather than just dropping tables so easily
665
-                error_log(
666
-                    sprintf(
667
-                        __(
668
-                            'It appears that database table "%1$s" exists when it shouldn\'t, and therefore may contain erroneous data. If you have previously restored your database from a backup that didn\'t remove the old tables, then we recommend: %2$s 1. create a new COMPLETE backup of your database, %2$s 2. delete ALL tables from your database, %2$s 3. restore to your previous backup. %2$s If, however, you have not restored to a backup, then somehow your "%3$s" WordPress option could not be read. You can probably ignore this message, but should investigate why that option is being removed.',
669
-                            'event_espresso'
670
-                        ),
671
-                        $wp_table_name,
672
-                        '<br/>',
673
-                        'espresso_db_update'
674
-                    )
675
-                );
676
-            }
677
-        }
678
-        $engine = str_replace('ENGINE=', '', $engine);
679
-        \EEH_Activation::getTableManager()->createTable($table_name, $sql, $engine);
680
-    }
681
-
682
-
683
-
684
-    /**
685
-     *    add_column_if_it_doesn't_exist
686
-     *    Checks if this column already exists on the specified table. Handy for addons which want to add a column
687
-     *
688
-     * @access     public
689
-     * @static
690
-     * @deprecated instead use TableManager::addColumn()
691
-     * @param string $table_name  (without "wp_", eg "esp_attendee"
692
-     * @param string $column_name
693
-     * @param string $column_info if your SQL were 'ALTER TABLE table_name ADD price VARCHAR(10)', this would be
694
-     *                            'VARCHAR(10)'
695
-     * @return bool|int
696
-     */
697
-    public static function add_column_if_it_doesnt_exist(
698
-        $table_name,
699
-        $column_name,
700
-        $column_info = 'INT UNSIGNED NOT NULL'
701
-    ) {
702
-        return \EEH_Activation::getTableManager()->addColumn($table_name, $column_name, $column_info);
703
-    }
704
-
705
-
706
-    /**
707
-     * get_fields_on_table
708
-     * Gets all the fields on the database table.
709
-     *
710
-     * @access     public
711
-     * @deprecated instead use TableManager::getTableColumns()
712
-     * @static
713
-     * @param string $table_name , without prefixed $wpdb->prefix
714
-     * @return array of database column names
715
-     */
716
-    public static function get_fields_on_table($table_name = null)
717
-    {
718
-        return \EEH_Activation::getTableManager()->getTableColumns($table_name);
719
-    }
720
-
721
-
722
-    /**
723
-     * db_table_is_empty
724
-     *
725
-     * @access     public\
726
-     * @deprecated instead use TableAnalysis::tableIsEmpty()
727
-     * @static
728
-     * @param string $table_name
729
-     * @return bool
730
-     */
731
-    public static function db_table_is_empty($table_name)
732
-    {
733
-        return \EEH_Activation::getTableAnalysis()->tableIsEmpty($table_name);
734
-    }
735
-
736
-
737
-    /**
738
-     * delete_db_table_if_empty
739
-     *
740
-     * @access public
741
-     * @static
742
-     * @param string $table_name
743
-     * @return bool | int
744
-     */
745
-    public static function delete_db_table_if_empty($table_name)
746
-    {
747
-        if (\EEH_Activation::getTableAnalysis()->tableIsEmpty($table_name)) {
748
-            return \EEH_Activation::getTableManager()->dropTable($table_name);
749
-        }
750
-        return false;
751
-    }
752
-
753
-
754
-    /**
755
-     * delete_unused_db_table
756
-     *
757
-     * @access     public
758
-     * @static
759
-     * @deprecated instead use TableManager::dropTable()
760
-     * @param string $table_name
761
-     * @return bool | int
762
-     */
763
-    public static function delete_unused_db_table($table_name)
764
-    {
765
-        return \EEH_Activation::getTableManager()->dropTable($table_name);
766
-    }
767
-
768
-
769
-    /**
770
-     * drop_index
771
-     *
772
-     * @access     public
773
-     * @static
774
-     * @deprecated instead use TableManager::dropIndex()
775
-     * @param string $table_name
776
-     * @param string $index_name
777
-     * @return bool | int
778
-     */
779
-    public static function drop_index($table_name, $index_name)
780
-    {
781
-        return \EEH_Activation::getTableManager()->dropIndex($table_name, $index_name);
782
-    }
783
-
784
-
785
-
786
-    /**
787
-     * create_database_tables
788
-     *
789
-     * @access public
790
-     * @static
791
-     * @throws EE_Error
792
-     * @return boolean success (whether database is setup properly or not)
793
-     */
794
-    public static function create_database_tables()
795
-    {
796
-        EE_Registry::instance()->load_core('Data_Migration_Manager');
797
-        //find the migration script that sets the database to be compatible with the code
798
-        $dms_name = EE_Data_Migration_Manager::instance()->get_most_up_to_date_dms();
799
-        if ($dms_name) {
800
-            $current_data_migration_script = EE_Registry::instance()->load_dms($dms_name);
801
-            $current_data_migration_script->set_migrating(false);
802
-            $current_data_migration_script->schema_changes_before_migration();
803
-            $current_data_migration_script->schema_changes_after_migration();
804
-            if ($current_data_migration_script->get_errors()) {
805
-                if (WP_DEBUG) {
806
-                    foreach ($current_data_migration_script->get_errors() as $error) {
807
-                        EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
808
-                    }
809
-                } else {
810
-                    EE_Error::add_error(
811
-                        __(
812
-                            'There were errors creating the Event Espresso database tables and Event Espresso has been 
265
+		$ee_cron_tasks_to_remove = EEH_Activation::get_cron_tasks($cron_tasks_to_remove);
266
+		foreach ($crons as $timestamp => $hooks_to_fire_at_time) {
267
+			if (is_array($hooks_to_fire_at_time)) {
268
+				foreach ($hooks_to_fire_at_time as $hook_name => $hook_actions) {
269
+					if (isset($ee_cron_tasks_to_remove[$hook_name])
270
+						&& is_array($ee_cron_tasks_to_remove[$hook_name])
271
+					) {
272
+						unset($crons[$timestamp][$hook_name]);
273
+					}
274
+				}
275
+				//also take care of any empty cron timestamps.
276
+				if (empty($hooks_to_fire_at_time)) {
277
+					unset($crons[$timestamp]);
278
+				}
279
+			}
280
+		}
281
+		_set_cron_array($crons);
282
+	}
283
+
284
+
285
+	/**
286
+	 *    CPT_initialization
287
+	 *    registers all EE CPTs ( Custom Post Types ) then flushes rewrite rules so that all endpoints exist
288
+	 *
289
+	 * @access public
290
+	 * @static
291
+	 * @return void
292
+	 */
293
+	public static function CPT_initialization()
294
+	{
295
+		// register Custom Post Types
296
+		EE_Registry::instance()->load_core('Register_CPTs');
297
+		flush_rewrite_rules();
298
+	}
299
+
300
+
301
+
302
+	/**
303
+	 *    reset_and_update_config
304
+	 * The following code was moved over from EE_Config so that it will no longer run on every request.
305
+	 * If there is old calendar config data saved, then it will get converted on activation.
306
+	 * This was basically a DMS before we had DMS's, and will get removed after a few more versions.
307
+	 *
308
+	 * @access public
309
+	 * @static
310
+	 * @return void
311
+	 */
312
+	public static function reset_and_update_config()
313
+	{
314
+		do_action('AHEE__EE_Config___load_core_config__start', array('EEH_Activation', 'load_calendar_config'));
315
+		add_filter(
316
+			'FHEE__EE_Config___load_core_config__config_settings',
317
+			array('EEH_Activation', 'migrate_old_config_data'),
318
+			10,
319
+			3
320
+		);
321
+		//EE_Config::reset();
322
+		if (! EE_Config::logging_enabled()) {
323
+			delete_option(EE_Config::LOG_NAME);
324
+		}
325
+	}
326
+
327
+
328
+	/**
329
+	 *    load_calendar_config
330
+	 *
331
+	 * @access    public
332
+	 * @return    void
333
+	 */
334
+	public static function load_calendar_config()
335
+	{
336
+		// grab array of all plugin folders and loop thru it
337
+		$plugins = glob(WP_PLUGIN_DIR . DS . '*', GLOB_ONLYDIR);
338
+		if (empty($plugins)) {
339
+			return;
340
+		}
341
+		foreach ($plugins as $plugin_path) {
342
+			// grab plugin folder name from path
343
+			$plugin = basename($plugin_path);
344
+			// drill down to Espresso plugins
345
+			// then to calendar related plugins
346
+			if (
347
+				strpos($plugin, 'espresso') !== false
348
+				|| strpos($plugin, 'Espresso') !== false
349
+				|| strpos($plugin, 'ee4') !== false
350
+				|| strpos($plugin, 'EE4') !== false
351
+				|| strpos($plugin, 'calendar') !== false
352
+			) {
353
+				// this is what we are looking for
354
+				$calendar_config = $plugin_path . DS . 'EE_Calendar_Config.php';
355
+				// does it exist in this folder ?
356
+				if (is_readable($calendar_config)) {
357
+					// YEAH! let's load it
358
+					require_once($calendar_config);
359
+				}
360
+			}
361
+		}
362
+	}
363
+
364
+
365
+
366
+	/**
367
+	 *    _migrate_old_config_data
368
+	 *
369
+	 * @access    public
370
+	 * @param array|stdClass $settings
371
+	 * @param string         $config
372
+	 * @param \EE_Config     $EE_Config
373
+	 * @return \stdClass
374
+	 */
375
+	public static function migrate_old_config_data($settings = array(), $config = '', EE_Config $EE_Config)
376
+	{
377
+		$convert_from_array = array('addons');
378
+		// in case old settings were saved as an array
379
+		if (is_array($settings) && in_array($config, $convert_from_array)) {
380
+			// convert existing settings to an object
381
+			$config_array = $settings;
382
+			$settings = new stdClass();
383
+			foreach ($config_array as $key => $value) {
384
+				if ($key === 'calendar' && class_exists('EE_Calendar_Config')) {
385
+					$EE_Config->set_config('addons', 'EE_Calendar', 'EE_Calendar_Config', $value);
386
+				} else {
387
+					$settings->{$key} = $value;
388
+				}
389
+			}
390
+			add_filter('FHEE__EE_Config___load_core_config__update_espresso_config', '__return_true');
391
+		}
392
+		return $settings;
393
+	}
394
+
395
+
396
+	/**
397
+	 * deactivate_event_espresso
398
+	 *
399
+	 * @access public
400
+	 * @static
401
+	 * @return void
402
+	 */
403
+	public static function deactivate_event_espresso()
404
+	{
405
+		// check permissions
406
+		if (current_user_can('activate_plugins')) {
407
+			deactivate_plugins(EE_PLUGIN_BASENAME, true);
408
+		}
409
+	}
410
+
411
+
412
+
413
+	/**
414
+	 * verify_default_pages_exist
415
+	 *
416
+	 * @access public
417
+	 * @static
418
+	 * @return void
419
+	 * @throws InvalidDataTypeException
420
+	 */
421
+	public static function verify_default_pages_exist()
422
+	{
423
+		$critical_page_problem = false;
424
+		$critical_pages = array(
425
+			array(
426
+				'id'   => 'reg_page_id',
427
+				'name' => __('Registration Checkout', 'event_espresso'),
428
+				'post' => null,
429
+				'code' => 'ESPRESSO_CHECKOUT',
430
+			),
431
+			array(
432
+				'id'   => 'txn_page_id',
433
+				'name' => __('Transactions', 'event_espresso'),
434
+				'post' => null,
435
+				'code' => 'ESPRESSO_TXN_PAGE',
436
+			),
437
+			array(
438
+				'id'   => 'thank_you_page_id',
439
+				'name' => __('Thank You', 'event_espresso'),
440
+				'post' => null,
441
+				'code' => 'ESPRESSO_THANK_YOU',
442
+			),
443
+			array(
444
+				'id'   => 'cancel_page_id',
445
+				'name' => __('Registration Cancelled', 'event_espresso'),
446
+				'post' => null,
447
+				'code' => 'ESPRESSO_CANCELLED',
448
+			),
449
+		);
450
+		$EE_Core_Config = EE_Registry::instance()->CFG->core;
451
+		foreach ($critical_pages as $critical_page) {
452
+			// is critical page ID set in config ?
453
+			if ($EE_Core_Config->{$critical_page['id']} !== false) {
454
+				// attempt to find post by ID
455
+				$critical_page['post'] = get_post($EE_Core_Config->{$critical_page['id']});
456
+			}
457
+			// no dice?
458
+			if ($critical_page['post'] === null) {
459
+				// attempt to find post by title
460
+				$critical_page['post'] = self::get_page_by_ee_shortcode($critical_page['code']);
461
+				// still nothing?
462
+				if ($critical_page['post'] === null) {
463
+					$critical_page = EEH_Activation::create_critical_page($critical_page);
464
+					// REALLY? Still nothing ??!?!?
465
+					if ($critical_page['post'] === null) {
466
+						$msg = __(
467
+							'The Event Espresso critical page configuration settings could not be updated.',
468
+							'event_espresso'
469
+						);
470
+						EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
471
+						break;
472
+					}
473
+				}
474
+			}
475
+			// check that Post ID matches critical page ID in config
476
+			if (
477
+				isset($critical_page['post']->ID)
478
+				&& $critical_page['post']->ID !== $EE_Core_Config->{$critical_page['id']}
479
+			) {
480
+				//update Config with post ID
481
+				$EE_Core_Config->{$critical_page['id']} = $critical_page['post']->ID;
482
+				if (! EE_Config::instance()->update_espresso_config(false, false)) {
483
+					$msg = __(
484
+						'The Event Espresso critical page configuration settings could not be updated.',
485
+						'event_espresso'
486
+					);
487
+					EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
488
+				}
489
+			}
490
+			$critical_page_problem =
491
+				! isset($critical_page['post']->post_status)
492
+				|| $critical_page['post']->post_status !== 'publish'
493
+				|| strpos($critical_page['post']->post_content, $critical_page['code']) === false
494
+					? true
495
+					: $critical_page_problem;
496
+		}
497
+		if ($critical_page_problem) {
498
+			new PersistentAdminNotice(
499
+				'critical_page_problem',
500
+				sprintf(
501
+					esc_html__(
502
+						'A potential issue has been detected with one or more of your Event Espresso pages. Go to %s to view your Event Espresso pages.',
503
+						'event_espresso'
504
+					),
505
+					'<a href="' . admin_url('admin.php?page=espresso_general_settings&action=critical_pages') . '">'
506
+					. __('Event Espresso Critical Pages Settings', 'event_espresso')
507
+					. '</a>'
508
+				)
509
+			);
510
+		}
511
+		if (EE_Error::has_notices()) {
512
+			EE_Error::get_notices(false, true, true);
513
+		}
514
+	}
515
+
516
+
517
+
518
+	/**
519
+	 * Returns the first post which uses the specified shortcode
520
+	 *
521
+	 * @param string $ee_shortcode usually one of the critical pages shortcodes, eg
522
+	 *                             ESPRESSO_THANK_YOU. So we will search fora post with the content
523
+	 *                             "[ESPRESSO_THANK_YOU"
524
+	 *                             (we don't search for the closing shortcode bracket because they might have added
525
+	 *                             parameter to the shortcode
526
+	 * @return WP_Post or NULl
527
+	 */
528
+	public static function get_page_by_ee_shortcode($ee_shortcode)
529
+	{
530
+		global $wpdb;
531
+		$shortcode_and_opening_bracket = '[' . $ee_shortcode;
532
+		$post_id = $wpdb->get_var("SELECT ID FROM {$wpdb->posts} WHERE post_content LIKE '%$shortcode_and_opening_bracket%' LIMIT 1");
533
+		if ($post_id) {
534
+			return get_post($post_id);
535
+		} else {
536
+			return null;
537
+		}
538
+	}
539
+
540
+
541
+	/**
542
+	 *    This function generates a post for critical espresso pages
543
+	 *
544
+	 * @access public
545
+	 * @static
546
+	 * @param array $critical_page
547
+	 * @return array
548
+	 */
549
+	public static function create_critical_page($critical_page)
550
+	{
551
+
552
+		$post_args = array(
553
+			'post_title'     => $critical_page['name'],
554
+			'post_status'    => 'publish',
555
+			'post_type'      => 'page',
556
+			'comment_status' => 'closed',
557
+			'post_content'   => '[' . $critical_page['code'] . ']',
558
+		);
559
+
560
+		$post_id = wp_insert_post($post_args);
561
+		if (! $post_id) {
562
+			$msg = sprintf(
563
+				__('The Event Espresso  critical page entitled "%s" could not be created.', 'event_espresso'),
564
+				$critical_page['name']
565
+			);
566
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
567
+			return $critical_page;
568
+		}
569
+		// get newly created post's details
570
+		if (! $critical_page['post'] = get_post($post_id)) {
571
+			$msg = sprintf(
572
+				__('The Event Espresso critical page entitled "%s" could not be retrieved.', 'event_espresso'),
573
+				$critical_page['name']
574
+			);
575
+			EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
576
+		}
577
+
578
+		return $critical_page;
579
+
580
+	}
581
+
582
+
583
+
584
+
585
+	/**
586
+	 * Tries to find the oldest admin for this site.  If there are no admins for this site then return NULL.
587
+	 * The role being used to check is filterable.
588
+	 *
589
+	 * @since  4.6.0
590
+	 * @global WPDB $wpdb
591
+	 * @return mixed null|int WP_user ID or NULL
592
+	 */
593
+	public static function get_default_creator_id()
594
+	{
595
+		global $wpdb;
596
+		if ( ! empty(self::$_default_creator_id)) {
597
+			return self::$_default_creator_id;
598
+		}/**/
599
+		$role_to_check = apply_filters('FHEE__EEH_Activation__get_default_creator_id__role_to_check', 'administrator');
600
+		//let's allow pre_filtering for early exits by alternative methods for getting id.  We check for truthy result and if so then exit early.
601
+		$pre_filtered_id = apply_filters(
602
+			'FHEE__EEH_Activation__get_default_creator_id__pre_filtered_id',
603
+			false,
604
+			$role_to_check
605
+		);
606
+		if ($pre_filtered_id !== false) {
607
+			return (int)$pre_filtered_id;
608
+		}
609
+		$capabilities_key = \EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix('capabilities');
610
+		$query = $wpdb->prepare(
611
+			"SELECT user_id FROM $wpdb->usermeta WHERE meta_key = '$capabilities_key' AND meta_value LIKE %s ORDER BY user_id ASC LIMIT 0,1",
612
+			'%' . $role_to_check . '%'
613
+		);
614
+		$user_id = $wpdb->get_var($query);
615
+		$user_id = apply_filters('FHEE__EEH_Activation_Helper__get_default_creator_id__user_id', $user_id);
616
+		if ($user_id && (int)$user_id) {
617
+			self::$_default_creator_id = (int)$user_id;
618
+			return self::$_default_creator_id;
619
+		} else {
620
+			return null;
621
+		}
622
+	}
623
+
624
+
625
+
626
+	/**
627
+	 * used by EE and EE addons during plugin activation to create tables.
628
+	 * Its a wrapper for EventEspresso\core\services\database\TableManager::createTable,
629
+	 * but includes extra logic regarding activations.
630
+	 *
631
+	 * @access public
632
+	 * @static
633
+	 * @param string  $table_name              without the $wpdb->prefix
634
+	 * @param string  $sql                     SQL for creating the table (contents between brackets in an SQL create
635
+	 *                                         table query)
636
+	 * @param string  $engine                  like 'ENGINE=MyISAM' or 'ENGINE=InnoDB'
637
+	 * @param boolean $drop_pre_existing_table set to TRUE when you want to make SURE the table is completely empty
638
+	 *                                         and new once this function is done (ie, you really do want to CREATE a
639
+	 *                                         table, and expect it to be empty once you're done) leave as FALSE when
640
+	 *                                         you just want to verify the table exists and matches this definition
641
+	 *                                         (and if it HAS data in it you want to leave it be)
642
+	 * @return void
643
+	 * @throws EE_Error if there are database errors
644
+	 */
645
+	public static function create_table($table_name, $sql, $engine = 'ENGINE=MyISAM ', $drop_pre_existing_table = false)
646
+	{
647
+		if (apply_filters('FHEE__EEH_Activation__create_table__short_circuit', false, $table_name, $sql)) {
648
+			return;
649
+		}
650
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
651
+		if ( ! function_exists('dbDelta')) {
652
+			require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
653
+		}
654
+		$tableAnalysis = \EEH_Activation::getTableAnalysis();
655
+		$wp_table_name = $tableAnalysis->ensureTableNameHasPrefix($table_name);
656
+		// do we need to first delete an existing version of this table ?
657
+		if ($drop_pre_existing_table && $tableAnalysis->tableExists($wp_table_name)) {
658
+			// ok, delete the table... but ONLY if it's empty
659
+			$deleted_safely = EEH_Activation::delete_db_table_if_empty($wp_table_name);
660
+			// table is NOT empty, are you SURE you want to delete this table ???
661
+			if ( ! $deleted_safely && defined('EE_DROP_BAD_TABLES') && EE_DROP_BAD_TABLES) {
662
+				\EEH_Activation::getTableManager()->dropTable($wp_table_name);
663
+			} else if ( ! $deleted_safely) {
664
+				// so we should be more cautious rather than just dropping tables so easily
665
+				error_log(
666
+					sprintf(
667
+						__(
668
+							'It appears that database table "%1$s" exists when it shouldn\'t, and therefore may contain erroneous data. If you have previously restored your database from a backup that didn\'t remove the old tables, then we recommend: %2$s 1. create a new COMPLETE backup of your database, %2$s 2. delete ALL tables from your database, %2$s 3. restore to your previous backup. %2$s If, however, you have not restored to a backup, then somehow your "%3$s" WordPress option could not be read. You can probably ignore this message, but should investigate why that option is being removed.',
669
+							'event_espresso'
670
+						),
671
+						$wp_table_name,
672
+						'<br/>',
673
+						'espresso_db_update'
674
+					)
675
+				);
676
+			}
677
+		}
678
+		$engine = str_replace('ENGINE=', '', $engine);
679
+		\EEH_Activation::getTableManager()->createTable($table_name, $sql, $engine);
680
+	}
681
+
682
+
683
+
684
+	/**
685
+	 *    add_column_if_it_doesn't_exist
686
+	 *    Checks if this column already exists on the specified table. Handy for addons which want to add a column
687
+	 *
688
+	 * @access     public
689
+	 * @static
690
+	 * @deprecated instead use TableManager::addColumn()
691
+	 * @param string $table_name  (without "wp_", eg "esp_attendee"
692
+	 * @param string $column_name
693
+	 * @param string $column_info if your SQL were 'ALTER TABLE table_name ADD price VARCHAR(10)', this would be
694
+	 *                            'VARCHAR(10)'
695
+	 * @return bool|int
696
+	 */
697
+	public static function add_column_if_it_doesnt_exist(
698
+		$table_name,
699
+		$column_name,
700
+		$column_info = 'INT UNSIGNED NOT NULL'
701
+	) {
702
+		return \EEH_Activation::getTableManager()->addColumn($table_name, $column_name, $column_info);
703
+	}
704
+
705
+
706
+	/**
707
+	 * get_fields_on_table
708
+	 * Gets all the fields on the database table.
709
+	 *
710
+	 * @access     public
711
+	 * @deprecated instead use TableManager::getTableColumns()
712
+	 * @static
713
+	 * @param string $table_name , without prefixed $wpdb->prefix
714
+	 * @return array of database column names
715
+	 */
716
+	public static function get_fields_on_table($table_name = null)
717
+	{
718
+		return \EEH_Activation::getTableManager()->getTableColumns($table_name);
719
+	}
720
+
721
+
722
+	/**
723
+	 * db_table_is_empty
724
+	 *
725
+	 * @access     public\
726
+	 * @deprecated instead use TableAnalysis::tableIsEmpty()
727
+	 * @static
728
+	 * @param string $table_name
729
+	 * @return bool
730
+	 */
731
+	public static function db_table_is_empty($table_name)
732
+	{
733
+		return \EEH_Activation::getTableAnalysis()->tableIsEmpty($table_name);
734
+	}
735
+
736
+
737
+	/**
738
+	 * delete_db_table_if_empty
739
+	 *
740
+	 * @access public
741
+	 * @static
742
+	 * @param string $table_name
743
+	 * @return bool | int
744
+	 */
745
+	public static function delete_db_table_if_empty($table_name)
746
+	{
747
+		if (\EEH_Activation::getTableAnalysis()->tableIsEmpty($table_name)) {
748
+			return \EEH_Activation::getTableManager()->dropTable($table_name);
749
+		}
750
+		return false;
751
+	}
752
+
753
+
754
+	/**
755
+	 * delete_unused_db_table
756
+	 *
757
+	 * @access     public
758
+	 * @static
759
+	 * @deprecated instead use TableManager::dropTable()
760
+	 * @param string $table_name
761
+	 * @return bool | int
762
+	 */
763
+	public static function delete_unused_db_table($table_name)
764
+	{
765
+		return \EEH_Activation::getTableManager()->dropTable($table_name);
766
+	}
767
+
768
+
769
+	/**
770
+	 * drop_index
771
+	 *
772
+	 * @access     public
773
+	 * @static
774
+	 * @deprecated instead use TableManager::dropIndex()
775
+	 * @param string $table_name
776
+	 * @param string $index_name
777
+	 * @return bool | int
778
+	 */
779
+	public static function drop_index($table_name, $index_name)
780
+	{
781
+		return \EEH_Activation::getTableManager()->dropIndex($table_name, $index_name);
782
+	}
783
+
784
+
785
+
786
+	/**
787
+	 * create_database_tables
788
+	 *
789
+	 * @access public
790
+	 * @static
791
+	 * @throws EE_Error
792
+	 * @return boolean success (whether database is setup properly or not)
793
+	 */
794
+	public static function create_database_tables()
795
+	{
796
+		EE_Registry::instance()->load_core('Data_Migration_Manager');
797
+		//find the migration script that sets the database to be compatible with the code
798
+		$dms_name = EE_Data_Migration_Manager::instance()->get_most_up_to_date_dms();
799
+		if ($dms_name) {
800
+			$current_data_migration_script = EE_Registry::instance()->load_dms($dms_name);
801
+			$current_data_migration_script->set_migrating(false);
802
+			$current_data_migration_script->schema_changes_before_migration();
803
+			$current_data_migration_script->schema_changes_after_migration();
804
+			if ($current_data_migration_script->get_errors()) {
805
+				if (WP_DEBUG) {
806
+					foreach ($current_data_migration_script->get_errors() as $error) {
807
+						EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
808
+					}
809
+				} else {
810
+					EE_Error::add_error(
811
+						__(
812
+							'There were errors creating the Event Espresso database tables and Event Espresso has been 
813 813
                             deactivated. To view the errors, please enable WP_DEBUG in your wp-config.php file.',
814
-                            'event_espresso'
815
-                        )
816
-                    );
817
-                }
818
-                return false;
819
-            }
820
-            EE_Data_Migration_Manager::instance()->update_current_database_state_to();
821
-        } else {
822
-            EE_Error::add_error(
823
-                __(
824
-                    'Could not determine most up-to-date data migration script from which to pull database schema
814
+							'event_espresso'
815
+						)
816
+					);
817
+				}
818
+				return false;
819
+			}
820
+			EE_Data_Migration_Manager::instance()->update_current_database_state_to();
821
+		} else {
822
+			EE_Error::add_error(
823
+				__(
824
+					'Could not determine most up-to-date data migration script from which to pull database schema
825 825
                      structure. So database is probably not setup properly',
826
-                    'event_espresso'
827
-                ),
828
-                __FILE__,
829
-                __FUNCTION__,
830
-                __LINE__
831
-            );
832
-            return false;
833
-        }
834
-        return true;
835
-    }
836
-
837
-
838
-
839
-    /**
840
-     * initialize_system_questions
841
-     *
842
-     * @access public
843
-     * @static
844
-     * @return void
845
-     */
846
-    public static function initialize_system_questions()
847
-    {
848
-        // QUESTION GROUPS
849
-        global $wpdb;
850
-        $table_name = \EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix('esp_question_group');
851
-        $SQL = "SELECT QSG_system FROM $table_name WHERE QSG_system != 0";
852
-        // what we have
853
-        $question_groups = $wpdb->get_col($SQL);
854
-        // check the response
855
-        $question_groups = is_array($question_groups) ? $question_groups : array();
856
-        // what we should have
857
-        $QSG_systems = array(1, 2);
858
-        // loop thru what we should have and compare to what we have
859
-        foreach ($QSG_systems as $QSG_system) {
860
-            // reset values array
861
-            $QSG_values = array();
862
-            // if we don't have what we should have (but use $QST_system as as string because that's what we got from the db)
863
-            if (! in_array("$QSG_system", $question_groups)) {
864
-                // add it
865
-                switch ($QSG_system) {
866
-                    case 1:
867
-                        $QSG_values = array(
868
-                            'QSG_name'            => __('Personal Information', 'event_espresso'),
869
-                            'QSG_identifier'      => 'personal-information-' . time(),
870
-                            'QSG_desc'            => '',
871
-                            'QSG_order'           => 1,
872
-                            'QSG_show_group_name' => 1,
873
-                            'QSG_show_group_desc' => 1,
874
-                            'QSG_system'          => EEM_Question_Group::system_personal,
875
-                            'QSG_deleted'         => 0,
876
-                        );
877
-                        break;
878
-                    case 2:
879
-                        $QSG_values = array(
880
-                            'QSG_name'            => __('Address Information', 'event_espresso'),
881
-                            'QSG_identifier'      => 'address-information-' . time(),
882
-                            'QSG_desc'            => '',
883
-                            'QSG_order'           => 2,
884
-                            'QSG_show_group_name' => 1,
885
-                            'QSG_show_group_desc' => 1,
886
-                            'QSG_system'          => EEM_Question_Group::system_address,
887
-                            'QSG_deleted'         => 0,
888
-                        );
889
-                        break;
890
-                }
891
-                // make sure we have some values before inserting them
892
-                if (! empty($QSG_values)) {
893
-                    // insert system question
894
-                    $wpdb->insert(
895
-                        $table_name,
896
-                        $QSG_values,
897
-                        array('%s', '%s', '%s', '%d', '%d', '%d', '%d', '%d')
898
-                    );
899
-                    $QSG_IDs[$QSG_system] = $wpdb->insert_id;
900
-                }
901
-            }
902
-        }
903
-        // QUESTIONS
904
-        global $wpdb;
905
-        $table_name = \EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix('esp_question');
906
-        $SQL = "SELECT QST_system FROM $table_name WHERE QST_system != ''";
907
-        // what we have
908
-        $questions = $wpdb->get_col($SQL);
909
-        // what we should have
910
-        $QST_systems = array(
911
-            'fname',
912
-            'lname',
913
-            'email',
914
-            'address',
915
-            'address2',
916
-            'city',
917
-            'country',
918
-            'state',
919
-            'zip',
920
-            'phone',
921
-        );
922
-        $order_for_group_1 = 1;
923
-        $order_for_group_2 = 1;
924
-        // loop thru what we should have and compare to what we have
925
-        foreach ($QST_systems as $QST_system) {
926
-            // reset values array
927
-            $QST_values = array();
928
-            // if we don't have what we should have
929
-            if (! in_array($QST_system, $questions)) {
930
-                // add it
931
-                switch ($QST_system) {
932
-                    case 'fname':
933
-                        $QST_values = array(
934
-                            'QST_display_text'  => __('First Name', 'event_espresso'),
935
-                            'QST_admin_label'   => __('First Name - System Question', 'event_espresso'),
936
-                            'QST_system'        => 'fname',
937
-                            'QST_type'          => 'TEXT',
938
-                            'QST_required'      => 1,
939
-                            'QST_required_text' => __('This field is required', 'event_espresso'),
940
-                            'QST_order'         => 1,
941
-                            'QST_admin_only'    => 0,
942
-                            'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
943
-                            'QST_wp_user'       => self::get_default_creator_id(),
944
-                            'QST_deleted'       => 0,
945
-                        );
946
-                        break;
947
-                    case 'lname':
948
-                        $QST_values = array(
949
-                            'QST_display_text'  => __('Last Name', 'event_espresso'),
950
-                            'QST_admin_label'   => __('Last Name - System Question', 'event_espresso'),
951
-                            'QST_system'        => 'lname',
952
-                            'QST_type'          => 'TEXT',
953
-                            'QST_required'      => 1,
954
-                            'QST_required_text' => __('This field is required', 'event_espresso'),
955
-                            'QST_order'         => 2,
956
-                            'QST_admin_only'    => 0,
957
-                            'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
958
-                            'QST_wp_user'       => self::get_default_creator_id(),
959
-                            'QST_deleted'       => 0,
960
-                        );
961
-                        break;
962
-                    case 'email':
963
-                        $QST_values = array(
964
-                            'QST_display_text'  => __('Email Address', 'event_espresso'),
965
-                            'QST_admin_label'   => __('Email Address - System Question', 'event_espresso'),
966
-                            'QST_system'        => 'email',
967
-                            'QST_type'          => 'EMAIL',
968
-                            'QST_required'      => 1,
969
-                            'QST_required_text' => __('This field is required', 'event_espresso'),
970
-                            'QST_order'         => 3,
971
-                            'QST_admin_only'    => 0,
972
-                            'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
973
-                            'QST_wp_user'       => self::get_default_creator_id(),
974
-                            'QST_deleted'       => 0,
975
-                        );
976
-                        break;
977
-                    case 'address':
978
-                        $QST_values = array(
979
-                            'QST_display_text'  => __('Address', 'event_espresso'),
980
-                            'QST_admin_label'   => __('Address - System Question', 'event_espresso'),
981
-                            'QST_system'        => 'address',
982
-                            'QST_type'          => 'TEXT',
983
-                            'QST_required'      => 0,
984
-                            'QST_required_text' => __('This field is required', 'event_espresso'),
985
-                            'QST_order'         => 4,
986
-                            'QST_admin_only'    => 0,
987
-                            'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
988
-                            'QST_wp_user'       => self::get_default_creator_id(),
989
-                            'QST_deleted'       => 0,
990
-                        );
991
-                        break;
992
-                    case 'address2':
993
-                        $QST_values = array(
994
-                            'QST_display_text'  => __('Address2', 'event_espresso'),
995
-                            'QST_admin_label'   => __('Address2 - System Question', 'event_espresso'),
996
-                            'QST_system'        => 'address2',
997
-                            'QST_type'          => 'TEXT',
998
-                            'QST_required'      => 0,
999
-                            'QST_required_text' => __('This field is required', 'event_espresso'),
1000
-                            'QST_order'         => 5,
1001
-                            'QST_admin_only'    => 0,
1002
-                            'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
1003
-                            'QST_wp_user'       => self::get_default_creator_id(),
1004
-                            'QST_deleted'       => 0,
1005
-                        );
1006
-                        break;
1007
-                    case 'city':
1008
-                        $QST_values = array(
1009
-                            'QST_display_text'  => __('City', 'event_espresso'),
1010
-                            'QST_admin_label'   => __('City - System Question', 'event_espresso'),
1011
-                            'QST_system'        => 'city',
1012
-                            'QST_type'          => 'TEXT',
1013
-                            'QST_required'      => 0,
1014
-                            'QST_required_text' => __('This field is required', 'event_espresso'),
1015
-                            'QST_order'         => 6,
1016
-                            'QST_admin_only'    => 0,
1017
-                            'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
1018
-                            'QST_wp_user'       => self::get_default_creator_id(),
1019
-                            'QST_deleted'       => 0,
1020
-                        );
1021
-                        break;
1022
-                    case 'country':
1023
-                        $QST_values = array(
1024
-                            'QST_display_text'  => __('Country', 'event_espresso'),
1025
-                            'QST_admin_label'   => __('Country - System Question', 'event_espresso'),
1026
-                            'QST_system'        => 'country',
1027
-                            'QST_type'          => 'COUNTRY',
1028
-                            'QST_required'      => 0,
1029
-                            'QST_required_text' => __('This field is required', 'event_espresso'),
1030
-                            'QST_order'         => 7,
1031
-                            'QST_admin_only'    => 0,
1032
-                            'QST_wp_user'       => self::get_default_creator_id(),
1033
-                            'QST_deleted'       => 0,
1034
-                        );
1035
-                        break;
1036
-                    case 'state':
1037
-                        $QST_values = array(
1038
-                            'QST_display_text'  => __('State/Province', 'event_espresso'),
1039
-                            'QST_admin_label'   => __('State/Province - System Question', 'event_espresso'),
1040
-                            'QST_system'        => 'state',
1041
-                            'QST_type'          => 'STATE',
1042
-                            'QST_required'      => 0,
1043
-                            'QST_required_text' => __('This field is required', 'event_espresso'),
1044
-                            'QST_order'         => 8,
1045
-                            'QST_admin_only'    => 0,
1046
-                            'QST_wp_user'       => self::get_default_creator_id(),
1047
-                            'QST_deleted'       => 0,
1048
-                        );
1049
-                        break;
1050
-                    case 'zip':
1051
-                        $QST_values = array(
1052
-                            'QST_display_text'  => __('Zip/Postal Code', 'event_espresso'),
1053
-                            'QST_admin_label'   => __('Zip/Postal Code - System Question', 'event_espresso'),
1054
-                            'QST_system'        => 'zip',
1055
-                            'QST_type'          => 'TEXT',
1056
-                            'QST_required'      => 0,
1057
-                            'QST_required_text' => __('This field is required', 'event_espresso'),
1058
-                            'QST_order'         => 9,
1059
-                            'QST_admin_only'    => 0,
1060
-                            'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
1061
-                            'QST_wp_user'       => self::get_default_creator_id(),
1062
-                            'QST_deleted'       => 0,
1063
-                        );
1064
-                        break;
1065
-                    case 'phone':
1066
-                        $QST_values = array(
1067
-                            'QST_display_text'  => __('Phone Number', 'event_espresso'),
1068
-                            'QST_admin_label'   => __('Phone Number - System Question', 'event_espresso'),
1069
-                            'QST_system'        => 'phone',
1070
-                            'QST_type'          => 'TEXT',
1071
-                            'QST_required'      => 0,
1072
-                            'QST_required_text' => __('This field is required', 'event_espresso'),
1073
-                            'QST_order'         => 10,
1074
-                            'QST_admin_only'    => 0,
1075
-                            'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
1076
-                            'QST_wp_user'       => self::get_default_creator_id(),
1077
-                            'QST_deleted'       => 0,
1078
-                        );
1079
-                        break;
1080
-                }
1081
-                if (! empty($QST_values)) {
1082
-                    // insert system question
1083
-                    $wpdb->insert(
1084
-                        $table_name,
1085
-                        $QST_values,
1086
-                        array('%s', '%s', '%s', '%s', '%d', '%s', '%d', '%d', '%d', '%d')
1087
-                    );
1088
-                    $QST_ID = $wpdb->insert_id;
1089
-                    // QUESTION GROUP QUESTIONS
1090
-                    if (in_array($QST_system, array('fname', 'lname', 'email'))) {
1091
-                        $system_question_we_want = EEM_Question_Group::system_personal;
1092
-                    } else {
1093
-                        $system_question_we_want = EEM_Question_Group::system_address;
1094
-                    }
1095
-                    if (isset($QSG_IDs[$system_question_we_want])) {
1096
-                        $QSG_ID = $QSG_IDs[$system_question_we_want];
1097
-                    } else {
1098
-                        $id_col = EEM_Question_Group::instance()
1099
-                                                    ->get_col(array(array('QSG_system' => $system_question_we_want)));
1100
-                        if (is_array($id_col)) {
1101
-                            $QSG_ID = reset($id_col);
1102
-                        } else {
1103
-                            //ok so we didn't find it in the db either?? that's weird because we should have inserted it at the start of this method
1104
-                            EE_Log::instance()->log(
1105
-                                __FILE__,
1106
-                                __FUNCTION__,
1107
-                                sprintf(
1108
-                                    __(
1109
-                                        'Could not associate question %1$s to a question group because no system question
826
+					'event_espresso'
827
+				),
828
+				__FILE__,
829
+				__FUNCTION__,
830
+				__LINE__
831
+			);
832
+			return false;
833
+		}
834
+		return true;
835
+	}
836
+
837
+
838
+
839
+	/**
840
+	 * initialize_system_questions
841
+	 *
842
+	 * @access public
843
+	 * @static
844
+	 * @return void
845
+	 */
846
+	public static function initialize_system_questions()
847
+	{
848
+		// QUESTION GROUPS
849
+		global $wpdb;
850
+		$table_name = \EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix('esp_question_group');
851
+		$SQL = "SELECT QSG_system FROM $table_name WHERE QSG_system != 0";
852
+		// what we have
853
+		$question_groups = $wpdb->get_col($SQL);
854
+		// check the response
855
+		$question_groups = is_array($question_groups) ? $question_groups : array();
856
+		// what we should have
857
+		$QSG_systems = array(1, 2);
858
+		// loop thru what we should have and compare to what we have
859
+		foreach ($QSG_systems as $QSG_system) {
860
+			// reset values array
861
+			$QSG_values = array();
862
+			// if we don't have what we should have (but use $QST_system as as string because that's what we got from the db)
863
+			if (! in_array("$QSG_system", $question_groups)) {
864
+				// add it
865
+				switch ($QSG_system) {
866
+					case 1:
867
+						$QSG_values = array(
868
+							'QSG_name'            => __('Personal Information', 'event_espresso'),
869
+							'QSG_identifier'      => 'personal-information-' . time(),
870
+							'QSG_desc'            => '',
871
+							'QSG_order'           => 1,
872
+							'QSG_show_group_name' => 1,
873
+							'QSG_show_group_desc' => 1,
874
+							'QSG_system'          => EEM_Question_Group::system_personal,
875
+							'QSG_deleted'         => 0,
876
+						);
877
+						break;
878
+					case 2:
879
+						$QSG_values = array(
880
+							'QSG_name'            => __('Address Information', 'event_espresso'),
881
+							'QSG_identifier'      => 'address-information-' . time(),
882
+							'QSG_desc'            => '',
883
+							'QSG_order'           => 2,
884
+							'QSG_show_group_name' => 1,
885
+							'QSG_show_group_desc' => 1,
886
+							'QSG_system'          => EEM_Question_Group::system_address,
887
+							'QSG_deleted'         => 0,
888
+						);
889
+						break;
890
+				}
891
+				// make sure we have some values before inserting them
892
+				if (! empty($QSG_values)) {
893
+					// insert system question
894
+					$wpdb->insert(
895
+						$table_name,
896
+						$QSG_values,
897
+						array('%s', '%s', '%s', '%d', '%d', '%d', '%d', '%d')
898
+					);
899
+					$QSG_IDs[$QSG_system] = $wpdb->insert_id;
900
+				}
901
+			}
902
+		}
903
+		// QUESTIONS
904
+		global $wpdb;
905
+		$table_name = \EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix('esp_question');
906
+		$SQL = "SELECT QST_system FROM $table_name WHERE QST_system != ''";
907
+		// what we have
908
+		$questions = $wpdb->get_col($SQL);
909
+		// what we should have
910
+		$QST_systems = array(
911
+			'fname',
912
+			'lname',
913
+			'email',
914
+			'address',
915
+			'address2',
916
+			'city',
917
+			'country',
918
+			'state',
919
+			'zip',
920
+			'phone',
921
+		);
922
+		$order_for_group_1 = 1;
923
+		$order_for_group_2 = 1;
924
+		// loop thru what we should have and compare to what we have
925
+		foreach ($QST_systems as $QST_system) {
926
+			// reset values array
927
+			$QST_values = array();
928
+			// if we don't have what we should have
929
+			if (! in_array($QST_system, $questions)) {
930
+				// add it
931
+				switch ($QST_system) {
932
+					case 'fname':
933
+						$QST_values = array(
934
+							'QST_display_text'  => __('First Name', 'event_espresso'),
935
+							'QST_admin_label'   => __('First Name - System Question', 'event_espresso'),
936
+							'QST_system'        => 'fname',
937
+							'QST_type'          => 'TEXT',
938
+							'QST_required'      => 1,
939
+							'QST_required_text' => __('This field is required', 'event_espresso'),
940
+							'QST_order'         => 1,
941
+							'QST_admin_only'    => 0,
942
+							'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
943
+							'QST_wp_user'       => self::get_default_creator_id(),
944
+							'QST_deleted'       => 0,
945
+						);
946
+						break;
947
+					case 'lname':
948
+						$QST_values = array(
949
+							'QST_display_text'  => __('Last Name', 'event_espresso'),
950
+							'QST_admin_label'   => __('Last Name - System Question', 'event_espresso'),
951
+							'QST_system'        => 'lname',
952
+							'QST_type'          => 'TEXT',
953
+							'QST_required'      => 1,
954
+							'QST_required_text' => __('This field is required', 'event_espresso'),
955
+							'QST_order'         => 2,
956
+							'QST_admin_only'    => 0,
957
+							'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
958
+							'QST_wp_user'       => self::get_default_creator_id(),
959
+							'QST_deleted'       => 0,
960
+						);
961
+						break;
962
+					case 'email':
963
+						$QST_values = array(
964
+							'QST_display_text'  => __('Email Address', 'event_espresso'),
965
+							'QST_admin_label'   => __('Email Address - System Question', 'event_espresso'),
966
+							'QST_system'        => 'email',
967
+							'QST_type'          => 'EMAIL',
968
+							'QST_required'      => 1,
969
+							'QST_required_text' => __('This field is required', 'event_espresso'),
970
+							'QST_order'         => 3,
971
+							'QST_admin_only'    => 0,
972
+							'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
973
+							'QST_wp_user'       => self::get_default_creator_id(),
974
+							'QST_deleted'       => 0,
975
+						);
976
+						break;
977
+					case 'address':
978
+						$QST_values = array(
979
+							'QST_display_text'  => __('Address', 'event_espresso'),
980
+							'QST_admin_label'   => __('Address - System Question', 'event_espresso'),
981
+							'QST_system'        => 'address',
982
+							'QST_type'          => 'TEXT',
983
+							'QST_required'      => 0,
984
+							'QST_required_text' => __('This field is required', 'event_espresso'),
985
+							'QST_order'         => 4,
986
+							'QST_admin_only'    => 0,
987
+							'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
988
+							'QST_wp_user'       => self::get_default_creator_id(),
989
+							'QST_deleted'       => 0,
990
+						);
991
+						break;
992
+					case 'address2':
993
+						$QST_values = array(
994
+							'QST_display_text'  => __('Address2', 'event_espresso'),
995
+							'QST_admin_label'   => __('Address2 - System Question', 'event_espresso'),
996
+							'QST_system'        => 'address2',
997
+							'QST_type'          => 'TEXT',
998
+							'QST_required'      => 0,
999
+							'QST_required_text' => __('This field is required', 'event_espresso'),
1000
+							'QST_order'         => 5,
1001
+							'QST_admin_only'    => 0,
1002
+							'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
1003
+							'QST_wp_user'       => self::get_default_creator_id(),
1004
+							'QST_deleted'       => 0,
1005
+						);
1006
+						break;
1007
+					case 'city':
1008
+						$QST_values = array(
1009
+							'QST_display_text'  => __('City', 'event_espresso'),
1010
+							'QST_admin_label'   => __('City - System Question', 'event_espresso'),
1011
+							'QST_system'        => 'city',
1012
+							'QST_type'          => 'TEXT',
1013
+							'QST_required'      => 0,
1014
+							'QST_required_text' => __('This field is required', 'event_espresso'),
1015
+							'QST_order'         => 6,
1016
+							'QST_admin_only'    => 0,
1017
+							'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
1018
+							'QST_wp_user'       => self::get_default_creator_id(),
1019
+							'QST_deleted'       => 0,
1020
+						);
1021
+						break;
1022
+					case 'country':
1023
+						$QST_values = array(
1024
+							'QST_display_text'  => __('Country', 'event_espresso'),
1025
+							'QST_admin_label'   => __('Country - System Question', 'event_espresso'),
1026
+							'QST_system'        => 'country',
1027
+							'QST_type'          => 'COUNTRY',
1028
+							'QST_required'      => 0,
1029
+							'QST_required_text' => __('This field is required', 'event_espresso'),
1030
+							'QST_order'         => 7,
1031
+							'QST_admin_only'    => 0,
1032
+							'QST_wp_user'       => self::get_default_creator_id(),
1033
+							'QST_deleted'       => 0,
1034
+						);
1035
+						break;
1036
+					case 'state':
1037
+						$QST_values = array(
1038
+							'QST_display_text'  => __('State/Province', 'event_espresso'),
1039
+							'QST_admin_label'   => __('State/Province - System Question', 'event_espresso'),
1040
+							'QST_system'        => 'state',
1041
+							'QST_type'          => 'STATE',
1042
+							'QST_required'      => 0,
1043
+							'QST_required_text' => __('This field is required', 'event_espresso'),
1044
+							'QST_order'         => 8,
1045
+							'QST_admin_only'    => 0,
1046
+							'QST_wp_user'       => self::get_default_creator_id(),
1047
+							'QST_deleted'       => 0,
1048
+						);
1049
+						break;
1050
+					case 'zip':
1051
+						$QST_values = array(
1052
+							'QST_display_text'  => __('Zip/Postal Code', 'event_espresso'),
1053
+							'QST_admin_label'   => __('Zip/Postal Code - System Question', 'event_espresso'),
1054
+							'QST_system'        => 'zip',
1055
+							'QST_type'          => 'TEXT',
1056
+							'QST_required'      => 0,
1057
+							'QST_required_text' => __('This field is required', 'event_espresso'),
1058
+							'QST_order'         => 9,
1059
+							'QST_admin_only'    => 0,
1060
+							'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
1061
+							'QST_wp_user'       => self::get_default_creator_id(),
1062
+							'QST_deleted'       => 0,
1063
+						);
1064
+						break;
1065
+					case 'phone':
1066
+						$QST_values = array(
1067
+							'QST_display_text'  => __('Phone Number', 'event_espresso'),
1068
+							'QST_admin_label'   => __('Phone Number - System Question', 'event_espresso'),
1069
+							'QST_system'        => 'phone',
1070
+							'QST_type'          => 'TEXT',
1071
+							'QST_required'      => 0,
1072
+							'QST_required_text' => __('This field is required', 'event_espresso'),
1073
+							'QST_order'         => 10,
1074
+							'QST_admin_only'    => 0,
1075
+							'QST_max'           => EEM_Question::instance()->absolute_max_for_system_question($QST_system),
1076
+							'QST_wp_user'       => self::get_default_creator_id(),
1077
+							'QST_deleted'       => 0,
1078
+						);
1079
+						break;
1080
+				}
1081
+				if (! empty($QST_values)) {
1082
+					// insert system question
1083
+					$wpdb->insert(
1084
+						$table_name,
1085
+						$QST_values,
1086
+						array('%s', '%s', '%s', '%s', '%d', '%s', '%d', '%d', '%d', '%d')
1087
+					);
1088
+					$QST_ID = $wpdb->insert_id;
1089
+					// QUESTION GROUP QUESTIONS
1090
+					if (in_array($QST_system, array('fname', 'lname', 'email'))) {
1091
+						$system_question_we_want = EEM_Question_Group::system_personal;
1092
+					} else {
1093
+						$system_question_we_want = EEM_Question_Group::system_address;
1094
+					}
1095
+					if (isset($QSG_IDs[$system_question_we_want])) {
1096
+						$QSG_ID = $QSG_IDs[$system_question_we_want];
1097
+					} else {
1098
+						$id_col = EEM_Question_Group::instance()
1099
+													->get_col(array(array('QSG_system' => $system_question_we_want)));
1100
+						if (is_array($id_col)) {
1101
+							$QSG_ID = reset($id_col);
1102
+						} else {
1103
+							//ok so we didn't find it in the db either?? that's weird because we should have inserted it at the start of this method
1104
+							EE_Log::instance()->log(
1105
+								__FILE__,
1106
+								__FUNCTION__,
1107
+								sprintf(
1108
+									__(
1109
+										'Could not associate question %1$s to a question group because no system question
1110 1110
                                          group existed',
1111
-                                        'event_espresso'
1112
-                                    ),
1113
-                                    $QST_ID),
1114
-                                'error');
1115
-                            continue;
1116
-                        }
1117
-                    }
1118
-                    // add system questions to groups
1119
-                    $wpdb->insert(
1120
-                        \EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix('esp_question_group_question'),
1121
-                        array(
1122
-                            'QSG_ID'    => $QSG_ID,
1123
-                            'QST_ID'    => $QST_ID,
1124
-                            'QGQ_order' => ($QSG_ID === 1) ? $order_for_group_1++ : $order_for_group_2++,
1125
-                        ),
1126
-                        array('%d', '%d', '%d')
1127
-                    );
1128
-                }
1129
-            }
1130
-        }
1131
-    }
1132
-
1133
-
1134
-    /**
1135
-     * Makes sure the default payment method (Invoice) is active.
1136
-     * This used to be done automatically as part of constructing the old gateways config
1137
-     *
1138
-     * @throws \EE_Error
1139
-     */
1140
-    public static function insert_default_payment_methods()
1141
-    {
1142
-        if (! EEM_Payment_Method::instance()->count_active(EEM_Payment_Method::scope_cart)) {
1143
-            EE_Registry::instance()->load_lib('Payment_Method_Manager');
1144
-            EE_Payment_Method_Manager::instance()->activate_a_payment_method_of_type('Invoice');
1145
-        } else {
1146
-            EEM_Payment_Method::instance()->verify_button_urls();
1147
-        }
1148
-    }
1149
-
1150
-    /**
1151
-     * insert_default_status_codes
1152
-     *
1153
-     * @access public
1154
-     * @static
1155
-     * @return void
1156
-     */
1157
-    public static function insert_default_status_codes()
1158
-    {
1159
-
1160
-        global $wpdb;
1161
-
1162
-        if (\EEH_Activation::getTableAnalysis()->tableExists(EEM_Status::instance()->table())) {
1163
-
1164
-            $table_name = EEM_Status::instance()->table();
1165
-
1166
-            $SQL = "DELETE FROM $table_name WHERE STS_ID IN ( 'ACT', 'NAC', 'NOP', 'OPN', 'CLS', 'PND', 'ONG', 'SEC', 'DRF', 'DEL', 'DEN', 'EXP', 'RPP', 'RCN', 'RDC', 'RAP', 'RNA', 'RWL', 'TAB', 'TIN', 'TFL', 'TCM', 'TOP', 'PAP', 'PCN', 'PFL', 'PDC', 'EDR', 'ESN', 'PPN', 'RIC', 'MSN', 'MFL', 'MID', 'MRS', 'MIC', 'MDO', 'MEX' );";
1167
-            $wpdb->query($SQL);
1168
-
1169
-            $SQL = "INSERT INTO $table_name
1111
+										'event_espresso'
1112
+									),
1113
+									$QST_ID),
1114
+								'error');
1115
+							continue;
1116
+						}
1117
+					}
1118
+					// add system questions to groups
1119
+					$wpdb->insert(
1120
+						\EEH_Activation::getTableAnalysis()->ensureTableNameHasPrefix('esp_question_group_question'),
1121
+						array(
1122
+							'QSG_ID'    => $QSG_ID,
1123
+							'QST_ID'    => $QST_ID,
1124
+							'QGQ_order' => ($QSG_ID === 1) ? $order_for_group_1++ : $order_for_group_2++,
1125
+						),
1126
+						array('%d', '%d', '%d')
1127
+					);
1128
+				}
1129
+			}
1130
+		}
1131
+	}
1132
+
1133
+
1134
+	/**
1135
+	 * Makes sure the default payment method (Invoice) is active.
1136
+	 * This used to be done automatically as part of constructing the old gateways config
1137
+	 *
1138
+	 * @throws \EE_Error
1139
+	 */
1140
+	public static function insert_default_payment_methods()
1141
+	{
1142
+		if (! EEM_Payment_Method::instance()->count_active(EEM_Payment_Method::scope_cart)) {
1143
+			EE_Registry::instance()->load_lib('Payment_Method_Manager');
1144
+			EE_Payment_Method_Manager::instance()->activate_a_payment_method_of_type('Invoice');
1145
+		} else {
1146
+			EEM_Payment_Method::instance()->verify_button_urls();
1147
+		}
1148
+	}
1149
+
1150
+	/**
1151
+	 * insert_default_status_codes
1152
+	 *
1153
+	 * @access public
1154
+	 * @static
1155
+	 * @return void
1156
+	 */
1157
+	public static function insert_default_status_codes()
1158
+	{
1159
+
1160
+		global $wpdb;
1161
+
1162
+		if (\EEH_Activation::getTableAnalysis()->tableExists(EEM_Status::instance()->table())) {
1163
+
1164
+			$table_name = EEM_Status::instance()->table();
1165
+
1166
+			$SQL = "DELETE FROM $table_name WHERE STS_ID IN ( 'ACT', 'NAC', 'NOP', 'OPN', 'CLS', 'PND', 'ONG', 'SEC', 'DRF', 'DEL', 'DEN', 'EXP', 'RPP', 'RCN', 'RDC', 'RAP', 'RNA', 'RWL', 'TAB', 'TIN', 'TFL', 'TCM', 'TOP', 'PAP', 'PCN', 'PFL', 'PDC', 'EDR', 'ESN', 'PPN', 'RIC', 'MSN', 'MFL', 'MID', 'MRS', 'MIC', 'MDO', 'MEX' );";
1167
+			$wpdb->query($SQL);
1168
+
1169
+			$SQL = "INSERT INTO $table_name
1170 1170
 					(STS_ID, STS_code, STS_type, STS_can_edit, STS_desc, STS_open) VALUES
1171 1171
 					('ACT', 'ACTIVE', 'event', 0, NULL, 1),
1172 1172
 					('NAC', 'NOT_ACTIVE', 'event', 0, NULL, 0),
@@ -1206,462 +1206,462 @@  discard block
 block discarded – undo
1206 1206
 					('MID', 'IDLE', 'message', 0, NULL, 1),
1207 1207
 					('MRS', 'RESEND', 'message', 0, NULL, 1),
1208 1208
 					('MIC', 'INCOMPLETE', 'message', 0, NULL, 0);";
1209
-            $wpdb->query($SQL);
1210
-
1211
-        }
1212
-
1213
-    }
1214
-
1215
-
1216
-    /**
1217
-     * generate_default_message_templates
1218
-     *
1219
-     * @static
1220
-     * @throws EE_Error
1221
-     * @return bool     true means new templates were created.
1222
-     *                  false means no templates were created.
1223
-     *                  This is NOT an error flag. To check for errors you will want
1224
-     *                  to use either EE_Error or a try catch for an EE_Error exception.
1225
-     */
1226
-    public static function generate_default_message_templates()
1227
-    {
1228
-        /** @type EE_Message_Resource_Manager $message_resource_manager */
1229
-        $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
1230
-        /*
1209
+			$wpdb->query($SQL);
1210
+
1211
+		}
1212
+
1213
+	}
1214
+
1215
+
1216
+	/**
1217
+	 * generate_default_message_templates
1218
+	 *
1219
+	 * @static
1220
+	 * @throws EE_Error
1221
+	 * @return bool     true means new templates were created.
1222
+	 *                  false means no templates were created.
1223
+	 *                  This is NOT an error flag. To check for errors you will want
1224
+	 *                  to use either EE_Error or a try catch for an EE_Error exception.
1225
+	 */
1226
+	public static function generate_default_message_templates()
1227
+	{
1228
+		/** @type EE_Message_Resource_Manager $message_resource_manager */
1229
+		$message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
1230
+		/*
1231 1231
          * This first method is taking care of ensuring any default messengers
1232 1232
          * that should be made active and have templates generated are done.
1233 1233
          */
1234
-        $new_templates_created_for_messenger = self::_activate_and_generate_default_messengers_and_message_templates(
1235
-            $message_resource_manager
1236
-        );
1237
-        /**
1238
-         * This method is verifying there are no NEW default message types
1239
-         * for ACTIVE messengers that need activated (and corresponding templates setup).
1240
-         */
1241
-        $new_templates_created_for_message_type = self::_activate_new_message_types_for_active_messengers_and_generate_default_templates(
1242
-            $message_resource_manager
1243
-        );
1244
-        //after all is done, let's persist these changes to the db.
1245
-        $message_resource_manager->update_has_activated_messengers_option();
1246
-        $message_resource_manager->update_active_messengers_option();
1247
-        // will return true if either of these are true.  Otherwise will return false.
1248
-        return $new_templates_created_for_message_type || $new_templates_created_for_messenger;
1249
-    }
1250
-
1251
-
1252
-
1253
-    /**
1254
-     * @param \EE_Message_Resource_Manager $message_resource_manager
1255
-     * @return array|bool
1256
-     * @throws \EE_Error
1257
-     */
1258
-    protected static function _activate_new_message_types_for_active_messengers_and_generate_default_templates(
1259
-        EE_Message_Resource_Manager $message_resource_manager
1260
-    ) {
1261
-        /** @type EE_messenger[] $active_messengers */
1262
-        $active_messengers = $message_resource_manager->active_messengers();
1263
-        $installed_message_types = $message_resource_manager->installed_message_types();
1264
-        $templates_created = false;
1265
-        foreach ($active_messengers as $active_messenger) {
1266
-            $default_message_type_names_for_messenger = $active_messenger->get_default_message_types();
1267
-            $default_message_type_names_to_activate = array();
1268
-            // looping through each default message type reported by the messenger
1269
-            // and setup the actual message types to activate.
1270
-            foreach ($default_message_type_names_for_messenger as $default_message_type_name_for_messenger) {
1271
-                // if already active or has already been activated before we skip
1272
-                // (otherwise we might reactivate something user's intentionally deactivated.)
1273
-                // we also skip if the message type is not installed.
1274
-                if (
1275
-                    $message_resource_manager->has_message_type_been_activated_for_messenger(
1276
-                        $default_message_type_name_for_messenger,
1277
-                        $active_messenger->name
1278
-                    )
1279
-                    || $message_resource_manager->is_message_type_active_for_messenger(
1280
-                        $active_messenger->name,
1281
-                        $default_message_type_name_for_messenger
1282
-                    )
1283
-                    || ! isset($installed_message_types[$default_message_type_name_for_messenger])
1284
-                ) {
1285
-                    continue;
1286
-                }
1287
-                $default_message_type_names_to_activate[] = $default_message_type_name_for_messenger;
1288
-            }
1289
-            //let's activate!
1290
-            $message_resource_manager->ensure_message_types_are_active(
1291
-                $default_message_type_names_to_activate,
1292
-                $active_messenger->name,
1293
-                false
1294
-            );
1295
-            //activate the templates for these message types
1296
-            if ( ! empty($default_message_type_names_to_activate)) {
1297
-                $templates_created = EEH_MSG_Template::generate_new_templates(
1298
-                    $active_messenger->name,
1299
-                    $default_message_type_names_for_messenger,
1300
-                    '',
1301
-                    true
1302
-                );
1303
-            }
1304
-        }
1305
-        return $templates_created;
1306
-    }
1307
-
1308
-
1309
-
1310
-    /**
1311
-     * This will activate and generate default messengers and default message types for those messengers.
1312
-     *
1313
-     * @param EE_message_Resource_Manager $message_resource_manager
1314
-     * @return array|bool  True means there were default messengers and message type templates generated.
1315
-     *                     False means that there were no templates generated
1316
-     *                     (which could simply mean there are no default message types for a messenger).
1317
-     * @throws EE_Error
1318
-     */
1319
-    protected static function _activate_and_generate_default_messengers_and_message_templates(
1320
-        EE_Message_Resource_Manager $message_resource_manager
1321
-    ) {
1322
-        /** @type EE_messenger[] $messengers_to_generate */
1323
-        $messengers_to_generate = self::_get_default_messengers_to_generate_on_activation($message_resource_manager);
1324
-        $installed_message_types = $message_resource_manager->installed_message_types();
1325
-        $templates_generated = false;
1326
-        foreach ($messengers_to_generate as $messenger_to_generate) {
1327
-            $default_message_type_names_for_messenger = $messenger_to_generate->get_default_message_types();
1328
-            //verify the default message types match an installed message type.
1329
-            foreach ($default_message_type_names_for_messenger as $key => $name) {
1330
-                if (
1331
-                    ! isset($installed_message_types[$name])
1332
-                    || $message_resource_manager->has_message_type_been_activated_for_messenger(
1333
-                        $name,
1334
-                        $messenger_to_generate->name
1335
-                    )
1336
-                ) {
1337
-                    unset($default_message_type_names_for_messenger[$key]);
1338
-                }
1339
-            }
1340
-            // in previous iterations, the active_messengers option in the db
1341
-            // needed updated before calling create templates. however with the changes this may not be necessary.
1342
-            // This comment is left here just in case we discover that we _do_ need to update before
1343
-            // passing off to create templates (after the refactor is done).
1344
-            // @todo remove this comment when determined not necessary.
1345
-            $message_resource_manager->activate_messenger(
1346
-                $messenger_to_generate->name,
1347
-                $default_message_type_names_for_messenger,
1348
-                false
1349
-            );
1350
-            //create any templates needing created (or will reactivate templates already generated as necessary).
1351
-            if ( ! empty($default_message_type_names_for_messenger)) {
1352
-                $templates_generated = EEH_MSG_Template::generate_new_templates(
1353
-                    $messenger_to_generate->name,
1354
-                    $default_message_type_names_for_messenger,
1355
-                    '',
1356
-                    true
1357
-                );
1358
-            }
1359
-        }
1360
-        return $templates_generated;
1361
-    }
1362
-
1363
-
1364
-    /**
1365
-     * This returns the default messengers to generate templates for on activation of EE.
1366
-     * It considers:
1367
-     * - whether a messenger is already active in the db.
1368
-     * - whether a messenger has been made active at any time in the past.
1369
-     *
1370
-     * @static
1371
-     * @param  EE_Message_Resource_Manager $message_resource_manager
1372
-     * @return EE_messenger[]
1373
-     */
1374
-    protected static function _get_default_messengers_to_generate_on_activation(
1375
-        EE_Message_Resource_Manager $message_resource_manager
1376
-    ) {
1377
-        $active_messengers    = $message_resource_manager->active_messengers();
1378
-        $installed_messengers = $message_resource_manager->installed_messengers();
1379
-        $has_activated        = $message_resource_manager->get_has_activated_messengers_option();
1380
-
1381
-        $messengers_to_generate = array();
1382
-        foreach ($installed_messengers as $installed_messenger) {
1383
-            //if installed messenger is a messenger that should be activated on install
1384
-            //and is not already active
1385
-            //and has never been activated
1386
-            if (
1387
-                ! $installed_messenger->activate_on_install
1388
-                || isset($active_messengers[$installed_messenger->name])
1389
-                || isset($has_activated[$installed_messenger->name])
1390
-            ) {
1391
-                continue;
1392
-            }
1393
-            $messengers_to_generate[$installed_messenger->name] = $installed_messenger;
1394
-        }
1395
-        return $messengers_to_generate;
1396
-    }
1397
-
1398
-
1399
-    /**
1400
-     * This simply validates active message types to ensure they actually match installed
1401
-     * message types.  If there's a mismatch then we deactivate the message type and ensure all related db
1402
-     * rows are set inactive.
1403
-     * Note: Messengers are no longer validated here as of 4.9.0 because they get validated automatically whenever
1404
-     * EE_Messenger_Resource_Manager is constructed.  Message Types are a bit more resource heavy for validation so they
1405
-     * are still handled in here.
1406
-     *
1407
-     * @since 4.3.1
1408
-     * @return void
1409
-     */
1410
-    public static function validate_messages_system()
1411
-    {
1412
-        /** @type EE_Message_Resource_Manager $message_resource_manager */
1413
-        $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
1414
-        $message_resource_manager->validate_active_message_types_are_installed();
1415
-        do_action('AHEE__EEH_Activation__validate_messages_system');
1416
-    }
1417
-
1418
-
1419
-    /**
1420
-     * create_no_ticket_prices_array
1421
-     *
1422
-     * @access public
1423
-     * @static
1424
-     * @return void
1425
-     */
1426
-    public static function create_no_ticket_prices_array()
1427
-    {
1428
-        // this creates an array for tracking events that have no active ticket prices created
1429
-        // this allows us to warn admins of the situation so that it can be corrected
1430
-        $espresso_no_ticket_prices = get_option('ee_no_ticket_prices', false);
1431
-        if (! $espresso_no_ticket_prices) {
1432
-            add_option('ee_no_ticket_prices', array(), '', false);
1433
-        }
1434
-    }
1435
-
1436
-
1437
-    /**
1438
-     * plugin_deactivation
1439
-     *
1440
-     * @access public
1441
-     * @static
1442
-     * @return void
1443
-     */
1444
-    public static function plugin_deactivation()
1445
-    {
1446
-    }
1447
-
1448
-
1449
-    /**
1450
-     * Finds all our EE4 custom post types, and deletes them and their associated data
1451
-     * (like post meta or term relations)
1452
-     *
1453
-     * @global wpdb $wpdb
1454
-     * @throws \EE_Error
1455
-     */
1456
-    public static function delete_all_espresso_cpt_data()
1457
-    {
1458
-        global $wpdb;
1459
-        //get all the CPT post_types
1460
-        $ee_post_types = array();
1461
-        foreach (EE_Registry::instance()->non_abstract_db_models as $model_name) {
1462
-            if (method_exists($model_name, 'instance')) {
1463
-                $model_obj = call_user_func(array($model_name, 'instance'));
1464
-                if ($model_obj instanceof EEM_CPT_Base) {
1465
-                    $ee_post_types[] = $wpdb->prepare("%s", $model_obj->post_type());
1466
-                }
1467
-            }
1468
-        }
1469
-        //get all our CPTs
1470
-        $query   = "SELECT ID FROM {$wpdb->posts} WHERE post_type IN (" . implode(",", $ee_post_types) . ")";
1471
-        $cpt_ids = $wpdb->get_col($query);
1472
-        //delete each post meta and term relations too
1473
-        foreach ($cpt_ids as $post_id) {
1474
-            wp_delete_post($post_id, true);
1475
-        }
1476
-    }
1477
-
1478
-    /**
1479
-     * Deletes all EE custom tables
1480
-     *
1481
-     * @return array
1482
-     */
1483
-    public static function drop_espresso_tables()
1484
-    {
1485
-        $tables = array();
1486
-        // load registry
1487
-        foreach (EE_Registry::instance()->non_abstract_db_models as $model_name) {
1488
-            if (method_exists($model_name, 'instance')) {
1489
-                $model_obj = call_user_func(array($model_name, 'instance'));
1490
-                if ($model_obj instanceof EEM_Base) {
1491
-                    foreach ($model_obj->get_tables() as $table) {
1492
-                        if (strpos($table->get_table_name(), 'esp_')
1493
-                            &&
1494
-                            (
1495
-                                is_main_site()//main site? nuke them all
1496
-                                || ! $table->is_global()//not main site,but not global either. nuke it
1497
-                            )
1498
-                        ) {
1499
-                            $tables[$table->get_table_name()] = $table->get_table_name();
1500
-                        }
1501
-                    }
1502
-                }
1503
-            }
1504
-        }
1505
-
1506
-        //there are some tables whose models were removed.
1507
-        //they should be removed when removing all EE core's data
1508
-        $tables_without_models = array(
1509
-            'esp_promotion',
1510
-            'esp_promotion_applied',
1511
-            'esp_promotion_object',
1512
-            'esp_promotion_rule',
1513
-            'esp_rule',
1514
-        );
1515
-        foreach ($tables_without_models as $table) {
1516
-            $tables[$table] = $table;
1517
-        }
1518
-        return \EEH_Activation::getTableManager()->dropTables($tables);
1519
-    }
1520
-
1521
-
1522
-
1523
-    /**
1524
-     * Drops all the tables mentioned in a single MYSQL query. Double-checks
1525
-     * each table name provided has a wpdb prefix attached, and that it exists.
1526
-     * Returns the list actually deleted
1527
-     *
1528
-     * @deprecated in 4.9.13. Instead use TableManager::dropTables()
1529
-     * @global WPDB $wpdb
1530
-     * @param array $table_names
1531
-     * @return array of table names which we deleted
1532
-     */
1533
-    public static function drop_tables($table_names)
1534
-    {
1535
-        return \EEH_Activation::getTableManager()->dropTables($table_names);
1536
-    }
1537
-
1538
-
1539
-
1540
-    /**
1541
-     * plugin_uninstall
1542
-     *
1543
-     * @access public
1544
-     * @static
1545
-     * @param bool $remove_all
1546
-     * @return void
1547
-     */
1548
-    public static function delete_all_espresso_tables_and_data($remove_all = true)
1549
-    {
1550
-        global $wpdb;
1551
-        self::drop_espresso_tables();
1552
-        $wp_options_to_delete = array(
1553
-            'ee_no_ticket_prices'                => true,
1554
-            'ee_active_messengers'               => true,
1555
-            'ee_has_activated_messenger'         => true,
1556
-            RewriteRules::OPTION_KEY_FLUSH_REWRITE_RULES => true,
1557
-            'ee_config'                          => false,
1558
-            'ee_data_migration_current_db_state' => true,
1559
-            'ee_data_migration_mapping_'         => false,
1560
-            'ee_data_migration_script_'          => false,
1561
-            'ee_data_migrations'                 => true,
1562
-            'ee_dms_map'                         => false,
1563
-            'ee_notices'                         => true,
1564
-            'lang_file_check_'                   => false,
1565
-            'ee_maintenance_mode'                => true,
1566
-            'ee_ueip_optin'                      => true,
1567
-            'ee_ueip_has_notified'               => true,
1568
-            'ee_plugin_activation_errors'        => true,
1569
-            'ee_id_mapping_from'                 => false,
1570
-            'espresso_persistent_admin_notices'  => true,
1571
-            'ee_encryption_key'                  => true,
1572
-            'pue_force_upgrade_'                 => false,
1573
-            'pue_json_error_'                    => false,
1574
-            'pue_install_key_'                   => false,
1575
-            'pue_verification_error_'            => false,
1576
-            'pu_dismissed_upgrade_'              => false,
1577
-            'external_updates-'                  => false,
1578
-            'ee_extra_data'                      => true,
1579
-            'ee_ssn_'                            => false,
1580
-            'ee_rss_'                            => false,
1581
-            'ee_rte_n_tx_'                       => false,
1582
-            'ee_pers_admin_notices'              => true,
1583
-            'ee_job_parameters_'                 => false,
1584
-            'ee_upload_directories_incomplete'   => true,
1585
-            'ee_verified_db_collations'          => true,
1586
-        );
1587
-        if (is_main_site()) {
1588
-            $wp_options_to_delete['ee_network_config'] = true;
1589
-        }
1590
-        $undeleted_options = array();
1591
-        foreach ($wp_options_to_delete as $option_name => $no_wildcard) {
1592
-            if ($no_wildcard) {
1593
-                if ( ! delete_option($option_name)) {
1594
-                    $undeleted_options[] = $option_name;
1595
-                }
1596
-            } else {
1597
-                $option_names_to_delete_from_wildcard = $wpdb->get_col("SELECT option_name FROM $wpdb->options WHERE option_name LIKE '%$option_name%'");
1598
-                foreach ($option_names_to_delete_from_wildcard as $option_name_from_wildcard) {
1599
-                    if ( ! delete_option($option_name_from_wildcard)) {
1600
-                        $undeleted_options[] = $option_name_from_wildcard;
1601
-                    }
1602
-                }
1603
-            }
1604
-        }
1605
-        //also, let's make sure the "ee_config_option_names" wp option stays out by removing the action that adds it
1606
-        remove_action('shutdown', array(EE_Config::instance(), 'shutdown'), 10);
1607
-        if ($remove_all && $espresso_db_update = get_option('espresso_db_update')) {
1608
-            $db_update_sans_ee4 = array();
1609
-            foreach ($espresso_db_update as $version => $times_activated) {
1610
-                if ((string)$version[0] === '3') {//if its NON EE4
1611
-                    $db_update_sans_ee4[$version] = $times_activated;
1612
-                }
1613
-            }
1614
-            update_option('espresso_db_update', $db_update_sans_ee4);
1615
-        }
1616
-        $errors = '';
1617
-        if ( ! empty($undeleted_options)) {
1618
-            $errors .= sprintf(
1619
-                __('The following wp-options could not be deleted: %s%s', 'event_espresso'),
1620
-                '<br/>',
1621
-                implode(',<br/>', $undeleted_options)
1622
-            );
1623
-        }
1624
-        if ( ! empty($errors)) {
1625
-            EE_Error::add_attention($errors, __FILE__, __FUNCTION__, __LINE__);
1626
-        }
1627
-    }
1628
-
1629
-    /**
1630
-     * Gets the mysql error code from the last used query by wpdb
1631
-     *
1632
-     * @return int mysql error code, see https://dev.mysql.com/doc/refman/5.5/en/error-messages-server.html
1633
-     */
1634
-    public static function last_wpdb_error_code()
1635
-    {
1636
-        global $wpdb;
1637
-        if ($wpdb->use_mysqli) {
1638
-            return mysqli_errno($wpdb->dbh);
1639
-        } else {
1640
-            return mysql_errno($wpdb->dbh);
1641
-        }
1642
-    }
1643
-
1644
-    /**
1645
-     * Checks that the database table exists. Also works on temporary tables (for unit tests mostly).
1646
-     *
1647
-     * @global wpdb  $wpdb
1648
-     * @deprecated instead use TableAnalysis::tableExists()
1649
-     * @param string $table_name with or without $wpdb->prefix
1650
-     * @return boolean
1651
-     */
1652
-    public static function table_exists($table_name)
1653
-    {
1654
-        return \EEH_Activation::getTableAnalysis()->tableExists($table_name);
1655
-    }
1656
-
1657
-    /**
1658
-     * Resets the cache on EEH_Activation
1659
-     */
1660
-    public static function reset()
1661
-    {
1662
-        self::$_default_creator_id                             = null;
1663
-        self::$_initialized_db_content_already_in_this_request = false;
1664
-    }
1234
+		$new_templates_created_for_messenger = self::_activate_and_generate_default_messengers_and_message_templates(
1235
+			$message_resource_manager
1236
+		);
1237
+		/**
1238
+		 * This method is verifying there are no NEW default message types
1239
+		 * for ACTIVE messengers that need activated (and corresponding templates setup).
1240
+		 */
1241
+		$new_templates_created_for_message_type = self::_activate_new_message_types_for_active_messengers_and_generate_default_templates(
1242
+			$message_resource_manager
1243
+		);
1244
+		//after all is done, let's persist these changes to the db.
1245
+		$message_resource_manager->update_has_activated_messengers_option();
1246
+		$message_resource_manager->update_active_messengers_option();
1247
+		// will return true if either of these are true.  Otherwise will return false.
1248
+		return $new_templates_created_for_message_type || $new_templates_created_for_messenger;
1249
+	}
1250
+
1251
+
1252
+
1253
+	/**
1254
+	 * @param \EE_Message_Resource_Manager $message_resource_manager
1255
+	 * @return array|bool
1256
+	 * @throws \EE_Error
1257
+	 */
1258
+	protected static function _activate_new_message_types_for_active_messengers_and_generate_default_templates(
1259
+		EE_Message_Resource_Manager $message_resource_manager
1260
+	) {
1261
+		/** @type EE_messenger[] $active_messengers */
1262
+		$active_messengers = $message_resource_manager->active_messengers();
1263
+		$installed_message_types = $message_resource_manager->installed_message_types();
1264
+		$templates_created = false;
1265
+		foreach ($active_messengers as $active_messenger) {
1266
+			$default_message_type_names_for_messenger = $active_messenger->get_default_message_types();
1267
+			$default_message_type_names_to_activate = array();
1268
+			// looping through each default message type reported by the messenger
1269
+			// and setup the actual message types to activate.
1270
+			foreach ($default_message_type_names_for_messenger as $default_message_type_name_for_messenger) {
1271
+				// if already active or has already been activated before we skip
1272
+				// (otherwise we might reactivate something user's intentionally deactivated.)
1273
+				// we also skip if the message type is not installed.
1274
+				if (
1275
+					$message_resource_manager->has_message_type_been_activated_for_messenger(
1276
+						$default_message_type_name_for_messenger,
1277
+						$active_messenger->name
1278
+					)
1279
+					|| $message_resource_manager->is_message_type_active_for_messenger(
1280
+						$active_messenger->name,
1281
+						$default_message_type_name_for_messenger
1282
+					)
1283
+					|| ! isset($installed_message_types[$default_message_type_name_for_messenger])
1284
+				) {
1285
+					continue;
1286
+				}
1287
+				$default_message_type_names_to_activate[] = $default_message_type_name_for_messenger;
1288
+			}
1289
+			//let's activate!
1290
+			$message_resource_manager->ensure_message_types_are_active(
1291
+				$default_message_type_names_to_activate,
1292
+				$active_messenger->name,
1293
+				false
1294
+			);
1295
+			//activate the templates for these message types
1296
+			if ( ! empty($default_message_type_names_to_activate)) {
1297
+				$templates_created = EEH_MSG_Template::generate_new_templates(
1298
+					$active_messenger->name,
1299
+					$default_message_type_names_for_messenger,
1300
+					'',
1301
+					true
1302
+				);
1303
+			}
1304
+		}
1305
+		return $templates_created;
1306
+	}
1307
+
1308
+
1309
+
1310
+	/**
1311
+	 * This will activate and generate default messengers and default message types for those messengers.
1312
+	 *
1313
+	 * @param EE_message_Resource_Manager $message_resource_manager
1314
+	 * @return array|bool  True means there were default messengers and message type templates generated.
1315
+	 *                     False means that there were no templates generated
1316
+	 *                     (which could simply mean there are no default message types for a messenger).
1317
+	 * @throws EE_Error
1318
+	 */
1319
+	protected static function _activate_and_generate_default_messengers_and_message_templates(
1320
+		EE_Message_Resource_Manager $message_resource_manager
1321
+	) {
1322
+		/** @type EE_messenger[] $messengers_to_generate */
1323
+		$messengers_to_generate = self::_get_default_messengers_to_generate_on_activation($message_resource_manager);
1324
+		$installed_message_types = $message_resource_manager->installed_message_types();
1325
+		$templates_generated = false;
1326
+		foreach ($messengers_to_generate as $messenger_to_generate) {
1327
+			$default_message_type_names_for_messenger = $messenger_to_generate->get_default_message_types();
1328
+			//verify the default message types match an installed message type.
1329
+			foreach ($default_message_type_names_for_messenger as $key => $name) {
1330
+				if (
1331
+					! isset($installed_message_types[$name])
1332
+					|| $message_resource_manager->has_message_type_been_activated_for_messenger(
1333
+						$name,
1334
+						$messenger_to_generate->name
1335
+					)
1336
+				) {
1337
+					unset($default_message_type_names_for_messenger[$key]);
1338
+				}
1339
+			}
1340
+			// in previous iterations, the active_messengers option in the db
1341
+			// needed updated before calling create templates. however with the changes this may not be necessary.
1342
+			// This comment is left here just in case we discover that we _do_ need to update before
1343
+			// passing off to create templates (after the refactor is done).
1344
+			// @todo remove this comment when determined not necessary.
1345
+			$message_resource_manager->activate_messenger(
1346
+				$messenger_to_generate->name,
1347
+				$default_message_type_names_for_messenger,
1348
+				false
1349
+			);
1350
+			//create any templates needing created (or will reactivate templates already generated as necessary).
1351
+			if ( ! empty($default_message_type_names_for_messenger)) {
1352
+				$templates_generated = EEH_MSG_Template::generate_new_templates(
1353
+					$messenger_to_generate->name,
1354
+					$default_message_type_names_for_messenger,
1355
+					'',
1356
+					true
1357
+				);
1358
+			}
1359
+		}
1360
+		return $templates_generated;
1361
+	}
1362
+
1363
+
1364
+	/**
1365
+	 * This returns the default messengers to generate templates for on activation of EE.
1366
+	 * It considers:
1367
+	 * - whether a messenger is already active in the db.
1368
+	 * - whether a messenger has been made active at any time in the past.
1369
+	 *
1370
+	 * @static
1371
+	 * @param  EE_Message_Resource_Manager $message_resource_manager
1372
+	 * @return EE_messenger[]
1373
+	 */
1374
+	protected static function _get_default_messengers_to_generate_on_activation(
1375
+		EE_Message_Resource_Manager $message_resource_manager
1376
+	) {
1377
+		$active_messengers    = $message_resource_manager->active_messengers();
1378
+		$installed_messengers = $message_resource_manager->installed_messengers();
1379
+		$has_activated        = $message_resource_manager->get_has_activated_messengers_option();
1380
+
1381
+		$messengers_to_generate = array();
1382
+		foreach ($installed_messengers as $installed_messenger) {
1383
+			//if installed messenger is a messenger that should be activated on install
1384
+			//and is not already active
1385
+			//and has never been activated
1386
+			if (
1387
+				! $installed_messenger->activate_on_install
1388
+				|| isset($active_messengers[$installed_messenger->name])
1389
+				|| isset($has_activated[$installed_messenger->name])
1390
+			) {
1391
+				continue;
1392
+			}
1393
+			$messengers_to_generate[$installed_messenger->name] = $installed_messenger;
1394
+		}
1395
+		return $messengers_to_generate;
1396
+	}
1397
+
1398
+
1399
+	/**
1400
+	 * This simply validates active message types to ensure they actually match installed
1401
+	 * message types.  If there's a mismatch then we deactivate the message type and ensure all related db
1402
+	 * rows are set inactive.
1403
+	 * Note: Messengers are no longer validated here as of 4.9.0 because they get validated automatically whenever
1404
+	 * EE_Messenger_Resource_Manager is constructed.  Message Types are a bit more resource heavy for validation so they
1405
+	 * are still handled in here.
1406
+	 *
1407
+	 * @since 4.3.1
1408
+	 * @return void
1409
+	 */
1410
+	public static function validate_messages_system()
1411
+	{
1412
+		/** @type EE_Message_Resource_Manager $message_resource_manager */
1413
+		$message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
1414
+		$message_resource_manager->validate_active_message_types_are_installed();
1415
+		do_action('AHEE__EEH_Activation__validate_messages_system');
1416
+	}
1417
+
1418
+
1419
+	/**
1420
+	 * create_no_ticket_prices_array
1421
+	 *
1422
+	 * @access public
1423
+	 * @static
1424
+	 * @return void
1425
+	 */
1426
+	public static function create_no_ticket_prices_array()
1427
+	{
1428
+		// this creates an array for tracking events that have no active ticket prices created
1429
+		// this allows us to warn admins of the situation so that it can be corrected
1430
+		$espresso_no_ticket_prices = get_option('ee_no_ticket_prices', false);
1431
+		if (! $espresso_no_ticket_prices) {
1432
+			add_option('ee_no_ticket_prices', array(), '', false);
1433
+		}
1434
+	}
1435
+
1436
+
1437
+	/**
1438
+	 * plugin_deactivation
1439
+	 *
1440
+	 * @access public
1441
+	 * @static
1442
+	 * @return void
1443
+	 */
1444
+	public static function plugin_deactivation()
1445
+	{
1446
+	}
1447
+
1448
+
1449
+	/**
1450
+	 * Finds all our EE4 custom post types, and deletes them and their associated data
1451
+	 * (like post meta or term relations)
1452
+	 *
1453
+	 * @global wpdb $wpdb
1454
+	 * @throws \EE_Error
1455
+	 */
1456
+	public static function delete_all_espresso_cpt_data()
1457
+	{
1458
+		global $wpdb;
1459
+		//get all the CPT post_types
1460
+		$ee_post_types = array();
1461
+		foreach (EE_Registry::instance()->non_abstract_db_models as $model_name) {
1462
+			if (method_exists($model_name, 'instance')) {
1463
+				$model_obj = call_user_func(array($model_name, 'instance'));
1464
+				if ($model_obj instanceof EEM_CPT_Base) {
1465
+					$ee_post_types[] = $wpdb->prepare("%s", $model_obj->post_type());
1466
+				}
1467
+			}
1468
+		}
1469
+		//get all our CPTs
1470
+		$query   = "SELECT ID FROM {$wpdb->posts} WHERE post_type IN (" . implode(",", $ee_post_types) . ")";
1471
+		$cpt_ids = $wpdb->get_col($query);
1472
+		//delete each post meta and term relations too
1473
+		foreach ($cpt_ids as $post_id) {
1474
+			wp_delete_post($post_id, true);
1475
+		}
1476
+	}
1477
+
1478
+	/**
1479
+	 * Deletes all EE custom tables
1480
+	 *
1481
+	 * @return array
1482
+	 */
1483
+	public static function drop_espresso_tables()
1484
+	{
1485
+		$tables = array();
1486
+		// load registry
1487
+		foreach (EE_Registry::instance()->non_abstract_db_models as $model_name) {
1488
+			if (method_exists($model_name, 'instance')) {
1489
+				$model_obj = call_user_func(array($model_name, 'instance'));
1490
+				if ($model_obj instanceof EEM_Base) {
1491
+					foreach ($model_obj->get_tables() as $table) {
1492
+						if (strpos($table->get_table_name(), 'esp_')
1493
+							&&
1494
+							(
1495
+								is_main_site()//main site? nuke them all
1496
+								|| ! $table->is_global()//not main site,but not global either. nuke it
1497
+							)
1498
+						) {
1499
+							$tables[$table->get_table_name()] = $table->get_table_name();
1500
+						}
1501
+					}
1502
+				}
1503
+			}
1504
+		}
1505
+
1506
+		//there are some tables whose models were removed.
1507
+		//they should be removed when removing all EE core's data
1508
+		$tables_without_models = array(
1509
+			'esp_promotion',
1510
+			'esp_promotion_applied',
1511
+			'esp_promotion_object',
1512
+			'esp_promotion_rule',
1513
+			'esp_rule',
1514
+		);
1515
+		foreach ($tables_without_models as $table) {
1516
+			$tables[$table] = $table;
1517
+		}
1518
+		return \EEH_Activation::getTableManager()->dropTables($tables);
1519
+	}
1520
+
1521
+
1522
+
1523
+	/**
1524
+	 * Drops all the tables mentioned in a single MYSQL query. Double-checks
1525
+	 * each table name provided has a wpdb prefix attached, and that it exists.
1526
+	 * Returns the list actually deleted
1527
+	 *
1528
+	 * @deprecated in 4.9.13. Instead use TableManager::dropTables()
1529
+	 * @global WPDB $wpdb
1530
+	 * @param array $table_names
1531
+	 * @return array of table names which we deleted
1532
+	 */
1533
+	public static function drop_tables($table_names)
1534
+	{
1535
+		return \EEH_Activation::getTableManager()->dropTables($table_names);
1536
+	}
1537
+
1538
+
1539
+
1540
+	/**
1541
+	 * plugin_uninstall
1542
+	 *
1543
+	 * @access public
1544
+	 * @static
1545
+	 * @param bool $remove_all
1546
+	 * @return void
1547
+	 */
1548
+	public static function delete_all_espresso_tables_and_data($remove_all = true)
1549
+	{
1550
+		global $wpdb;
1551
+		self::drop_espresso_tables();
1552
+		$wp_options_to_delete = array(
1553
+			'ee_no_ticket_prices'                => true,
1554
+			'ee_active_messengers'               => true,
1555
+			'ee_has_activated_messenger'         => true,
1556
+			RewriteRules::OPTION_KEY_FLUSH_REWRITE_RULES => true,
1557
+			'ee_config'                          => false,
1558
+			'ee_data_migration_current_db_state' => true,
1559
+			'ee_data_migration_mapping_'         => false,
1560
+			'ee_data_migration_script_'          => false,
1561
+			'ee_data_migrations'                 => true,
1562
+			'ee_dms_map'                         => false,
1563
+			'ee_notices'                         => true,
1564
+			'lang_file_check_'                   => false,
1565
+			'ee_maintenance_mode'                => true,
1566
+			'ee_ueip_optin'                      => true,
1567
+			'ee_ueip_has_notified'               => true,
1568
+			'ee_plugin_activation_errors'        => true,
1569
+			'ee_id_mapping_from'                 => false,
1570
+			'espresso_persistent_admin_notices'  => true,
1571
+			'ee_encryption_key'                  => true,
1572
+			'pue_force_upgrade_'                 => false,
1573
+			'pue_json_error_'                    => false,
1574
+			'pue_install_key_'                   => false,
1575
+			'pue_verification_error_'            => false,
1576
+			'pu_dismissed_upgrade_'              => false,
1577
+			'external_updates-'                  => false,
1578
+			'ee_extra_data'                      => true,
1579
+			'ee_ssn_'                            => false,
1580
+			'ee_rss_'                            => false,
1581
+			'ee_rte_n_tx_'                       => false,
1582
+			'ee_pers_admin_notices'              => true,
1583
+			'ee_job_parameters_'                 => false,
1584
+			'ee_upload_directories_incomplete'   => true,
1585
+			'ee_verified_db_collations'          => true,
1586
+		);
1587
+		if (is_main_site()) {
1588
+			$wp_options_to_delete['ee_network_config'] = true;
1589
+		}
1590
+		$undeleted_options = array();
1591
+		foreach ($wp_options_to_delete as $option_name => $no_wildcard) {
1592
+			if ($no_wildcard) {
1593
+				if ( ! delete_option($option_name)) {
1594
+					$undeleted_options[] = $option_name;
1595
+				}
1596
+			} else {
1597
+				$option_names_to_delete_from_wildcard = $wpdb->get_col("SELECT option_name FROM $wpdb->options WHERE option_name LIKE '%$option_name%'");
1598
+				foreach ($option_names_to_delete_from_wildcard as $option_name_from_wildcard) {
1599
+					if ( ! delete_option($option_name_from_wildcard)) {
1600
+						$undeleted_options[] = $option_name_from_wildcard;
1601
+					}
1602
+				}
1603
+			}
1604
+		}
1605
+		//also, let's make sure the "ee_config_option_names" wp option stays out by removing the action that adds it
1606
+		remove_action('shutdown', array(EE_Config::instance(), 'shutdown'), 10);
1607
+		if ($remove_all && $espresso_db_update = get_option('espresso_db_update')) {
1608
+			$db_update_sans_ee4 = array();
1609
+			foreach ($espresso_db_update as $version => $times_activated) {
1610
+				if ((string)$version[0] === '3') {//if its NON EE4
1611
+					$db_update_sans_ee4[$version] = $times_activated;
1612
+				}
1613
+			}
1614
+			update_option('espresso_db_update', $db_update_sans_ee4);
1615
+		}
1616
+		$errors = '';
1617
+		if ( ! empty($undeleted_options)) {
1618
+			$errors .= sprintf(
1619
+				__('The following wp-options could not be deleted: %s%s', 'event_espresso'),
1620
+				'<br/>',
1621
+				implode(',<br/>', $undeleted_options)
1622
+			);
1623
+		}
1624
+		if ( ! empty($errors)) {
1625
+			EE_Error::add_attention($errors, __FILE__, __FUNCTION__, __LINE__);
1626
+		}
1627
+	}
1628
+
1629
+	/**
1630
+	 * Gets the mysql error code from the last used query by wpdb
1631
+	 *
1632
+	 * @return int mysql error code, see https://dev.mysql.com/doc/refman/5.5/en/error-messages-server.html
1633
+	 */
1634
+	public static function last_wpdb_error_code()
1635
+	{
1636
+		global $wpdb;
1637
+		if ($wpdb->use_mysqli) {
1638
+			return mysqli_errno($wpdb->dbh);
1639
+		} else {
1640
+			return mysql_errno($wpdb->dbh);
1641
+		}
1642
+	}
1643
+
1644
+	/**
1645
+	 * Checks that the database table exists. Also works on temporary tables (for unit tests mostly).
1646
+	 *
1647
+	 * @global wpdb  $wpdb
1648
+	 * @deprecated instead use TableAnalysis::tableExists()
1649
+	 * @param string $table_name with or without $wpdb->prefix
1650
+	 * @return boolean
1651
+	 */
1652
+	public static function table_exists($table_name)
1653
+	{
1654
+		return \EEH_Activation::getTableAnalysis()->tableExists($table_name);
1655
+	}
1656
+
1657
+	/**
1658
+	 * Resets the cache on EEH_Activation
1659
+	 */
1660
+	public static function reset()
1661
+	{
1662
+		self::$_default_creator_id                             = null;
1663
+		self::$_initialized_db_content_already_in_this_request = false;
1664
+	}
1665 1665
 }
1666 1666
 // End of file EEH_Activation.helper.php
1667 1667
 // Location: /helpers/EEH_Activation.core.php
Please login to merge, or discard this patch.
reg_steps/payment_options/EE_SPCO_Reg_Step_Payment_Options.class.php 1 patch
Indentation   +2870 added lines, -2870 removed lines patch added patch discarded remove patch
@@ -15,2874 +15,2874 @@
 block discarded – undo
15 15
 class EE_SPCO_Reg_Step_Payment_Options extends EE_SPCO_Reg_Step
16 16
 {
17 17
 
18
-    /**
19
-     * @access protected
20
-     * @var EE_Line_Item_Display $Line_Item_Display
21
-     */
22
-    protected $line_item_display;
23
-
24
-    /**
25
-     * @access protected
26
-     * @var boolean $handle_IPN_in_this_request
27
-     */
28
-    protected $handle_IPN_in_this_request = false;
29
-
30
-
31
-    /**
32
-     *    set_hooks - for hooking into EE Core, other modules, etc
33
-     *
34
-     * @access    public
35
-     * @return    void
36
-     */
37
-    public static function set_hooks()
38
-    {
39
-        add_filter(
40
-            'FHEE__SPCO__EE_Line_Item_Filter_Collection',
41
-            array('EE_SPCO_Reg_Step_Payment_Options', 'add_spco_line_item_filters')
42
-        );
43
-        add_action(
44
-            'wp_ajax_switch_spco_billing_form',
45
-            array('EE_SPCO_Reg_Step_Payment_Options', 'switch_spco_billing_form')
46
-        );
47
-        add_action(
48
-            'wp_ajax_nopriv_switch_spco_billing_form',
49
-            array('EE_SPCO_Reg_Step_Payment_Options', 'switch_spco_billing_form')
50
-        );
51
-        add_action('wp_ajax_save_payer_details', array('EE_SPCO_Reg_Step_Payment_Options', 'save_payer_details'));
52
-        add_action(
53
-            'wp_ajax_nopriv_save_payer_details',
54
-            array('EE_SPCO_Reg_Step_Payment_Options', 'save_payer_details')
55
-        );
56
-        add_action(
57
-            'wp_ajax_get_transaction_details_for_gateways',
58
-            array('EE_SPCO_Reg_Step_Payment_Options', 'get_transaction_details')
59
-        );
60
-        add_action(
61
-            'wp_ajax_nopriv_get_transaction_details_for_gateways',
62
-            array('EE_SPCO_Reg_Step_Payment_Options', 'get_transaction_details')
63
-        );
64
-        add_filter(
65
-            'FHEE__EED_Recaptcha___bypass_recaptcha__bypass_request_params_array',
66
-            array('EE_SPCO_Reg_Step_Payment_Options', 'bypass_recaptcha_for_load_payment_method'),
67
-            10,
68
-            1
69
-        );
70
-    }
71
-
72
-
73
-    /**
74
-     *    ajax switch_spco_billing_form
75
-     *
76
-     * @throws \EE_Error
77
-     */
78
-    public static function switch_spco_billing_form()
79
-    {
80
-        EED_Single_Page_Checkout::process_ajax_request('switch_payment_method');
81
-    }
82
-
83
-
84
-    /**
85
-     *    ajax save_payer_details
86
-     *
87
-     * @throws \EE_Error
88
-     */
89
-    public static function save_payer_details()
90
-    {
91
-        EED_Single_Page_Checkout::process_ajax_request('save_payer_details_via_ajax');
92
-    }
93
-
94
-
95
-    /**
96
-     *    ajax get_transaction_details
97
-     *
98
-     * @throws \EE_Error
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 \EventEspresso\core\exceptions\InvalidDataTypeException
113
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
114
-     */
115
-    public static function bypass_recaptcha_for_load_payment_method()
116
-    {
117
-        return array(
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->_slug     = 'payment_options';
134
-        $this->_name     = esc_html__('Payment Options', 'event_espresso');
135
-        $this->_template = SPCO_REG_STEPS_PATH . $this->_slug . DS . 'payment_options_main.template.php';
136
-        $this->checkout  = $checkout;
137
-        $this->_reset_success_message();
138
-        $this->set_instructions(
139
-            esc_html__(
140
-                'Please select a method of payment and provide any necessary billing information before proceeding.',
141
-                'event_espresso'
142
-            )
143
-        );
144
-    }
145
-
146
-
147
-    /**
148
-     * @return null
149
-     */
150
-    public function line_item_display()
151
-    {
152
-        return $this->line_item_display;
153
-    }
154
-
155
-
156
-    /**
157
-     * @param null $line_item_display
158
-     */
159
-    public function set_line_item_display($line_item_display)
160
-    {
161
-        $this->line_item_display = $line_item_display;
162
-    }
163
-
164
-
165
-    /**
166
-     * @return boolean
167
-     */
168
-    public function handle_IPN_in_this_request()
169
-    {
170
-        return $this->handle_IPN_in_this_request;
171
-    }
172
-
173
-
174
-    /**
175
-     * @param boolean $handle_IPN_in_this_request
176
-     */
177
-    public function set_handle_IPN_in_this_request($handle_IPN_in_this_request)
178
-    {
179
-        $this->handle_IPN_in_this_request = filter_var($handle_IPN_in_this_request, FILTER_VALIDATE_BOOLEAN);
180
-    }
181
-
182
-
183
-    /**
184
-     * translate_js_strings
185
-     *
186
-     * @return void
187
-     */
188
-    public function translate_js_strings()
189
-    {
190
-        EE_Registry::$i18n_js_strings['no_payment_method']      = esc_html__(
191
-            'Please select a method of payment in order to continue.',
192
-            'event_espresso'
193
-        );
194
-        EE_Registry::$i18n_js_strings['invalid_payment_method'] = esc_html__(
195
-            'A valid method of payment could not be determined. Please refresh the page and try again.',
196
-            'event_espresso'
197
-        );
198
-        EE_Registry::$i18n_js_strings['forwarding_to_offsite']  = esc_html__(
199
-            'Forwarding to Secure Payment Provider.',
200
-            'event_espresso'
201
-        );
202
-    }
203
-
204
-
205
-    /**
206
-     * enqueue_styles_and_scripts
207
-     *
208
-     * @return void
209
-     * @throws EE_Error
210
-     * @throws InvalidArgumentException
211
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
212
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
213
-     */
214
-    public function enqueue_styles_and_scripts()
215
-    {
216
-        $transaction = $this->checkout->transaction;
217
-        //if the transaction isn't set or nothing is owed on it, don't enqueue any JS
218
-        if (! $transaction instanceof EE_Transaction || EEH_Money::compare_floats($transaction->remaining(), 0)) {
219
-            return;
220
-        }
221
-        foreach (EEM_Payment_Method::instance()->get_all_for_transaction($transaction, EEM_Payment_Method::scope_cart) as $payment_method) {
222
-            $type_obj = $payment_method->type_obj();
223
-            if ($type_obj instanceof EE_PMT_Base) {
224
-                $billing_form = $type_obj->generate_new_billing_form($transaction);
225
-                if ($billing_form instanceof EE_Form_Section_Proper) {
226
-                    $billing_form->enqueue_js();
227
-                }
228
-            }
229
-        }
230
-    }
231
-
232
-
233
-    /**
234
-     * initialize_reg_step
235
-     *
236
-     * @return bool
237
-     * @throws EE_Error
238
-     * @throws InvalidArgumentException
239
-     * @throws ReflectionException
240
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
241
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
242
-     */
243
-    public function initialize_reg_step()
244
-    {
245
-        // TODO: if /when we implement donations, then this will need overriding
246
-        if (// don't need payment options for:
247
-            // 	registrations made via the admin
248
-            // 	completed transactions
249
-            // 	overpaid transactions
250
-            // 	$ 0.00 transactions (no payment required)
251
-            ! $this->checkout->payment_required()
252
-            // but do NOT remove if current action being called belongs to this reg step
253
-            && ! is_callable(array($this, $this->checkout->action))
254
-            && ! $this->completed()
255
-        ) {
256
-            // and if so, then we no longer need the Payment Options step
257
-            if ($this->is_current_step()) {
258
-                $this->checkout->generate_reg_form = false;
259
-            }
260
-            $this->checkout->remove_reg_step($this->_slug);
261
-            // DEBUG LOG
262
-            //$this->checkout->log( __CLASS__, __FUNCTION__, __LINE__ );
263
-            return false;
264
-        }
265
-        // load EEM_Payment_Method
266
-        EE_Registry::instance()->load_model('Payment_Method');
267
-        // get all active payment methods
268
-        $this->checkout->available_payment_methods = EEM_Payment_Method::instance()->get_all_for_transaction(
269
-            $this->checkout->transaction,
270
-            EEM_Payment_Method::scope_cart
271
-        );
272
-        return true;
273
-    }
274
-
275
-
276
-    /**
277
-     * @return EE_Form_Section_Proper
278
-     * @throws EE_Error
279
-     * @throws InvalidArgumentException
280
-     * @throws ReflectionException
281
-     * @throws \EventEspresso\core\exceptions\EntityNotFoundException
282
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
283
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
284
-     * @throws \EventEspresso\core\exceptions\InvalidStatusException
285
-     */
286
-    public function generate_reg_form()
287
-    {
288
-        // reset in case someone changes their mind
289
-        $this->_reset_selected_method_of_payment();
290
-        // set some defaults
291
-        $this->checkout->selected_method_of_payment = 'payments_closed';
292
-        $registrations_requiring_payment            = array();
293
-        $registrations_for_free_events              = array();
294
-        $registrations_requiring_pre_approval       = array();
295
-        $sold_out_events                            = array();
296
-        $insufficient_spaces_available              = array();
297
-        $no_payment_required                        = true;
298
-        // loop thru registrations to gather info
299
-        $registrations         = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
300
-        $ejected_registrations = EE_SPCO_Reg_Step_Payment_Options::find_registrations_that_lost_their_space(
301
-            $registrations,
302
-            $this->checkout->revisit
303
-        );
304
-        foreach ($registrations as $REG_ID => $registration) {
305
-            /** @var $registration EE_Registration */
306
-            // has this registration lost it's space ?
307
-            if (isset($ejected_registrations[ $REG_ID ])) {
308
-                if ($registration->event()->is_sold_out() || $registration->event()->is_sold_out(true)) {
309
-                    $sold_out_events[ $registration->event()->ID() ] = $registration->event();
310
-                } else {
311
-                    $insufficient_spaces_available[ $registration->event()->ID() ] = $registration->event();
312
-                }
313
-                continue;
314
-            }
315
-            // event requires admin approval
316
-            if ($registration->status_ID() === EEM_Registration::status_id_not_approved) {
317
-                // add event to list of events with pre-approval reg status
318
-                $registrations_requiring_pre_approval[$REG_ID] = $registration;
319
-                do_action(
320
-                    'AHEE__EE_SPCO_Reg_Step_Payment_Options__generate_reg_form__event_requires_pre_approval',
321
-                    $registration->event(),
322
-                    $this
323
-                );
324
-                continue;
325
-            }
326
-            if ($this->checkout->revisit
327
-                && $registration->status_ID() !== EEM_Registration::status_id_approved
328
-                && (
329
-                    $registration->event()->is_sold_out()
330
-                    || $registration->event()->is_sold_out(true)
331
-                )
332
-            ) {
333
-                // add event to list of events that are sold out
334
-                $sold_out_events[$registration->event()->ID()] = $registration->event();
335
-                do_action(
336
-                    'AHEE__EE_SPCO_Reg_Step_Payment_Options__generate_reg_form__sold_out_event',
337
-                    $registration->event(),
338
-                    $this
339
-                );
340
-                continue;
341
-            }
342
-            // are they allowed to pay now and is there monies owing?
343
-            if ($registration->owes_monies_and_can_pay()) {
344
-                $registrations_requiring_payment[$REG_ID] = $registration;
345
-                do_action(
346
-                    'AHEE__EE_SPCO_Reg_Step_Payment_Options__generate_reg_form__event_requires_payment',
347
-                    $registration->event(),
348
-                    $this
349
-                );
350
-            } elseif (! $this->checkout->revisit
351
-                && $registration->status_ID() !== EEM_Registration::status_id_not_approved
352
-                && $registration->ticket()->is_free()
353
-            ) {
354
-                $registrations_for_free_events[$registration->event()->ID()] = $registration;
355
-            }
356
-        }
357
-        $subsections = array();
358
-        // now decide which template to load
359
-        if (! empty($sold_out_events)) {
360
-            $subsections['sold_out_events'] = $this->_sold_out_events($sold_out_events);
361
-        }
362
-        if (! empty($insufficient_spaces_available)) {
363
-            $subsections['insufficient_space'] = $this->_insufficient_spaces_available(
364
-                $insufficient_spaces_available
365
-            );
366
-        }
367
-        if (! empty($registrations_requiring_pre_approval)) {
368
-            $subsections['registrations_requiring_pre_approval'] = $this->_registrations_requiring_pre_approval(
369
-                $registrations_requiring_pre_approval
370
-            );
371
-        }
372
-        if (! empty($registrations_for_free_events)) {
373
-            $subsections['no_payment_required'] = $this->_no_payment_required($registrations_for_free_events);
374
-        }
375
-        if (! empty($registrations_requiring_payment)) {
376
-            if ($this->checkout->amount_owing > 0) {
377
-                // autoload Line_Item_Display classes
378
-                EEH_Autoloader::register_line_item_filter_autoloaders();
379
-                $line_item_filter_processor = new EE_Line_Item_Filter_Processor(
380
-                    apply_filters(
381
-                        'FHEE__SPCO__EE_Line_Item_Filter_Collection',
382
-                        new EE_Line_Item_Filter_Collection()
383
-                    ),
384
-                    $this->checkout->cart->get_grand_total()
385
-                );
386
-                /** @var EE_Line_Item $filtered_line_item_tree */
387
-                $filtered_line_item_tree = $line_item_filter_processor->process();
388
-                EEH_Autoloader::register_line_item_display_autoloaders();
389
-                $this->set_line_item_display(new EE_Line_Item_Display('spco'));
390
-                $subsections['payment_options'] = $this->_display_payment_options(
391
-                    $this->line_item_display->display_line_item(
392
-                        $filtered_line_item_tree,
393
-                        array('registrations' => $registrations)
394
-                    )
395
-                );
396
-                $this->checkout->amount_owing   = $filtered_line_item_tree->total();
397
-                $this->_apply_registration_payments_to_amount_owing($registrations);
398
-            }
399
-            $no_payment_required = false;
400
-        } else {
401
-            $this->_hide_reg_step_submit_button_if_revisit();
402
-        }
403
-        $this->_save_selected_method_of_payment();
404
-
405
-        $subsections['default_hidden_inputs'] = $this->reg_step_hidden_inputs();
406
-        $subsections['extra_hidden_inputs']   = $this->_extra_hidden_inputs($no_payment_required);
407
-
408
-        return new EE_Form_Section_Proper(
409
-            array(
410
-                'name'            => $this->reg_form_name(),
411
-                'html_id'         => $this->reg_form_name(),
412
-                'subsections'     => $subsections,
413
-                'layout_strategy' => new EE_No_Layout(),
414
-            )
415
-        );
416
-    }
417
-
418
-
419
-    /**
420
-     * add line item filters required for this reg step
421
-     * these filters are applied via this line in EE_SPCO_Reg_Step_Payment_Options::set_hooks():
422
-     *        add_filter( 'FHEE__SPCO__EE_Line_Item_Filter_Collection', array( 'EE_SPCO_Reg_Step_Payment_Options',
423
-     *        'add_spco_line_item_filters' ) ); so any code that wants to use the same set of filters during the
424
-     *        payment options reg step, can apply these filters via the following: apply_filters(
425
-     *        'FHEE__SPCO__EE_Line_Item_Filter_Collection', new EE_Line_Item_Filter_Collection() ) or to an existing
426
-     *        filter collection by passing that instead of instantiating a new collection
427
-     *
428
-     * @param \EE_Line_Item_Filter_Collection $line_item_filter_collection
429
-     * @return EE_Line_Item_Filter_Collection
430
-     * @throws EE_Error
431
-     * @throws InvalidArgumentException
432
-     * @throws ReflectionException
433
-     * @throws \EventEspresso\core\exceptions\EntityNotFoundException
434
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
435
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
436
-     * @throws \EventEspresso\core\exceptions\InvalidStatusException
437
-     */
438
-    public static function add_spco_line_item_filters(EE_Line_Item_Filter_Collection $line_item_filter_collection)
439
-    {
440
-        if (! EE_Registry::instance()->SSN instanceof EE_Session) {
441
-            return $line_item_filter_collection;
442
-        }
443
-        if (! EE_Registry::instance()->SSN->checkout() instanceof EE_Checkout) {
444
-            return $line_item_filter_collection;
445
-        }
446
-        if (! EE_Registry::instance()->SSN->checkout()->transaction instanceof EE_Transaction) {
447
-            return $line_item_filter_collection;
448
-        }
449
-        $line_item_filter_collection->add(
450
-            new EE_Billable_Line_Item_Filter(
451
-                EE_SPCO_Reg_Step_Payment_Options::remove_ejected_registrations(
452
-                    EE_Registry::instance()->SSN->checkout()->transaction->registrations(
453
-                        EE_Registry::instance()->SSN->checkout()->reg_cache_where_params
454
-                    )
455
-                )
456
-            )
457
-        );
458
-        $line_item_filter_collection->add(new EE_Non_Zero_Line_Item_Filter());
459
-        return $line_item_filter_collection;
460
-    }
461
-
462
-
463
-    /**
464
-     * remove_ejected_registrations
465
-     * if a registrant has lost their potential space at an event due to lack of payment,
466
-     * then this method removes them from the list of registrations being paid for during this request
467
-     *
468
-     * @param \EE_Registration[] $registrations
469
-     * @return EE_Registration[]
470
-     * @throws EE_Error
471
-     * @throws InvalidArgumentException
472
-     * @throws ReflectionException
473
-     * @throws \EventEspresso\core\exceptions\EntityNotFoundException
474
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
475
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
476
-     * @throws \EventEspresso\core\exceptions\InvalidStatusException
477
-     */
478
-    public static function remove_ejected_registrations(array $registrations)
479
-    {
480
-        $ejected_registrations = EE_SPCO_Reg_Step_Payment_Options::find_registrations_that_lost_their_space(
481
-            $registrations,
482
-            EE_Registry::instance()->SSN->checkout()->revisit
483
-        );
484
-        foreach ($registrations as $REG_ID => $registration) {
485
-            // has this registration lost it's space ?
486
-            if (isset($ejected_registrations[$REG_ID])) {
487
-                unset($registrations[$REG_ID]);
488
-                continue;
489
-            }
490
-        }
491
-        return $registrations;
492
-    }
493
-
494
-
495
-    /**
496
-     * find_registrations_that_lost_their_space
497
-     * If a registrant chooses an offline payment method like Invoice,
498
-     * then no space is reserved for them at the event until they fully pay fo that site
499
-     * (unless the event's default reg status is set to APPROVED)
500
-     * if a registrant then later returns to pay, but the number of spaces available has been reduced due to sales,
501
-     * then this method will determine which registrations have lost the ability to complete the reg process.
502
-     *
503
-     * @param \EE_Registration[] $registrations
504
-     * @param bool               $revisit
505
-     * @return array
506
-     * @throws EE_Error
507
-     * @throws InvalidArgumentException
508
-     * @throws ReflectionException
509
-     * @throws \EventEspresso\core\exceptions\EntityNotFoundException
510
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
511
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
512
-     * @throws \EventEspresso\core\exceptions\InvalidStatusException
513
-     */
514
-    public static function find_registrations_that_lost_their_space(array $registrations, $revisit = false)
515
-    {
516
-        // registrations per event
517
-        $event_reg_count = array();
518
-        // spaces left per event
519
-        $event_spaces_remaining = array();
520
-        // tickets left sorted by ID
521
-        $tickets_remaining = array();
522
-        // registrations that have lost their space
523
-        $ejected_registrations = array();
524
-        foreach ($registrations as $REG_ID => $registration) {
525
-            if ($registration->status_ID() === EEM_Registration::status_id_approved
526
-                || apply_filters(
527
-                    'FHEE__EE_SPCO_Reg_Step_Payment_Options__find_registrations_that_lost_their_space__allow_reg_payment',
528
-                    false,
529
-                    $registration,
530
-                    $revisit
531
-                )
532
-            ) {
533
-                continue;
534
-            }
535
-            $EVT_ID = $registration->event_ID();
536
-            $ticket = $registration->ticket();
537
-            if (! isset($tickets_remaining[$ticket->ID()])) {
538
-                $tickets_remaining[$ticket->ID()] = $ticket->remaining();
539
-            }
540
-            if ($tickets_remaining[$ticket->ID()] > 0) {
541
-                if (! isset($event_reg_count[$EVT_ID])) {
542
-                    $event_reg_count[$EVT_ID] = 0;
543
-                }
544
-                $event_reg_count[$EVT_ID]++;
545
-                if (! isset($event_spaces_remaining[$EVT_ID])) {
546
-                    $event_spaces_remaining[$EVT_ID] = $registration->event()->spaces_remaining_for_sale();
547
-                }
548
-            }
549
-            if ($revisit
550
-                && ($tickets_remaining[$ticket->ID()] === 0
551
-                    || $event_reg_count[$EVT_ID] > $event_spaces_remaining[$EVT_ID]
552
-                )
553
-            ) {
554
-                $ejected_registrations[$REG_ID] = $registration->event();
555
-                if ($registration->status_ID() !== EEM_Registration::status_id_wait_list) {
556
-                    /** @type EE_Registration_Processor $registration_processor */
557
-                    $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
558
-                    // at this point, we should have enough details about the registrant to consider the registration
559
-                    // NOT incomplete
560
-                    $registration_processor->manually_update_registration_status(
561
-                        $registration,
562
-                        EEM_Registration::status_id_wait_list
563
-                    );
564
-                }
565
-            }
566
-        }
567
-        return $ejected_registrations;
568
-    }
569
-
570
-
571
-    /**
572
-     * _hide_reg_step_submit_button
573
-     * removes the html for the reg step submit button
574
-     * by replacing it with an empty string via filter callback
575
-     *
576
-     * @return void
577
-     */
578
-    protected function _adjust_registration_status_if_event_old_sold()
579
-    {
580
-    }
581
-
582
-
583
-    /**
584
-     * _hide_reg_step_submit_button
585
-     * removes the html for the reg step submit button
586
-     * by replacing it with an empty string via filter callback
587
-     *
588
-     * @return void
589
-     */
590
-    protected function _hide_reg_step_submit_button_if_revisit()
591
-    {
592
-        if ($this->checkout->revisit) {
593
-            add_filter('FHEE__EE_SPCO_Reg_Step__reg_step_submit_button__sbmt_btn_html', '__return_empty_string');
594
-        }
595
-    }
596
-
597
-
598
-    /**
599
-     * sold_out_events
600
-     * displays notices regarding events that have sold out since hte registrant first signed up
601
-     *
602
-     * @param \EE_Event[] $sold_out_events_array
603
-     * @return \EE_Form_Section_Proper
604
-     * @throws \EE_Error
605
-     */
606
-    private function _sold_out_events($sold_out_events_array = array())
607
-    {
608
-        // set some defaults
609
-        $this->checkout->selected_method_of_payment = 'events_sold_out';
610
-        $sold_out_events                            = '';
611
-        foreach ($sold_out_events_array as $sold_out_event) {
612
-            $sold_out_events .= EEH_HTML::li(
613
-                EEH_HTML::span(
614
-                    '  ' . $sold_out_event->name(),
615
-                    '',
616
-                    'dashicons dashicons-marker ee-icon-size-16 pink-text'
617
-                )
618
-            );
619
-        }
620
-        return new EE_Form_Section_Proper(
621
-            array(
622
-                'layout_strategy' => new EE_Template_Layout(
623
-                    array(
624
-                        'layout_template_file' => SPCO_REG_STEPS_PATH
625
-                                                  . $this->_slug
626
-                                                  . DS
627
-                                                  . 'sold_out_events.template.php',
628
-                        'template_args'        => apply_filters(
629
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___sold_out_events__template_args',
630
-                            array(
631
-                                'sold_out_events'     => $sold_out_events,
632
-                                'sold_out_events_msg' => apply_filters(
633
-                                    'FHEE__EE_SPCO_Reg_Step_Payment_Options___sold_out_events__sold_out_events_msg',
634
-                                    sprintf(
635
-                                        esc_html__(
636
-                                            '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',
637
-                                            'event_espresso'
638
-                                        ),
639
-                                        '<strong>',
640
-                                        '</strong>',
641
-                                        '<br />'
642
-                                    )
643
-                                ),
644
-                            )
645
-                        ),
646
-                    )
647
-                ),
648
-            )
649
-        );
650
-    }
651
-
652
-
653
-    /**
654
-     * _insufficient_spaces_available
655
-     * displays notices regarding events that do not have enough remaining spaces
656
-     * to satisfy the current number of registrations looking to pay
657
-     *
658
-     * @param \EE_Event[] $insufficient_spaces_events_array
659
-     * @return \EE_Form_Section_Proper
660
-     * @throws \EE_Error
661
-     */
662
-    private function _insufficient_spaces_available($insufficient_spaces_events_array = array())
663
-    {
664
-        // set some defaults
665
-        $this->checkout->selected_method_of_payment = 'invoice';
666
-        $insufficient_space_events                  = '';
667
-        foreach ($insufficient_spaces_events_array as $event) {
668
-            if ($event instanceof EE_Event) {
669
-                $insufficient_space_events .= EEH_HTML::li(
670
-                    EEH_HTML::span(' ' . $event->name(), '', 'dashicons dashicons-marker ee-icon-size-16 pink-text')
671
-                );
672
-            }
673
-        }
674
-        return new EE_Form_Section_Proper(
675
-            array(
676
-                'subsections'     => array(
677
-                    'default_hidden_inputs' => $this->reg_step_hidden_inputs(),
678
-                    'extra_hidden_inputs'   => $this->_extra_hidden_inputs(),
679
-                ),
680
-                'layout_strategy' => new EE_Template_Layout(
681
-                    array(
682
-                        'layout_template_file' => SPCO_REG_STEPS_PATH
683
-                                                  . $this->_slug
684
-                                                  . DS
685
-                                                  . 'sold_out_events.template.php',
686
-                        'template_args'        => apply_filters(
687
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___insufficient_spaces_available__template_args',
688
-                            array(
689
-                                'sold_out_events'     => $insufficient_space_events,
690
-                                'sold_out_events_msg' => apply_filters(
691
-                                    'FHEE__EE_SPCO_Reg_Step_Payment_Options___insufficient_spaces_available__insufficient_space_msg',
692
-                                    esc_html__(
693
-                                        '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.',
694
-                                        'event_espresso'
695
-                                    )
696
-                                ),
697
-                            )
698
-                        ),
699
-                    )
700
-                ),
701
-            )
702
-        );
703
-    }
704
-
705
-
706
-    /**
707
-     * registrations_requiring_pre_approval
708
-     *
709
-     * @param array $registrations_requiring_pre_approval
710
-     * @return EE_Form_Section_Proper
711
-     * @throws EE_Error
712
-     * @throws \EventEspresso\core\exceptions\EntityNotFoundException
713
-     */
714
-    private function _registrations_requiring_pre_approval($registrations_requiring_pre_approval = array())
715
-    {
716
-        $events_requiring_pre_approval = '';
717
-        foreach ($registrations_requiring_pre_approval as $registration) {
718
-            if ($registration instanceof EE_Registration && $registration->event() instanceof EE_Event) {
719
-                $events_requiring_pre_approval[$registration->event()->ID()] = EEH_HTML::li(
720
-                    EEH_HTML::span(
721
-                        '',
722
-                        '',
723
-                        'dashicons dashicons-marker ee-icon-size-16 orange-text'
724
-                    )
725
-                    . EEH_HTML::span($registration->event()->name(), '', 'orange-text')
726
-                );
727
-            }
728
-        }
729
-        return new EE_Form_Section_Proper(
730
-            array(
731
-                'layout_strategy' => new EE_Template_Layout(
732
-                    array(
733
-                        'layout_template_file' => SPCO_REG_STEPS_PATH
734
-                                                  . $this->_slug
735
-                                                  . DS
736
-                                                  . 'events_requiring_pre_approval.template.php', // layout_template
737
-                        'template_args'        => apply_filters(
738
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___sold_out_events__template_args',
739
-                            array(
740
-                                'events_requiring_pre_approval'     => implode('', $events_requiring_pre_approval),
741
-                                'events_requiring_pre_approval_msg' => apply_filters(
742
-                                    'FHEE__EE_SPCO_Reg_Step_Payment_Options___events_requiring_pre_approval__events_requiring_pre_approval_msg',
743
-                                    esc_html__(
744
-                                        '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.',
745
-                                        'event_espresso'
746
-                                    )
747
-                                ),
748
-                            )
749
-                        ),
750
-                    )
751
-                ),
752
-            )
753
-        );
754
-    }
755
-
756
-
757
-    /**
758
-     * _no_payment_required
759
-     *
760
-     * @param \EE_Event[] $registrations_for_free_events
761
-     * @return \EE_Form_Section_Proper
762
-     * @throws \EE_Error
763
-     */
764
-    private function _no_payment_required($registrations_for_free_events = array())
765
-    {
766
-        // set some defaults
767
-        $this->checkout->selected_method_of_payment = 'no_payment_required';
768
-        // generate no_payment_required form
769
-        return new EE_Form_Section_Proper(
770
-            array(
771
-                'layout_strategy' => new EE_Template_Layout(
772
-                    array(
773
-                        'layout_template_file' => SPCO_REG_STEPS_PATH
774
-                                                  . $this->_slug
775
-                                                  . DS
776
-                                                  . 'no_payment_required.template.php', // layout_template
777
-                        'template_args'        => apply_filters(
778
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___no_payment_required__template_args',
779
-                            array(
780
-                                'revisit'                       => $this->checkout->revisit,
781
-                                'registrations'                 => array(),
782
-                                'ticket_count'                  => array(),
783
-                                'registrations_for_free_events' => $registrations_for_free_events,
784
-                                'no_payment_required_msg'       => EEH_HTML::p(
785
-                                    esc_html__('This is a free event, so no billing will occur.', 'event_espresso')
786
-                                ),
787
-                            )
788
-                        ),
789
-                    )
790
-                ),
791
-            )
792
-        );
793
-    }
794
-
795
-
796
-    /**
797
-     * _display_payment_options
798
-     *
799
-     * @param string $transaction_details
800
-     * @return EE_Form_Section_Proper
801
-     * @throws EE_Error
802
-     * @throws InvalidArgumentException
803
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
804
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
805
-     */
806
-    private function _display_payment_options($transaction_details = '')
807
-    {
808
-        // has method_of_payment been set by no-js user?
809
-        $this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment();
810
-        // build payment options form
811
-        return apply_filters(
812
-            'FHEE__EE_SPCO_Reg_Step_Payment_Options___display_payment_options__payment_options_form',
813
-            new EE_Form_Section_Proper(
814
-                array(
815
-                    'subsections'     => array(
816
-                        'before_payment_options' => apply_filters(
817
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___display_payment_options__before_payment_options',
818
-                            new EE_Form_Section_Proper(
819
-                                array('layout_strategy' => new EE_Div_Per_Section_Layout())
820
-                            )
821
-                        ),
822
-                        'payment_options'        => $this->_setup_payment_options(),
823
-                        'after_payment_options'  => apply_filters(
824
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___display_payment_options__after_payment_options',
825
-                            new EE_Form_Section_Proper(
826
-                                array('layout_strategy' => new EE_Div_Per_Section_Layout())
827
-                            )
828
-                        ),
829
-                    ),
830
-                    'layout_strategy' => new EE_Template_Layout(
831
-                        array(
832
-                            'layout_template_file' => $this->_template,
833
-                            'template_args'        => apply_filters(
834
-                                'FHEE__EE_SPCO_Reg_Step_Payment_Options___display_payment_options__template_args',
835
-                                array(
836
-                                    'reg_count'                 => $this->line_item_display->total_items(),
837
-                                    'transaction_details'       => $transaction_details,
838
-                                    'available_payment_methods' => array(),
839
-                                )
840
-                            ),
841
-                        )
842
-                    ),
843
-                )
844
-            )
845
-        );
846
-    }
847
-
848
-
849
-    /**
850
-     * _extra_hidden_inputs
851
-     *
852
-     * @param bool $no_payment_required
853
-     * @return \EE_Form_Section_Proper
854
-     * @throws \EE_Error
855
-     */
856
-    private function _extra_hidden_inputs($no_payment_required = true)
857
-    {
858
-        return new EE_Form_Section_Proper(
859
-            array(
860
-                'html_id'         => 'ee-' . $this->slug() . '-extra-hidden-inputs',
861
-                'layout_strategy' => new EE_Div_Per_Section_Layout(),
862
-                'subsections'     => array(
863
-                    'spco_no_payment_required' => new EE_Hidden_Input(
864
-                        array(
865
-                            'normalization_strategy' => new EE_Boolean_Normalization(),
866
-                            'html_name'              => 'spco_no_payment_required',
867
-                            'html_id'                => 'spco-no-payment-required-payment_options',
868
-                            'default'                => $no_payment_required,
869
-                        )
870
-                    ),
871
-                    'spco_transaction_id'      => new EE_Fixed_Hidden_Input(
872
-                        array(
873
-                            'normalization_strategy' => new EE_Int_Normalization(),
874
-                            'html_name'              => 'spco_transaction_id',
875
-                            'html_id'                => 'spco-transaction-id',
876
-                            'default'                => $this->checkout->transaction->ID(),
877
-                        )
878
-                    ),
879
-                ),
880
-            )
881
-        );
882
-    }
883
-
884
-
885
-    /**
886
-     *    _apply_registration_payments_to_amount_owing
887
-     *
888
-     * @access protected
889
-     * @param array $registrations
890
-     * @throws EE_Error
891
-     */
892
-    protected function _apply_registration_payments_to_amount_owing(array $registrations)
893
-    {
894
-        $payments = array();
895
-        foreach ($registrations as $registration) {
896
-            if ($registration instanceof EE_Registration && $registration->owes_monies_and_can_pay()) {
897
-                $payments += $registration->registration_payments();
898
-            }
899
-        }
900
-        if (! empty($payments)) {
901
-            foreach ($payments as $payment) {
902
-                if ($payment instanceof EE_Registration_Payment) {
903
-                    $this->checkout->amount_owing -= $payment->amount();
904
-                }
905
-            }
906
-        }
907
-    }
908
-
909
-
910
-    /**
911
-     *    _reset_selected_method_of_payment
912
-     *
913
-     * @access    private
914
-     * @param    bool $force_reset
915
-     * @return void
916
-     * @throws InvalidArgumentException
917
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
918
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
919
-     */
920
-    private function _reset_selected_method_of_payment($force_reset = false)
921
-    {
922
-        $reset_payment_method = $force_reset
923
-            ? true
924
-            : sanitize_text_field(EE_Registry::instance()->REQ->get('reset_payment_method', false));
925
-        if ($reset_payment_method) {
926
-            $this->checkout->selected_method_of_payment = null;
927
-            $this->checkout->payment_method             = null;
928
-            $this->checkout->billing_form               = null;
929
-            $this->_save_selected_method_of_payment();
930
-        }
931
-    }
932
-
933
-
934
-    /**
935
-     * _save_selected_method_of_payment
936
-     * stores the selected_method_of_payment in the session
937
-     * so that it's available for all subsequent requests including AJAX
938
-     *
939
-     * @access        private
940
-     * @param string $selected_method_of_payment
941
-     * @return void
942
-     * @throws InvalidArgumentException
943
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
944
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
945
-     */
946
-    private function _save_selected_method_of_payment($selected_method_of_payment = '')
947
-    {
948
-        $selected_method_of_payment = ! empty($selected_method_of_payment)
949
-            ? $selected_method_of_payment
950
-            : $this->checkout->selected_method_of_payment;
951
-        EE_Registry::instance()->SSN->set_session_data(
952
-            array('selected_method_of_payment' => $selected_method_of_payment)
953
-        );
954
-    }
955
-
956
-
957
-    /**
958
-     * _setup_payment_options
959
-     *
960
-     * @return EE_Form_Section_Proper
961
-     * @throws EE_Error
962
-     * @throws InvalidArgumentException
963
-     * @throws ReflectionException
964
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
965
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
966
-     */
967
-    public function _setup_payment_options()
968
-    {
969
-        // load payment method classes
970
-        $this->checkout->available_payment_methods = $this->_get_available_payment_methods();
971
-        if (empty($this->checkout->available_payment_methods)) {
972
-            EE_Error::add_error(
973
-                apply_filters(
974
-                    'FHEE__EE_SPCO_Reg_Step_Payment_Options___setup_payment_options__error_message_no_payment_methods',
975
-                    sprintf(
976
-                        esc_html__(
977
-                            '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.',
978
-                            'event_espresso'
979
-                        ),
980
-                        '<br>',
981
-                        EE_Registry::instance()->CFG->organization->get_pretty('email')
982
-                    )
983
-                ),
984
-                __FILE__,
985
-                __FUNCTION__,
986
-                __LINE__
987
-            );
988
-        }
989
-        // switch up header depending on number of available payment methods
990
-        $payment_method_header     = count($this->checkout->available_payment_methods) > 1
991
-            ? apply_filters(
992
-                'FHEE__registration_page_payment_options__method_of_payment_hdr',
993
-                esc_html__('Please Select Your Method of Payment', 'event_espresso')
994
-            )
995
-            : apply_filters(
996
-                'FHEE__registration_page_payment_options__method_of_payment_hdr',
997
-                esc_html__('Method of Payment', 'event_espresso')
998
-            );
999
-        $available_payment_methods = array(
1000
-            // display the "Payment Method" header
1001
-            'payment_method_header' => new EE_Form_Section_HTML(
1002
-                EEH_HTML::h4($payment_method_header, 'method-of-payment-hdr')
1003
-            ),
1004
-        );
1005
-        // the list of actual payment methods ( invoice, paypal, etc ) in a  ( slug => HTML )  format
1006
-        $available_payment_method_options = array();
1007
-        $default_payment_method_option    = array();
1008
-        // additional instructions to be displayed and hidden below payment methods (adding a clearing div to start)
1009
-        $payment_methods_billing_info = array(
1010
-            new EE_Form_Section_HTML(
1011
-                EEH_HTML::div('<br />', '', '', 'clear:both;')
1012
-            ),
1013
-        );
1014
-        // loop through payment methods
1015
-        foreach ($this->checkout->available_payment_methods as $payment_method) {
1016
-            if ($payment_method instanceof EE_Payment_Method) {
1017
-                $payment_method_button = EEH_HTML::img(
1018
-                    $payment_method->button_url(),
1019
-                    $payment_method->name(),
1020
-                    'spco-payment-method-' . $payment_method->slug() . '-btn-img',
1021
-                    'spco-payment-method-btn-img'
1022
-                );
1023
-                // check if any payment methods are set as default
1024
-                // if payment method is already selected OR nothing is selected and this payment method should be
1025
-                // open_by_default
1026
-                if (($this->checkout->selected_method_of_payment === $payment_method->slug())
1027
-                    || (! $this->checkout->selected_method_of_payment && $payment_method->open_by_default())
1028
-                ) {
1029
-                    $this->checkout->selected_method_of_payment = $payment_method->slug();
1030
-                    $this->_save_selected_method_of_payment();
1031
-                    $default_payment_method_option[$payment_method->slug()] = $payment_method_button;
1032
-                } else {
1033
-                    $available_payment_method_options[$payment_method->slug()] = $payment_method_button;
1034
-                }
1035
-                $payment_methods_billing_info[$payment_method->slug() . '-info'] = $this->_payment_method_billing_info(
1036
-                    $payment_method
1037
-                );
1038
-            }
1039
-        }
1040
-        // prepend available_payment_method_options with default_payment_method_option so that it appears first in list
1041
-        // of PMs
1042
-        $available_payment_method_options = $default_payment_method_option + $available_payment_method_options;
1043
-        // now generate the actual form  inputs
1044
-        $available_payment_methods['available_payment_methods'] = $this->_available_payment_method_inputs(
1045
-            $available_payment_method_options
1046
-        );
1047
-        $available_payment_methods                              += $payment_methods_billing_info;
1048
-        // build the available payment methods form
1049
-        return new EE_Form_Section_Proper(
1050
-            array(
1051
-                'html_id'         => 'spco-available-methods-of-payment-dv',
1052
-                'subsections'     => $available_payment_methods,
1053
-                'layout_strategy' => new EE_Div_Per_Section_Layout(),
1054
-            )
1055
-        );
1056
-    }
1057
-
1058
-
1059
-    /**
1060
-     * _get_available_payment_methods
1061
-     *
1062
-     * @return EE_Payment_Method[]
1063
-     * @throws EE_Error
1064
-     * @throws InvalidArgumentException
1065
-     * @throws ReflectionException
1066
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1067
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1068
-     */
1069
-    protected function _get_available_payment_methods()
1070
-    {
1071
-        if (! empty($this->checkout->available_payment_methods)) {
1072
-            return $this->checkout->available_payment_methods;
1073
-        }
1074
-        $available_payment_methods = array();
1075
-        // load EEM_Payment_Method
1076
-        EE_Registry::instance()->load_model('Payment_Method');
1077
-        /** @type EEM_Payment_Method $EEM_Payment_Method */
1078
-        $EEM_Payment_Method = EE_Registry::instance()->LIB->EEM_Payment_Method;
1079
-        // get all active payment methods
1080
-        $payment_methods = $EEM_Payment_Method->get_all_for_transaction(
1081
-            $this->checkout->transaction,
1082
-            EEM_Payment_Method::scope_cart
1083
-        );
1084
-        foreach ($payment_methods as $payment_method) {
1085
-            if ($payment_method instanceof EE_Payment_Method) {
1086
-                $available_payment_methods[$payment_method->slug()] = $payment_method;
1087
-            }
1088
-        }
1089
-        return $available_payment_methods;
1090
-    }
1091
-
1092
-
1093
-    /**
1094
-     *    _available_payment_method_inputs
1095
-     *
1096
-     * @access    private
1097
-     * @param    array $available_payment_method_options
1098
-     * @return    \EE_Form_Section_Proper
1099
-     */
1100
-    private function _available_payment_method_inputs($available_payment_method_options = array())
1101
-    {
1102
-        // generate inputs
1103
-        return new EE_Form_Section_Proper(
1104
-            array(
1105
-                'html_id'         => 'ee-available-payment-method-inputs',
1106
-                'layout_strategy' => new EE_Div_Per_Section_Layout(),
1107
-                'subsections'     => array(
1108
-                    '' => new EE_Radio_Button_Input(
1109
-                        $available_payment_method_options,
1110
-                        array(
1111
-                            'html_name'          => 'selected_method_of_payment',
1112
-                            'html_class'         => 'spco-payment-method',
1113
-                            'default'            => $this->checkout->selected_method_of_payment,
1114
-                            'label_size'         => 11,
1115
-                            'enforce_label_size' => true,
1116
-                        )
1117
-                    ),
1118
-                ),
1119
-            )
1120
-        );
1121
-    }
1122
-
1123
-
1124
-    /**
1125
-     *    _payment_method_billing_info
1126
-     *
1127
-     * @access    private
1128
-     * @param    EE_Payment_Method $payment_method
1129
-     * @return EE_Form_Section_Proper
1130
-     * @throws EE_Error
1131
-     * @throws InvalidArgumentException
1132
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1133
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1134
-     */
1135
-    private function _payment_method_billing_info(EE_Payment_Method $payment_method)
1136
-    {
1137
-        $currently_selected = $this->checkout->selected_method_of_payment === $payment_method->slug()
1138
-            ? true
1139
-            : false;
1140
-        // generate the billing form for payment method
1141
-        $billing_form                 = $currently_selected
1142
-            ? $this->_get_billing_form_for_payment_method($payment_method)
1143
-            : new EE_Form_Section_HTML();
1144
-        $this->checkout->billing_form = $currently_selected
1145
-            ? $billing_form
1146
-            : $this->checkout->billing_form;
1147
-        // it's all in the details
1148
-        $info_html = EEH_HTML::h3(
1149
-            esc_html__('Important information regarding your payment', 'event_espresso'),
1150
-            '',
1151
-            'spco-payment-method-hdr'
1152
-        );
1153
-        // add some info regarding the step, either from what's saved in the admin,
1154
-        // or a default string depending on whether the PM has a billing form or not
1155
-        if ($payment_method->description()) {
1156
-            $payment_method_info = $payment_method->description();
1157
-        } elseif ($billing_form instanceof EE_Billing_Info_Form) {
1158
-            $payment_method_info = sprintf(
1159
-                esc_html__(
1160
-                    'Please provide the following billing information, then click the "%1$s" button below in order to proceed.',
1161
-                    'event_espresso'
1162
-                ),
1163
-                $this->submit_button_text()
1164
-            );
1165
-        } else {
1166
-            $payment_method_info = sprintf(
1167
-                esc_html__('Please click the "%1$s" button below in order to proceed.', 'event_espresso'),
1168
-                $this->submit_button_text()
1169
-            );
1170
-        }
1171
-        $info_html .= EEH_HTML::p(
1172
-            apply_filters(
1173
-                'FHEE__EE_SPCO_Reg_Step_Payment_Options___payment_method_billing_info__payment_method_info',
1174
-                $payment_method_info
1175
-            ),
1176
-            '',
1177
-            'spco-payment-method-desc ee-attention'
1178
-        );
1179
-        return new EE_Form_Section_Proper(
1180
-            array(
1181
-                'html_id'         => 'spco-payment-method-info-' . $payment_method->slug(),
1182
-                'html_class'      => 'spco-payment-method-info-dv',
1183
-                // only display the selected or default PM
1184
-                'html_style'      => $currently_selected ? '' : 'display:none;',
1185
-                'layout_strategy' => new EE_Div_Per_Section_Layout(),
1186
-                'subsections'     => array(
1187
-                    'info'         => new EE_Form_Section_HTML($info_html),
1188
-                    'billing_form' => $currently_selected ? $billing_form : new EE_Form_Section_HTML(),
1189
-                ),
1190
-            )
1191
-        );
1192
-    }
1193
-
1194
-
1195
-    /**
1196
-     * get_billing_form_html_for_payment_method
1197
-     *
1198
-     * @access public
1199
-     * @return string
1200
-     * @throws EE_Error
1201
-     * @throws InvalidArgumentException
1202
-     * @throws ReflectionException
1203
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1204
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1205
-     */
1206
-    public function get_billing_form_html_for_payment_method()
1207
-    {
1208
-        // how have they chosen to pay?
1209
-        $this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment(true);
1210
-        $this->checkout->payment_method             = $this->_get_payment_method_for_selected_method_of_payment();
1211
-        if (! $this->checkout->payment_method instanceof EE_Payment_Method) {
1212
-            return false;
1213
-        }
1214
-        if (apply_filters(
1215
-            'FHEE__EE_SPCO_Reg_Step_Payment_Options__registration_checkout__selected_payment_method__display_success',
1216
-            false
1217
-        )) {
1218
-            EE_Error::add_success(
1219
-                apply_filters(
1220
-                    'FHEE__Single_Page_Checkout__registration_checkout__selected_payment_method',
1221
-                    sprintf(
1222
-                        esc_html__(
1223
-                            'You have selected "%s" as your method of payment. Please note the important payment information below.',
1224
-                            'event_espresso'
1225
-                        ),
1226
-                        $this->checkout->payment_method->name()
1227
-                    )
1228
-                )
1229
-            );
1230
-        }
1231
-        // now generate billing form for selected method of payment
1232
-        $payment_method_billing_form = $this->_get_billing_form_for_payment_method($this->checkout->payment_method);
1233
-        // fill form with attendee info if applicable
1234
-        if ($payment_method_billing_form instanceof EE_Billing_Attendee_Info_Form
1235
-            && $this->checkout->transaction_has_primary_registrant()
1236
-        ) {
1237
-            $payment_method_billing_form->populate_from_attendee(
1238
-                $this->checkout->transaction->primary_registration()->attendee()
1239
-            );
1240
-        }
1241
-        // and debug content
1242
-        if ($payment_method_billing_form instanceof EE_Billing_Info_Form
1243
-            && $this->checkout->payment_method->type_obj() instanceof EE_PMT_Base
1244
-        ) {
1245
-            $payment_method_billing_form =
1246
-                $this->checkout->payment_method->type_obj()->apply_billing_form_debug_settings(
1247
-                    $payment_method_billing_form
1248
-                );
1249
-        }
1250
-        $billing_info = $payment_method_billing_form instanceof EE_Form_Section_Proper
1251
-            ? $payment_method_billing_form->get_html()
1252
-            : '';
1253
-        $this->checkout->json_response->set_return_data(array('payment_method_info' => $billing_info));
1254
-        // localize validation rules for main form
1255
-        $this->checkout->current_step->reg_form->localize_validation_rules();
1256
-        $this->checkout->json_response->add_validation_rules(EE_Form_Section_Proper::js_localization());
1257
-        return true;
1258
-    }
1259
-
1260
-
1261
-    /**
1262
-     * _get_billing_form_for_payment_method
1263
-     *
1264
-     * @access private
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 \EventEspresso\core\exceptions\InvalidDataTypeException
1270
-     * @throws \EventEspresso\core\exceptions\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
-            array('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
-                && EE_Registry::instance()->REQ->is_set('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
-     * @access private
1313
-     * @param boolean $required whether to throw an error if the "selected_method_of_payment"
1314
-     *                          is not found in the incoming request
1315
-     * @param string  $request_param
1316
-     * @return NULL|string
1317
-     * @throws EE_Error
1318
-     * @throws InvalidArgumentException
1319
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1320
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1321
-     */
1322
-    private function _get_selected_method_of_payment(
1323
-        $required = false,
1324
-        $request_param = 'selected_method_of_payment'
1325
-    ) {
1326
-        // is selected_method_of_payment set in the request ?
1327
-        $selected_method_of_payment = EE_Registry::instance()->REQ->get($request_param, false);
1328
-        if ($selected_method_of_payment) {
1329
-            // sanitize it
1330
-            $selected_method_of_payment = is_array($selected_method_of_payment)
1331
-                ? array_shift($selected_method_of_payment)
1332
-                : $selected_method_of_payment;
1333
-            $selected_method_of_payment = sanitize_text_field($selected_method_of_payment);
1334
-            // store it in the session so that it's available for all subsequent requests including AJAX
1335
-            $this->_save_selected_method_of_payment($selected_method_of_payment);
1336
-        } else {
1337
-            // or is is set in the session ?
1338
-            $selected_method_of_payment = EE_Registry::instance()->SSN->get_session_data(
1339
-                'selected_method_of_payment'
1340
-            );
1341
-        }
1342
-        // do ya really really gotta have it?
1343
-        if (empty($selected_method_of_payment) && $required) {
1344
-            EE_Error::add_error(
1345
-                sprintf(
1346
-                    esc_html__(
1347
-                        '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.',
1348
-                        'event_espresso'
1349
-                    ),
1350
-                    '<br/>',
1351
-                    '<br/>',
1352
-                    EE_Registry::instance()->CFG->organization->get_pretty('email')
1353
-                ),
1354
-                __FILE__,
1355
-                __FUNCTION__,
1356
-                __LINE__
1357
-            );
1358
-            return null;
1359
-        }
1360
-        return $selected_method_of_payment;
1361
-    }
1362
-
1363
-
1364
-
1365
-
1366
-
1367
-
1368
-    /********************************************************************************************************/
1369
-    /***********************************  SWITCH PAYMENT METHOD  ************************************/
1370
-    /********************************************************************************************************/
1371
-    /**
1372
-     * switch_payment_method
1373
-     *
1374
-     * @access public
1375
-     * @return string
1376
-     * @throws EE_Error
1377
-     * @throws InvalidArgumentException
1378
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1379
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1380
-     */
1381
-    public function switch_payment_method()
1382
-    {
1383
-        if (! $this->_verify_payment_method_is_set()) {
1384
-            return false;
1385
-        }
1386
-        if (apply_filters(
1387
-            'FHEE__EE_SPCO_Reg_Step_Payment_Options__registration_checkout__selected_payment_method__display_success',
1388
-            false
1389
-        )) {
1390
-            EE_Error::add_success(
1391
-                apply_filters(
1392
-                    'FHEE__Single_Page_Checkout__registration_checkout__selected_payment_method',
1393
-                    sprintf(
1394
-                        esc_html__(
1395
-                            'You have selected "%s" as your method of payment. Please note the important payment information below.',
1396
-                            'event_espresso'
1397
-                        ),
1398
-                        $this->checkout->payment_method->name()
1399
-                    )
1400
-                )
1401
-            );
1402
-        }
1403
-        // generate billing form for selected method of payment if it hasn't been done already
1404
-        if ($this->checkout->payment_method->type_obj()->has_billing_form()) {
1405
-            $this->checkout->billing_form = $this->_get_billing_form_for_payment_method(
1406
-                $this->checkout->payment_method
1407
-            );
1408
-        }
1409
-        // fill form with attendee info if applicable
1410
-        if (apply_filters(
1411
-            'FHEE__populate_billing_form_fields_from_attendee',
1412
-            (
1413
-                $this->checkout->billing_form instanceof EE_Billing_Attendee_Info_Form
1414
-                && $this->checkout->transaction_has_primary_registrant()
1415
-            ),
1416
-            $this->checkout->billing_form,
1417
-            $this->checkout->transaction
1418
-        )
1419
-        ) {
1420
-            $this->checkout->billing_form->populate_from_attendee(
1421
-                $this->checkout->transaction->primary_registration()->attendee()
1422
-            );
1423
-        }
1424
-        // and debug content
1425
-        if ($this->checkout->billing_form instanceof EE_Billing_Info_Form
1426
-            && $this->checkout->payment_method->type_obj() instanceof EE_PMT_Base
1427
-        ) {
1428
-            $this->checkout->billing_form =
1429
-                $this->checkout->payment_method->type_obj()->apply_billing_form_debug_settings(
1430
-                    $this->checkout->billing_form
1431
-                );
1432
-        }
1433
-        // get html and validation rules for form
1434
-        if ($this->checkout->billing_form instanceof EE_Form_Section_Proper) {
1435
-            $this->checkout->json_response->set_return_data(
1436
-                array('payment_method_info' => $this->checkout->billing_form->get_html())
1437
-            );
1438
-            // localize validation rules for main form
1439
-            $this->checkout->billing_form->localize_validation_rules(true);
1440
-            $this->checkout->json_response->add_validation_rules(EE_Form_Section_Proper::js_localization());
1441
-        } else {
1442
-            $this->checkout->json_response->set_return_data(array('payment_method_info' => ''));
1443
-        }
1444
-        //prevents advancement to next step
1445
-        $this->checkout->continue_reg = false;
1446
-        return true;
1447
-    }
1448
-
1449
-
1450
-    /**
1451
-     * _verify_payment_method_is_set
1452
-     *
1453
-     * @return bool
1454
-     * @throws EE_Error
1455
-     * @throws InvalidArgumentException
1456
-     * @throws ReflectionException
1457
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1458
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1459
-     */
1460
-    protected function _verify_payment_method_is_set()
1461
-    {
1462
-        // generate billing form for selected method of payment if it hasn't been done already
1463
-        if (empty($this->checkout->selected_method_of_payment)) {
1464
-            // how have they chosen to pay?
1465
-            $this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment(true);
1466
-        } else {
1467
-            // choose your own adventure based on method_of_payment
1468
-            switch ($this->checkout->selected_method_of_payment) {
1469
-                case 'events_sold_out' :
1470
-                    EE_Error::add_attention(
1471
-                        apply_filters(
1472
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___verify_payment_method_is_set__sold_out_events_msg',
1473
-                            esc_html__(
1474
-                                '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.',
1475
-                                'event_espresso'
1476
-                            )
1477
-                        ),
1478
-                        __FILE__, __FUNCTION__, __LINE__
1479
-                    );
1480
-                    return false;
1481
-                    break;
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__, __FUNCTION__, __LINE__
1492
-                    );
1493
-                    return false;
1494
-                    break;
1495
-                case 'no_payment_required' :
1496
-                    EE_Error::add_attention(
1497
-                        apply_filters(
1498
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___verify_payment_method_is_set__no_payment_required_msg',
1499
-                            esc_html__(
1500
-                                '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.',
1501
-                                'event_espresso'
1502
-                            )
1503
-                        ),
1504
-                        __FILE__, __FUNCTION__, __LINE__
1505
-                    );
1506
-                    return false;
1507
-                    break;
1508
-                default:
1509
-            }
1510
-        }
1511
-        // verify payment method
1512
-        if (! $this->checkout->payment_method instanceof EE_Payment_Method) {
1513
-            // get payment method for selected method of payment
1514
-            $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment();
1515
-        }
1516
-        return $this->checkout->payment_method instanceof EE_Payment_Method ? true : false;
1517
-    }
1518
-
1519
-
1520
-
1521
-    /********************************************************************************************************/
1522
-    /***************************************  SAVE PAYER DETAILS  ****************************************/
1523
-    /********************************************************************************************************/
1524
-    /**
1525
-     * save_payer_details_via_ajax
1526
-     *
1527
-     * @return void
1528
-     * @throws EE_Error
1529
-     * @throws InvalidArgumentException
1530
-     * @throws ReflectionException
1531
-     * @throws RuntimeException
1532
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1533
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1534
-     */
1535
-    public function save_payer_details_via_ajax()
1536
-    {
1537
-        if (! $this->_verify_payment_method_is_set()) {
1538
-            return;
1539
-        }
1540
-        // generate billing form for selected method of payment if it hasn't been done already
1541
-        if ($this->checkout->payment_method->type_obj()->has_billing_form()) {
1542
-            $this->checkout->billing_form = $this->_get_billing_form_for_payment_method(
1543
-                $this->checkout->payment_method
1544
-            );
1545
-        }
1546
-        // generate primary attendee from payer info if applicable
1547
-        if (! $this->checkout->transaction_has_primary_registrant()) {
1548
-            $attendee = $this->_create_attendee_from_request_data();
1549
-            if ($attendee instanceof EE_Attendee) {
1550
-                foreach ($this->checkout->transaction->registrations() as $registration) {
1551
-                    if ($registration->is_primary_registrant()) {
1552
-                        $this->checkout->primary_attendee_obj = $attendee;
1553
-                        $registration->_add_relation_to($attendee, 'Attendee');
1554
-                        $registration->set_attendee_id($attendee->ID());
1555
-                        $registration->update_cache_after_object_save('Attendee', $attendee);
1556
-                    }
1557
-                }
1558
-            }
1559
-        }
1560
-    }
1561
-
1562
-
1563
-    /**
1564
-     * create_attendee_from_request_data
1565
-     * uses info from alternate GET or POST data (such as AJAX) to create a new attendee
1566
-     *
1567
-     * @return EE_Attendee
1568
-     * @throws EE_Error
1569
-     * @throws InvalidArgumentException
1570
-     * @throws ReflectionException
1571
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1572
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1573
-     */
1574
-    protected function _create_attendee_from_request_data()
1575
-    {
1576
-        // get State ID
1577
-        $STA_ID = ! empty($_REQUEST['state']) ? sanitize_text_field($_REQUEST['state']) : '';
1578
-        if (! empty($STA_ID)) {
1579
-            // can we get state object from name ?
1580
-            EE_Registry::instance()->load_model('State');
1581
-            $state  = EEM_State::instance()->get_col(array(array('STA_name' => $STA_ID), 'limit' => 1), 'STA_ID');
1582
-            $STA_ID = is_array($state) && ! empty($state) ? reset($state) : $STA_ID;
1583
-        }
1584
-        // get Country ISO
1585
-        $CNT_ISO = ! empty($_REQUEST['country']) ? sanitize_text_field($_REQUEST['country']) : '';
1586
-        if (! empty($CNT_ISO)) {
1587
-            // can we get country object from name ?
1588
-            EE_Registry::instance()->load_model('Country');
1589
-            $country = EEM_Country::instance()->get_col(
1590
-                array(array('CNT_name' => $CNT_ISO), 'limit' => 1),
1591
-                'CNT_ISO'
1592
-            );
1593
-            $CNT_ISO = is_array($country) && ! empty($country) ? reset($country) : $CNT_ISO;
1594
-        }
1595
-        // grab attendee data
1596
-        $attendee_data = array(
1597
-            'ATT_fname'    => ! empty($_REQUEST['first_name']) ? sanitize_text_field($_REQUEST['first_name']) : '',
1598
-            'ATT_lname'    => ! empty($_REQUEST['last_name']) ? sanitize_text_field($_REQUEST['last_name']) : '',
1599
-            'ATT_email'    => ! empty($_REQUEST['email']) ? sanitize_email($_REQUEST['email']) : '',
1600
-            'ATT_address'  => ! empty($_REQUEST['address']) ? sanitize_text_field($_REQUEST['address']) : '',
1601
-            'ATT_address2' => ! empty($_REQUEST['address2']) ? sanitize_text_field($_REQUEST['address2']) : '',
1602
-            'ATT_city'     => ! empty($_REQUEST['city']) ? sanitize_text_field($_REQUEST['city']) : '',
1603
-            'STA_ID'       => $STA_ID,
1604
-            'CNT_ISO'      => $CNT_ISO,
1605
-            'ATT_zip'      => ! empty($_REQUEST['zip']) ? sanitize_text_field($_REQUEST['zip']) : '',
1606
-            'ATT_phone'    => ! empty($_REQUEST['phone']) ? sanitize_text_field($_REQUEST['phone']) : '',
1607
-        );
1608
-        // validate the email address since it is the most important piece of info
1609
-        if (empty($attendee_data['ATT_email']) || $attendee_data['ATT_email'] !== $_REQUEST['email']) {
1610
-            EE_Error::add_error(
1611
-                esc_html__('An invalid email address was submitted.', 'event_espresso'),
1612
-                __FILE__,
1613
-                __FUNCTION__,
1614
-                __LINE__
1615
-            );
1616
-        }
1617
-        // does this attendee already exist in the db ? we're searching using a combination of first name, last name,
1618
-        // AND email address
1619
-        if (! empty($attendee_data['ATT_fname'])
1620
-            && ! empty($attendee_data['ATT_lname'])
1621
-            && ! empty($attendee_data['ATT_email'])
1622
-        ) {
1623
-            $existing_attendee = EE_Registry::instance()->LIB->EEM_Attendee->find_existing_attendee(
1624
-                array(
1625
-                    'ATT_fname' => $attendee_data['ATT_fname'],
1626
-                    'ATT_lname' => $attendee_data['ATT_lname'],
1627
-                    'ATT_email' => $attendee_data['ATT_email'],
1628
-                )
1629
-            );
1630
-            if ($existing_attendee instanceof EE_Attendee) {
1631
-                return $existing_attendee;
1632
-            }
1633
-        }
1634
-        // no existing attendee? kk let's create a new one
1635
-        // kinda lame, but we need a first and last name to create an attendee, so use the email address if those
1636
-        // don't exist
1637
-        $attendee_data['ATT_fname'] = ! empty($attendee_data['ATT_fname'])
1638
-            ? $attendee_data['ATT_fname']
1639
-            : $attendee_data['ATT_email'];
1640
-        $attendee_data['ATT_lname'] = ! empty($attendee_data['ATT_lname'])
1641
-            ? $attendee_data['ATT_lname']
1642
-            : $attendee_data['ATT_email'];
1643
-        return EE_Attendee::new_instance($attendee_data);
1644
-    }
1645
-
1646
-
1647
-
1648
-    /********************************************************************************************************/
1649
-    /****************************************  PROCESS REG STEP  *****************************************/
1650
-    /********************************************************************************************************/
1651
-    /**
1652
-     * process_reg_step
1653
-     *
1654
-     * @return bool
1655
-     * @throws EE_Error
1656
-     * @throws InvalidArgumentException
1657
-     * @throws ReflectionException
1658
-     * @throws \EventEspresso\core\exceptions\EntityNotFoundException
1659
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1660
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1661
-     * @throws \EventEspresso\core\exceptions\InvalidStatusException
1662
-     */
1663
-    public function process_reg_step()
1664
-    {
1665
-        // how have they chosen to pay?
1666
-        $this->checkout->selected_method_of_payment = $this->checkout->transaction->is_free()
1667
-            ? 'no_payment_required'
1668
-            : $this->_get_selected_method_of_payment(true);
1669
-        // choose your own adventure based on method_of_payment
1670
-        switch ($this->checkout->selected_method_of_payment) {
1671
-
1672
-            case 'events_sold_out' :
1673
-                $this->checkout->redirect     = true;
1674
-                $this->checkout->redirect_url = $this->checkout->cancel_page_url;
1675
-                $this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
1676
-                // mark this reg step as completed
1677
-                $this->set_completed();
1678
-                return false;
1679
-                break;
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
-                break;
1697
-
1698
-            case 'no_payment_required' :
1699
-                if (apply_filters(
1700
-                    'FHEE__EE_SPCO_Reg_Step_Payment_Options__process_reg_step__no_payment_required__display_success',
1701
-                    false
1702
-                )) {
1703
-                    EE_Error::add_success(
1704
-                        esc_html__('no payment required.', 'event_espresso'),
1705
-                        __FILE__,
1706
-                        __FUNCTION__,
1707
-                        __LINE__
1708
-                    );
1709
-                }
1710
-                // mark this reg step as completed
1711
-                $this->set_completed();
1712
-                return true;
1713
-                break;
1714
-
1715
-            default:
1716
-                $registrations         = EE_Registry::instance()->SSN->checkout()->transaction->registrations(
1717
-                    EE_Registry::instance()->SSN->checkout()->reg_cache_where_params
1718
-                );
1719
-                $ejected_registrations = EE_SPCO_Reg_Step_Payment_Options::find_registrations_that_lost_their_space(
1720
-                    $registrations,
1721
-                    EE_Registry::instance()->SSN->checkout()->revisit
1722
-                );
1723
-                // calculate difference between the two arrays
1724
-                $registrations = array_diff($registrations, $ejected_registrations);
1725
-                if (empty($registrations)) {
1726
-                    $this->_redirect_because_event_sold_out();
1727
-                    return false;
1728
-                }
1729
-                $payment_successful = $this->_process_payment();
1730
-                if ($payment_successful) {
1731
-                    $this->checkout->continue_reg = true;
1732
-                    $this->_maybe_set_completed($this->checkout->payment_method);
1733
-                } else {
1734
-                    $this->checkout->continue_reg = false;
1735
-                }
1736
-                return $payment_successful;
1737
-        }
1738
-    }
1739
-
1740
-
1741
-    /**
1742
-     * _redirect_because_event_sold_out
1743
-     *
1744
-     * @access protected
1745
-     * @return void
1746
-     */
1747
-    protected function _redirect_because_event_sold_out()
1748
-    {
1749
-        $this->checkout->continue_reg = false;
1750
-        // set redirect URL
1751
-        $this->checkout->redirect_url = add_query_arg(
1752
-            array('e_reg_url_link' => $this->checkout->reg_url_link),
1753
-            $this->checkout->current_step->reg_step_url()
1754
-        );
1755
-        $this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
1756
-    }
1757
-
1758
-
1759
-    /**
1760
-     * _maybe_set_completed
1761
-     *
1762
-     * @access protected
1763
-     * @param \EE_Payment_Method $payment_method
1764
-     * @return void
1765
-     * @throws \EE_Error
1766
-     */
1767
-    protected function _maybe_set_completed(EE_Payment_Method $payment_method)
1768
-    {
1769
-        switch ($payment_method->type_obj()->payment_occurs()) {
1770
-            case EE_PMT_Base::offsite :
1771
-                break;
1772
-            case EE_PMT_Base::onsite :
1773
-            case EE_PMT_Base::offline :
1774
-                // mark this reg step as completed
1775
-                $this->set_completed();
1776
-                break;
1777
-        }
1778
-    }
1779
-
1780
-
1781
-    /**
1782
-     *    update_reg_step
1783
-     *    this is the final step after a user  revisits the site to retry a payment
1784
-     *
1785
-     * @return bool
1786
-     * @throws EE_Error
1787
-     * @throws InvalidArgumentException
1788
-     * @throws ReflectionException
1789
-     * @throws \EventEspresso\core\exceptions\EntityNotFoundException
1790
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1791
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1792
-     * @throws \EventEspresso\core\exceptions\InvalidStatusException
1793
-     */
1794
-    public function update_reg_step()
1795
-    {
1796
-        $success = true;
1797
-        // if payment required
1798
-        if ($this->checkout->transaction->total() > 0) {
1799
-            do_action(
1800
-                'AHEE__EE_Single_Page_Checkout__process_finalize_registration__before_gateway',
1801
-                $this->checkout->transaction
1802
-            );
1803
-            // attempt payment via payment method
1804
-            $success = $this->process_reg_step();
1805
-        }
1806
-        if ($success && ! $this->checkout->redirect) {
1807
-            $this->checkout->cart->get_grand_total()->save_this_and_descendants_to_txn(
1808
-                $this->checkout->transaction->ID()
1809
-            );
1810
-            // set return URL
1811
-            $this->checkout->redirect_url = add_query_arg(
1812
-                array('e_reg_url_link' => $this->checkout->reg_url_link),
1813
-                $this->checkout->thank_you_page_url
1814
-            );
1815
-        }
1816
-        return $success;
1817
-    }
1818
-
1819
-
1820
-    /**
1821
-     *    _process_payment
1822
-     *
1823
-     * @access private
1824
-     * @return bool
1825
-     * @throws EE_Error
1826
-     * @throws InvalidArgumentException
1827
-     * @throws ReflectionException
1828
-     * @throws RuntimeException
1829
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1830
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1831
-     */
1832
-    private function _process_payment()
1833
-    {
1834
-        // basically confirm that the event hasn't sold out since they hit the page
1835
-        if (! $this->_last_second_ticket_verifications()) {
1836
-            return false;
1837
-        }
1838
-        // ya gotta make a choice man
1839
-        if (empty($this->checkout->selected_method_of_payment)) {
1840
-            $this->checkout->json_response->set_plz_select_method_of_payment(
1841
-                esc_html__('Please select a method of payment before proceeding.', 'event_espresso')
1842
-            );
1843
-            return false;
1844
-        }
1845
-        // get EE_Payment_Method object
1846
-        if (! $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment()) {
1847
-            return false;
1848
-        }
1849
-        // setup billing form
1850
-        if ($this->checkout->payment_method->is_on_site()) {
1851
-            $this->checkout->billing_form = $this->_get_billing_form_for_payment_method(
1852
-                $this->checkout->payment_method
1853
-            );
1854
-            // bad billing form ?
1855
-            if (! $this->_billing_form_is_valid()) {
1856
-                return false;
1857
-            }
1858
-        }
1859
-        // ensure primary registrant has been fully processed
1860
-        if (! $this->_setup_primary_registrant_prior_to_payment()) {
1861
-            return false;
1862
-        }
1863
-        // if session is close to expiring (under 10 minutes by default)
1864
-        if ((time() - EE_Registry::instance()->SSN->expiration()) < EE_Registry::instance()->SSN->extension()) {
1865
-            // add some time to session expiration so that payment can be completed
1866
-            EE_Registry::instance()->SSN->extend_expiration();
1867
-        }
1868
-        /** @type EE_Transaction_Processor $transaction_processor */
1869
-        //$transaction_processor = EE_Registry::instance()->load_class( 'Transaction_Processor' );
1870
-        // in case a registrant leaves to an Off-Site Gateway and never returns, we want to approve any registrations
1871
-        // for events with a default reg status of Approved
1872
-        // $transaction_processor->toggle_registration_statuses_for_default_approved_events(
1873
-        //      $this->checkout->transaction, $this->checkout->reg_cache_where_params
1874
-        // );
1875
-        // attempt payment
1876
-        $payment = $this->_attempt_payment($this->checkout->payment_method);
1877
-        // process results
1878
-        $payment = $this->_validate_payment($payment);
1879
-        $payment = $this->_post_payment_processing($payment);
1880
-        // verify payment
1881
-        if ($payment instanceof EE_Payment) {
1882
-            // store that for later
1883
-            $this->checkout->payment = $payment;
1884
-            // we can also consider the TXN to not have been failed, so temporarily upgrade it's status to abandoned
1885
-            $this->checkout->transaction->toggle_failed_transaction_status();
1886
-            $payment_status = $payment->status();
1887
-            if (
1888
-                $payment_status === EEM_Payment::status_id_approved
1889
-                || $payment_status === EEM_Payment::status_id_pending
1890
-            ) {
1891
-                return true;
1892
-            } else {
1893
-                return false;
1894
-            }
1895
-        } else if ($payment === true) {
1896
-            // please note that offline payment methods will NOT make a payment,
1897
-            // but instead just mark themselves as the PMD_ID on the transaction, and return true
1898
-            $this->checkout->payment = $payment;
1899
-            return true;
1900
-        }
1901
-        // where's my money?
1902
-        return false;
1903
-    }
1904
-
1905
-
1906
-    /**
1907
-     * _last_second_ticket_verifications
1908
-     *
1909
-     * @access public
1910
-     * @return bool
1911
-     * @throws EE_Error
1912
-     */
1913
-    protected function _last_second_ticket_verifications()
1914
-    {
1915
-        // don't bother re-validating if not a return visit
1916
-        if (! $this->checkout->revisit) {
1917
-            return true;
1918
-        }
1919
-        $registrations = $this->checkout->transaction->registrations();
1920
-        if (empty($registrations)) {
1921
-            return false;
1922
-        }
1923
-        foreach ($registrations as $registration) {
1924
-            if ($registration instanceof EE_Registration && ! $registration->is_approved()) {
1925
-                $event = $registration->event_obj();
1926
-                if ($event instanceof EE_Event && $event->is_sold_out(true)) {
1927
-                    EE_Error::add_error(
1928
-                        apply_filters(
1929
-                            'FHEE__EE_SPCO_Reg_Step_Payment_Options___last_second_ticket_verifications__sold_out_events_msg',
1930
-                            sprintf(
1931
-                                esc_html__(
1932
-                                    '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.',
1933
-                                    'event_espresso'
1934
-                                ),
1935
-                                $event->name()
1936
-                            )
1937
-                        ),
1938
-                        __FILE__,
1939
-                        __FUNCTION__,
1940
-                        __LINE__
1941
-                    );
1942
-                    return false;
1943
-                }
1944
-            }
1945
-        }
1946
-        return true;
1947
-    }
1948
-
1949
-
1950
-    /**
1951
-     * redirect_form
1952
-     *
1953
-     * @access public
1954
-     * @return bool
1955
-     * @throws EE_Error
1956
-     * @throws InvalidArgumentException
1957
-     * @throws ReflectionException
1958
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1959
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1960
-     */
1961
-    public function redirect_form()
1962
-    {
1963
-        $payment_method_billing_info = $this->_payment_method_billing_info(
1964
-            $this->_get_payment_method_for_selected_method_of_payment()
1965
-        );
1966
-        $html                        = $payment_method_billing_info->get_html();
1967
-        $html                        .= $this->checkout->redirect_form;
1968
-        EE_Registry::instance()->REQ->add_output($html);
1969
-        return true;
1970
-    }
1971
-
1972
-
1973
-    /**
1974
-     * _billing_form_is_valid
1975
-     *
1976
-     * @access private
1977
-     * @return bool
1978
-     * @throws \EE_Error
1979
-     */
1980
-    private function _billing_form_is_valid()
1981
-    {
1982
-        if (! $this->checkout->payment_method->type_obj()->has_billing_form()) {
1983
-            return true;
1984
-        }
1985
-        if ($this->checkout->billing_form instanceof EE_Billing_Info_Form) {
1986
-            if ($this->checkout->billing_form->was_submitted()) {
1987
-                $this->checkout->billing_form->receive_form_submission();
1988
-                if ($this->checkout->billing_form->is_valid()) {
1989
-                    return true;
1990
-                }
1991
-                $validation_errors = $this->checkout->billing_form->get_validation_errors_accumulated();
1992
-                $error_strings     = array();
1993
-                foreach ($validation_errors as $validation_error) {
1994
-                    if ($validation_error instanceof EE_Validation_Error) {
1995
-                        $form_section = $validation_error->get_form_section();
1996
-                        if ($form_section instanceof EE_Form_Input_Base) {
1997
-                            $label = $form_section->html_label_text();
1998
-                        } elseif ($form_section instanceof EE_Form_Section_Base) {
1999
-                            $label = $form_section->name();
2000
-                        } else {
2001
-                            $label = esc_html__('Validation Error', 'event_espresso');
2002
-                        }
2003
-                        $error_strings[] = sprintf('%1$s: %2$s', $label, $validation_error->getMessage());
2004
-                    }
2005
-                }
2006
-                EE_Error::add_error(
2007
-                    sprintf(
2008
-                        esc_html__(
2009
-                            'One or more billing form inputs are invalid and require correction before proceeding. %1$s %2$s',
2010
-                            'event_espresso'
2011
-                        ),
2012
-                        '<br/>',
2013
-                        implode('<br/>', $error_strings)
2014
-                    ),
2015
-                    __FILE__,
2016
-                    __FUNCTION__,
2017
-                    __LINE__
2018
-                );
2019
-            } else {
2020
-                EE_Error::add_error(
2021
-                    esc_html__(
2022
-                        'The billing form was not submitted or something prevented it\'s submission.',
2023
-                        'event_espresso'
2024
-                    ),
2025
-                    __FILE__,
2026
-                    __FUNCTION__,
2027
-                    __LINE__
2028
-                );
2029
-            }
2030
-        } else {
2031
-            EE_Error::add_error(
2032
-                esc_html__('The submitted billing form is invalid possibly due to a technical reason.', 'event_espresso'),
2033
-                __FILE__,
2034
-                __FUNCTION__,
2035
-                __LINE__
2036
-            );
2037
-        }
2038
-        return false;
2039
-    }
2040
-
2041
-
2042
-    /**
2043
-     * _setup_primary_registrant_prior_to_payment
2044
-     * ensures that the primary registrant has a valid attendee object created with the critical details populated
2045
-     * (first & last name & email) and that both the transaction object and primary registration object have been saved
2046
-     * plz note that any other registrations will NOT be saved at this point (because they may not have any details
2047
-     * yet)
2048
-     *
2049
-     * @access private
2050
-     * @return bool
2051
-     * @throws EE_Error
2052
-     * @throws InvalidArgumentException
2053
-     * @throws ReflectionException
2054
-     * @throws RuntimeException
2055
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2056
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2057
-     */
2058
-    private function _setup_primary_registrant_prior_to_payment()
2059
-    {
2060
-        // check if transaction has a primary registrant and that it has a related Attendee object
2061
-        // if not, then we need to at least gather some primary registrant data before attempting payment
2062
-        if (
2063
-            $this->checkout->billing_form instanceof EE_Billing_Attendee_Info_Form
2064
-            && ! $this->checkout->transaction_has_primary_registrant()
2065
-            && ! $this->_capture_primary_registration_data_from_billing_form()
2066
-        ) {
2067
-            return false;
2068
-        }
2069
-        // because saving an object clears it's cache, we need to do the chevy shuffle
2070
-        // grab the primary_registration object
2071
-        $primary_registration = $this->checkout->transaction->primary_registration();
2072
-        // at this point we'll consider a TXN to not have been failed
2073
-        $this->checkout->transaction->toggle_failed_transaction_status();
2074
-        // save the TXN ( which clears cached copy of primary_registration)
2075
-        $this->checkout->transaction->save();
2076
-        // grab TXN ID and save it to the primary_registration
2077
-        $primary_registration->set_transaction_id($this->checkout->transaction->ID());
2078
-        // save what we have so far
2079
-        $primary_registration->save();
2080
-        return true;
2081
-    }
2082
-
2083
-
2084
-    /**
2085
-     * _capture_primary_registration_data_from_billing_form
2086
-     *
2087
-     * @access private
2088
-     * @return bool
2089
-     * @throws EE_Error
2090
-     * @throws InvalidArgumentException
2091
-     * @throws ReflectionException
2092
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2093
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2094
-     */
2095
-    private function _capture_primary_registration_data_from_billing_form()
2096
-    {
2097
-        // convert billing form data into an attendee
2098
-        $this->checkout->primary_attendee_obj = $this->checkout->billing_form->create_attendee_from_billing_form_data();
2099
-        if (! $this->checkout->primary_attendee_obj instanceof EE_Attendee) {
2100
-            EE_Error::add_error(
2101
-                sprintf(
2102
-                    esc_html__(
2103
-                        'The billing form details could not be used for attendee details due to a technical issue.%sPlease try again or contact %s for assistance.',
2104
-                        'event_espresso'
2105
-                    ),
2106
-                    '<br/>',
2107
-                    EE_Registry::instance()->CFG->organization->get_pretty('email')
2108
-                ),
2109
-                __FILE__,
2110
-                __FUNCTION__,
2111
-                __LINE__
2112
-            );
2113
-            return false;
2114
-        }
2115
-        $primary_registration = $this->checkout->transaction->primary_registration();
2116
-        if (! $primary_registration instanceof EE_Registration) {
2117
-            EE_Error::add_error(
2118
-                sprintf(
2119
-                    esc_html__(
2120
-                        'The primary registrant for this transaction could not be determined due to a technical issue.%sPlease try again or contact %s for assistance.',
2121
-                        'event_espresso'
2122
-                    ),
2123
-                    '<br/>',
2124
-                    EE_Registry::instance()->CFG->organization->get_pretty('email')
2125
-                ),
2126
-                __FILE__,
2127
-                __FUNCTION__,
2128
-                __LINE__
2129
-            );
2130
-            return false;
2131
-        }
2132
-        if (! $primary_registration->_add_relation_to($this->checkout->primary_attendee_obj, 'Attendee')
2133
-              instanceof
2134
-              EE_Attendee
2135
-        ) {
2136
-            EE_Error::add_error(
2137
-                sprintf(
2138
-                    esc_html__(
2139
-                        'The primary registrant could not be associated with this transaction due to a technical issue.%sPlease try again or contact %s for assistance.',
2140
-                        'event_espresso'
2141
-                    ),
2142
-                    '<br/>',
2143
-                    EE_Registry::instance()->CFG->organization->get_pretty('email')
2144
-                ),
2145
-                __FILE__,
2146
-                __FUNCTION__,
2147
-                __LINE__
2148
-            );
2149
-            return false;
2150
-        }
2151
-        /** @type EE_Registration_Processor $registration_processor */
2152
-        $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
2153
-        // at this point, we should have enough details about the registrant to consider the registration NOT incomplete
2154
-        $registration_processor->toggle_incomplete_registration_status_to_default($primary_registration);
2155
-        return true;
2156
-    }
2157
-
2158
-
2159
-    /**
2160
-     * _get_payment_method_for_selected_method_of_payment
2161
-     * retrieves a valid payment method
2162
-     *
2163
-     * @access public
2164
-     * @return EE_Payment_Method
2165
-     * @throws EE_Error
2166
-     * @throws InvalidArgumentException
2167
-     * @throws ReflectionException
2168
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2169
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2170
-     */
2171
-    private function _get_payment_method_for_selected_method_of_payment()
2172
-    {
2173
-        if ($this->checkout->selected_method_of_payment === 'events_sold_out') {
2174
-            $this->_redirect_because_event_sold_out();
2175
-            return null;
2176
-        }
2177
-        // get EE_Payment_Method object
2178
-        if (isset($this->checkout->available_payment_methods[$this->checkout->selected_method_of_payment])) {
2179
-            $payment_method = $this->checkout->available_payment_methods[$this->checkout->selected_method_of_payment];
2180
-        } else {
2181
-            // load EEM_Payment_Method
2182
-            EE_Registry::instance()->load_model('Payment_Method');
2183
-            /** @type EEM_Payment_Method $EEM_Payment_Method */
2184
-            $EEM_Payment_Method = EE_Registry::instance()->LIB->EEM_Payment_Method;
2185
-            $payment_method     = $EEM_Payment_Method->get_one_by_slug($this->checkout->selected_method_of_payment);
2186
-        }
2187
-        // verify $payment_method
2188
-        if (! $payment_method instanceof EE_Payment_Method) {
2189
-            // not a payment
2190
-            EE_Error::add_error(
2191
-                sprintf(
2192
-                    esc_html__(
2193
-                        'The selected method of payment could not be determined due to a technical issue.%sPlease try again or contact %s for assistance.',
2194
-                        'event_espresso'
2195
-                    ),
2196
-                    '<br/>',
2197
-                    EE_Registry::instance()->CFG->organization->get_pretty('email')
2198
-                ),
2199
-                __FILE__,
2200
-                __FUNCTION__,
2201
-                __LINE__
2202
-            );
2203
-            return null;
2204
-        }
2205
-        // and verify it has a valid Payment_Method Type object
2206
-        if (! $payment_method->type_obj() instanceof EE_PMT_Base) {
2207
-            // not a payment
2208
-            EE_Error::add_error(
2209
-                sprintf(
2210
-                    esc_html__(
2211
-                        'A valid payment method could not be determined due to a technical issue.%sPlease try again or contact %s for assistance.',
2212
-                        'event_espresso'
2213
-                    ),
2214
-                    '<br/>',
2215
-                    EE_Registry::instance()->CFG->organization->get_pretty('email')
2216
-                ),
2217
-                __FILE__,
2218
-                __FUNCTION__,
2219
-                __LINE__
2220
-            );
2221
-            return null;
2222
-        }
2223
-        return $payment_method;
2224
-    }
2225
-
2226
-
2227
-    /**
2228
-     *    _attempt_payment
2229
-     *
2230
-     * @access    private
2231
-     * @type    EE_Payment_Method $payment_method
2232
-     * @return mixed EE_Payment | boolean
2233
-     * @throws EE_Error
2234
-     * @throws InvalidArgumentException
2235
-     * @throws ReflectionException
2236
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2237
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2238
-     */
2239
-    private function _attempt_payment(EE_Payment_Method $payment_method)
2240
-    {
2241
-        $payment = null;
2242
-        $this->checkout->transaction->save();
2243
-        $payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
2244
-        if (! $payment_processor instanceof EE_Payment_Processor) {
2245
-            return false;
2246
-        }
2247
-        try {
2248
-            $payment_processor->set_revisit($this->checkout->revisit);
2249
-            // generate payment object
2250
-            $payment = $payment_processor->process_payment(
2251
-                $payment_method,
2252
-                $this->checkout->transaction,
2253
-                $this->checkout->amount_owing,
2254
-                $this->checkout->billing_form,
2255
-                $this->_get_return_url($payment_method),
2256
-                'CART',
2257
-                $this->checkout->admin_request,
2258
-                true,
2259
-                $this->reg_step_url()
2260
-            );
2261
-        } catch (Exception $e) {
2262
-            $this->_handle_payment_processor_exception($e);
2263
-        }
2264
-        return $payment;
2265
-    }
2266
-
2267
-
2268
-    /**
2269
-     * _handle_payment_processor_exception
2270
-     *
2271
-     * @access protected
2272
-     * @param \Exception $e
2273
-     * @return void
2274
-     * @throws EE_Error
2275
-     * @throws InvalidArgumentException
2276
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2277
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2278
-     */
2279
-    protected function _handle_payment_processor_exception(Exception $e)
2280
-    {
2281
-        EE_Error::add_error(
2282
-            sprintf(
2283
-                esc_html__(
2284
-                    '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',
2285
-                    'event_espresso'
2286
-                ),
2287
-                '<br/>',
2288
-                EE_Registry::instance()->CFG->organization->get_pretty('email'),
2289
-                $e->getMessage(),
2290
-                $e->getFile(),
2291
-                $e->getLine()
2292
-            ),
2293
-            __FILE__,
2294
-            __FUNCTION__,
2295
-            __LINE__
2296
-        );
2297
-    }
2298
-
2299
-
2300
-    /**
2301
-     * _get_return_url
2302
-     *
2303
-     * @access protected
2304
-     * @param \EE_Payment_Method $payment_method
2305
-     * @return string
2306
-     * @throws \EE_Error
2307
-     */
2308
-    protected function _get_return_url(EE_Payment_Method $payment_method)
2309
-    {
2310
-        $return_url = '';
2311
-        switch ($payment_method->type_obj()->payment_occurs()) {
2312
-            case EE_PMT_Base::offsite :
2313
-                $return_url = add_query_arg(
2314
-                    array(
2315
-                        'action'                     => 'process_gateway_response',
2316
-                        'selected_method_of_payment' => $this->checkout->selected_method_of_payment,
2317
-                        'spco_txn'                   => $this->checkout->transaction->ID(),
2318
-                    ),
2319
-                    $this->reg_step_url()
2320
-                );
2321
-                break;
2322
-            case EE_PMT_Base::onsite :
2323
-            case EE_PMT_Base::offline :
2324
-                $return_url = $this->checkout->next_step->reg_step_url();
2325
-                break;
2326
-        }
2327
-        return $return_url;
2328
-    }
2329
-
2330
-
2331
-    /**
2332
-     * _validate_payment
2333
-     *
2334
-     * @access private
2335
-     * @param EE_Payment $payment
2336
-     * @return EE_Payment|FALSE
2337
-     * @throws EE_Error
2338
-     * @throws InvalidArgumentException
2339
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2340
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2341
-     */
2342
-    private function _validate_payment($payment = null)
2343
-    {
2344
-        if ($this->checkout->payment_method->is_off_line()) {
2345
-            return true;
2346
-        }
2347
-        // verify payment object
2348
-        if (! $payment instanceof EE_Payment) {
2349
-            // not a payment
2350
-            EE_Error::add_error(
2351
-                sprintf(
2352
-                    esc_html__(
2353
-                        'A valid payment was not generated due to a technical issue.%1$sPlease try again or contact %2$s for assistance.',
2354
-                        'event_espresso'
2355
-                    ),
2356
-                    '<br/>',
2357
-                    EE_Registry::instance()->CFG->organization->get_pretty('email')
2358
-                ),
2359
-                __FILE__,
2360
-                __FUNCTION__,
2361
-                __LINE__
2362
-            );
2363
-            return false;
2364
-        }
2365
-        return $payment;
2366
-    }
2367
-
2368
-
2369
-    /**
2370
-     * _post_payment_processing
2371
-     *
2372
-     * @access private
2373
-     * @param EE_Payment|bool $payment
2374
-     * @return bool
2375
-     * @throws EE_Error
2376
-     * @throws InvalidArgumentException
2377
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2378
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2379
-     */
2380
-    private function _post_payment_processing($payment = null)
2381
-    {
2382
-        // Off-Line payment?
2383
-        if ($payment === true) {
2384
-            //$this->_setup_redirect_for_next_step();
2385
-            return true;
2386
-            // On-Site payment?
2387
-        } else if ($this->checkout->payment_method->is_on_site()) {
2388
-            if (! $this->_process_payment_status($payment, EE_PMT_Base::onsite)) {
2389
-                //$this->_setup_redirect_for_next_step();
2390
-                $this->checkout->continue_reg = false;
2391
-            }
2392
-            // Off-Site payment?
2393
-        } else if ($this->checkout->payment_method->is_off_site()) {
2394
-            // if a payment object was made and it specifies a redirect url, then we'll setup that redirect info
2395
-            if ($payment instanceof EE_Payment && $payment->redirect_url()) {
2396
-                do_action('AHEE_log', __CLASS__, __FUNCTION__, $payment->redirect_url(), '$payment->redirect_url()');
2397
-                $this->checkout->redirect      = true;
2398
-                $this->checkout->redirect_form = $payment->redirect_form();
2399
-                $this->checkout->redirect_url  = $this->reg_step_url('redirect_form');
2400
-                // set JSON response
2401
-                $this->checkout->json_response->set_redirect_form($this->checkout->redirect_form);
2402
-                // and lastly, let's bump the payment status to pending
2403
-                $payment->set_status(EEM_Payment::status_id_pending);
2404
-                $payment->save();
2405
-            } else {
2406
-                // not a payment
2407
-                $this->checkout->continue_reg = false;
2408
-                EE_Error::add_error(
2409
-                    sprintf(
2410
-                        esc_html__(
2411
-                            'It appears the Off Site Payment Method was not configured properly.%sPlease try again or contact %s for assistance.',
2412
-                            'event_espresso'
2413
-                        ),
2414
-                        '<br/>',
2415
-                        EE_Registry::instance()->CFG->organization->get_pretty('email')
2416
-                    ),
2417
-                    __FILE__,
2418
-                    __FUNCTION__,
2419
-                    __LINE__
2420
-                );
2421
-            }
2422
-        } else {
2423
-            // ummm ya... not Off-Line, not On-Site, not off-Site ????
2424
-            $this->checkout->continue_reg = false;
2425
-            return false;
2426
-        }
2427
-        return $payment;
2428
-    }
2429
-
2430
-
2431
-    /**
2432
-     *    _process_payment_status
2433
-     *
2434
-     * @access private
2435
-     * @type    EE_Payment $payment
2436
-     * @param string       $payment_occurs
2437
-     * @return bool
2438
-     * @throws EE_Error
2439
-     * @throws InvalidArgumentException
2440
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2441
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2442
-     */
2443
-    private function _process_payment_status($payment, $payment_occurs = EE_PMT_Base::offline)
2444
-    {
2445
-        // off-line payment? carry on
2446
-        if ($payment_occurs === EE_PMT_Base::offline) {
2447
-            return true;
2448
-        }
2449
-        // verify payment validity
2450
-        if ($payment instanceof EE_Payment) {
2451
-            do_action('AHEE_log', __CLASS__, __FUNCTION__, $payment->status(), '$payment->status()');
2452
-            $msg = $payment->gateway_response();
2453
-            // check results
2454
-            switch ($payment->status()) {
2455
-                // good payment
2456
-                case EEM_Payment::status_id_approved :
2457
-                    EE_Error::add_success(
2458
-                        esc_html__('Your payment was processed successfully.', 'event_espresso'),
2459
-                        __FILE__,
2460
-                        __FUNCTION__,
2461
-                        __LINE__
2462
-                    );
2463
-                    return true;
2464
-                    break;
2465
-                // slow payment
2466
-                case EEM_Payment::status_id_pending :
2467
-                    if (empty($msg)) {
2468
-                        $msg = esc_html__(
2469
-                            'Your payment appears to have been processed successfully, but the Instant Payment Notification has not yet been received. It should arrive shortly.',
2470
-                            'event_espresso'
2471
-                        );
2472
-                    }
2473
-                    EE_Error::add_success($msg, __FILE__, __FUNCTION__, __LINE__);
2474
-                    return true;
2475
-                    break;
2476
-                // don't wanna payment
2477
-                case EEM_Payment::status_id_cancelled :
2478
-                    if (empty($msg)) {
2479
-                        $msg = _n(
2480
-                            'Payment cancelled. Please try again.',
2481
-                            'Payment cancelled. Please try again or select another method of payment.',
2482
-                            count($this->checkout->available_payment_methods),
2483
-                            'event_espresso'
2484
-                        );
2485
-                    }
2486
-                    EE_Error::add_attention($msg, __FILE__, __FUNCTION__, __LINE__);
2487
-                    return false;
2488
-                    break;
2489
-                // not enough payment
2490
-                case EEM_Payment::status_id_declined :
2491
-                    if (empty($msg)) {
2492
-                        $msg = _n(
2493
-                            'We\'re sorry but your payment was declined. Please try again.',
2494
-                            'We\'re sorry but your payment was declined. Please try again or select another method of payment.',
2495
-                            count($this->checkout->available_payment_methods),
2496
-                            'event_espresso'
2497
-                        );
2498
-                    }
2499
-                    EE_Error::add_attention($msg, __FILE__, __FUNCTION__, __LINE__);
2500
-                    return false;
2501
-                    break;
2502
-                // bad payment
2503
-                case EEM_Payment::status_id_failed :
2504
-                    if (! empty($msg)) {
2505
-                        EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2506
-                        return false;
2507
-                    }
2508
-                    // default to error below
2509
-                    break;
2510
-            }
2511
-        }
2512
-        // off-site payment gateway responses are too unreliable, so let's just assume that
2513
-        // the payment processing is just running slower than the registrant's request
2514
-        if ($payment_occurs === EE_PMT_Base::offsite) {
2515
-            return true;
2516
-        }
2517
-        EE_Error::add_error(
2518
-            sprintf(
2519
-                esc_html__(
2520
-                    'Your payment could not be processed successfully due to a technical issue.%sPlease try again or contact %s for assistance.',
2521
-                    'event_espresso'
2522
-                ),
2523
-                '<br/>',
2524
-                EE_Registry::instance()->CFG->organization->get_pretty('email')
2525
-            ),
2526
-            __FILE__,
2527
-            __FUNCTION__,
2528
-            __LINE__
2529
-        );
2530
-        return false;
2531
-    }
2532
-
2533
-
2534
-
2535
-
2536
-
2537
-
2538
-    /********************************************************************************************************/
2539
-    /**********************************  PROCESS GATEWAY RESPONSE  **********************************/
2540
-    /********************************************************************************************************/
2541
-    /**
2542
-     * process_gateway_response
2543
-     * this is the return point for Off-Site Payment Methods
2544
-     * It will attempt to "handle the IPN" if it appears that this has not already occurred,
2545
-     * otherwise, it will load up the last payment made for the TXN.
2546
-     * If the payment retrieved looks good, it will then either:
2547
-     *    complete the current step and allow advancement to the next reg step
2548
-     *        or present the payment options again
2549
-     *
2550
-     * @access private
2551
-     * @return EE_Payment|FALSE
2552
-     * @throws EE_Error
2553
-     * @throws InvalidArgumentException
2554
-     * @throws ReflectionException
2555
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2556
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2557
-     * @throws \EventEspresso\core\exceptions\InvalidSessionDataException
2558
-     */
2559
-    public function process_gateway_response()
2560
-    {
2561
-        $payment = null;
2562
-        // how have they chosen to pay?
2563
-        $this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment(true);
2564
-        // get EE_Payment_Method object
2565
-        if (! $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment()) {
2566
-            $this->checkout->continue_reg = false;
2567
-            return false;
2568
-        }
2569
-        if (! $this->checkout->payment_method->is_off_site()) {
2570
-            return false;
2571
-        }
2572
-        $this->_validate_offsite_return();
2573
-        // DEBUG LOG
2574
-        //$this->checkout->log(
2575
-        //	__CLASS__, __FUNCTION__, __LINE__,
2576
-        //	array(
2577
-        //		'selected_method_of_payment' => $this->checkout->selected_method_of_payment,
2578
-        //		'payment_method' => $this->checkout->payment_method,
2579
-        //	),
2580
-        //	true
2581
-        //);
2582
-        // verify TXN
2583
-        if ($this->checkout->transaction instanceof EE_Transaction) {
2584
-            $gateway = $this->checkout->payment_method->type_obj()->get_gateway();
2585
-            if (! $gateway instanceof EE_Offsite_Gateway) {
2586
-                $this->checkout->continue_reg = false;
2587
-                return false;
2588
-            }
2589
-            $payment = $this->_process_off_site_payment($gateway);
2590
-            $payment = $this->_process_cancelled_payments($payment);
2591
-            $payment = $this->_validate_payment($payment);
2592
-            // if payment was not declined by the payment gateway or cancelled by the registrant
2593
-            if ($this->_process_payment_status($payment, EE_PMT_Base::offsite)) {
2594
-                //$this->_setup_redirect_for_next_step();
2595
-                // store that for later
2596
-                $this->checkout->payment = $payment;
2597
-                // mark this reg step as completed, as long as gateway doesn't use a separate IPN request,
2598
-                // because we will complete this step during the IPN processing then
2599
-                if ($gateway instanceof EE_Offsite_Gateway && ! $this->handle_IPN_in_this_request()) {
2600
-                    $this->set_completed();
2601
-                }
2602
-                return true;
2603
-            }
2604
-        }
2605
-        // DEBUG LOG
2606
-        //$this->checkout->log( __CLASS__, __FUNCTION__, __LINE__,
2607
-        //	array( 'payment' => $payment )
2608
-        //);
2609
-        $this->checkout->continue_reg = false;
2610
-        return false;
2611
-    }
2612
-
2613
-
2614
-    /**
2615
-     * _validate_return
2616
-     *
2617
-     * @access private
2618
-     * @return void
2619
-     * @throws EE_Error
2620
-     * @throws InvalidArgumentException
2621
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2622
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2623
-     * @throws \EventEspresso\core\exceptions\InvalidSessionDataException
2624
-     */
2625
-    private function _validate_offsite_return()
2626
-    {
2627
-        $TXN_ID = (int)EE_Registry::instance()->REQ->get('spco_txn', 0);
2628
-        if ($TXN_ID !== $this->checkout->transaction->ID()) {
2629
-            // Houston... we might have a problem
2630
-            $invalid_TXN = false;
2631
-            // first gather some info
2632
-            $valid_TXN          = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
2633
-            $primary_registrant = $valid_TXN instanceof EE_Transaction
2634
-                ? $valid_TXN->primary_registration()
2635
-                : null;
2636
-            // let's start by retrieving the cart for this TXN
2637
-            $cart = $this->checkout->get_cart_for_transaction($this->checkout->transaction);
2638
-            if ($cart instanceof EE_Cart) {
2639
-                // verify that the current cart has tickets
2640
-                $tickets = $cart->get_tickets();
2641
-                if (empty($tickets)) {
2642
-                    $invalid_TXN = true;
2643
-                }
2644
-            } else {
2645
-                $invalid_TXN = true;
2646
-            }
2647
-            $valid_TXN_SID = $primary_registrant instanceof EE_Registration
2648
-                ? $primary_registrant->session_ID()
2649
-                : null;
2650
-            // validate current Session ID and compare against valid TXN session ID
2651
-            if (
2652
-                $invalid_TXN // if this is already true, then skip other checks
2653
-                || EE_Session::instance()->id() === null
2654
-                || (
2655
-                    // WARNING !!!
2656
-                    // this could be PayPal sending back duplicate requests (ya they do that)
2657
-                    // or it **could** mean someone is simply registering AGAIN after having just done so
2658
-                    // so now we need to determine if this current TXN looks valid or not
2659
-                    // and whether this reg step has even been started ?
2660
-                    EE_Session::instance()->id() === $valid_TXN_SID
2661
-                    // really? you're half way through this reg step, but you never started it ?
2662
-                    && $this->checkout->transaction->reg_step_completed($this->slug()) === false
2663
-                )
2664
-            ) {
2665
-                $invalid_TXN = true;
2666
-            }
2667
-            if ($invalid_TXN) {
2668
-                // is the valid TXN completed ?
2669
-                if ($valid_TXN instanceof EE_Transaction) {
2670
-                    // has this step even been started ?
2671
-                    $reg_step_completed = $valid_TXN->reg_step_completed($this->slug());
2672
-                    if ($reg_step_completed !== false && $reg_step_completed !== true) {
2673
-                        // so it **looks** like this is a double request from PayPal
2674
-                        // so let's try to pick up where we left off
2675
-                        $this->checkout->transaction = $valid_TXN;
2676
-                        $this->checkout->refresh_all_entities(true);
2677
-                        return;
2678
-                    }
2679
-                }
2680
-                // you appear to be lost?
2681
-                $this->_redirect_wayward_request($primary_registrant);
2682
-            }
2683
-        }
2684
-    }
2685
-
2686
-
2687
-    /**
2688
-     * _redirect_wayward_request
2689
-     *
2690
-     * @access private
2691
-     * @param \EE_Registration|null $primary_registrant
2692
-     * @return bool
2693
-     * @throws EE_Error
2694
-     * @throws InvalidArgumentException
2695
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2696
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2697
-     */
2698
-    private function _redirect_wayward_request(EE_Registration $primary_registrant)
2699
-    {
2700
-        if (! $primary_registrant instanceof EE_Registration) {
2701
-            // try redirecting based on the current TXN
2702
-            $primary_registrant = $this->checkout->transaction instanceof EE_Transaction
2703
-                ? $this->checkout->transaction->primary_registration()
2704
-                : null;
2705
-        }
2706
-        if (! $primary_registrant instanceof EE_Registration) {
2707
-            EE_Error::add_error(
2708
-                sprintf(
2709
-                    esc_html__(
2710
-                        '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.',
2711
-                        'event_espresso'
2712
-                    ),
2713
-                    '<br/>',
2714
-                    EE_Registry::instance()->CFG->organization->get_pretty('email')
2715
-                ),
2716
-                __FILE__,
2717
-                __FUNCTION__,
2718
-                __LINE__
2719
-            );
2720
-            return false;
2721
-        }
2722
-        // make sure transaction is not locked
2723
-        $this->checkout->transaction->unlock();
2724
-        wp_safe_redirect(
2725
-            add_query_arg(
2726
-                array(
2727
-                    'e_reg_url_link' => $primary_registrant->reg_url_link(),
2728
-                ),
2729
-                $this->checkout->thank_you_page_url
2730
-            )
2731
-        );
2732
-        exit();
2733
-    }
2734
-
2735
-
2736
-    /**
2737
-     * _process_off_site_payment
2738
-     *
2739
-     * @access private
2740
-     * @param \EE_Offsite_Gateway $gateway
2741
-     * @return EE_Payment
2742
-     * @throws EE_Error
2743
-     * @throws InvalidArgumentException
2744
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2745
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2746
-     */
2747
-    private function _process_off_site_payment(EE_Offsite_Gateway $gateway)
2748
-    {
2749
-        try {
2750
-            $request_data = \EE_Registry::instance()->REQ->params();
2751
-            // if gateway uses_separate_IPN_request, then we don't have to process the IPN manually
2752
-            $this->set_handle_IPN_in_this_request(
2753
-                $gateway->handle_IPN_in_this_request($request_data, false)
2754
-            );
2755
-            if ($this->handle_IPN_in_this_request()) {
2756
-                // get payment details and process results
2757
-                /** @type EE_Payment_Processor $payment_processor */
2758
-                $payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
2759
-                $payment           = $payment_processor->process_ipn(
2760
-                    $request_data,
2761
-                    $this->checkout->transaction,
2762
-                    $this->checkout->payment_method,
2763
-                    true,
2764
-                    false
2765
-                );
2766
-                //$payment_source = 'process_ipn';
2767
-            } else {
2768
-                $payment = $this->checkout->transaction->last_payment();
2769
-                //$payment_source = 'last_payment';
2770
-            }
2771
-        } catch (Exception $e) {
2772
-            // let's just eat the exception and try to move on using any previously set payment info
2773
-            $payment = $this->checkout->transaction->last_payment();
2774
-            //$payment_source = 'last_payment after Exception';
2775
-            // but if we STILL don't have a payment object
2776
-            if (! $payment instanceof EE_Payment) {
2777
-                // then we'll object ! ( not object like a thing... but object like what a lawyer says ! )
2778
-                $this->_handle_payment_processor_exception($e);
2779
-            }
2780
-        }
2781
-        // DEBUG LOG
2782
-        //$this->checkout->log( __CLASS__, __FUNCTION__, __LINE__,
2783
-        //	array(
2784
-        //		'process_ipn_payment' => $payment,
2785
-        //		'payment_source'      => $payment_source,
2786
-        //	)
2787
-        //);
2788
-        return $payment;
2789
-    }
2790
-
2791
-
2792
-    /**
2793
-     * _process_cancelled_payments
2794
-     * just makes sure that the payment status gets updated correctly
2795
-     * so tha tan error isn't generated during payment validation
2796
-     *
2797
-     * @access private
2798
-     * @param EE_Payment $payment
2799
-     * @return EE_Payment | FALSE
2800
-     * @throws \EE_Error
2801
-     */
2802
-    private function _process_cancelled_payments($payment = null)
2803
-    {
2804
-        if (
2805
-            $payment instanceof EE_Payment
2806
-            && isset($_REQUEST['ee_cancel_payment'])
2807
-            && $payment->status() === EEM_Payment::status_id_failed
2808
-        ) {
2809
-            $payment->set_status(EEM_Payment::status_id_cancelled);
2810
-        }
2811
-        return $payment;
2812
-    }
2813
-
2814
-
2815
-    /**
2816
-     *    get_transaction_details_for_gateways
2817
-     *
2818
-     * @access    public
2819
-     * @return int
2820
-     * @throws EE_Error
2821
-     * @throws InvalidArgumentException
2822
-     * @throws ReflectionException
2823
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2824
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2825
-     */
2826
-    public function get_transaction_details_for_gateways()
2827
-    {
2828
-        $txn_details = array();
2829
-        // ya gotta make a choice man
2830
-        if (empty($this->checkout->selected_method_of_payment)) {
2831
-            $txn_details = array(
2832
-                'error' => esc_html__('Please select a method of payment before proceeding.', 'event_espresso'),
2833
-            );
2834
-        }
2835
-        // get EE_Payment_Method object
2836
-        if (
2837
-            empty($txn_details)
2838
-            &&
2839
-            ! $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment()
2840
-        ) {
2841
-            $txn_details = array(
2842
-                'selected_method_of_payment' => $this->checkout->selected_method_of_payment,
2843
-                'error'                      => esc_html__(
2844
-                    'A valid Payment Method could not be determined.',
2845
-                    'event_espresso'
2846
-                ),
2847
-            );
2848
-        }
2849
-        if (empty($txn_details) && $this->checkout->transaction instanceof EE_Transaction) {
2850
-            $return_url  = $this->_get_return_url($this->checkout->payment_method);
2851
-            $txn_details = array(
2852
-                'TXN_ID'         => $this->checkout->transaction->ID(),
2853
-                'TXN_timestamp'  => $this->checkout->transaction->datetime(),
2854
-                'TXN_total'      => $this->checkout->transaction->total(),
2855
-                'TXN_paid'       => $this->checkout->transaction->paid(),
2856
-                'TXN_reg_steps'  => $this->checkout->transaction->reg_steps(),
2857
-                'STS_ID'         => $this->checkout->transaction->status_ID(),
2858
-                'PMD_ID'         => $this->checkout->transaction->payment_method_ID(),
2859
-                'payment_amount' => $this->checkout->amount_owing,
2860
-                'return_url'     => $return_url,
2861
-                'cancel_url'     => add_query_arg(array('ee_cancel_payment' => true), $return_url),
2862
-                'notify_url'     => EE_Config::instance()->core->txn_page_url(
2863
-                    array(
2864
-                        'e_reg_url_link'    => $this->checkout->transaction->primary_registration()->reg_url_link(),
2865
-                        'ee_payment_method' => $this->checkout->payment_method->slug(),
2866
-                    )
2867
-                ),
2868
-            );
2869
-        }
2870
-        echo wp_json_encode($txn_details);
2871
-        exit();
2872
-    }
2873
-
2874
-
2875
-    /**
2876
-     *    __sleep
2877
-     * to conserve db space, let's remove the reg_form and the EE_Checkout object from EE_SPCO_Reg_Step objects upon
2878
-     * serialization EE_Checkout will handle the reimplementation of itself upon waking, but we won't bother with the
2879
-     * reg form, because if needed, it will be regenerated anyways
2880
-     *
2881
-     * @return array
2882
-     */
2883
-    public function __sleep()
2884
-    {
2885
-        // remove the reg form and the checkout
2886
-        return array_diff(array_keys(get_object_vars($this)), array('reg_form', 'checkout', 'line_item_display'));
2887
-    }
18
+	/**
19
+	 * @access protected
20
+	 * @var EE_Line_Item_Display $Line_Item_Display
21
+	 */
22
+	protected $line_item_display;
23
+
24
+	/**
25
+	 * @access protected
26
+	 * @var boolean $handle_IPN_in_this_request
27
+	 */
28
+	protected $handle_IPN_in_this_request = false;
29
+
30
+
31
+	/**
32
+	 *    set_hooks - for hooking into EE Core, other modules, etc
33
+	 *
34
+	 * @access    public
35
+	 * @return    void
36
+	 */
37
+	public static function set_hooks()
38
+	{
39
+		add_filter(
40
+			'FHEE__SPCO__EE_Line_Item_Filter_Collection',
41
+			array('EE_SPCO_Reg_Step_Payment_Options', 'add_spco_line_item_filters')
42
+		);
43
+		add_action(
44
+			'wp_ajax_switch_spco_billing_form',
45
+			array('EE_SPCO_Reg_Step_Payment_Options', 'switch_spco_billing_form')
46
+		);
47
+		add_action(
48
+			'wp_ajax_nopriv_switch_spco_billing_form',
49
+			array('EE_SPCO_Reg_Step_Payment_Options', 'switch_spco_billing_form')
50
+		);
51
+		add_action('wp_ajax_save_payer_details', array('EE_SPCO_Reg_Step_Payment_Options', 'save_payer_details'));
52
+		add_action(
53
+			'wp_ajax_nopriv_save_payer_details',
54
+			array('EE_SPCO_Reg_Step_Payment_Options', 'save_payer_details')
55
+		);
56
+		add_action(
57
+			'wp_ajax_get_transaction_details_for_gateways',
58
+			array('EE_SPCO_Reg_Step_Payment_Options', 'get_transaction_details')
59
+		);
60
+		add_action(
61
+			'wp_ajax_nopriv_get_transaction_details_for_gateways',
62
+			array('EE_SPCO_Reg_Step_Payment_Options', 'get_transaction_details')
63
+		);
64
+		add_filter(
65
+			'FHEE__EED_Recaptcha___bypass_recaptcha__bypass_request_params_array',
66
+			array('EE_SPCO_Reg_Step_Payment_Options', 'bypass_recaptcha_for_load_payment_method'),
67
+			10,
68
+			1
69
+		);
70
+	}
71
+
72
+
73
+	/**
74
+	 *    ajax switch_spco_billing_form
75
+	 *
76
+	 * @throws \EE_Error
77
+	 */
78
+	public static function switch_spco_billing_form()
79
+	{
80
+		EED_Single_Page_Checkout::process_ajax_request('switch_payment_method');
81
+	}
82
+
83
+
84
+	/**
85
+	 *    ajax save_payer_details
86
+	 *
87
+	 * @throws \EE_Error
88
+	 */
89
+	public static function save_payer_details()
90
+	{
91
+		EED_Single_Page_Checkout::process_ajax_request('save_payer_details_via_ajax');
92
+	}
93
+
94
+
95
+	/**
96
+	 *    ajax get_transaction_details
97
+	 *
98
+	 * @throws \EE_Error
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 \EventEspresso\core\exceptions\InvalidDataTypeException
113
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
114
+	 */
115
+	public static function bypass_recaptcha_for_load_payment_method()
116
+	{
117
+		return array(
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->_slug     = 'payment_options';
134
+		$this->_name     = esc_html__('Payment Options', 'event_espresso');
135
+		$this->_template = SPCO_REG_STEPS_PATH . $this->_slug . DS . 'payment_options_main.template.php';
136
+		$this->checkout  = $checkout;
137
+		$this->_reset_success_message();
138
+		$this->set_instructions(
139
+			esc_html__(
140
+				'Please select a method of payment and provide any necessary billing information before proceeding.',
141
+				'event_espresso'
142
+			)
143
+		);
144
+	}
145
+
146
+
147
+	/**
148
+	 * @return null
149
+	 */
150
+	public function line_item_display()
151
+	{
152
+		return $this->line_item_display;
153
+	}
154
+
155
+
156
+	/**
157
+	 * @param null $line_item_display
158
+	 */
159
+	public function set_line_item_display($line_item_display)
160
+	{
161
+		$this->line_item_display = $line_item_display;
162
+	}
163
+
164
+
165
+	/**
166
+	 * @return boolean
167
+	 */
168
+	public function handle_IPN_in_this_request()
169
+	{
170
+		return $this->handle_IPN_in_this_request;
171
+	}
172
+
173
+
174
+	/**
175
+	 * @param boolean $handle_IPN_in_this_request
176
+	 */
177
+	public function set_handle_IPN_in_this_request($handle_IPN_in_this_request)
178
+	{
179
+		$this->handle_IPN_in_this_request = filter_var($handle_IPN_in_this_request, FILTER_VALIDATE_BOOLEAN);
180
+	}
181
+
182
+
183
+	/**
184
+	 * translate_js_strings
185
+	 *
186
+	 * @return void
187
+	 */
188
+	public function translate_js_strings()
189
+	{
190
+		EE_Registry::$i18n_js_strings['no_payment_method']      = esc_html__(
191
+			'Please select a method of payment in order to continue.',
192
+			'event_espresso'
193
+		);
194
+		EE_Registry::$i18n_js_strings['invalid_payment_method'] = esc_html__(
195
+			'A valid method of payment could not be determined. Please refresh the page and try again.',
196
+			'event_espresso'
197
+		);
198
+		EE_Registry::$i18n_js_strings['forwarding_to_offsite']  = esc_html__(
199
+			'Forwarding to Secure Payment Provider.',
200
+			'event_espresso'
201
+		);
202
+	}
203
+
204
+
205
+	/**
206
+	 * enqueue_styles_and_scripts
207
+	 *
208
+	 * @return void
209
+	 * @throws EE_Error
210
+	 * @throws InvalidArgumentException
211
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
212
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
213
+	 */
214
+	public function enqueue_styles_and_scripts()
215
+	{
216
+		$transaction = $this->checkout->transaction;
217
+		//if the transaction isn't set or nothing is owed on it, don't enqueue any JS
218
+		if (! $transaction instanceof EE_Transaction || EEH_Money::compare_floats($transaction->remaining(), 0)) {
219
+			return;
220
+		}
221
+		foreach (EEM_Payment_Method::instance()->get_all_for_transaction($transaction, EEM_Payment_Method::scope_cart) as $payment_method) {
222
+			$type_obj = $payment_method->type_obj();
223
+			if ($type_obj instanceof EE_PMT_Base) {
224
+				$billing_form = $type_obj->generate_new_billing_form($transaction);
225
+				if ($billing_form instanceof EE_Form_Section_Proper) {
226
+					$billing_form->enqueue_js();
227
+				}
228
+			}
229
+		}
230
+	}
231
+
232
+
233
+	/**
234
+	 * initialize_reg_step
235
+	 *
236
+	 * @return bool
237
+	 * @throws EE_Error
238
+	 * @throws InvalidArgumentException
239
+	 * @throws ReflectionException
240
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
241
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
242
+	 */
243
+	public function initialize_reg_step()
244
+	{
245
+		// TODO: if /when we implement donations, then this will need overriding
246
+		if (// don't need payment options for:
247
+			// 	registrations made via the admin
248
+			// 	completed transactions
249
+			// 	overpaid transactions
250
+			// 	$ 0.00 transactions (no payment required)
251
+			! $this->checkout->payment_required()
252
+			// but do NOT remove if current action being called belongs to this reg step
253
+			&& ! is_callable(array($this, $this->checkout->action))
254
+			&& ! $this->completed()
255
+		) {
256
+			// and if so, then we no longer need the Payment Options step
257
+			if ($this->is_current_step()) {
258
+				$this->checkout->generate_reg_form = false;
259
+			}
260
+			$this->checkout->remove_reg_step($this->_slug);
261
+			// DEBUG LOG
262
+			//$this->checkout->log( __CLASS__, __FUNCTION__, __LINE__ );
263
+			return false;
264
+		}
265
+		// load EEM_Payment_Method
266
+		EE_Registry::instance()->load_model('Payment_Method');
267
+		// get all active payment methods
268
+		$this->checkout->available_payment_methods = EEM_Payment_Method::instance()->get_all_for_transaction(
269
+			$this->checkout->transaction,
270
+			EEM_Payment_Method::scope_cart
271
+		);
272
+		return true;
273
+	}
274
+
275
+
276
+	/**
277
+	 * @return EE_Form_Section_Proper
278
+	 * @throws EE_Error
279
+	 * @throws InvalidArgumentException
280
+	 * @throws ReflectionException
281
+	 * @throws \EventEspresso\core\exceptions\EntityNotFoundException
282
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
283
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
284
+	 * @throws \EventEspresso\core\exceptions\InvalidStatusException
285
+	 */
286
+	public function generate_reg_form()
287
+	{
288
+		// reset in case someone changes their mind
289
+		$this->_reset_selected_method_of_payment();
290
+		// set some defaults
291
+		$this->checkout->selected_method_of_payment = 'payments_closed';
292
+		$registrations_requiring_payment            = array();
293
+		$registrations_for_free_events              = array();
294
+		$registrations_requiring_pre_approval       = array();
295
+		$sold_out_events                            = array();
296
+		$insufficient_spaces_available              = array();
297
+		$no_payment_required                        = true;
298
+		// loop thru registrations to gather info
299
+		$registrations         = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
300
+		$ejected_registrations = EE_SPCO_Reg_Step_Payment_Options::find_registrations_that_lost_their_space(
301
+			$registrations,
302
+			$this->checkout->revisit
303
+		);
304
+		foreach ($registrations as $REG_ID => $registration) {
305
+			/** @var $registration EE_Registration */
306
+			// has this registration lost it's space ?
307
+			if (isset($ejected_registrations[ $REG_ID ])) {
308
+				if ($registration->event()->is_sold_out() || $registration->event()->is_sold_out(true)) {
309
+					$sold_out_events[ $registration->event()->ID() ] = $registration->event();
310
+				} else {
311
+					$insufficient_spaces_available[ $registration->event()->ID() ] = $registration->event();
312
+				}
313
+				continue;
314
+			}
315
+			// event requires admin approval
316
+			if ($registration->status_ID() === EEM_Registration::status_id_not_approved) {
317
+				// add event to list of events with pre-approval reg status
318
+				$registrations_requiring_pre_approval[$REG_ID] = $registration;
319
+				do_action(
320
+					'AHEE__EE_SPCO_Reg_Step_Payment_Options__generate_reg_form__event_requires_pre_approval',
321
+					$registration->event(),
322
+					$this
323
+				);
324
+				continue;
325
+			}
326
+			if ($this->checkout->revisit
327
+				&& $registration->status_ID() !== EEM_Registration::status_id_approved
328
+				&& (
329
+					$registration->event()->is_sold_out()
330
+					|| $registration->event()->is_sold_out(true)
331
+				)
332
+			) {
333
+				// add event to list of events that are sold out
334
+				$sold_out_events[$registration->event()->ID()] = $registration->event();
335
+				do_action(
336
+					'AHEE__EE_SPCO_Reg_Step_Payment_Options__generate_reg_form__sold_out_event',
337
+					$registration->event(),
338
+					$this
339
+				);
340
+				continue;
341
+			}
342
+			// are they allowed to pay now and is there monies owing?
343
+			if ($registration->owes_monies_and_can_pay()) {
344
+				$registrations_requiring_payment[$REG_ID] = $registration;
345
+				do_action(
346
+					'AHEE__EE_SPCO_Reg_Step_Payment_Options__generate_reg_form__event_requires_payment',
347
+					$registration->event(),
348
+					$this
349
+				);
350
+			} elseif (! $this->checkout->revisit
351
+				&& $registration->status_ID() !== EEM_Registration::status_id_not_approved
352
+				&& $registration->ticket()->is_free()
353
+			) {
354
+				$registrations_for_free_events[$registration->event()->ID()] = $registration;
355
+			}
356
+		}
357
+		$subsections = array();
358
+		// now decide which template to load
359
+		if (! empty($sold_out_events)) {
360
+			$subsections['sold_out_events'] = $this->_sold_out_events($sold_out_events);
361
+		}
362
+		if (! empty($insufficient_spaces_available)) {
363
+			$subsections['insufficient_space'] = $this->_insufficient_spaces_available(
364
+				$insufficient_spaces_available
365
+			);
366
+		}
367
+		if (! empty($registrations_requiring_pre_approval)) {
368
+			$subsections['registrations_requiring_pre_approval'] = $this->_registrations_requiring_pre_approval(
369
+				$registrations_requiring_pre_approval
370
+			);
371
+		}
372
+		if (! empty($registrations_for_free_events)) {
373
+			$subsections['no_payment_required'] = $this->_no_payment_required($registrations_for_free_events);
374
+		}
375
+		if (! empty($registrations_requiring_payment)) {
376
+			if ($this->checkout->amount_owing > 0) {
377
+				// autoload Line_Item_Display classes
378
+				EEH_Autoloader::register_line_item_filter_autoloaders();
379
+				$line_item_filter_processor = new EE_Line_Item_Filter_Processor(
380
+					apply_filters(
381
+						'FHEE__SPCO__EE_Line_Item_Filter_Collection',
382
+						new EE_Line_Item_Filter_Collection()
383
+					),
384
+					$this->checkout->cart->get_grand_total()
385
+				);
386
+				/** @var EE_Line_Item $filtered_line_item_tree */
387
+				$filtered_line_item_tree = $line_item_filter_processor->process();
388
+				EEH_Autoloader::register_line_item_display_autoloaders();
389
+				$this->set_line_item_display(new EE_Line_Item_Display('spco'));
390
+				$subsections['payment_options'] = $this->_display_payment_options(
391
+					$this->line_item_display->display_line_item(
392
+						$filtered_line_item_tree,
393
+						array('registrations' => $registrations)
394
+					)
395
+				);
396
+				$this->checkout->amount_owing   = $filtered_line_item_tree->total();
397
+				$this->_apply_registration_payments_to_amount_owing($registrations);
398
+			}
399
+			$no_payment_required = false;
400
+		} else {
401
+			$this->_hide_reg_step_submit_button_if_revisit();
402
+		}
403
+		$this->_save_selected_method_of_payment();
404
+
405
+		$subsections['default_hidden_inputs'] = $this->reg_step_hidden_inputs();
406
+		$subsections['extra_hidden_inputs']   = $this->_extra_hidden_inputs($no_payment_required);
407
+
408
+		return new EE_Form_Section_Proper(
409
+			array(
410
+				'name'            => $this->reg_form_name(),
411
+				'html_id'         => $this->reg_form_name(),
412
+				'subsections'     => $subsections,
413
+				'layout_strategy' => new EE_No_Layout(),
414
+			)
415
+		);
416
+	}
417
+
418
+
419
+	/**
420
+	 * add line item filters required for this reg step
421
+	 * these filters are applied via this line in EE_SPCO_Reg_Step_Payment_Options::set_hooks():
422
+	 *        add_filter( 'FHEE__SPCO__EE_Line_Item_Filter_Collection', array( 'EE_SPCO_Reg_Step_Payment_Options',
423
+	 *        'add_spco_line_item_filters' ) ); so any code that wants to use the same set of filters during the
424
+	 *        payment options reg step, can apply these filters via the following: apply_filters(
425
+	 *        'FHEE__SPCO__EE_Line_Item_Filter_Collection', new EE_Line_Item_Filter_Collection() ) or to an existing
426
+	 *        filter collection by passing that instead of instantiating a new collection
427
+	 *
428
+	 * @param \EE_Line_Item_Filter_Collection $line_item_filter_collection
429
+	 * @return EE_Line_Item_Filter_Collection
430
+	 * @throws EE_Error
431
+	 * @throws InvalidArgumentException
432
+	 * @throws ReflectionException
433
+	 * @throws \EventEspresso\core\exceptions\EntityNotFoundException
434
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
435
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
436
+	 * @throws \EventEspresso\core\exceptions\InvalidStatusException
437
+	 */
438
+	public static function add_spco_line_item_filters(EE_Line_Item_Filter_Collection $line_item_filter_collection)
439
+	{
440
+		if (! EE_Registry::instance()->SSN instanceof EE_Session) {
441
+			return $line_item_filter_collection;
442
+		}
443
+		if (! EE_Registry::instance()->SSN->checkout() instanceof EE_Checkout) {
444
+			return $line_item_filter_collection;
445
+		}
446
+		if (! EE_Registry::instance()->SSN->checkout()->transaction instanceof EE_Transaction) {
447
+			return $line_item_filter_collection;
448
+		}
449
+		$line_item_filter_collection->add(
450
+			new EE_Billable_Line_Item_Filter(
451
+				EE_SPCO_Reg_Step_Payment_Options::remove_ejected_registrations(
452
+					EE_Registry::instance()->SSN->checkout()->transaction->registrations(
453
+						EE_Registry::instance()->SSN->checkout()->reg_cache_where_params
454
+					)
455
+				)
456
+			)
457
+		);
458
+		$line_item_filter_collection->add(new EE_Non_Zero_Line_Item_Filter());
459
+		return $line_item_filter_collection;
460
+	}
461
+
462
+
463
+	/**
464
+	 * remove_ejected_registrations
465
+	 * if a registrant has lost their potential space at an event due to lack of payment,
466
+	 * then this method removes them from the list of registrations being paid for during this request
467
+	 *
468
+	 * @param \EE_Registration[] $registrations
469
+	 * @return EE_Registration[]
470
+	 * @throws EE_Error
471
+	 * @throws InvalidArgumentException
472
+	 * @throws ReflectionException
473
+	 * @throws \EventEspresso\core\exceptions\EntityNotFoundException
474
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
475
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
476
+	 * @throws \EventEspresso\core\exceptions\InvalidStatusException
477
+	 */
478
+	public static function remove_ejected_registrations(array $registrations)
479
+	{
480
+		$ejected_registrations = EE_SPCO_Reg_Step_Payment_Options::find_registrations_that_lost_their_space(
481
+			$registrations,
482
+			EE_Registry::instance()->SSN->checkout()->revisit
483
+		);
484
+		foreach ($registrations as $REG_ID => $registration) {
485
+			// has this registration lost it's space ?
486
+			if (isset($ejected_registrations[$REG_ID])) {
487
+				unset($registrations[$REG_ID]);
488
+				continue;
489
+			}
490
+		}
491
+		return $registrations;
492
+	}
493
+
494
+
495
+	/**
496
+	 * find_registrations_that_lost_their_space
497
+	 * If a registrant chooses an offline payment method like Invoice,
498
+	 * then no space is reserved for them at the event until they fully pay fo that site
499
+	 * (unless the event's default reg status is set to APPROVED)
500
+	 * if a registrant then later returns to pay, but the number of spaces available has been reduced due to sales,
501
+	 * then this method will determine which registrations have lost the ability to complete the reg process.
502
+	 *
503
+	 * @param \EE_Registration[] $registrations
504
+	 * @param bool               $revisit
505
+	 * @return array
506
+	 * @throws EE_Error
507
+	 * @throws InvalidArgumentException
508
+	 * @throws ReflectionException
509
+	 * @throws \EventEspresso\core\exceptions\EntityNotFoundException
510
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
511
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
512
+	 * @throws \EventEspresso\core\exceptions\InvalidStatusException
513
+	 */
514
+	public static function find_registrations_that_lost_their_space(array $registrations, $revisit = false)
515
+	{
516
+		// registrations per event
517
+		$event_reg_count = array();
518
+		// spaces left per event
519
+		$event_spaces_remaining = array();
520
+		// tickets left sorted by ID
521
+		$tickets_remaining = array();
522
+		// registrations that have lost their space
523
+		$ejected_registrations = array();
524
+		foreach ($registrations as $REG_ID => $registration) {
525
+			if ($registration->status_ID() === EEM_Registration::status_id_approved
526
+				|| apply_filters(
527
+					'FHEE__EE_SPCO_Reg_Step_Payment_Options__find_registrations_that_lost_their_space__allow_reg_payment',
528
+					false,
529
+					$registration,
530
+					$revisit
531
+				)
532
+			) {
533
+				continue;
534
+			}
535
+			$EVT_ID = $registration->event_ID();
536
+			$ticket = $registration->ticket();
537
+			if (! isset($tickets_remaining[$ticket->ID()])) {
538
+				$tickets_remaining[$ticket->ID()] = $ticket->remaining();
539
+			}
540
+			if ($tickets_remaining[$ticket->ID()] > 0) {
541
+				if (! isset($event_reg_count[$EVT_ID])) {
542
+					$event_reg_count[$EVT_ID] = 0;
543
+				}
544
+				$event_reg_count[$EVT_ID]++;
545
+				if (! isset($event_spaces_remaining[$EVT_ID])) {
546
+					$event_spaces_remaining[$EVT_ID] = $registration->event()->spaces_remaining_for_sale();
547
+				}
548
+			}
549
+			if ($revisit
550
+				&& ($tickets_remaining[$ticket->ID()] === 0
551
+					|| $event_reg_count[$EVT_ID] > $event_spaces_remaining[$EVT_ID]
552
+				)
553
+			) {
554
+				$ejected_registrations[$REG_ID] = $registration->event();
555
+				if ($registration->status_ID() !== EEM_Registration::status_id_wait_list) {
556
+					/** @type EE_Registration_Processor $registration_processor */
557
+					$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
558
+					// at this point, we should have enough details about the registrant to consider the registration
559
+					// NOT incomplete
560
+					$registration_processor->manually_update_registration_status(
561
+						$registration,
562
+						EEM_Registration::status_id_wait_list
563
+					);
564
+				}
565
+			}
566
+		}
567
+		return $ejected_registrations;
568
+	}
569
+
570
+
571
+	/**
572
+	 * _hide_reg_step_submit_button
573
+	 * removes the html for the reg step submit button
574
+	 * by replacing it with an empty string via filter callback
575
+	 *
576
+	 * @return void
577
+	 */
578
+	protected function _adjust_registration_status_if_event_old_sold()
579
+	{
580
+	}
581
+
582
+
583
+	/**
584
+	 * _hide_reg_step_submit_button
585
+	 * removes the html for the reg step submit button
586
+	 * by replacing it with an empty string via filter callback
587
+	 *
588
+	 * @return void
589
+	 */
590
+	protected function _hide_reg_step_submit_button_if_revisit()
591
+	{
592
+		if ($this->checkout->revisit) {
593
+			add_filter('FHEE__EE_SPCO_Reg_Step__reg_step_submit_button__sbmt_btn_html', '__return_empty_string');
594
+		}
595
+	}
596
+
597
+
598
+	/**
599
+	 * sold_out_events
600
+	 * displays notices regarding events that have sold out since hte registrant first signed up
601
+	 *
602
+	 * @param \EE_Event[] $sold_out_events_array
603
+	 * @return \EE_Form_Section_Proper
604
+	 * @throws \EE_Error
605
+	 */
606
+	private function _sold_out_events($sold_out_events_array = array())
607
+	{
608
+		// set some defaults
609
+		$this->checkout->selected_method_of_payment = 'events_sold_out';
610
+		$sold_out_events                            = '';
611
+		foreach ($sold_out_events_array as $sold_out_event) {
612
+			$sold_out_events .= EEH_HTML::li(
613
+				EEH_HTML::span(
614
+					'  ' . $sold_out_event->name(),
615
+					'',
616
+					'dashicons dashicons-marker ee-icon-size-16 pink-text'
617
+				)
618
+			);
619
+		}
620
+		return new EE_Form_Section_Proper(
621
+			array(
622
+				'layout_strategy' => new EE_Template_Layout(
623
+					array(
624
+						'layout_template_file' => SPCO_REG_STEPS_PATH
625
+												  . $this->_slug
626
+												  . DS
627
+												  . 'sold_out_events.template.php',
628
+						'template_args'        => apply_filters(
629
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___sold_out_events__template_args',
630
+							array(
631
+								'sold_out_events'     => $sold_out_events,
632
+								'sold_out_events_msg' => apply_filters(
633
+									'FHEE__EE_SPCO_Reg_Step_Payment_Options___sold_out_events__sold_out_events_msg',
634
+									sprintf(
635
+										esc_html__(
636
+											'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',
637
+											'event_espresso'
638
+										),
639
+										'<strong>',
640
+										'</strong>',
641
+										'<br />'
642
+									)
643
+								),
644
+							)
645
+						),
646
+					)
647
+				),
648
+			)
649
+		);
650
+	}
651
+
652
+
653
+	/**
654
+	 * _insufficient_spaces_available
655
+	 * displays notices regarding events that do not have enough remaining spaces
656
+	 * to satisfy the current number of registrations looking to pay
657
+	 *
658
+	 * @param \EE_Event[] $insufficient_spaces_events_array
659
+	 * @return \EE_Form_Section_Proper
660
+	 * @throws \EE_Error
661
+	 */
662
+	private function _insufficient_spaces_available($insufficient_spaces_events_array = array())
663
+	{
664
+		// set some defaults
665
+		$this->checkout->selected_method_of_payment = 'invoice';
666
+		$insufficient_space_events                  = '';
667
+		foreach ($insufficient_spaces_events_array as $event) {
668
+			if ($event instanceof EE_Event) {
669
+				$insufficient_space_events .= EEH_HTML::li(
670
+					EEH_HTML::span(' ' . $event->name(), '', 'dashicons dashicons-marker ee-icon-size-16 pink-text')
671
+				);
672
+			}
673
+		}
674
+		return new EE_Form_Section_Proper(
675
+			array(
676
+				'subsections'     => array(
677
+					'default_hidden_inputs' => $this->reg_step_hidden_inputs(),
678
+					'extra_hidden_inputs'   => $this->_extra_hidden_inputs(),
679
+				),
680
+				'layout_strategy' => new EE_Template_Layout(
681
+					array(
682
+						'layout_template_file' => SPCO_REG_STEPS_PATH
683
+												  . $this->_slug
684
+												  . DS
685
+												  . 'sold_out_events.template.php',
686
+						'template_args'        => apply_filters(
687
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___insufficient_spaces_available__template_args',
688
+							array(
689
+								'sold_out_events'     => $insufficient_space_events,
690
+								'sold_out_events_msg' => apply_filters(
691
+									'FHEE__EE_SPCO_Reg_Step_Payment_Options___insufficient_spaces_available__insufficient_space_msg',
692
+									esc_html__(
693
+										'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.',
694
+										'event_espresso'
695
+									)
696
+								),
697
+							)
698
+						),
699
+					)
700
+				),
701
+			)
702
+		);
703
+	}
704
+
705
+
706
+	/**
707
+	 * registrations_requiring_pre_approval
708
+	 *
709
+	 * @param array $registrations_requiring_pre_approval
710
+	 * @return EE_Form_Section_Proper
711
+	 * @throws EE_Error
712
+	 * @throws \EventEspresso\core\exceptions\EntityNotFoundException
713
+	 */
714
+	private function _registrations_requiring_pre_approval($registrations_requiring_pre_approval = array())
715
+	{
716
+		$events_requiring_pre_approval = '';
717
+		foreach ($registrations_requiring_pre_approval as $registration) {
718
+			if ($registration instanceof EE_Registration && $registration->event() instanceof EE_Event) {
719
+				$events_requiring_pre_approval[$registration->event()->ID()] = EEH_HTML::li(
720
+					EEH_HTML::span(
721
+						'',
722
+						'',
723
+						'dashicons dashicons-marker ee-icon-size-16 orange-text'
724
+					)
725
+					. EEH_HTML::span($registration->event()->name(), '', 'orange-text')
726
+				);
727
+			}
728
+		}
729
+		return new EE_Form_Section_Proper(
730
+			array(
731
+				'layout_strategy' => new EE_Template_Layout(
732
+					array(
733
+						'layout_template_file' => SPCO_REG_STEPS_PATH
734
+												  . $this->_slug
735
+												  . DS
736
+												  . 'events_requiring_pre_approval.template.php', // layout_template
737
+						'template_args'        => apply_filters(
738
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___sold_out_events__template_args',
739
+							array(
740
+								'events_requiring_pre_approval'     => implode('', $events_requiring_pre_approval),
741
+								'events_requiring_pre_approval_msg' => apply_filters(
742
+									'FHEE__EE_SPCO_Reg_Step_Payment_Options___events_requiring_pre_approval__events_requiring_pre_approval_msg',
743
+									esc_html__(
744
+										'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.',
745
+										'event_espresso'
746
+									)
747
+								),
748
+							)
749
+						),
750
+					)
751
+				),
752
+			)
753
+		);
754
+	}
755
+
756
+
757
+	/**
758
+	 * _no_payment_required
759
+	 *
760
+	 * @param \EE_Event[] $registrations_for_free_events
761
+	 * @return \EE_Form_Section_Proper
762
+	 * @throws \EE_Error
763
+	 */
764
+	private function _no_payment_required($registrations_for_free_events = array())
765
+	{
766
+		// set some defaults
767
+		$this->checkout->selected_method_of_payment = 'no_payment_required';
768
+		// generate no_payment_required form
769
+		return new EE_Form_Section_Proper(
770
+			array(
771
+				'layout_strategy' => new EE_Template_Layout(
772
+					array(
773
+						'layout_template_file' => SPCO_REG_STEPS_PATH
774
+												  . $this->_slug
775
+												  . DS
776
+												  . 'no_payment_required.template.php', // layout_template
777
+						'template_args'        => apply_filters(
778
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___no_payment_required__template_args',
779
+							array(
780
+								'revisit'                       => $this->checkout->revisit,
781
+								'registrations'                 => array(),
782
+								'ticket_count'                  => array(),
783
+								'registrations_for_free_events' => $registrations_for_free_events,
784
+								'no_payment_required_msg'       => EEH_HTML::p(
785
+									esc_html__('This is a free event, so no billing will occur.', 'event_espresso')
786
+								),
787
+							)
788
+						),
789
+					)
790
+				),
791
+			)
792
+		);
793
+	}
794
+
795
+
796
+	/**
797
+	 * _display_payment_options
798
+	 *
799
+	 * @param string $transaction_details
800
+	 * @return EE_Form_Section_Proper
801
+	 * @throws EE_Error
802
+	 * @throws InvalidArgumentException
803
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
804
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
805
+	 */
806
+	private function _display_payment_options($transaction_details = '')
807
+	{
808
+		// has method_of_payment been set by no-js user?
809
+		$this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment();
810
+		// build payment options form
811
+		return apply_filters(
812
+			'FHEE__EE_SPCO_Reg_Step_Payment_Options___display_payment_options__payment_options_form',
813
+			new EE_Form_Section_Proper(
814
+				array(
815
+					'subsections'     => array(
816
+						'before_payment_options' => apply_filters(
817
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___display_payment_options__before_payment_options',
818
+							new EE_Form_Section_Proper(
819
+								array('layout_strategy' => new EE_Div_Per_Section_Layout())
820
+							)
821
+						),
822
+						'payment_options'        => $this->_setup_payment_options(),
823
+						'after_payment_options'  => apply_filters(
824
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___display_payment_options__after_payment_options',
825
+							new EE_Form_Section_Proper(
826
+								array('layout_strategy' => new EE_Div_Per_Section_Layout())
827
+							)
828
+						),
829
+					),
830
+					'layout_strategy' => new EE_Template_Layout(
831
+						array(
832
+							'layout_template_file' => $this->_template,
833
+							'template_args'        => apply_filters(
834
+								'FHEE__EE_SPCO_Reg_Step_Payment_Options___display_payment_options__template_args',
835
+								array(
836
+									'reg_count'                 => $this->line_item_display->total_items(),
837
+									'transaction_details'       => $transaction_details,
838
+									'available_payment_methods' => array(),
839
+								)
840
+							),
841
+						)
842
+					),
843
+				)
844
+			)
845
+		);
846
+	}
847
+
848
+
849
+	/**
850
+	 * _extra_hidden_inputs
851
+	 *
852
+	 * @param bool $no_payment_required
853
+	 * @return \EE_Form_Section_Proper
854
+	 * @throws \EE_Error
855
+	 */
856
+	private function _extra_hidden_inputs($no_payment_required = true)
857
+	{
858
+		return new EE_Form_Section_Proper(
859
+			array(
860
+				'html_id'         => 'ee-' . $this->slug() . '-extra-hidden-inputs',
861
+				'layout_strategy' => new EE_Div_Per_Section_Layout(),
862
+				'subsections'     => array(
863
+					'spco_no_payment_required' => new EE_Hidden_Input(
864
+						array(
865
+							'normalization_strategy' => new EE_Boolean_Normalization(),
866
+							'html_name'              => 'spco_no_payment_required',
867
+							'html_id'                => 'spco-no-payment-required-payment_options',
868
+							'default'                => $no_payment_required,
869
+						)
870
+					),
871
+					'spco_transaction_id'      => new EE_Fixed_Hidden_Input(
872
+						array(
873
+							'normalization_strategy' => new EE_Int_Normalization(),
874
+							'html_name'              => 'spco_transaction_id',
875
+							'html_id'                => 'spco-transaction-id',
876
+							'default'                => $this->checkout->transaction->ID(),
877
+						)
878
+					),
879
+				),
880
+			)
881
+		);
882
+	}
883
+
884
+
885
+	/**
886
+	 *    _apply_registration_payments_to_amount_owing
887
+	 *
888
+	 * @access protected
889
+	 * @param array $registrations
890
+	 * @throws EE_Error
891
+	 */
892
+	protected function _apply_registration_payments_to_amount_owing(array $registrations)
893
+	{
894
+		$payments = array();
895
+		foreach ($registrations as $registration) {
896
+			if ($registration instanceof EE_Registration && $registration->owes_monies_and_can_pay()) {
897
+				$payments += $registration->registration_payments();
898
+			}
899
+		}
900
+		if (! empty($payments)) {
901
+			foreach ($payments as $payment) {
902
+				if ($payment instanceof EE_Registration_Payment) {
903
+					$this->checkout->amount_owing -= $payment->amount();
904
+				}
905
+			}
906
+		}
907
+	}
908
+
909
+
910
+	/**
911
+	 *    _reset_selected_method_of_payment
912
+	 *
913
+	 * @access    private
914
+	 * @param    bool $force_reset
915
+	 * @return void
916
+	 * @throws InvalidArgumentException
917
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
918
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
919
+	 */
920
+	private function _reset_selected_method_of_payment($force_reset = false)
921
+	{
922
+		$reset_payment_method = $force_reset
923
+			? true
924
+			: sanitize_text_field(EE_Registry::instance()->REQ->get('reset_payment_method', false));
925
+		if ($reset_payment_method) {
926
+			$this->checkout->selected_method_of_payment = null;
927
+			$this->checkout->payment_method             = null;
928
+			$this->checkout->billing_form               = null;
929
+			$this->_save_selected_method_of_payment();
930
+		}
931
+	}
932
+
933
+
934
+	/**
935
+	 * _save_selected_method_of_payment
936
+	 * stores the selected_method_of_payment in the session
937
+	 * so that it's available for all subsequent requests including AJAX
938
+	 *
939
+	 * @access        private
940
+	 * @param string $selected_method_of_payment
941
+	 * @return void
942
+	 * @throws InvalidArgumentException
943
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
944
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
945
+	 */
946
+	private function _save_selected_method_of_payment($selected_method_of_payment = '')
947
+	{
948
+		$selected_method_of_payment = ! empty($selected_method_of_payment)
949
+			? $selected_method_of_payment
950
+			: $this->checkout->selected_method_of_payment;
951
+		EE_Registry::instance()->SSN->set_session_data(
952
+			array('selected_method_of_payment' => $selected_method_of_payment)
953
+		);
954
+	}
955
+
956
+
957
+	/**
958
+	 * _setup_payment_options
959
+	 *
960
+	 * @return EE_Form_Section_Proper
961
+	 * @throws EE_Error
962
+	 * @throws InvalidArgumentException
963
+	 * @throws ReflectionException
964
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
965
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
966
+	 */
967
+	public function _setup_payment_options()
968
+	{
969
+		// load payment method classes
970
+		$this->checkout->available_payment_methods = $this->_get_available_payment_methods();
971
+		if (empty($this->checkout->available_payment_methods)) {
972
+			EE_Error::add_error(
973
+				apply_filters(
974
+					'FHEE__EE_SPCO_Reg_Step_Payment_Options___setup_payment_options__error_message_no_payment_methods',
975
+					sprintf(
976
+						esc_html__(
977
+							'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.',
978
+							'event_espresso'
979
+						),
980
+						'<br>',
981
+						EE_Registry::instance()->CFG->organization->get_pretty('email')
982
+					)
983
+				),
984
+				__FILE__,
985
+				__FUNCTION__,
986
+				__LINE__
987
+			);
988
+		}
989
+		// switch up header depending on number of available payment methods
990
+		$payment_method_header     = count($this->checkout->available_payment_methods) > 1
991
+			? apply_filters(
992
+				'FHEE__registration_page_payment_options__method_of_payment_hdr',
993
+				esc_html__('Please Select Your Method of Payment', 'event_espresso')
994
+			)
995
+			: apply_filters(
996
+				'FHEE__registration_page_payment_options__method_of_payment_hdr',
997
+				esc_html__('Method of Payment', 'event_espresso')
998
+			);
999
+		$available_payment_methods = array(
1000
+			// display the "Payment Method" header
1001
+			'payment_method_header' => new EE_Form_Section_HTML(
1002
+				EEH_HTML::h4($payment_method_header, 'method-of-payment-hdr')
1003
+			),
1004
+		);
1005
+		// the list of actual payment methods ( invoice, paypal, etc ) in a  ( slug => HTML )  format
1006
+		$available_payment_method_options = array();
1007
+		$default_payment_method_option    = array();
1008
+		// additional instructions to be displayed and hidden below payment methods (adding a clearing div to start)
1009
+		$payment_methods_billing_info = array(
1010
+			new EE_Form_Section_HTML(
1011
+				EEH_HTML::div('<br />', '', '', 'clear:both;')
1012
+			),
1013
+		);
1014
+		// loop through payment methods
1015
+		foreach ($this->checkout->available_payment_methods as $payment_method) {
1016
+			if ($payment_method instanceof EE_Payment_Method) {
1017
+				$payment_method_button = EEH_HTML::img(
1018
+					$payment_method->button_url(),
1019
+					$payment_method->name(),
1020
+					'spco-payment-method-' . $payment_method->slug() . '-btn-img',
1021
+					'spco-payment-method-btn-img'
1022
+				);
1023
+				// check if any payment methods are set as default
1024
+				// if payment method is already selected OR nothing is selected and this payment method should be
1025
+				// open_by_default
1026
+				if (($this->checkout->selected_method_of_payment === $payment_method->slug())
1027
+					|| (! $this->checkout->selected_method_of_payment && $payment_method->open_by_default())
1028
+				) {
1029
+					$this->checkout->selected_method_of_payment = $payment_method->slug();
1030
+					$this->_save_selected_method_of_payment();
1031
+					$default_payment_method_option[$payment_method->slug()] = $payment_method_button;
1032
+				} else {
1033
+					$available_payment_method_options[$payment_method->slug()] = $payment_method_button;
1034
+				}
1035
+				$payment_methods_billing_info[$payment_method->slug() . '-info'] = $this->_payment_method_billing_info(
1036
+					$payment_method
1037
+				);
1038
+			}
1039
+		}
1040
+		// prepend available_payment_method_options with default_payment_method_option so that it appears first in list
1041
+		// of PMs
1042
+		$available_payment_method_options = $default_payment_method_option + $available_payment_method_options;
1043
+		// now generate the actual form  inputs
1044
+		$available_payment_methods['available_payment_methods'] = $this->_available_payment_method_inputs(
1045
+			$available_payment_method_options
1046
+		);
1047
+		$available_payment_methods                              += $payment_methods_billing_info;
1048
+		// build the available payment methods form
1049
+		return new EE_Form_Section_Proper(
1050
+			array(
1051
+				'html_id'         => 'spco-available-methods-of-payment-dv',
1052
+				'subsections'     => $available_payment_methods,
1053
+				'layout_strategy' => new EE_Div_Per_Section_Layout(),
1054
+			)
1055
+		);
1056
+	}
1057
+
1058
+
1059
+	/**
1060
+	 * _get_available_payment_methods
1061
+	 *
1062
+	 * @return EE_Payment_Method[]
1063
+	 * @throws EE_Error
1064
+	 * @throws InvalidArgumentException
1065
+	 * @throws ReflectionException
1066
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1067
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1068
+	 */
1069
+	protected function _get_available_payment_methods()
1070
+	{
1071
+		if (! empty($this->checkout->available_payment_methods)) {
1072
+			return $this->checkout->available_payment_methods;
1073
+		}
1074
+		$available_payment_methods = array();
1075
+		// load EEM_Payment_Method
1076
+		EE_Registry::instance()->load_model('Payment_Method');
1077
+		/** @type EEM_Payment_Method $EEM_Payment_Method */
1078
+		$EEM_Payment_Method = EE_Registry::instance()->LIB->EEM_Payment_Method;
1079
+		// get all active payment methods
1080
+		$payment_methods = $EEM_Payment_Method->get_all_for_transaction(
1081
+			$this->checkout->transaction,
1082
+			EEM_Payment_Method::scope_cart
1083
+		);
1084
+		foreach ($payment_methods as $payment_method) {
1085
+			if ($payment_method instanceof EE_Payment_Method) {
1086
+				$available_payment_methods[$payment_method->slug()] = $payment_method;
1087
+			}
1088
+		}
1089
+		return $available_payment_methods;
1090
+	}
1091
+
1092
+
1093
+	/**
1094
+	 *    _available_payment_method_inputs
1095
+	 *
1096
+	 * @access    private
1097
+	 * @param    array $available_payment_method_options
1098
+	 * @return    \EE_Form_Section_Proper
1099
+	 */
1100
+	private function _available_payment_method_inputs($available_payment_method_options = array())
1101
+	{
1102
+		// generate inputs
1103
+		return new EE_Form_Section_Proper(
1104
+			array(
1105
+				'html_id'         => 'ee-available-payment-method-inputs',
1106
+				'layout_strategy' => new EE_Div_Per_Section_Layout(),
1107
+				'subsections'     => array(
1108
+					'' => new EE_Radio_Button_Input(
1109
+						$available_payment_method_options,
1110
+						array(
1111
+							'html_name'          => 'selected_method_of_payment',
1112
+							'html_class'         => 'spco-payment-method',
1113
+							'default'            => $this->checkout->selected_method_of_payment,
1114
+							'label_size'         => 11,
1115
+							'enforce_label_size' => true,
1116
+						)
1117
+					),
1118
+				),
1119
+			)
1120
+		);
1121
+	}
1122
+
1123
+
1124
+	/**
1125
+	 *    _payment_method_billing_info
1126
+	 *
1127
+	 * @access    private
1128
+	 * @param    EE_Payment_Method $payment_method
1129
+	 * @return EE_Form_Section_Proper
1130
+	 * @throws EE_Error
1131
+	 * @throws InvalidArgumentException
1132
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1133
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1134
+	 */
1135
+	private function _payment_method_billing_info(EE_Payment_Method $payment_method)
1136
+	{
1137
+		$currently_selected = $this->checkout->selected_method_of_payment === $payment_method->slug()
1138
+			? true
1139
+			: false;
1140
+		// generate the billing form for payment method
1141
+		$billing_form                 = $currently_selected
1142
+			? $this->_get_billing_form_for_payment_method($payment_method)
1143
+			: new EE_Form_Section_HTML();
1144
+		$this->checkout->billing_form = $currently_selected
1145
+			? $billing_form
1146
+			: $this->checkout->billing_form;
1147
+		// it's all in the details
1148
+		$info_html = EEH_HTML::h3(
1149
+			esc_html__('Important information regarding your payment', 'event_espresso'),
1150
+			'',
1151
+			'spco-payment-method-hdr'
1152
+		);
1153
+		// add some info regarding the step, either from what's saved in the admin,
1154
+		// or a default string depending on whether the PM has a billing form or not
1155
+		if ($payment_method->description()) {
1156
+			$payment_method_info = $payment_method->description();
1157
+		} elseif ($billing_form instanceof EE_Billing_Info_Form) {
1158
+			$payment_method_info = sprintf(
1159
+				esc_html__(
1160
+					'Please provide the following billing information, then click the "%1$s" button below in order to proceed.',
1161
+					'event_espresso'
1162
+				),
1163
+				$this->submit_button_text()
1164
+			);
1165
+		} else {
1166
+			$payment_method_info = sprintf(
1167
+				esc_html__('Please click the "%1$s" button below in order to proceed.', 'event_espresso'),
1168
+				$this->submit_button_text()
1169
+			);
1170
+		}
1171
+		$info_html .= EEH_HTML::p(
1172
+			apply_filters(
1173
+				'FHEE__EE_SPCO_Reg_Step_Payment_Options___payment_method_billing_info__payment_method_info',
1174
+				$payment_method_info
1175
+			),
1176
+			'',
1177
+			'spco-payment-method-desc ee-attention'
1178
+		);
1179
+		return new EE_Form_Section_Proper(
1180
+			array(
1181
+				'html_id'         => 'spco-payment-method-info-' . $payment_method->slug(),
1182
+				'html_class'      => 'spco-payment-method-info-dv',
1183
+				// only display the selected or default PM
1184
+				'html_style'      => $currently_selected ? '' : 'display:none;',
1185
+				'layout_strategy' => new EE_Div_Per_Section_Layout(),
1186
+				'subsections'     => array(
1187
+					'info'         => new EE_Form_Section_HTML($info_html),
1188
+					'billing_form' => $currently_selected ? $billing_form : new EE_Form_Section_HTML(),
1189
+				),
1190
+			)
1191
+		);
1192
+	}
1193
+
1194
+
1195
+	/**
1196
+	 * get_billing_form_html_for_payment_method
1197
+	 *
1198
+	 * @access public
1199
+	 * @return string
1200
+	 * @throws EE_Error
1201
+	 * @throws InvalidArgumentException
1202
+	 * @throws ReflectionException
1203
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1204
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1205
+	 */
1206
+	public function get_billing_form_html_for_payment_method()
1207
+	{
1208
+		// how have they chosen to pay?
1209
+		$this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment(true);
1210
+		$this->checkout->payment_method             = $this->_get_payment_method_for_selected_method_of_payment();
1211
+		if (! $this->checkout->payment_method instanceof EE_Payment_Method) {
1212
+			return false;
1213
+		}
1214
+		if (apply_filters(
1215
+			'FHEE__EE_SPCO_Reg_Step_Payment_Options__registration_checkout__selected_payment_method__display_success',
1216
+			false
1217
+		)) {
1218
+			EE_Error::add_success(
1219
+				apply_filters(
1220
+					'FHEE__Single_Page_Checkout__registration_checkout__selected_payment_method',
1221
+					sprintf(
1222
+						esc_html__(
1223
+							'You have selected "%s" as your method of payment. Please note the important payment information below.',
1224
+							'event_espresso'
1225
+						),
1226
+						$this->checkout->payment_method->name()
1227
+					)
1228
+				)
1229
+			);
1230
+		}
1231
+		// now generate billing form for selected method of payment
1232
+		$payment_method_billing_form = $this->_get_billing_form_for_payment_method($this->checkout->payment_method);
1233
+		// fill form with attendee info if applicable
1234
+		if ($payment_method_billing_form instanceof EE_Billing_Attendee_Info_Form
1235
+			&& $this->checkout->transaction_has_primary_registrant()
1236
+		) {
1237
+			$payment_method_billing_form->populate_from_attendee(
1238
+				$this->checkout->transaction->primary_registration()->attendee()
1239
+			);
1240
+		}
1241
+		// and debug content
1242
+		if ($payment_method_billing_form instanceof EE_Billing_Info_Form
1243
+			&& $this->checkout->payment_method->type_obj() instanceof EE_PMT_Base
1244
+		) {
1245
+			$payment_method_billing_form =
1246
+				$this->checkout->payment_method->type_obj()->apply_billing_form_debug_settings(
1247
+					$payment_method_billing_form
1248
+				);
1249
+		}
1250
+		$billing_info = $payment_method_billing_form instanceof EE_Form_Section_Proper
1251
+			? $payment_method_billing_form->get_html()
1252
+			: '';
1253
+		$this->checkout->json_response->set_return_data(array('payment_method_info' => $billing_info));
1254
+		// localize validation rules for main form
1255
+		$this->checkout->current_step->reg_form->localize_validation_rules();
1256
+		$this->checkout->json_response->add_validation_rules(EE_Form_Section_Proper::js_localization());
1257
+		return true;
1258
+	}
1259
+
1260
+
1261
+	/**
1262
+	 * _get_billing_form_for_payment_method
1263
+	 *
1264
+	 * @access private
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 \EventEspresso\core\exceptions\InvalidDataTypeException
1270
+	 * @throws \EventEspresso\core\exceptions\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
+			array('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
+				&& EE_Registry::instance()->REQ->is_set('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
+	 * @access private
1313
+	 * @param boolean $required whether to throw an error if the "selected_method_of_payment"
1314
+	 *                          is not found in the incoming request
1315
+	 * @param string  $request_param
1316
+	 * @return NULL|string
1317
+	 * @throws EE_Error
1318
+	 * @throws InvalidArgumentException
1319
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1320
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1321
+	 */
1322
+	private function _get_selected_method_of_payment(
1323
+		$required = false,
1324
+		$request_param = 'selected_method_of_payment'
1325
+	) {
1326
+		// is selected_method_of_payment set in the request ?
1327
+		$selected_method_of_payment = EE_Registry::instance()->REQ->get($request_param, false);
1328
+		if ($selected_method_of_payment) {
1329
+			// sanitize it
1330
+			$selected_method_of_payment = is_array($selected_method_of_payment)
1331
+				? array_shift($selected_method_of_payment)
1332
+				: $selected_method_of_payment;
1333
+			$selected_method_of_payment = sanitize_text_field($selected_method_of_payment);
1334
+			// store it in the session so that it's available for all subsequent requests including AJAX
1335
+			$this->_save_selected_method_of_payment($selected_method_of_payment);
1336
+		} else {
1337
+			// or is is set in the session ?
1338
+			$selected_method_of_payment = EE_Registry::instance()->SSN->get_session_data(
1339
+				'selected_method_of_payment'
1340
+			);
1341
+		}
1342
+		// do ya really really gotta have it?
1343
+		if (empty($selected_method_of_payment) && $required) {
1344
+			EE_Error::add_error(
1345
+				sprintf(
1346
+					esc_html__(
1347
+						'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.',
1348
+						'event_espresso'
1349
+					),
1350
+					'<br/>',
1351
+					'<br/>',
1352
+					EE_Registry::instance()->CFG->organization->get_pretty('email')
1353
+				),
1354
+				__FILE__,
1355
+				__FUNCTION__,
1356
+				__LINE__
1357
+			);
1358
+			return null;
1359
+		}
1360
+		return $selected_method_of_payment;
1361
+	}
1362
+
1363
+
1364
+
1365
+
1366
+
1367
+
1368
+	/********************************************************************************************************/
1369
+	/***********************************  SWITCH PAYMENT METHOD  ************************************/
1370
+	/********************************************************************************************************/
1371
+	/**
1372
+	 * switch_payment_method
1373
+	 *
1374
+	 * @access public
1375
+	 * @return string
1376
+	 * @throws EE_Error
1377
+	 * @throws InvalidArgumentException
1378
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1379
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1380
+	 */
1381
+	public function switch_payment_method()
1382
+	{
1383
+		if (! $this->_verify_payment_method_is_set()) {
1384
+			return false;
1385
+		}
1386
+		if (apply_filters(
1387
+			'FHEE__EE_SPCO_Reg_Step_Payment_Options__registration_checkout__selected_payment_method__display_success',
1388
+			false
1389
+		)) {
1390
+			EE_Error::add_success(
1391
+				apply_filters(
1392
+					'FHEE__Single_Page_Checkout__registration_checkout__selected_payment_method',
1393
+					sprintf(
1394
+						esc_html__(
1395
+							'You have selected "%s" as your method of payment. Please note the important payment information below.',
1396
+							'event_espresso'
1397
+						),
1398
+						$this->checkout->payment_method->name()
1399
+					)
1400
+				)
1401
+			);
1402
+		}
1403
+		// generate billing form for selected method of payment if it hasn't been done already
1404
+		if ($this->checkout->payment_method->type_obj()->has_billing_form()) {
1405
+			$this->checkout->billing_form = $this->_get_billing_form_for_payment_method(
1406
+				$this->checkout->payment_method
1407
+			);
1408
+		}
1409
+		// fill form with attendee info if applicable
1410
+		if (apply_filters(
1411
+			'FHEE__populate_billing_form_fields_from_attendee',
1412
+			(
1413
+				$this->checkout->billing_form instanceof EE_Billing_Attendee_Info_Form
1414
+				&& $this->checkout->transaction_has_primary_registrant()
1415
+			),
1416
+			$this->checkout->billing_form,
1417
+			$this->checkout->transaction
1418
+		)
1419
+		) {
1420
+			$this->checkout->billing_form->populate_from_attendee(
1421
+				$this->checkout->transaction->primary_registration()->attendee()
1422
+			);
1423
+		}
1424
+		// and debug content
1425
+		if ($this->checkout->billing_form instanceof EE_Billing_Info_Form
1426
+			&& $this->checkout->payment_method->type_obj() instanceof EE_PMT_Base
1427
+		) {
1428
+			$this->checkout->billing_form =
1429
+				$this->checkout->payment_method->type_obj()->apply_billing_form_debug_settings(
1430
+					$this->checkout->billing_form
1431
+				);
1432
+		}
1433
+		// get html and validation rules for form
1434
+		if ($this->checkout->billing_form instanceof EE_Form_Section_Proper) {
1435
+			$this->checkout->json_response->set_return_data(
1436
+				array('payment_method_info' => $this->checkout->billing_form->get_html())
1437
+			);
1438
+			// localize validation rules for main form
1439
+			$this->checkout->billing_form->localize_validation_rules(true);
1440
+			$this->checkout->json_response->add_validation_rules(EE_Form_Section_Proper::js_localization());
1441
+		} else {
1442
+			$this->checkout->json_response->set_return_data(array('payment_method_info' => ''));
1443
+		}
1444
+		//prevents advancement to next step
1445
+		$this->checkout->continue_reg = false;
1446
+		return true;
1447
+	}
1448
+
1449
+
1450
+	/**
1451
+	 * _verify_payment_method_is_set
1452
+	 *
1453
+	 * @return bool
1454
+	 * @throws EE_Error
1455
+	 * @throws InvalidArgumentException
1456
+	 * @throws ReflectionException
1457
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1458
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1459
+	 */
1460
+	protected function _verify_payment_method_is_set()
1461
+	{
1462
+		// generate billing form for selected method of payment if it hasn't been done already
1463
+		if (empty($this->checkout->selected_method_of_payment)) {
1464
+			// how have they chosen to pay?
1465
+			$this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment(true);
1466
+		} else {
1467
+			// choose your own adventure based on method_of_payment
1468
+			switch ($this->checkout->selected_method_of_payment) {
1469
+				case 'events_sold_out' :
1470
+					EE_Error::add_attention(
1471
+						apply_filters(
1472
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___verify_payment_method_is_set__sold_out_events_msg',
1473
+							esc_html__(
1474
+								'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.',
1475
+								'event_espresso'
1476
+							)
1477
+						),
1478
+						__FILE__, __FUNCTION__, __LINE__
1479
+					);
1480
+					return false;
1481
+					break;
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__, __FUNCTION__, __LINE__
1492
+					);
1493
+					return false;
1494
+					break;
1495
+				case 'no_payment_required' :
1496
+					EE_Error::add_attention(
1497
+						apply_filters(
1498
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___verify_payment_method_is_set__no_payment_required_msg',
1499
+							esc_html__(
1500
+								'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.',
1501
+								'event_espresso'
1502
+							)
1503
+						),
1504
+						__FILE__, __FUNCTION__, __LINE__
1505
+					);
1506
+					return false;
1507
+					break;
1508
+				default:
1509
+			}
1510
+		}
1511
+		// verify payment method
1512
+		if (! $this->checkout->payment_method instanceof EE_Payment_Method) {
1513
+			// get payment method for selected method of payment
1514
+			$this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment();
1515
+		}
1516
+		return $this->checkout->payment_method instanceof EE_Payment_Method ? true : false;
1517
+	}
1518
+
1519
+
1520
+
1521
+	/********************************************************************************************************/
1522
+	/***************************************  SAVE PAYER DETAILS  ****************************************/
1523
+	/********************************************************************************************************/
1524
+	/**
1525
+	 * save_payer_details_via_ajax
1526
+	 *
1527
+	 * @return void
1528
+	 * @throws EE_Error
1529
+	 * @throws InvalidArgumentException
1530
+	 * @throws ReflectionException
1531
+	 * @throws RuntimeException
1532
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1533
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1534
+	 */
1535
+	public function save_payer_details_via_ajax()
1536
+	{
1537
+		if (! $this->_verify_payment_method_is_set()) {
1538
+			return;
1539
+		}
1540
+		// generate billing form for selected method of payment if it hasn't been done already
1541
+		if ($this->checkout->payment_method->type_obj()->has_billing_form()) {
1542
+			$this->checkout->billing_form = $this->_get_billing_form_for_payment_method(
1543
+				$this->checkout->payment_method
1544
+			);
1545
+		}
1546
+		// generate primary attendee from payer info if applicable
1547
+		if (! $this->checkout->transaction_has_primary_registrant()) {
1548
+			$attendee = $this->_create_attendee_from_request_data();
1549
+			if ($attendee instanceof EE_Attendee) {
1550
+				foreach ($this->checkout->transaction->registrations() as $registration) {
1551
+					if ($registration->is_primary_registrant()) {
1552
+						$this->checkout->primary_attendee_obj = $attendee;
1553
+						$registration->_add_relation_to($attendee, 'Attendee');
1554
+						$registration->set_attendee_id($attendee->ID());
1555
+						$registration->update_cache_after_object_save('Attendee', $attendee);
1556
+					}
1557
+				}
1558
+			}
1559
+		}
1560
+	}
1561
+
1562
+
1563
+	/**
1564
+	 * create_attendee_from_request_data
1565
+	 * uses info from alternate GET or POST data (such as AJAX) to create a new attendee
1566
+	 *
1567
+	 * @return EE_Attendee
1568
+	 * @throws EE_Error
1569
+	 * @throws InvalidArgumentException
1570
+	 * @throws ReflectionException
1571
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1572
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1573
+	 */
1574
+	protected function _create_attendee_from_request_data()
1575
+	{
1576
+		// get State ID
1577
+		$STA_ID = ! empty($_REQUEST['state']) ? sanitize_text_field($_REQUEST['state']) : '';
1578
+		if (! empty($STA_ID)) {
1579
+			// can we get state object from name ?
1580
+			EE_Registry::instance()->load_model('State');
1581
+			$state  = EEM_State::instance()->get_col(array(array('STA_name' => $STA_ID), 'limit' => 1), 'STA_ID');
1582
+			$STA_ID = is_array($state) && ! empty($state) ? reset($state) : $STA_ID;
1583
+		}
1584
+		// get Country ISO
1585
+		$CNT_ISO = ! empty($_REQUEST['country']) ? sanitize_text_field($_REQUEST['country']) : '';
1586
+		if (! empty($CNT_ISO)) {
1587
+			// can we get country object from name ?
1588
+			EE_Registry::instance()->load_model('Country');
1589
+			$country = EEM_Country::instance()->get_col(
1590
+				array(array('CNT_name' => $CNT_ISO), 'limit' => 1),
1591
+				'CNT_ISO'
1592
+			);
1593
+			$CNT_ISO = is_array($country) && ! empty($country) ? reset($country) : $CNT_ISO;
1594
+		}
1595
+		// grab attendee data
1596
+		$attendee_data = array(
1597
+			'ATT_fname'    => ! empty($_REQUEST['first_name']) ? sanitize_text_field($_REQUEST['first_name']) : '',
1598
+			'ATT_lname'    => ! empty($_REQUEST['last_name']) ? sanitize_text_field($_REQUEST['last_name']) : '',
1599
+			'ATT_email'    => ! empty($_REQUEST['email']) ? sanitize_email($_REQUEST['email']) : '',
1600
+			'ATT_address'  => ! empty($_REQUEST['address']) ? sanitize_text_field($_REQUEST['address']) : '',
1601
+			'ATT_address2' => ! empty($_REQUEST['address2']) ? sanitize_text_field($_REQUEST['address2']) : '',
1602
+			'ATT_city'     => ! empty($_REQUEST['city']) ? sanitize_text_field($_REQUEST['city']) : '',
1603
+			'STA_ID'       => $STA_ID,
1604
+			'CNT_ISO'      => $CNT_ISO,
1605
+			'ATT_zip'      => ! empty($_REQUEST['zip']) ? sanitize_text_field($_REQUEST['zip']) : '',
1606
+			'ATT_phone'    => ! empty($_REQUEST['phone']) ? sanitize_text_field($_REQUEST['phone']) : '',
1607
+		);
1608
+		// validate the email address since it is the most important piece of info
1609
+		if (empty($attendee_data['ATT_email']) || $attendee_data['ATT_email'] !== $_REQUEST['email']) {
1610
+			EE_Error::add_error(
1611
+				esc_html__('An invalid email address was submitted.', 'event_espresso'),
1612
+				__FILE__,
1613
+				__FUNCTION__,
1614
+				__LINE__
1615
+			);
1616
+		}
1617
+		// does this attendee already exist in the db ? we're searching using a combination of first name, last name,
1618
+		// AND email address
1619
+		if (! empty($attendee_data['ATT_fname'])
1620
+			&& ! empty($attendee_data['ATT_lname'])
1621
+			&& ! empty($attendee_data['ATT_email'])
1622
+		) {
1623
+			$existing_attendee = EE_Registry::instance()->LIB->EEM_Attendee->find_existing_attendee(
1624
+				array(
1625
+					'ATT_fname' => $attendee_data['ATT_fname'],
1626
+					'ATT_lname' => $attendee_data['ATT_lname'],
1627
+					'ATT_email' => $attendee_data['ATT_email'],
1628
+				)
1629
+			);
1630
+			if ($existing_attendee instanceof EE_Attendee) {
1631
+				return $existing_attendee;
1632
+			}
1633
+		}
1634
+		// no existing attendee? kk let's create a new one
1635
+		// kinda lame, but we need a first and last name to create an attendee, so use the email address if those
1636
+		// don't exist
1637
+		$attendee_data['ATT_fname'] = ! empty($attendee_data['ATT_fname'])
1638
+			? $attendee_data['ATT_fname']
1639
+			: $attendee_data['ATT_email'];
1640
+		$attendee_data['ATT_lname'] = ! empty($attendee_data['ATT_lname'])
1641
+			? $attendee_data['ATT_lname']
1642
+			: $attendee_data['ATT_email'];
1643
+		return EE_Attendee::new_instance($attendee_data);
1644
+	}
1645
+
1646
+
1647
+
1648
+	/********************************************************************************************************/
1649
+	/****************************************  PROCESS REG STEP  *****************************************/
1650
+	/********************************************************************************************************/
1651
+	/**
1652
+	 * process_reg_step
1653
+	 *
1654
+	 * @return bool
1655
+	 * @throws EE_Error
1656
+	 * @throws InvalidArgumentException
1657
+	 * @throws ReflectionException
1658
+	 * @throws \EventEspresso\core\exceptions\EntityNotFoundException
1659
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1660
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1661
+	 * @throws \EventEspresso\core\exceptions\InvalidStatusException
1662
+	 */
1663
+	public function process_reg_step()
1664
+	{
1665
+		// how have they chosen to pay?
1666
+		$this->checkout->selected_method_of_payment = $this->checkout->transaction->is_free()
1667
+			? 'no_payment_required'
1668
+			: $this->_get_selected_method_of_payment(true);
1669
+		// choose your own adventure based on method_of_payment
1670
+		switch ($this->checkout->selected_method_of_payment) {
1671
+
1672
+			case 'events_sold_out' :
1673
+				$this->checkout->redirect     = true;
1674
+				$this->checkout->redirect_url = $this->checkout->cancel_page_url;
1675
+				$this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
1676
+				// mark this reg step as completed
1677
+				$this->set_completed();
1678
+				return false;
1679
+				break;
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
+				break;
1697
+
1698
+			case 'no_payment_required' :
1699
+				if (apply_filters(
1700
+					'FHEE__EE_SPCO_Reg_Step_Payment_Options__process_reg_step__no_payment_required__display_success',
1701
+					false
1702
+				)) {
1703
+					EE_Error::add_success(
1704
+						esc_html__('no payment required.', 'event_espresso'),
1705
+						__FILE__,
1706
+						__FUNCTION__,
1707
+						__LINE__
1708
+					);
1709
+				}
1710
+				// mark this reg step as completed
1711
+				$this->set_completed();
1712
+				return true;
1713
+				break;
1714
+
1715
+			default:
1716
+				$registrations         = EE_Registry::instance()->SSN->checkout()->transaction->registrations(
1717
+					EE_Registry::instance()->SSN->checkout()->reg_cache_where_params
1718
+				);
1719
+				$ejected_registrations = EE_SPCO_Reg_Step_Payment_Options::find_registrations_that_lost_their_space(
1720
+					$registrations,
1721
+					EE_Registry::instance()->SSN->checkout()->revisit
1722
+				);
1723
+				// calculate difference between the two arrays
1724
+				$registrations = array_diff($registrations, $ejected_registrations);
1725
+				if (empty($registrations)) {
1726
+					$this->_redirect_because_event_sold_out();
1727
+					return false;
1728
+				}
1729
+				$payment_successful = $this->_process_payment();
1730
+				if ($payment_successful) {
1731
+					$this->checkout->continue_reg = true;
1732
+					$this->_maybe_set_completed($this->checkout->payment_method);
1733
+				} else {
1734
+					$this->checkout->continue_reg = false;
1735
+				}
1736
+				return $payment_successful;
1737
+		}
1738
+	}
1739
+
1740
+
1741
+	/**
1742
+	 * _redirect_because_event_sold_out
1743
+	 *
1744
+	 * @access protected
1745
+	 * @return void
1746
+	 */
1747
+	protected function _redirect_because_event_sold_out()
1748
+	{
1749
+		$this->checkout->continue_reg = false;
1750
+		// set redirect URL
1751
+		$this->checkout->redirect_url = add_query_arg(
1752
+			array('e_reg_url_link' => $this->checkout->reg_url_link),
1753
+			$this->checkout->current_step->reg_step_url()
1754
+		);
1755
+		$this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
1756
+	}
1757
+
1758
+
1759
+	/**
1760
+	 * _maybe_set_completed
1761
+	 *
1762
+	 * @access protected
1763
+	 * @param \EE_Payment_Method $payment_method
1764
+	 * @return void
1765
+	 * @throws \EE_Error
1766
+	 */
1767
+	protected function _maybe_set_completed(EE_Payment_Method $payment_method)
1768
+	{
1769
+		switch ($payment_method->type_obj()->payment_occurs()) {
1770
+			case EE_PMT_Base::offsite :
1771
+				break;
1772
+			case EE_PMT_Base::onsite :
1773
+			case EE_PMT_Base::offline :
1774
+				// mark this reg step as completed
1775
+				$this->set_completed();
1776
+				break;
1777
+		}
1778
+	}
1779
+
1780
+
1781
+	/**
1782
+	 *    update_reg_step
1783
+	 *    this is the final step after a user  revisits the site to retry a payment
1784
+	 *
1785
+	 * @return bool
1786
+	 * @throws EE_Error
1787
+	 * @throws InvalidArgumentException
1788
+	 * @throws ReflectionException
1789
+	 * @throws \EventEspresso\core\exceptions\EntityNotFoundException
1790
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1791
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1792
+	 * @throws \EventEspresso\core\exceptions\InvalidStatusException
1793
+	 */
1794
+	public function update_reg_step()
1795
+	{
1796
+		$success = true;
1797
+		// if payment required
1798
+		if ($this->checkout->transaction->total() > 0) {
1799
+			do_action(
1800
+				'AHEE__EE_Single_Page_Checkout__process_finalize_registration__before_gateway',
1801
+				$this->checkout->transaction
1802
+			);
1803
+			// attempt payment via payment method
1804
+			$success = $this->process_reg_step();
1805
+		}
1806
+		if ($success && ! $this->checkout->redirect) {
1807
+			$this->checkout->cart->get_grand_total()->save_this_and_descendants_to_txn(
1808
+				$this->checkout->transaction->ID()
1809
+			);
1810
+			// set return URL
1811
+			$this->checkout->redirect_url = add_query_arg(
1812
+				array('e_reg_url_link' => $this->checkout->reg_url_link),
1813
+				$this->checkout->thank_you_page_url
1814
+			);
1815
+		}
1816
+		return $success;
1817
+	}
1818
+
1819
+
1820
+	/**
1821
+	 *    _process_payment
1822
+	 *
1823
+	 * @access private
1824
+	 * @return bool
1825
+	 * @throws EE_Error
1826
+	 * @throws InvalidArgumentException
1827
+	 * @throws ReflectionException
1828
+	 * @throws RuntimeException
1829
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1830
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1831
+	 */
1832
+	private function _process_payment()
1833
+	{
1834
+		// basically confirm that the event hasn't sold out since they hit the page
1835
+		if (! $this->_last_second_ticket_verifications()) {
1836
+			return false;
1837
+		}
1838
+		// ya gotta make a choice man
1839
+		if (empty($this->checkout->selected_method_of_payment)) {
1840
+			$this->checkout->json_response->set_plz_select_method_of_payment(
1841
+				esc_html__('Please select a method of payment before proceeding.', 'event_espresso')
1842
+			);
1843
+			return false;
1844
+		}
1845
+		// get EE_Payment_Method object
1846
+		if (! $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment()) {
1847
+			return false;
1848
+		}
1849
+		// setup billing form
1850
+		if ($this->checkout->payment_method->is_on_site()) {
1851
+			$this->checkout->billing_form = $this->_get_billing_form_for_payment_method(
1852
+				$this->checkout->payment_method
1853
+			);
1854
+			// bad billing form ?
1855
+			if (! $this->_billing_form_is_valid()) {
1856
+				return false;
1857
+			}
1858
+		}
1859
+		// ensure primary registrant has been fully processed
1860
+		if (! $this->_setup_primary_registrant_prior_to_payment()) {
1861
+			return false;
1862
+		}
1863
+		// if session is close to expiring (under 10 minutes by default)
1864
+		if ((time() - EE_Registry::instance()->SSN->expiration()) < EE_Registry::instance()->SSN->extension()) {
1865
+			// add some time to session expiration so that payment can be completed
1866
+			EE_Registry::instance()->SSN->extend_expiration();
1867
+		}
1868
+		/** @type EE_Transaction_Processor $transaction_processor */
1869
+		//$transaction_processor = EE_Registry::instance()->load_class( 'Transaction_Processor' );
1870
+		// in case a registrant leaves to an Off-Site Gateway and never returns, we want to approve any registrations
1871
+		// for events with a default reg status of Approved
1872
+		// $transaction_processor->toggle_registration_statuses_for_default_approved_events(
1873
+		//      $this->checkout->transaction, $this->checkout->reg_cache_where_params
1874
+		// );
1875
+		// attempt payment
1876
+		$payment = $this->_attempt_payment($this->checkout->payment_method);
1877
+		// process results
1878
+		$payment = $this->_validate_payment($payment);
1879
+		$payment = $this->_post_payment_processing($payment);
1880
+		// verify payment
1881
+		if ($payment instanceof EE_Payment) {
1882
+			// store that for later
1883
+			$this->checkout->payment = $payment;
1884
+			// we can also consider the TXN to not have been failed, so temporarily upgrade it's status to abandoned
1885
+			$this->checkout->transaction->toggle_failed_transaction_status();
1886
+			$payment_status = $payment->status();
1887
+			if (
1888
+				$payment_status === EEM_Payment::status_id_approved
1889
+				|| $payment_status === EEM_Payment::status_id_pending
1890
+			) {
1891
+				return true;
1892
+			} else {
1893
+				return false;
1894
+			}
1895
+		} else if ($payment === true) {
1896
+			// please note that offline payment methods will NOT make a payment,
1897
+			// but instead just mark themselves as the PMD_ID on the transaction, and return true
1898
+			$this->checkout->payment = $payment;
1899
+			return true;
1900
+		}
1901
+		// where's my money?
1902
+		return false;
1903
+	}
1904
+
1905
+
1906
+	/**
1907
+	 * _last_second_ticket_verifications
1908
+	 *
1909
+	 * @access public
1910
+	 * @return bool
1911
+	 * @throws EE_Error
1912
+	 */
1913
+	protected function _last_second_ticket_verifications()
1914
+	{
1915
+		// don't bother re-validating if not a return visit
1916
+		if (! $this->checkout->revisit) {
1917
+			return true;
1918
+		}
1919
+		$registrations = $this->checkout->transaction->registrations();
1920
+		if (empty($registrations)) {
1921
+			return false;
1922
+		}
1923
+		foreach ($registrations as $registration) {
1924
+			if ($registration instanceof EE_Registration && ! $registration->is_approved()) {
1925
+				$event = $registration->event_obj();
1926
+				if ($event instanceof EE_Event && $event->is_sold_out(true)) {
1927
+					EE_Error::add_error(
1928
+						apply_filters(
1929
+							'FHEE__EE_SPCO_Reg_Step_Payment_Options___last_second_ticket_verifications__sold_out_events_msg',
1930
+							sprintf(
1931
+								esc_html__(
1932
+									'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.',
1933
+									'event_espresso'
1934
+								),
1935
+								$event->name()
1936
+							)
1937
+						),
1938
+						__FILE__,
1939
+						__FUNCTION__,
1940
+						__LINE__
1941
+					);
1942
+					return false;
1943
+				}
1944
+			}
1945
+		}
1946
+		return true;
1947
+	}
1948
+
1949
+
1950
+	/**
1951
+	 * redirect_form
1952
+	 *
1953
+	 * @access public
1954
+	 * @return bool
1955
+	 * @throws EE_Error
1956
+	 * @throws InvalidArgumentException
1957
+	 * @throws ReflectionException
1958
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
1959
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
1960
+	 */
1961
+	public function redirect_form()
1962
+	{
1963
+		$payment_method_billing_info = $this->_payment_method_billing_info(
1964
+			$this->_get_payment_method_for_selected_method_of_payment()
1965
+		);
1966
+		$html                        = $payment_method_billing_info->get_html();
1967
+		$html                        .= $this->checkout->redirect_form;
1968
+		EE_Registry::instance()->REQ->add_output($html);
1969
+		return true;
1970
+	}
1971
+
1972
+
1973
+	/**
1974
+	 * _billing_form_is_valid
1975
+	 *
1976
+	 * @access private
1977
+	 * @return bool
1978
+	 * @throws \EE_Error
1979
+	 */
1980
+	private function _billing_form_is_valid()
1981
+	{
1982
+		if (! $this->checkout->payment_method->type_obj()->has_billing_form()) {
1983
+			return true;
1984
+		}
1985
+		if ($this->checkout->billing_form instanceof EE_Billing_Info_Form) {
1986
+			if ($this->checkout->billing_form->was_submitted()) {
1987
+				$this->checkout->billing_form->receive_form_submission();
1988
+				if ($this->checkout->billing_form->is_valid()) {
1989
+					return true;
1990
+				}
1991
+				$validation_errors = $this->checkout->billing_form->get_validation_errors_accumulated();
1992
+				$error_strings     = array();
1993
+				foreach ($validation_errors as $validation_error) {
1994
+					if ($validation_error instanceof EE_Validation_Error) {
1995
+						$form_section = $validation_error->get_form_section();
1996
+						if ($form_section instanceof EE_Form_Input_Base) {
1997
+							$label = $form_section->html_label_text();
1998
+						} elseif ($form_section instanceof EE_Form_Section_Base) {
1999
+							$label = $form_section->name();
2000
+						} else {
2001
+							$label = esc_html__('Validation Error', 'event_espresso');
2002
+						}
2003
+						$error_strings[] = sprintf('%1$s: %2$s', $label, $validation_error->getMessage());
2004
+					}
2005
+				}
2006
+				EE_Error::add_error(
2007
+					sprintf(
2008
+						esc_html__(
2009
+							'One or more billing form inputs are invalid and require correction before proceeding. %1$s %2$s',
2010
+							'event_espresso'
2011
+						),
2012
+						'<br/>',
2013
+						implode('<br/>', $error_strings)
2014
+					),
2015
+					__FILE__,
2016
+					__FUNCTION__,
2017
+					__LINE__
2018
+				);
2019
+			} else {
2020
+				EE_Error::add_error(
2021
+					esc_html__(
2022
+						'The billing form was not submitted or something prevented it\'s submission.',
2023
+						'event_espresso'
2024
+					),
2025
+					__FILE__,
2026
+					__FUNCTION__,
2027
+					__LINE__
2028
+				);
2029
+			}
2030
+		} else {
2031
+			EE_Error::add_error(
2032
+				esc_html__('The submitted billing form is invalid possibly due to a technical reason.', 'event_espresso'),
2033
+				__FILE__,
2034
+				__FUNCTION__,
2035
+				__LINE__
2036
+			);
2037
+		}
2038
+		return false;
2039
+	}
2040
+
2041
+
2042
+	/**
2043
+	 * _setup_primary_registrant_prior_to_payment
2044
+	 * ensures that the primary registrant has a valid attendee object created with the critical details populated
2045
+	 * (first & last name & email) and that both the transaction object and primary registration object have been saved
2046
+	 * plz note that any other registrations will NOT be saved at this point (because they may not have any details
2047
+	 * yet)
2048
+	 *
2049
+	 * @access private
2050
+	 * @return bool
2051
+	 * @throws EE_Error
2052
+	 * @throws InvalidArgumentException
2053
+	 * @throws ReflectionException
2054
+	 * @throws RuntimeException
2055
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2056
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2057
+	 */
2058
+	private function _setup_primary_registrant_prior_to_payment()
2059
+	{
2060
+		// check if transaction has a primary registrant and that it has a related Attendee object
2061
+		// if not, then we need to at least gather some primary registrant data before attempting payment
2062
+		if (
2063
+			$this->checkout->billing_form instanceof EE_Billing_Attendee_Info_Form
2064
+			&& ! $this->checkout->transaction_has_primary_registrant()
2065
+			&& ! $this->_capture_primary_registration_data_from_billing_form()
2066
+		) {
2067
+			return false;
2068
+		}
2069
+		// because saving an object clears it's cache, we need to do the chevy shuffle
2070
+		// grab the primary_registration object
2071
+		$primary_registration = $this->checkout->transaction->primary_registration();
2072
+		// at this point we'll consider a TXN to not have been failed
2073
+		$this->checkout->transaction->toggle_failed_transaction_status();
2074
+		// save the TXN ( which clears cached copy of primary_registration)
2075
+		$this->checkout->transaction->save();
2076
+		// grab TXN ID and save it to the primary_registration
2077
+		$primary_registration->set_transaction_id($this->checkout->transaction->ID());
2078
+		// save what we have so far
2079
+		$primary_registration->save();
2080
+		return true;
2081
+	}
2082
+
2083
+
2084
+	/**
2085
+	 * _capture_primary_registration_data_from_billing_form
2086
+	 *
2087
+	 * @access private
2088
+	 * @return bool
2089
+	 * @throws EE_Error
2090
+	 * @throws InvalidArgumentException
2091
+	 * @throws ReflectionException
2092
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2093
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2094
+	 */
2095
+	private function _capture_primary_registration_data_from_billing_form()
2096
+	{
2097
+		// convert billing form data into an attendee
2098
+		$this->checkout->primary_attendee_obj = $this->checkout->billing_form->create_attendee_from_billing_form_data();
2099
+		if (! $this->checkout->primary_attendee_obj instanceof EE_Attendee) {
2100
+			EE_Error::add_error(
2101
+				sprintf(
2102
+					esc_html__(
2103
+						'The billing form details could not be used for attendee details due to a technical issue.%sPlease try again or contact %s for assistance.',
2104
+						'event_espresso'
2105
+					),
2106
+					'<br/>',
2107
+					EE_Registry::instance()->CFG->organization->get_pretty('email')
2108
+				),
2109
+				__FILE__,
2110
+				__FUNCTION__,
2111
+				__LINE__
2112
+			);
2113
+			return false;
2114
+		}
2115
+		$primary_registration = $this->checkout->transaction->primary_registration();
2116
+		if (! $primary_registration instanceof EE_Registration) {
2117
+			EE_Error::add_error(
2118
+				sprintf(
2119
+					esc_html__(
2120
+						'The primary registrant for this transaction could not be determined due to a technical issue.%sPlease try again or contact %s for assistance.',
2121
+						'event_espresso'
2122
+					),
2123
+					'<br/>',
2124
+					EE_Registry::instance()->CFG->organization->get_pretty('email')
2125
+				),
2126
+				__FILE__,
2127
+				__FUNCTION__,
2128
+				__LINE__
2129
+			);
2130
+			return false;
2131
+		}
2132
+		if (! $primary_registration->_add_relation_to($this->checkout->primary_attendee_obj, 'Attendee')
2133
+			  instanceof
2134
+			  EE_Attendee
2135
+		) {
2136
+			EE_Error::add_error(
2137
+				sprintf(
2138
+					esc_html__(
2139
+						'The primary registrant could not be associated with this transaction due to a technical issue.%sPlease try again or contact %s for assistance.',
2140
+						'event_espresso'
2141
+					),
2142
+					'<br/>',
2143
+					EE_Registry::instance()->CFG->organization->get_pretty('email')
2144
+				),
2145
+				__FILE__,
2146
+				__FUNCTION__,
2147
+				__LINE__
2148
+			);
2149
+			return false;
2150
+		}
2151
+		/** @type EE_Registration_Processor $registration_processor */
2152
+		$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
2153
+		// at this point, we should have enough details about the registrant to consider the registration NOT incomplete
2154
+		$registration_processor->toggle_incomplete_registration_status_to_default($primary_registration);
2155
+		return true;
2156
+	}
2157
+
2158
+
2159
+	/**
2160
+	 * _get_payment_method_for_selected_method_of_payment
2161
+	 * retrieves a valid payment method
2162
+	 *
2163
+	 * @access public
2164
+	 * @return EE_Payment_Method
2165
+	 * @throws EE_Error
2166
+	 * @throws InvalidArgumentException
2167
+	 * @throws ReflectionException
2168
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2169
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2170
+	 */
2171
+	private function _get_payment_method_for_selected_method_of_payment()
2172
+	{
2173
+		if ($this->checkout->selected_method_of_payment === 'events_sold_out') {
2174
+			$this->_redirect_because_event_sold_out();
2175
+			return null;
2176
+		}
2177
+		// get EE_Payment_Method object
2178
+		if (isset($this->checkout->available_payment_methods[$this->checkout->selected_method_of_payment])) {
2179
+			$payment_method = $this->checkout->available_payment_methods[$this->checkout->selected_method_of_payment];
2180
+		} else {
2181
+			// load EEM_Payment_Method
2182
+			EE_Registry::instance()->load_model('Payment_Method');
2183
+			/** @type EEM_Payment_Method $EEM_Payment_Method */
2184
+			$EEM_Payment_Method = EE_Registry::instance()->LIB->EEM_Payment_Method;
2185
+			$payment_method     = $EEM_Payment_Method->get_one_by_slug($this->checkout->selected_method_of_payment);
2186
+		}
2187
+		// verify $payment_method
2188
+		if (! $payment_method instanceof EE_Payment_Method) {
2189
+			// not a payment
2190
+			EE_Error::add_error(
2191
+				sprintf(
2192
+					esc_html__(
2193
+						'The selected method of payment could not be determined due to a technical issue.%sPlease try again or contact %s for assistance.',
2194
+						'event_espresso'
2195
+					),
2196
+					'<br/>',
2197
+					EE_Registry::instance()->CFG->organization->get_pretty('email')
2198
+				),
2199
+				__FILE__,
2200
+				__FUNCTION__,
2201
+				__LINE__
2202
+			);
2203
+			return null;
2204
+		}
2205
+		// and verify it has a valid Payment_Method Type object
2206
+		if (! $payment_method->type_obj() instanceof EE_PMT_Base) {
2207
+			// not a payment
2208
+			EE_Error::add_error(
2209
+				sprintf(
2210
+					esc_html__(
2211
+						'A valid payment method could not be determined due to a technical issue.%sPlease try again or contact %s for assistance.',
2212
+						'event_espresso'
2213
+					),
2214
+					'<br/>',
2215
+					EE_Registry::instance()->CFG->organization->get_pretty('email')
2216
+				),
2217
+				__FILE__,
2218
+				__FUNCTION__,
2219
+				__LINE__
2220
+			);
2221
+			return null;
2222
+		}
2223
+		return $payment_method;
2224
+	}
2225
+
2226
+
2227
+	/**
2228
+	 *    _attempt_payment
2229
+	 *
2230
+	 * @access    private
2231
+	 * @type    EE_Payment_Method $payment_method
2232
+	 * @return mixed EE_Payment | boolean
2233
+	 * @throws EE_Error
2234
+	 * @throws InvalidArgumentException
2235
+	 * @throws ReflectionException
2236
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2237
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2238
+	 */
2239
+	private function _attempt_payment(EE_Payment_Method $payment_method)
2240
+	{
2241
+		$payment = null;
2242
+		$this->checkout->transaction->save();
2243
+		$payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
2244
+		if (! $payment_processor instanceof EE_Payment_Processor) {
2245
+			return false;
2246
+		}
2247
+		try {
2248
+			$payment_processor->set_revisit($this->checkout->revisit);
2249
+			// generate payment object
2250
+			$payment = $payment_processor->process_payment(
2251
+				$payment_method,
2252
+				$this->checkout->transaction,
2253
+				$this->checkout->amount_owing,
2254
+				$this->checkout->billing_form,
2255
+				$this->_get_return_url($payment_method),
2256
+				'CART',
2257
+				$this->checkout->admin_request,
2258
+				true,
2259
+				$this->reg_step_url()
2260
+			);
2261
+		} catch (Exception $e) {
2262
+			$this->_handle_payment_processor_exception($e);
2263
+		}
2264
+		return $payment;
2265
+	}
2266
+
2267
+
2268
+	/**
2269
+	 * _handle_payment_processor_exception
2270
+	 *
2271
+	 * @access protected
2272
+	 * @param \Exception $e
2273
+	 * @return void
2274
+	 * @throws EE_Error
2275
+	 * @throws InvalidArgumentException
2276
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2277
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2278
+	 */
2279
+	protected function _handle_payment_processor_exception(Exception $e)
2280
+	{
2281
+		EE_Error::add_error(
2282
+			sprintf(
2283
+				esc_html__(
2284
+					'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',
2285
+					'event_espresso'
2286
+				),
2287
+				'<br/>',
2288
+				EE_Registry::instance()->CFG->organization->get_pretty('email'),
2289
+				$e->getMessage(),
2290
+				$e->getFile(),
2291
+				$e->getLine()
2292
+			),
2293
+			__FILE__,
2294
+			__FUNCTION__,
2295
+			__LINE__
2296
+		);
2297
+	}
2298
+
2299
+
2300
+	/**
2301
+	 * _get_return_url
2302
+	 *
2303
+	 * @access protected
2304
+	 * @param \EE_Payment_Method $payment_method
2305
+	 * @return string
2306
+	 * @throws \EE_Error
2307
+	 */
2308
+	protected function _get_return_url(EE_Payment_Method $payment_method)
2309
+	{
2310
+		$return_url = '';
2311
+		switch ($payment_method->type_obj()->payment_occurs()) {
2312
+			case EE_PMT_Base::offsite :
2313
+				$return_url = add_query_arg(
2314
+					array(
2315
+						'action'                     => 'process_gateway_response',
2316
+						'selected_method_of_payment' => $this->checkout->selected_method_of_payment,
2317
+						'spco_txn'                   => $this->checkout->transaction->ID(),
2318
+					),
2319
+					$this->reg_step_url()
2320
+				);
2321
+				break;
2322
+			case EE_PMT_Base::onsite :
2323
+			case EE_PMT_Base::offline :
2324
+				$return_url = $this->checkout->next_step->reg_step_url();
2325
+				break;
2326
+		}
2327
+		return $return_url;
2328
+	}
2329
+
2330
+
2331
+	/**
2332
+	 * _validate_payment
2333
+	 *
2334
+	 * @access private
2335
+	 * @param EE_Payment $payment
2336
+	 * @return EE_Payment|FALSE
2337
+	 * @throws EE_Error
2338
+	 * @throws InvalidArgumentException
2339
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2340
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2341
+	 */
2342
+	private function _validate_payment($payment = null)
2343
+	{
2344
+		if ($this->checkout->payment_method->is_off_line()) {
2345
+			return true;
2346
+		}
2347
+		// verify payment object
2348
+		if (! $payment instanceof EE_Payment) {
2349
+			// not a payment
2350
+			EE_Error::add_error(
2351
+				sprintf(
2352
+					esc_html__(
2353
+						'A valid payment was not generated due to a technical issue.%1$sPlease try again or contact %2$s for assistance.',
2354
+						'event_espresso'
2355
+					),
2356
+					'<br/>',
2357
+					EE_Registry::instance()->CFG->organization->get_pretty('email')
2358
+				),
2359
+				__FILE__,
2360
+				__FUNCTION__,
2361
+				__LINE__
2362
+			);
2363
+			return false;
2364
+		}
2365
+		return $payment;
2366
+	}
2367
+
2368
+
2369
+	/**
2370
+	 * _post_payment_processing
2371
+	 *
2372
+	 * @access private
2373
+	 * @param EE_Payment|bool $payment
2374
+	 * @return bool
2375
+	 * @throws EE_Error
2376
+	 * @throws InvalidArgumentException
2377
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2378
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2379
+	 */
2380
+	private function _post_payment_processing($payment = null)
2381
+	{
2382
+		// Off-Line payment?
2383
+		if ($payment === true) {
2384
+			//$this->_setup_redirect_for_next_step();
2385
+			return true;
2386
+			// On-Site payment?
2387
+		} else if ($this->checkout->payment_method->is_on_site()) {
2388
+			if (! $this->_process_payment_status($payment, EE_PMT_Base::onsite)) {
2389
+				//$this->_setup_redirect_for_next_step();
2390
+				$this->checkout->continue_reg = false;
2391
+			}
2392
+			// Off-Site payment?
2393
+		} else if ($this->checkout->payment_method->is_off_site()) {
2394
+			// if a payment object was made and it specifies a redirect url, then we'll setup that redirect info
2395
+			if ($payment instanceof EE_Payment && $payment->redirect_url()) {
2396
+				do_action('AHEE_log', __CLASS__, __FUNCTION__, $payment->redirect_url(), '$payment->redirect_url()');
2397
+				$this->checkout->redirect      = true;
2398
+				$this->checkout->redirect_form = $payment->redirect_form();
2399
+				$this->checkout->redirect_url  = $this->reg_step_url('redirect_form');
2400
+				// set JSON response
2401
+				$this->checkout->json_response->set_redirect_form($this->checkout->redirect_form);
2402
+				// and lastly, let's bump the payment status to pending
2403
+				$payment->set_status(EEM_Payment::status_id_pending);
2404
+				$payment->save();
2405
+			} else {
2406
+				// not a payment
2407
+				$this->checkout->continue_reg = false;
2408
+				EE_Error::add_error(
2409
+					sprintf(
2410
+						esc_html__(
2411
+							'It appears the Off Site Payment Method was not configured properly.%sPlease try again or contact %s for assistance.',
2412
+							'event_espresso'
2413
+						),
2414
+						'<br/>',
2415
+						EE_Registry::instance()->CFG->organization->get_pretty('email')
2416
+					),
2417
+					__FILE__,
2418
+					__FUNCTION__,
2419
+					__LINE__
2420
+				);
2421
+			}
2422
+		} else {
2423
+			// ummm ya... not Off-Line, not On-Site, not off-Site ????
2424
+			$this->checkout->continue_reg = false;
2425
+			return false;
2426
+		}
2427
+		return $payment;
2428
+	}
2429
+
2430
+
2431
+	/**
2432
+	 *    _process_payment_status
2433
+	 *
2434
+	 * @access private
2435
+	 * @type    EE_Payment $payment
2436
+	 * @param string       $payment_occurs
2437
+	 * @return bool
2438
+	 * @throws EE_Error
2439
+	 * @throws InvalidArgumentException
2440
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2441
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2442
+	 */
2443
+	private function _process_payment_status($payment, $payment_occurs = EE_PMT_Base::offline)
2444
+	{
2445
+		// off-line payment? carry on
2446
+		if ($payment_occurs === EE_PMT_Base::offline) {
2447
+			return true;
2448
+		}
2449
+		// verify payment validity
2450
+		if ($payment instanceof EE_Payment) {
2451
+			do_action('AHEE_log', __CLASS__, __FUNCTION__, $payment->status(), '$payment->status()');
2452
+			$msg = $payment->gateway_response();
2453
+			// check results
2454
+			switch ($payment->status()) {
2455
+				// good payment
2456
+				case EEM_Payment::status_id_approved :
2457
+					EE_Error::add_success(
2458
+						esc_html__('Your payment was processed successfully.', 'event_espresso'),
2459
+						__FILE__,
2460
+						__FUNCTION__,
2461
+						__LINE__
2462
+					);
2463
+					return true;
2464
+					break;
2465
+				// slow payment
2466
+				case EEM_Payment::status_id_pending :
2467
+					if (empty($msg)) {
2468
+						$msg = esc_html__(
2469
+							'Your payment appears to have been processed successfully, but the Instant Payment Notification has not yet been received. It should arrive shortly.',
2470
+							'event_espresso'
2471
+						);
2472
+					}
2473
+					EE_Error::add_success($msg, __FILE__, __FUNCTION__, __LINE__);
2474
+					return true;
2475
+					break;
2476
+				// don't wanna payment
2477
+				case EEM_Payment::status_id_cancelled :
2478
+					if (empty($msg)) {
2479
+						$msg = _n(
2480
+							'Payment cancelled. Please try again.',
2481
+							'Payment cancelled. Please try again or select another method of payment.',
2482
+							count($this->checkout->available_payment_methods),
2483
+							'event_espresso'
2484
+						);
2485
+					}
2486
+					EE_Error::add_attention($msg, __FILE__, __FUNCTION__, __LINE__);
2487
+					return false;
2488
+					break;
2489
+				// not enough payment
2490
+				case EEM_Payment::status_id_declined :
2491
+					if (empty($msg)) {
2492
+						$msg = _n(
2493
+							'We\'re sorry but your payment was declined. Please try again.',
2494
+							'We\'re sorry but your payment was declined. Please try again or select another method of payment.',
2495
+							count($this->checkout->available_payment_methods),
2496
+							'event_espresso'
2497
+						);
2498
+					}
2499
+					EE_Error::add_attention($msg, __FILE__, __FUNCTION__, __LINE__);
2500
+					return false;
2501
+					break;
2502
+				// bad payment
2503
+				case EEM_Payment::status_id_failed :
2504
+					if (! empty($msg)) {
2505
+						EE_Error::add_error($msg, __FILE__, __FUNCTION__, __LINE__);
2506
+						return false;
2507
+					}
2508
+					// default to error below
2509
+					break;
2510
+			}
2511
+		}
2512
+		// off-site payment gateway responses are too unreliable, so let's just assume that
2513
+		// the payment processing is just running slower than the registrant's request
2514
+		if ($payment_occurs === EE_PMT_Base::offsite) {
2515
+			return true;
2516
+		}
2517
+		EE_Error::add_error(
2518
+			sprintf(
2519
+				esc_html__(
2520
+					'Your payment could not be processed successfully due to a technical issue.%sPlease try again or contact %s for assistance.',
2521
+					'event_espresso'
2522
+				),
2523
+				'<br/>',
2524
+				EE_Registry::instance()->CFG->organization->get_pretty('email')
2525
+			),
2526
+			__FILE__,
2527
+			__FUNCTION__,
2528
+			__LINE__
2529
+		);
2530
+		return false;
2531
+	}
2532
+
2533
+
2534
+
2535
+
2536
+
2537
+
2538
+	/********************************************************************************************************/
2539
+	/**********************************  PROCESS GATEWAY RESPONSE  **********************************/
2540
+	/********************************************************************************************************/
2541
+	/**
2542
+	 * process_gateway_response
2543
+	 * this is the return point for Off-Site Payment Methods
2544
+	 * It will attempt to "handle the IPN" if it appears that this has not already occurred,
2545
+	 * otherwise, it will load up the last payment made for the TXN.
2546
+	 * If the payment retrieved looks good, it will then either:
2547
+	 *    complete the current step and allow advancement to the next reg step
2548
+	 *        or present the payment options again
2549
+	 *
2550
+	 * @access private
2551
+	 * @return EE_Payment|FALSE
2552
+	 * @throws EE_Error
2553
+	 * @throws InvalidArgumentException
2554
+	 * @throws ReflectionException
2555
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2556
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2557
+	 * @throws \EventEspresso\core\exceptions\InvalidSessionDataException
2558
+	 */
2559
+	public function process_gateway_response()
2560
+	{
2561
+		$payment = null;
2562
+		// how have they chosen to pay?
2563
+		$this->checkout->selected_method_of_payment = $this->_get_selected_method_of_payment(true);
2564
+		// get EE_Payment_Method object
2565
+		if (! $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment()) {
2566
+			$this->checkout->continue_reg = false;
2567
+			return false;
2568
+		}
2569
+		if (! $this->checkout->payment_method->is_off_site()) {
2570
+			return false;
2571
+		}
2572
+		$this->_validate_offsite_return();
2573
+		// DEBUG LOG
2574
+		//$this->checkout->log(
2575
+		//	__CLASS__, __FUNCTION__, __LINE__,
2576
+		//	array(
2577
+		//		'selected_method_of_payment' => $this->checkout->selected_method_of_payment,
2578
+		//		'payment_method' => $this->checkout->payment_method,
2579
+		//	),
2580
+		//	true
2581
+		//);
2582
+		// verify TXN
2583
+		if ($this->checkout->transaction instanceof EE_Transaction) {
2584
+			$gateway = $this->checkout->payment_method->type_obj()->get_gateway();
2585
+			if (! $gateway instanceof EE_Offsite_Gateway) {
2586
+				$this->checkout->continue_reg = false;
2587
+				return false;
2588
+			}
2589
+			$payment = $this->_process_off_site_payment($gateway);
2590
+			$payment = $this->_process_cancelled_payments($payment);
2591
+			$payment = $this->_validate_payment($payment);
2592
+			// if payment was not declined by the payment gateway or cancelled by the registrant
2593
+			if ($this->_process_payment_status($payment, EE_PMT_Base::offsite)) {
2594
+				//$this->_setup_redirect_for_next_step();
2595
+				// store that for later
2596
+				$this->checkout->payment = $payment;
2597
+				// mark this reg step as completed, as long as gateway doesn't use a separate IPN request,
2598
+				// because we will complete this step during the IPN processing then
2599
+				if ($gateway instanceof EE_Offsite_Gateway && ! $this->handle_IPN_in_this_request()) {
2600
+					$this->set_completed();
2601
+				}
2602
+				return true;
2603
+			}
2604
+		}
2605
+		// DEBUG LOG
2606
+		//$this->checkout->log( __CLASS__, __FUNCTION__, __LINE__,
2607
+		//	array( 'payment' => $payment )
2608
+		//);
2609
+		$this->checkout->continue_reg = false;
2610
+		return false;
2611
+	}
2612
+
2613
+
2614
+	/**
2615
+	 * _validate_return
2616
+	 *
2617
+	 * @access private
2618
+	 * @return void
2619
+	 * @throws EE_Error
2620
+	 * @throws InvalidArgumentException
2621
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2622
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2623
+	 * @throws \EventEspresso\core\exceptions\InvalidSessionDataException
2624
+	 */
2625
+	private function _validate_offsite_return()
2626
+	{
2627
+		$TXN_ID = (int)EE_Registry::instance()->REQ->get('spco_txn', 0);
2628
+		if ($TXN_ID !== $this->checkout->transaction->ID()) {
2629
+			// Houston... we might have a problem
2630
+			$invalid_TXN = false;
2631
+			// first gather some info
2632
+			$valid_TXN          = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
2633
+			$primary_registrant = $valid_TXN instanceof EE_Transaction
2634
+				? $valid_TXN->primary_registration()
2635
+				: null;
2636
+			// let's start by retrieving the cart for this TXN
2637
+			$cart = $this->checkout->get_cart_for_transaction($this->checkout->transaction);
2638
+			if ($cart instanceof EE_Cart) {
2639
+				// verify that the current cart has tickets
2640
+				$tickets = $cart->get_tickets();
2641
+				if (empty($tickets)) {
2642
+					$invalid_TXN = true;
2643
+				}
2644
+			} else {
2645
+				$invalid_TXN = true;
2646
+			}
2647
+			$valid_TXN_SID = $primary_registrant instanceof EE_Registration
2648
+				? $primary_registrant->session_ID()
2649
+				: null;
2650
+			// validate current Session ID and compare against valid TXN session ID
2651
+			if (
2652
+				$invalid_TXN // if this is already true, then skip other checks
2653
+				|| EE_Session::instance()->id() === null
2654
+				|| (
2655
+					// WARNING !!!
2656
+					// this could be PayPal sending back duplicate requests (ya they do that)
2657
+					// or it **could** mean someone is simply registering AGAIN after having just done so
2658
+					// so now we need to determine if this current TXN looks valid or not
2659
+					// and whether this reg step has even been started ?
2660
+					EE_Session::instance()->id() === $valid_TXN_SID
2661
+					// really? you're half way through this reg step, but you never started it ?
2662
+					&& $this->checkout->transaction->reg_step_completed($this->slug()) === false
2663
+				)
2664
+			) {
2665
+				$invalid_TXN = true;
2666
+			}
2667
+			if ($invalid_TXN) {
2668
+				// is the valid TXN completed ?
2669
+				if ($valid_TXN instanceof EE_Transaction) {
2670
+					// has this step even been started ?
2671
+					$reg_step_completed = $valid_TXN->reg_step_completed($this->slug());
2672
+					if ($reg_step_completed !== false && $reg_step_completed !== true) {
2673
+						// so it **looks** like this is a double request from PayPal
2674
+						// so let's try to pick up where we left off
2675
+						$this->checkout->transaction = $valid_TXN;
2676
+						$this->checkout->refresh_all_entities(true);
2677
+						return;
2678
+					}
2679
+				}
2680
+				// you appear to be lost?
2681
+				$this->_redirect_wayward_request($primary_registrant);
2682
+			}
2683
+		}
2684
+	}
2685
+
2686
+
2687
+	/**
2688
+	 * _redirect_wayward_request
2689
+	 *
2690
+	 * @access private
2691
+	 * @param \EE_Registration|null $primary_registrant
2692
+	 * @return bool
2693
+	 * @throws EE_Error
2694
+	 * @throws InvalidArgumentException
2695
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2696
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2697
+	 */
2698
+	private function _redirect_wayward_request(EE_Registration $primary_registrant)
2699
+	{
2700
+		if (! $primary_registrant instanceof EE_Registration) {
2701
+			// try redirecting based on the current TXN
2702
+			$primary_registrant = $this->checkout->transaction instanceof EE_Transaction
2703
+				? $this->checkout->transaction->primary_registration()
2704
+				: null;
2705
+		}
2706
+		if (! $primary_registrant instanceof EE_Registration) {
2707
+			EE_Error::add_error(
2708
+				sprintf(
2709
+					esc_html__(
2710
+						'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.',
2711
+						'event_espresso'
2712
+					),
2713
+					'<br/>',
2714
+					EE_Registry::instance()->CFG->organization->get_pretty('email')
2715
+				),
2716
+				__FILE__,
2717
+				__FUNCTION__,
2718
+				__LINE__
2719
+			);
2720
+			return false;
2721
+		}
2722
+		// make sure transaction is not locked
2723
+		$this->checkout->transaction->unlock();
2724
+		wp_safe_redirect(
2725
+			add_query_arg(
2726
+				array(
2727
+					'e_reg_url_link' => $primary_registrant->reg_url_link(),
2728
+				),
2729
+				$this->checkout->thank_you_page_url
2730
+			)
2731
+		);
2732
+		exit();
2733
+	}
2734
+
2735
+
2736
+	/**
2737
+	 * _process_off_site_payment
2738
+	 *
2739
+	 * @access private
2740
+	 * @param \EE_Offsite_Gateway $gateway
2741
+	 * @return EE_Payment
2742
+	 * @throws EE_Error
2743
+	 * @throws InvalidArgumentException
2744
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2745
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2746
+	 */
2747
+	private function _process_off_site_payment(EE_Offsite_Gateway $gateway)
2748
+	{
2749
+		try {
2750
+			$request_data = \EE_Registry::instance()->REQ->params();
2751
+			// if gateway uses_separate_IPN_request, then we don't have to process the IPN manually
2752
+			$this->set_handle_IPN_in_this_request(
2753
+				$gateway->handle_IPN_in_this_request($request_data, false)
2754
+			);
2755
+			if ($this->handle_IPN_in_this_request()) {
2756
+				// get payment details and process results
2757
+				/** @type EE_Payment_Processor $payment_processor */
2758
+				$payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
2759
+				$payment           = $payment_processor->process_ipn(
2760
+					$request_data,
2761
+					$this->checkout->transaction,
2762
+					$this->checkout->payment_method,
2763
+					true,
2764
+					false
2765
+				);
2766
+				//$payment_source = 'process_ipn';
2767
+			} else {
2768
+				$payment = $this->checkout->transaction->last_payment();
2769
+				//$payment_source = 'last_payment';
2770
+			}
2771
+		} catch (Exception $e) {
2772
+			// let's just eat the exception and try to move on using any previously set payment info
2773
+			$payment = $this->checkout->transaction->last_payment();
2774
+			//$payment_source = 'last_payment after Exception';
2775
+			// but if we STILL don't have a payment object
2776
+			if (! $payment instanceof EE_Payment) {
2777
+				// then we'll object ! ( not object like a thing... but object like what a lawyer says ! )
2778
+				$this->_handle_payment_processor_exception($e);
2779
+			}
2780
+		}
2781
+		// DEBUG LOG
2782
+		//$this->checkout->log( __CLASS__, __FUNCTION__, __LINE__,
2783
+		//	array(
2784
+		//		'process_ipn_payment' => $payment,
2785
+		//		'payment_source'      => $payment_source,
2786
+		//	)
2787
+		//);
2788
+		return $payment;
2789
+	}
2790
+
2791
+
2792
+	/**
2793
+	 * _process_cancelled_payments
2794
+	 * just makes sure that the payment status gets updated correctly
2795
+	 * so tha tan error isn't generated during payment validation
2796
+	 *
2797
+	 * @access private
2798
+	 * @param EE_Payment $payment
2799
+	 * @return EE_Payment | FALSE
2800
+	 * @throws \EE_Error
2801
+	 */
2802
+	private function _process_cancelled_payments($payment = null)
2803
+	{
2804
+		if (
2805
+			$payment instanceof EE_Payment
2806
+			&& isset($_REQUEST['ee_cancel_payment'])
2807
+			&& $payment->status() === EEM_Payment::status_id_failed
2808
+		) {
2809
+			$payment->set_status(EEM_Payment::status_id_cancelled);
2810
+		}
2811
+		return $payment;
2812
+	}
2813
+
2814
+
2815
+	/**
2816
+	 *    get_transaction_details_for_gateways
2817
+	 *
2818
+	 * @access    public
2819
+	 * @return int
2820
+	 * @throws EE_Error
2821
+	 * @throws InvalidArgumentException
2822
+	 * @throws ReflectionException
2823
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
2824
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
2825
+	 */
2826
+	public function get_transaction_details_for_gateways()
2827
+	{
2828
+		$txn_details = array();
2829
+		// ya gotta make a choice man
2830
+		if (empty($this->checkout->selected_method_of_payment)) {
2831
+			$txn_details = array(
2832
+				'error' => esc_html__('Please select a method of payment before proceeding.', 'event_espresso'),
2833
+			);
2834
+		}
2835
+		// get EE_Payment_Method object
2836
+		if (
2837
+			empty($txn_details)
2838
+			&&
2839
+			! $this->checkout->payment_method = $this->_get_payment_method_for_selected_method_of_payment()
2840
+		) {
2841
+			$txn_details = array(
2842
+				'selected_method_of_payment' => $this->checkout->selected_method_of_payment,
2843
+				'error'                      => esc_html__(
2844
+					'A valid Payment Method could not be determined.',
2845
+					'event_espresso'
2846
+				),
2847
+			);
2848
+		}
2849
+		if (empty($txn_details) && $this->checkout->transaction instanceof EE_Transaction) {
2850
+			$return_url  = $this->_get_return_url($this->checkout->payment_method);
2851
+			$txn_details = array(
2852
+				'TXN_ID'         => $this->checkout->transaction->ID(),
2853
+				'TXN_timestamp'  => $this->checkout->transaction->datetime(),
2854
+				'TXN_total'      => $this->checkout->transaction->total(),
2855
+				'TXN_paid'       => $this->checkout->transaction->paid(),
2856
+				'TXN_reg_steps'  => $this->checkout->transaction->reg_steps(),
2857
+				'STS_ID'         => $this->checkout->transaction->status_ID(),
2858
+				'PMD_ID'         => $this->checkout->transaction->payment_method_ID(),
2859
+				'payment_amount' => $this->checkout->amount_owing,
2860
+				'return_url'     => $return_url,
2861
+				'cancel_url'     => add_query_arg(array('ee_cancel_payment' => true), $return_url),
2862
+				'notify_url'     => EE_Config::instance()->core->txn_page_url(
2863
+					array(
2864
+						'e_reg_url_link'    => $this->checkout->transaction->primary_registration()->reg_url_link(),
2865
+						'ee_payment_method' => $this->checkout->payment_method->slug(),
2866
+					)
2867
+				),
2868
+			);
2869
+		}
2870
+		echo wp_json_encode($txn_details);
2871
+		exit();
2872
+	}
2873
+
2874
+
2875
+	/**
2876
+	 *    __sleep
2877
+	 * to conserve db space, let's remove the reg_form and the EE_Checkout object from EE_SPCO_Reg_Step objects upon
2878
+	 * serialization EE_Checkout will handle the reimplementation of itself upon waking, but we won't bother with the
2879
+	 * reg form, because if needed, it will be regenerated anyways
2880
+	 *
2881
+	 * @return array
2882
+	 */
2883
+	public function __sleep()
2884
+	{
2885
+		// remove the reg form and the checkout
2886
+		return array_diff(array_keys(get_object_vars($this)), array('reg_form', 'checkout', 'line_item_display'));
2887
+	}
2888 2888
 }
Please login to merge, or discard this patch.
admin_pages/transactions/Transactions_Admin_Page.core.php 2 patches
Indentation   +2433 added lines, -2433 removed lines patch added patch discarded remove patch
@@ -16,2437 +16,2437 @@
 block discarded – undo
16 16
 class Transactions_Admin_Page extends EE_Admin_Page
17 17
 {
18 18
 
19
-    /**
20
-     * @var EE_Transaction
21
-     */
22
-    private $_transaction;
23
-
24
-    /**
25
-     * @var EE_Session
26
-     */
27
-    private $_session;
28
-
29
-    /**
30
-     * @var array $_txn_status
31
-     */
32
-    private static $_txn_status;
33
-
34
-    /**
35
-     * @var array $_pay_status
36
-     */
37
-    private static $_pay_status;
38
-
39
-    /**
40
-     * @var array $_existing_reg_payment_REG_IDs
41
-     */
42
-    protected $_existing_reg_payment_REG_IDs = null;
43
-
44
-
45
-    /**
46
-     * @Constructor
47
-     * @access public
48
-     * @param bool $routing
49
-     * @throws EE_Error
50
-     * @throws InvalidArgumentException
51
-     * @throws ReflectionException
52
-     * @throws InvalidDataTypeException
53
-     * @throws InvalidInterfaceException
54
-     */
55
-    public function __construct($routing = true)
56
-    {
57
-        parent::__construct($routing);
58
-    }
59
-
60
-
61
-    /**
62
-     *    _init_page_props
63
-     *
64
-     * @return void
65
-     */
66
-    protected function _init_page_props()
67
-    {
68
-        $this->page_slug        = TXN_PG_SLUG;
69
-        $this->page_label       = esc_html__('Transactions', 'event_espresso');
70
-        $this->_admin_base_url  = TXN_ADMIN_URL;
71
-        $this->_admin_base_path = TXN_ADMIN;
72
-    }
73
-
74
-
75
-    /**
76
-     *    _ajax_hooks
77
-     *
78
-     * @return void
79
-     */
80
-    protected function _ajax_hooks()
81
-    {
82
-        add_action('wp_ajax_espresso_apply_payment', array($this, 'apply_payments_or_refunds'));
83
-        add_action('wp_ajax_espresso_apply_refund', array($this, 'apply_payments_or_refunds'));
84
-        add_action('wp_ajax_espresso_delete_payment', array($this, 'delete_payment'));
85
-    }
86
-
87
-
88
-    /**
89
-     *    _define_page_props
90
-     *
91
-     * @return void
92
-     */
93
-    protected function _define_page_props()
94
-    {
95
-        $this->_admin_page_title = $this->page_label;
96
-        $this->_labels           = array(
97
-            'buttons' => array(
98
-                'add'    => esc_html__('Add New Transaction', 'event_espresso'),
99
-                'edit'   => esc_html__('Edit Transaction', 'event_espresso'),
100
-                'delete' => esc_html__('Delete Transaction', 'event_espresso'),
101
-            ),
102
-        );
103
-    }
104
-
105
-
106
-    /**
107
-     *        grab url requests and route them
108
-     *
109
-     * @access private
110
-     * @return void
111
-     * @throws EE_Error
112
-     * @throws InvalidArgumentException
113
-     * @throws InvalidDataTypeException
114
-     * @throws InvalidInterfaceException
115
-     */
116
-    public function _set_page_routes()
117
-    {
118
-
119
-        $this->_set_transaction_status_array();
120
-
121
-        $txn_id = ! empty($this->_req_data['TXN_ID'])
122
-                  && ! is_array($this->_req_data['TXN_ID'])
123
-            ? $this->_req_data['TXN_ID']
124
-            : 0;
125
-
126
-        $this->_page_routes = array(
127
-
128
-            'default' => array(
129
-                'func'       => '_transactions_overview_list_table',
130
-                'capability' => 'ee_read_transactions',
131
-            ),
132
-
133
-            'view_transaction' => array(
134
-                'func'       => '_transaction_details',
135
-                'capability' => 'ee_read_transaction',
136
-                'obj_id'     => $txn_id,
137
-            ),
138
-
139
-            'send_payment_reminder' => array(
140
-                'func'       => '_send_payment_reminder',
141
-                'noheader'   => true,
142
-                'capability' => 'ee_send_message',
143
-            ),
144
-
145
-            'espresso_apply_payment' => array(
146
-                'func'       => 'apply_payments_or_refunds',
147
-                'noheader'   => true,
148
-                'capability' => 'ee_edit_payments',
149
-            ),
150
-
151
-            'espresso_apply_refund' => array(
152
-                'func'       => 'apply_payments_or_refunds',
153
-                'noheader'   => true,
154
-                'capability' => 'ee_edit_payments',
155
-            ),
156
-
157
-            'espresso_delete_payment' => array(
158
-                'func'       => 'delete_payment',
159
-                'noheader'   => true,
160
-                'capability' => 'ee_delete_payments',
161
-            ),
162
-
163
-        );
164
-    }
165
-
166
-
167
-    protected function _set_page_config()
168
-    {
169
-        $this->_page_config = array(
170
-            'default'          => array(
171
-                'nav'           => array(
172
-                    'label' => esc_html__('Overview', 'event_espresso'),
173
-                    'order' => 10,
174
-                ),
175
-                'list_table'    => 'EE_Admin_Transactions_List_Table',
176
-                'help_tabs'     => array(
177
-                    'transactions_overview_help_tab'                       => array(
178
-                        'title'    => esc_html__('Transactions Overview', 'event_espresso'),
179
-                        'filename' => 'transactions_overview',
180
-                    ),
181
-                    'transactions_overview_table_column_headings_help_tab' => array(
182
-                        'title'    => esc_html__('Transactions Table Column Headings', 'event_espresso'),
183
-                        'filename' => 'transactions_overview_table_column_headings',
184
-                    ),
185
-                    'transactions_overview_views_filters_help_tab'         => array(
186
-                        'title'    => esc_html__('Transaction Views & Filters & Search', 'event_espresso'),
187
-                        'filename' => 'transactions_overview_views_filters_search',
188
-                    ),
189
-                ),
190
-                'help_tour'     => array('Transactions_Overview_Help_Tour'),
191
-                /**
192
-                 * commented out because currently we are not displaying tips for transaction list table status but this
193
-                 * may change in a later iteration so want to keep the code for then.
194
-                 */
195
-                //'qtips' => array( 'Transactions_List_Table_Tips' ),
196
-                'require_nonce' => false,
197
-            ),
198
-            'view_transaction' => array(
199
-                'nav'       => array(
200
-                    'label'      => esc_html__('View Transaction', 'event_espresso'),
201
-                    'order'      => 5,
202
-                    'url'        => isset($this->_req_data['TXN_ID'])
203
-                        ? add_query_arg(array('TXN_ID' => $this->_req_data['TXN_ID']), $this->_current_page_view_url)
204
-                        : $this->_admin_base_url,
205
-                    'persistent' => false,
206
-                ),
207
-                'help_tabs' => array(
208
-                    'transactions_view_transaction_help_tab'                                              => array(
209
-                        'title'    => esc_html__('View Transaction', 'event_espresso'),
210
-                        'filename' => 'transactions_view_transaction',
211
-                    ),
212
-                    'transactions_view_transaction_transaction_details_table_help_tab'                    => array(
213
-                        'title'    => esc_html__('Transaction Details Table', 'event_espresso'),
214
-                        'filename' => 'transactions_view_transaction_transaction_details_table',
215
-                    ),
216
-                    'transactions_view_transaction_attendees_registered_help_tab'                         => array(
217
-                        'title'    => esc_html__('Attendees Registered', 'event_espresso'),
218
-                        'filename' => 'transactions_view_transaction_attendees_registered',
219
-                    ),
220
-                    'transactions_view_transaction_views_primary_registrant_billing_information_help_tab' => array(
221
-                        'title'    => esc_html__('Primary Registrant & Billing Information', 'event_espresso'),
222
-                        'filename' => 'transactions_view_transaction_primary_registrant_billing_information',
223
-                    ),
224
-                ),
225
-                'qtips'     => array('Transaction_Details_Tips'),
226
-                'help_tour' => array('Transaction_Details_Help_Tour'),
227
-                'metaboxes' => array('_transaction_details_metaboxes'),
228
-
229
-                'require_nonce' => false,
230
-            ),
231
-        );
232
-    }
233
-
234
-
235
-    /**
236
-     * The below methods aren't used by this class currently
237
-     */
238
-    protected function _add_screen_options()
239
-    {
240
-        //noop
241
-    }
242
-
243
-    protected function _add_feature_pointers()
244
-    {
245
-        //noop
246
-    }
247
-
248
-    public function admin_init()
249
-    {
250
-        // IF a registration was JUST added via the admin...
251
-        if (isset(
252
-            $this->_req_data['redirect_from'],
253
-            $this->_req_data['EVT_ID'],
254
-            $this->_req_data['event_name']
255
-        )) {
256
-            // then set a cookie so that we can block any attempts to use
257
-            // the back button as a way to enter another registration.
258
-            setcookie(
259
-                'ee_registration_added',
260
-                $this->_req_data['EVT_ID'], time() + WEEK_IN_SECONDS, '/'
261
-            );
262
-            // and update the global
263
-            $_COOKIE['ee_registration_added'] = $this->_req_data['EVT_ID'];
264
-        }
265
-        EE_Registry::$i18n_js_strings['invalid_server_response'] = esc_html__(
266
-            'An error occurred! Your request may have been processed, but a valid response from the server was not received. Please refresh the page and try again.',
267
-            'event_espresso'
268
-        );
269
-        EE_Registry::$i18n_js_strings['error_occurred']          = esc_html__(
270
-            'An error occurred! Please refresh the page and try again.',
271
-            'event_espresso'
272
-        );
273
-        EE_Registry::$i18n_js_strings['txn_status_array']        = self::$_txn_status;
274
-        EE_Registry::$i18n_js_strings['pay_status_array']        = self::$_pay_status;
275
-        EE_Registry::$i18n_js_strings['payments_total']          = esc_html__('Payments Total', 'event_espresso');
276
-        EE_Registry::$i18n_js_strings['transaction_overpaid']    = esc_html__(
277
-            'This transaction has been overpaid ! Payments Total',
278
-            'event_espresso'
279
-        );
280
-    }
281
-
282
-    public function admin_notices()
283
-    {
284
-        //noop
285
-    }
286
-
287
-    public function admin_footer_scripts()
288
-    {
289
-        //noop
290
-    }
291
-
292
-
293
-    /**
294
-     * _set_transaction_status_array
295
-     * sets list of transaction statuses
296
-     *
297
-     * @access private
298
-     * @return void
299
-     * @throws EE_Error
300
-     * @throws InvalidArgumentException
301
-     * @throws InvalidDataTypeException
302
-     * @throws InvalidInterfaceException
303
-     */
304
-    private function _set_transaction_status_array()
305
-    {
306
-        self::$_txn_status = EEM_Transaction::instance()->status_array(true);
307
-    }
308
-
309
-
310
-    /**
311
-     * get_transaction_status_array
312
-     * return the transaction status array for wp_list_table
313
-     *
314
-     * @access public
315
-     * @return array
316
-     */
317
-    public function get_transaction_status_array()
318
-    {
319
-        return self::$_txn_status;
320
-    }
321
-
322
-
323
-    /**
324
-     *    get list of payment statuses
325
-     *
326
-     * @access private
327
-     * @return void
328
-     * @throws EE_Error
329
-     * @throws InvalidArgumentException
330
-     * @throws InvalidDataTypeException
331
-     * @throws InvalidInterfaceException
332
-     */
333
-    private function _get_payment_status_array()
334
-    {
335
-        self::$_pay_status                      = EEM_Payment::instance()->status_array(true);
336
-        $this->_template_args['payment_status'] = self::$_pay_status;
337
-
338
-    }
339
-
340
-
341
-    /**
342
-     *    _add_screen_options_default
343
-     *
344
-     * @access protected
345
-     * @return void
346
-     * @throws InvalidArgumentException
347
-     * @throws InvalidDataTypeException
348
-     * @throws InvalidInterfaceException
349
-     */
350
-    protected function _add_screen_options_default()
351
-    {
352
-        $this->_per_page_screen_option();
353
-    }
354
-
355
-
356
-    /**
357
-     * load_scripts_styles
358
-     *
359
-     * @access public
360
-     * @return void
361
-     */
362
-    public function load_scripts_styles()
363
-    {
364
-        //enqueue style
365
-        wp_register_style(
366
-            'espresso_txn',
367
-            TXN_ASSETS_URL . 'espresso_transactions_admin.css',
368
-            array(),
369
-            EVENT_ESPRESSO_VERSION
370
-        );
371
-        wp_enqueue_style('espresso_txn');
372
-        //scripts
373
-        wp_register_script('espresso_txn', TXN_ASSETS_URL . 'espresso_transactions_admin.js', array(
374
-            'ee_admin_js',
375
-            'ee-datepicker',
376
-            'jquery-ui-datepicker',
377
-            'jquery-ui-draggable',
378
-            'ee-dialog',
379
-            'ee-accounting',
380
-            'ee-serialize-full-array',
381
-        ), EVENT_ESPRESSO_VERSION, true);
382
-        wp_enqueue_script('espresso_txn');
383
-    }
384
-
385
-
386
-    /**
387
-     *    load_scripts_styles_view_transaction
388
-     *
389
-     * @access public
390
-     * @return void
391
-     */
392
-    public function load_scripts_styles_view_transaction()
393
-    {
394
-        //styles
395
-        wp_enqueue_style('espresso-ui-theme');
396
-    }
397
-
398
-
399
-    /**
400
-     *    load_scripts_styles_default
401
-     *
402
-     * @access public
403
-     * @return void
404
-     */
405
-    public function load_scripts_styles_default()
406
-    {
407
-        //styles
408
-        wp_enqueue_style('espresso-ui-theme');
409
-    }
410
-
411
-
412
-    /**
413
-     *    _set_list_table_views_default
414
-     *
415
-     * @access protected
416
-     * @return void
417
-     */
418
-    protected function _set_list_table_views_default()
419
-    {
420
-        $this->_views = array(
421
-            'all'       => array(
422
-                'slug'  => 'all',
423
-                'label' => esc_html__('View All Transactions', 'event_espresso'),
424
-                'count' => 0,
425
-            ),
426
-            'abandoned' => array(
427
-                'slug'  => 'abandoned',
428
-                'label' => esc_html__('Abandoned Transactions', 'event_espresso'),
429
-                'count' => 0,
430
-            ),
431
-            'failed'    => array(
432
-                'slug'  => 'failed',
433
-                'label' => esc_html__('Failed Transactions', 'event_espresso'),
434
-                'count' => 0,
435
-            ),
436
-        );
437
-    }
438
-
439
-
440
-    /**
441
-     * _set_transaction_object
442
-     * This sets the _transaction property for the transaction details screen
443
-     *
444
-     * @access private
445
-     * @return void
446
-     * @throws EE_Error
447
-     * @throws InvalidArgumentException
448
-     * @throws RuntimeException
449
-     * @throws InvalidDataTypeException
450
-     * @throws InvalidInterfaceException
451
-     * @throws ReflectionException
452
-     */
453
-    private function _set_transaction_object()
454
-    {
455
-        if ($this->_transaction instanceof EE_Transaction) {
456
-            return;
457
-        } //get out we've already set the object
458
-
459
-        $TXN_ID = ! empty($this->_req_data['TXN_ID'])
460
-            ? absint($this->_req_data['TXN_ID'])
461
-            : false;
462
-
463
-        //get transaction object
464
-        $this->_transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
465
-        $this->_session     = $this->_transaction instanceof EE_Transaction
466
-            ? $this->_transaction->get('TXN_session_data')
467
-            : null;
468
-        $this->_transaction->verify_abandoned_transaction_status();
469
-
470
-        if (! $this->_transaction instanceof EE_Transaction) {
471
-            $error_msg = sprintf(
472
-                esc_html__(
473
-                    'An error occurred and the details for the transaction with the ID # %d could not be retrieved.',
474
-                    'event_espresso'
475
-                ),
476
-                $TXN_ID
477
-            );
478
-            EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
479
-        }
480
-    }
481
-
482
-
483
-    /**
484
-     *    _transaction_legend_items
485
-     *
486
-     * @access protected
487
-     * @return array
488
-     * @throws EE_Error
489
-     * @throws InvalidArgumentException
490
-     * @throws ReflectionException
491
-     * @throws InvalidDataTypeException
492
-     * @throws InvalidInterfaceException
493
-     */
494
-    protected function _transaction_legend_items()
495
-    {
496
-        EE_Registry::instance()->load_helper('MSG_Template');
497
-        $items = array();
498
-
499
-        if (EE_Registry::instance()->CAP->current_user_can(
500
-            'ee_read_global_messages',
501
-            'view_filtered_messages'
502
-        )) {
503
-            $related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
504
-            if (is_array($related_for_icon)
505
-                && isset($related_for_icon['css_class'], $related_for_icon['label'])
506
-            ) {
507
-                $items['view_related_messages'] = array(
508
-                    'class' => $related_for_icon['css_class'],
509
-                    'desc'  => $related_for_icon['label'],
510
-                );
511
-            }
512
-        }
513
-
514
-        $items = apply_filters(
515
-            'FHEE__Transactions_Admin_Page___transaction_legend_items__items',
516
-            array_merge(
517
-                $items,
518
-                array(
519
-                    'view_details'          => array(
520
-                        'class' => 'dashicons dashicons-cart',
521
-                        'desc'  => esc_html__('View Transaction Details', 'event_espresso'),
522
-                    ),
523
-                    'view_invoice'          => array(
524
-                        'class' => 'dashicons dashicons-media-spreadsheet',
525
-                        'desc'  => esc_html__('View Transaction Invoice', 'event_espresso'),
526
-                    ),
527
-                    'view_receipt'          => array(
528
-                        'class' => 'dashicons dashicons-media-default',
529
-                        'desc'  => esc_html__('View Transaction Receipt', 'event_espresso'),
530
-                    ),
531
-                    'view_registration'     => array(
532
-                        'class' => 'dashicons dashicons-clipboard',
533
-                        'desc'  => esc_html__('View Registration Details', 'event_espresso'),
534
-                    ),
535
-                    'payment_overview_link' => array(
536
-                        'class' => 'dashicons dashicons-money',
537
-                        'desc'  => esc_html__('Make Payment on Frontend', 'event_espresso'),
538
-                    ),
539
-                )
540
-            )
541
-        );
542
-
543
-        if (EE_Registry::instance()->CAP->current_user_can(
544
-            'ee_send_message',
545
-            'espresso_transactions_send_payment_reminder'
546
-        )) {
547
-            if (EEH_MSG_Template::is_mt_active('payment_reminder')) {
548
-                $items['send_payment_reminder'] = array(
549
-                    'class' => 'dashicons dashicons-email-alt',
550
-                    'desc'  => esc_html__('Send Payment Reminder', 'event_espresso'),
551
-                );
552
-            } else {
553
-                $items['blank*'] = array(
554
-                    'class' => '',
555
-                    'desc'  => '',
556
-                );
557
-            }
558
-        } else {
559
-            $items['blank*'] = array(
560
-                'class' => '',
561
-                'desc'  => '',
562
-            );
563
-        }
564
-        $more_items = apply_filters(
565
-            'FHEE__Transactions_Admin_Page___transaction_legend_items__more_items',
566
-            array(
567
-                'overpaid'   => array(
568
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::overpaid_status_code,
569
-                    'desc'  => EEH_Template::pretty_status(
570
-                        EEM_Transaction::overpaid_status_code,
571
-                        false,
572
-                        'sentence'
573
-                    ),
574
-                ),
575
-                'complete'   => array(
576
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::complete_status_code,
577
-                    'desc'  => EEH_Template::pretty_status(
578
-                        EEM_Transaction::complete_status_code,
579
-                        false,
580
-                        'sentence'
581
-                    ),
582
-                ),
583
-                'incomplete' => array(
584
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::incomplete_status_code,
585
-                    'desc'  => EEH_Template::pretty_status(
586
-                        EEM_Transaction::incomplete_status_code,
587
-                        false,
588
-                        'sentence'
589
-                    ),
590
-                ),
591
-                'abandoned'  => array(
592
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::abandoned_status_code,
593
-                    'desc'  => EEH_Template::pretty_status(
594
-                        EEM_Transaction::abandoned_status_code,
595
-                        false,
596
-                        'sentence'
597
-                    ),
598
-                ),
599
-                'failed'     => array(
600
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::failed_status_code,
601
-                    'desc'  => EEH_Template::pretty_status(
602
-                        EEM_Transaction::failed_status_code,
603
-                        false,
604
-                        'sentence'
605
-                    ),
606
-                ),
607
-            )
608
-        );
609
-
610
-        return array_merge($items, $more_items);
611
-    }
612
-
613
-
614
-    /**
615
-     *    _transactions_overview_list_table
616
-     *
617
-     * @access protected
618
-     * @return void
619
-     * @throws DomainException
620
-     * @throws EE_Error
621
-     * @throws InvalidArgumentException
622
-     * @throws InvalidDataTypeException
623
-     * @throws InvalidInterfaceException
624
-     * @throws ReflectionException
625
-     */
626
-    protected function _transactions_overview_list_table()
627
-    {
628
-        $this->_admin_page_title = esc_html__('Transactions', 'event_espresso');
629
-        $event = isset($this->_req_data['EVT_ID'])
630
-            ? EEM_Event::instance()->get_one_by_ID($this->_req_data['EVT_ID'])
631
-            : null;
632
-        $this->_template_args['admin_page_header'] = $event instanceof EE_Event
633
-            ? sprintf(
634
-                esc_html__(
635
-                    '%sViewing Transactions for the Event: %s%s',
636
-                    'event_espresso'
637
-                ),
638
-                '<h3>',
639
-                '<a href="'
640
-                . EE_Admin_Page::add_query_args_and_nonce(
641
-                    array('action' => 'edit', 'post' => $event->ID()),
642
-                    EVENTS_ADMIN_URL
643
-                )
644
-                . '" title="'
645
-                . esc_attr__(
646
-                    'Click to Edit event',
647
-                    'event_espresso'
648
-                )
649
-                . '">' . $event->get('EVT_name') . '</a>',
650
-                '</h3>'
651
-            )
652
-            : '';
653
-        $this->_template_args['after_list_table']  = $this->_display_legend($this->_transaction_legend_items());
654
-        $this->display_admin_list_table_page_with_no_sidebar();
655
-    }
656
-
657
-
658
-    /**
659
-     *    _transaction_details
660
-     * generates HTML for the View Transaction Details Admin page
661
-     *
662
-     * @access protected
663
-     * @return void
664
-     * @throws DomainException
665
-     * @throws EE_Error
666
-     * @throws InvalidArgumentException
667
-     * @throws InvalidDataTypeException
668
-     * @throws InvalidInterfaceException
669
-     * @throws RuntimeException
670
-     * @throws ReflectionException
671
-     */
672
-    protected function _transaction_details()
673
-    {
674
-        do_action('AHEE__Transactions_Admin_Page__transaction_details__start', $this->_transaction);
675
-
676
-        $this->_set_transaction_status_array();
677
-
678
-        $this->_template_args                      = array();
679
-        $this->_template_args['transactions_page'] = $this->_wp_page_slug;
680
-
681
-        $this->_set_transaction_object();
682
-
683
-        $primary_registration = $this->_transaction->primary_registration();
684
-        $attendee = $primary_registration instanceof EE_Registration
685
-            ? $primary_registration->attendee()
686
-            : null;
687
-
688
-        $this->_template_args['txn_nmbr']['value'] = $this->_transaction->ID();
689
-        $this->_template_args['txn_nmbr']['label'] = esc_html__('Transaction Number', 'event_espresso');
690
-
691
-        $this->_template_args['txn_datetime']['value'] = $this->_transaction->get_i18n_datetime('TXN_timestamp');
692
-        $this->_template_args['txn_datetime']['label'] = esc_html__('Date', 'event_espresso');
693
-
694
-        $this->_template_args['txn_status']['value'] = self::$_txn_status[$this->_transaction->get('STS_ID')];
695
-        $this->_template_args['txn_status']['label'] = esc_html__('Transaction Status', 'event_espresso');
696
-        $this->_template_args['txn_status']['class'] = 'status-' . $this->_transaction->get('STS_ID');
697
-
698
-        $this->_template_args['grand_total'] = $this->_transaction->get('TXN_total');
699
-        $this->_template_args['total_paid']  = $this->_transaction->get('TXN_paid');
700
-
701
-        $amount_due = $this->_transaction->get('TXN_total') - $this->_transaction->get('TXN_paid');
702
-        $this->_template_args['amount_due'] = EEH_Template::format_currency(
703
-            $amount_due,
704
-            true
705
-        );
706
-        if (EE_Registry::instance()->CFG->currency->sign_b4) {
707
-            $this->_template_args['amount_due'] = EE_Registry::instance()->CFG->currency->sign
708
-                                                  . $this->_template_args['amount_due'];
709
-        } else {
710
-            $this->_template_args['amount_due'] .= EE_Registry::instance()->CFG->currency->sign;
711
-        }
712
-        $this->_template_args['amount_due_class'] = '';
713
-
714
-        if ($this->_transaction->get('TXN_paid') == $this->_transaction->get('TXN_total')) {
715
-            // paid in full
716
-            $this->_template_args['amount_due'] = false;
717
-        } elseif ($this->_transaction->get('TXN_paid') > $this->_transaction->get('TXN_total')) {
718
-            // overpaid
719
-            $this->_template_args['amount_due_class'] = 'txn-overview-no-payment-spn';
720
-        } elseif ($this->_transaction->get('TXN_total') > 0
721
-                  && $this->_transaction->get('TXN_paid') > 0
722
-        ) {
723
-            // monies owing
724
-            $this->_template_args['amount_due_class'] = 'txn-overview-part-payment-spn';
725
-        } elseif ($this->_transaction->get('TXN_total') > 0
726
-                  && $this->_transaction->get('TXN_paid') == 0
727
-        ) {
728
-            // no payments made yet
729
-            $this->_template_args['amount_due_class'] = 'txn-overview-no-payment-spn';
730
-        } elseif ($this->_transaction->get('TXN_total') == 0) {
731
-            // free event
732
-            $this->_template_args['amount_due'] = false;
733
-        }
734
-
735
-        $payment_method = $this->_transaction->payment_method();
736
-
737
-        $this->_template_args['method_of_payment_name'] = $payment_method instanceof EE_Payment_Method
738
-            ? $payment_method->admin_name()
739
-            : esc_html__('Unknown', 'event_espresso');
740
-
741
-        $this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
742
-        // link back to overview
743
-        $this->_template_args['txn_overview_url'] = ! empty($_SERVER['HTTP_REFERER'])
744
-            ? $_SERVER['HTTP_REFERER']
745
-            : TXN_ADMIN_URL;
746
-
747
-
748
-        // next link
749
-        $next_txn                                 = $this->_transaction->next(
750
-            null,
751
-            array(array('STS_ID' => array('!=', EEM_Transaction::failed_status_code))),
752
-            'TXN_ID'
753
-        );
754
-        $this->_template_args['next_transaction'] = $next_txn
755
-            ? $this->_next_link(
756
-                EE_Admin_Page::add_query_args_and_nonce(
757
-                    array('action' => 'view_transaction', 'TXN_ID' => $next_txn['TXN_ID']),
758
-                    TXN_ADMIN_URL
759
-                ),
760
-                'dashicons dashicons-arrow-right ee-icon-size-22'
761
-            )
762
-            : '';
763
-        // previous link
764
-        $previous_txn                                 = $this->_transaction->previous(
765
-            null,
766
-            array(array('STS_ID' => array('!=', EEM_Transaction::failed_status_code))),
767
-            'TXN_ID'
768
-        );
769
-        $this->_template_args['previous_transaction'] = $previous_txn
770
-            ? $this->_previous_link(
771
-                EE_Admin_Page::add_query_args_and_nonce(
772
-                    array('action' => 'view_transaction', 'TXN_ID' => $previous_txn['TXN_ID']),
773
-                    TXN_ADMIN_URL
774
-                ),
775
-                'dashicons dashicons-arrow-left ee-icon-size-22'
776
-            )
777
-            : '';
778
-
779
-        // were we just redirected here after adding a new registration ???
780
-        if (isset(
781
-            $this->_req_data['redirect_from'],
782
-            $this->_req_data['EVT_ID'],
783
-            $this->_req_data['event_name']
784
-        )) {
785
-            if (EE_Registry::instance()->CAP->current_user_can(
786
-                'ee_edit_registrations',
787
-                'espresso_registrations_new_registration',
788
-                $this->_req_data['EVT_ID']
789
-            )) {
790
-                $this->_admin_page_title .= '<a id="add-new-registration" class="add-new-h2 button-primary" href="';
791
-                $this->_admin_page_title .= EE_Admin_Page::add_query_args_and_nonce(
792
-                    array(
793
-                        'page'     => 'espresso_registrations',
794
-                        'action'   => 'new_registration',
795
-                        'return'   => 'default',
796
-                        'TXN_ID'   => $this->_transaction->ID(),
797
-                        'event_id' => $this->_req_data['EVT_ID'],
798
-                    ),
799
-                    REG_ADMIN_URL
800
-                );
801
-                $this->_admin_page_title .= '">';
802
-
803
-                $this->_admin_page_title .= sprintf(
804
-                    esc_html__('Add Another New Registration to Event: "%1$s" ?', 'event_espresso'),
805
-                    htmlentities(urldecode($this->_req_data['event_name']), ENT_QUOTES, 'UTF-8')
806
-                );
807
-                $this->_admin_page_title .= '</a>';
808
-            }
809
-            EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
810
-        }
811
-        // grab messages at the last second
812
-        $this->_template_args['notices'] = EE_Error::get_notices();
813
-        // path to template
814
-        $template_path                             = TXN_TEMPLATE_PATH . 'txn_admin_details_header.template.php';
815
-        $this->_template_args['admin_page_header'] = EEH_Template::display_template(
816
-            $template_path,
817
-            $this->_template_args,
818
-            true
819
-        );
820
-
821
-        // the details template wrapper
822
-        $this->display_admin_page_with_sidebar();
823
-
824
-    }
825
-
826
-
827
-    /**
828
-     *        _transaction_details_metaboxes
829
-     *
830
-     * @access protected
831
-     * @return void
832
-     * @throws EE_Error
833
-     * @throws InvalidArgumentException
834
-     * @throws InvalidDataTypeException
835
-     * @throws InvalidInterfaceException
836
-     * @throws RuntimeException
837
-     * @throws ReflectionException
838
-     */
839
-    protected function _transaction_details_metaboxes()
840
-    {
841
-
842
-        $this->_set_transaction_object();
843
-
844
-        add_meta_box(
845
-            'edit-txn-details-mbox',
846
-            esc_html__('Transaction Details', 'event_espresso'),
847
-            array($this, 'txn_details_meta_box'),
848
-            $this->_wp_page_slug,
849
-            'normal',
850
-            'high'
851
-        );
852
-        add_meta_box(
853
-            'edit-txn-attendees-mbox',
854
-            esc_html__('Attendees Registered in this Transaction', 'event_espresso'),
855
-            array($this, 'txn_attendees_meta_box'),
856
-            $this->_wp_page_slug,
857
-            'normal',
858
-            'high',
859
-            array('TXN_ID' => $this->_transaction->ID())
860
-        );
861
-        add_meta_box(
862
-            'edit-txn-registrant-mbox',
863
-            esc_html__('Primary Contact', 'event_espresso'),
864
-            array($this, 'txn_registrant_side_meta_box'),
865
-            $this->_wp_page_slug,
866
-            'side',
867
-            'high'
868
-        );
869
-        add_meta_box(
870
-            'edit-txn-billing-info-mbox',
871
-            esc_html__('Billing Information', 'event_espresso'),
872
-            array($this, 'txn_billing_info_side_meta_box'),
873
-            $this->_wp_page_slug,
874
-            'side',
875
-            'high'
876
-        );
877
-    }
878
-
879
-
880
-    /**
881
-     * Callback for transaction actions metabox.
882
-     *
883
-     * @param EE_Transaction|null $transaction
884
-     * @throws DomainException
885
-     * @throws EE_Error
886
-     * @throws InvalidArgumentException
887
-     * @throws InvalidDataTypeException
888
-     * @throws InvalidInterfaceException
889
-     * @throws ReflectionException
890
-     * @throws RuntimeException
891
-     */
892
-    public function getActionButtons(EE_Transaction $transaction = null)
893
-    {
894
-        $content = '';
895
-        $actions = array();
896
-        if (! $transaction instanceof EE_Transaction) {
897
-            return $content;
898
-        }
899
-        /** @var EE_Registration $primary_registration */
900
-        $primary_registration = $transaction->primary_registration();
901
-        $attendee = $primary_registration instanceof EE_Registration
902
-            ? $primary_registration->attendee()
903
-            : null;
904
-
905
-        if ($attendee instanceof EE_Attendee
906
-            && EE_Registry::instance()->CAP->current_user_can(
907
-                'ee_send_message',
908
-                'espresso_transactions_send_payment_reminder'
909
-            )
910
-        ) {
911
-            $actions['payment_reminder'] =
912
-                EEH_MSG_Template::is_mt_active('payment_reminder')
913
-                && $this->_transaction->get('STS_ID') !== EEM_Transaction::complete_status_code
914
-                && $this->_transaction->get('STS_ID') !== EEM_Transaction::overpaid_status_code
915
-                    ? EEH_Template::get_button_or_link(
916
-                        EE_Admin_Page::add_query_args_and_nonce(
917
-                            array(
918
-                                'action'      => 'send_payment_reminder',
919
-                                'TXN_ID'      => $this->_transaction->ID(),
920
-                                'redirect_to' => 'view_transaction',
921
-                            ),
922
-                            TXN_ADMIN_URL
923
-                        ),
924
-                        esc_html__(' Send Payment Reminder', 'event_espresso'),
925
-                        'button secondary-button',
926
-                        'dashicons dashicons-email-alt'
927
-                    )
928
-                    : '';
929
-        }
930
-
931
-        if ($primary_registration instanceof EE_Registration
932
-            && EEH_MSG_Template::is_mt_active('receipt')
933
-        ) {
934
-            $actions['receipt'] = EEH_Template::get_button_or_link(
935
-                $primary_registration->receipt_url(),
936
-                esc_html__('View Receipt', 'event_espresso'),
937
-                'button secondary-button',
938
-                'dashicons dashicons-media-default'
939
-            );
940
-        }
941
-
942
-        if ($primary_registration instanceof EE_Registration
943
-            && EEH_MSG_Template::is_mt_active('invoice')
944
-        ) {
945
-            $actions['invoice'] = EEH_Template::get_button_or_link(
946
-                $primary_registration->invoice_url(),
947
-                esc_html__('View Invoice', 'event_espresso'),
948
-                'button secondary-button',
949
-                'dashicons dashicons-media-spreadsheet'
950
-            );
951
-        }
952
-        $actions = array_filter(
953
-            apply_filters('FHEE__Transactions_Admin_Page__getActionButtons__actions', $actions, $transaction)
954
-        );
955
-        if ($actions) {
956
-            $content = '<ul>';
957
-            $content .= '<li>' . implode('</li><li>', $actions) . '</li>';
958
-            $content .= '</uL>';
959
-        }
960
-        return $content;
961
-    }
962
-
963
-
964
-    /**
965
-     * txn_details_meta_box
966
-     * generates HTML for the Transaction main meta box
967
-     *
968
-     * @return void
969
-     * @throws DomainException
970
-     * @throws EE_Error
971
-     * @throws InvalidArgumentException
972
-     * @throws InvalidDataTypeException
973
-     * @throws InvalidInterfaceException
974
-     * @throws RuntimeException
975
-     * @throws ReflectionException
976
-     */
977
-    public function txn_details_meta_box()
978
-    {
979
-        $this->_set_transaction_object();
980
-        $this->_template_args['TXN_ID']   = $this->_transaction->ID();
981
-        $this->_template_args['attendee'] = $this->_transaction->primary_registration() instanceof EE_Registration
982
-            ? $this->_transaction->primary_registration()->attendee()
983
-            : null;
984
-        $this->_template_args['can_edit_payments'] = EE_Registry::instance()->CAP->current_user_can(
985
-            'ee_edit_payments',
986
-            'apply_payment_or_refund_from_registration_details'
987
-        );
988
-        $this->_template_args['can_delete_payments'] = EE_Registry::instance()->CAP->current_user_can(
989
-            'ee_delete_payments',
990
-            'delete_payment_from_registration_details'
991
-        );
992
-
993
-        //get line table
994
-        EEH_Autoloader::register_line_item_display_autoloaders();
995
-        $Line_Item_Display                       = new EE_Line_Item_Display(
996
-            'admin_table',
997
-            'EE_Admin_Table_Line_Item_Display_Strategy'
998
-        );
999
-        $this->_template_args['line_item_table'] = $Line_Item_Display->display_line_item(
1000
-            $this->_transaction->total_line_item()
1001
-        );
1002
-        $this->_template_args['REG_code']        = $this->_transaction->get_first_related('Registration')
1003
-                                                                      ->get('REG_code');
1004
-
1005
-        // process taxes
1006
-        $taxes                         = $this->_transaction->get_many_related(
1007
-            'Line_Item',
1008
-            array(array('LIN_type' => EEM_Line_Item::type_tax))
1009
-        );
1010
-        $this->_template_args['taxes'] = ! empty($taxes) ? $taxes : false;
1011
-
1012
-        $this->_template_args['grand_total']     = EEH_Template::format_currency(
1013
-            $this->_transaction->get('TXN_total'),
1014
-            false,
1015
-            false
1016
-        );
1017
-        $this->_template_args['grand_raw_total'] = $this->_transaction->get('TXN_total');
1018
-        $this->_template_args['TXN_status']      = $this->_transaction->get('STS_ID');
1019
-
1020
-        // process payment details
1021
-        $payments = $this->_transaction->get_many_related('Payment');
1022
-        if (! empty($payments)) {
1023
-            $this->_template_args['payments']              = $payments;
1024
-            $this->_template_args['existing_reg_payments'] = $this->_get_registration_payment_IDs($payments);
1025
-        } else {
1026
-            $this->_template_args['payments']              = false;
1027
-            $this->_template_args['existing_reg_payments'] = array();
1028
-        }
1029
-
1030
-        $this->_template_args['edit_payment_url']   = add_query_arg(array('action' => 'edit_payment'), TXN_ADMIN_URL);
1031
-        $this->_template_args['delete_payment_url'] = add_query_arg(
1032
-            array('action' => 'espresso_delete_payment'),
1033
-            TXN_ADMIN_URL
1034
-        );
1035
-
1036
-        if (isset($txn_details['invoice_number'])) {
1037
-            $this->_template_args['txn_details']['invoice_number']['value'] = $this->_template_args['REG_code'];
1038
-            $this->_template_args['txn_details']['invoice_number']['label'] = esc_html__(
1039
-                'Invoice Number',
1040
-                'event_espresso'
1041
-            );
1042
-        }
1043
-
1044
-        $this->_template_args['txn_details']['registration_session']['value'] = $this->_transaction
1045
-            ->get_first_related('Registration')
1046
-            ->get('REG_session');
1047
-        $this->_template_args['txn_details']['registration_session']['label'] = esc_html__(
1048
-            'Registration Session',
1049
-            'event_espresso'
1050
-        );
1051
-
1052
-        $this->_template_args['txn_details']['ip_address']['value'] = isset($this->_session['ip_address'])
1053
-            ? $this->_session['ip_address']
1054
-            : '';
1055
-        $this->_template_args['txn_details']['ip_address']['label'] = esc_html__(
1056
-            'Transaction placed from IP',
1057
-            'event_espresso'
1058
-        );
1059
-
1060
-        $this->_template_args['txn_details']['user_agent']['value'] = isset($this->_session['user_agent'])
1061
-            ? $this->_session['user_agent']
1062
-            : '';
1063
-        $this->_template_args['txn_details']['user_agent']['label'] = esc_html__(
1064
-            'Registrant User Agent',
1065
-            'event_espresso'
1066
-        );
1067
-
1068
-        $reg_steps = '<ul>';
1069
-        foreach ($this->_transaction->reg_steps() as $reg_step => $reg_step_status) {
1070
-            if ($reg_step_status === true) {
1071
-                $reg_steps .= '<li style="color:#70cc50">'
1072
-                              . sprintf(
1073
-                                  esc_html__('%1$s : Completed', 'event_espresso'),
1074
-                                  ucwords(str_replace('_', ' ', $reg_step))
1075
-                              )
1076
-                              . '</li>';
1077
-            } elseif (is_numeric($reg_step_status) && $reg_step_status !== false) {
1078
-                $reg_steps .= '<li style="color:#2EA2CC">'
1079
-                              . sprintf(
1080
-                                  esc_html__('%1$s : Initiated %2$s', 'event_espresso'),
1081
-                                  ucwords(str_replace('_', ' ', $reg_step)),
1082
-                                  date(
1083
-                                      get_option('date_format') . ' ' . get_option('time_format'),
1084
-                                      ($reg_step_status + (get_option('gmt_offset') * HOUR_IN_SECONDS))
1085
-                                  )
1086
-                              )
1087
-                              . '</li>';
1088
-            } else {
1089
-                $reg_steps .= '<li style="color:#E76700">'
1090
-                              . sprintf(
1091
-                                  esc_html__('%1$s : Never Initiated', 'event_espresso'),
1092
-                                  ucwords(str_replace('_', ' ', $reg_step))
1093
-                              )
1094
-                              . '</li>';
1095
-            }
1096
-        }
1097
-        $reg_steps                                                 .= '</ul>';
1098
-        $this->_template_args['txn_details']['reg_steps']['value'] = $reg_steps;
1099
-        $this->_template_args['txn_details']['reg_steps']['label'] = esc_html__(
1100
-            'Registration Step Progress',
1101
-            'event_espresso'
1102
-        );
1103
-
1104
-
1105
-        $this->_get_registrations_to_apply_payment_to();
1106
-        $this->_get_payment_methods($payments);
1107
-        $this->_get_payment_status_array();
1108
-        $this->_get_reg_status_selection(); //sets up the template args for the reg status array for the transaction.
1109
-
1110
-        $this->_template_args['transaction_form_url']    = add_query_arg(array(
1111
-            'action'  => 'edit_transaction',
1112
-            'process' => 'transaction',
1113
-        ), TXN_ADMIN_URL);
1114
-        $this->_template_args['apply_payment_form_url']  = add_query_arg(array(
1115
-            'page'   => 'espresso_transactions',
1116
-            'action' => 'espresso_apply_payment',
1117
-        ), WP_AJAX_URL);
1118
-        $this->_template_args['delete_payment_form_url'] = add_query_arg(array(
1119
-            'page'   => 'espresso_transactions',
1120
-            'action' => 'espresso_delete_payment',
1121
-        ), WP_AJAX_URL);
1122
-
1123
-        $this->_template_args['action_buttons'] = $this->getActionButtons($this->_transaction);
1124
-
1125
-        // 'espresso_delete_payment_nonce'
1126
-
1127
-        $template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_txn_details.template.php';
1128
-        echo EEH_Template::display_template($template_path, $this->_template_args, true);
1129
-    }
1130
-
1131
-
1132
-    /**
1133
-     * _get_registration_payment_IDs
1134
-     *    generates an array of Payment IDs and their corresponding Registration IDs
1135
-     *
1136
-     * @access protected
1137
-     * @param EE_Payment[] $payments
1138
-     * @return array
1139
-     * @throws EE_Error
1140
-     * @throws InvalidArgumentException
1141
-     * @throws InvalidDataTypeException
1142
-     * @throws InvalidInterfaceException
1143
-     * @throws ReflectionException
1144
-     */
1145
-    protected function _get_registration_payment_IDs($payments = array())
1146
-    {
1147
-        $existing_reg_payments = array();
1148
-        // get all reg payments for these payments
1149
-        $reg_payments = EEM_Registration_Payment::instance()->get_all(array(
1150
-            array(
1151
-                'PAY_ID' => array(
1152
-                    'IN',
1153
-                    array_keys($payments),
1154
-                ),
1155
-            ),
1156
-        ));
1157
-        if (! empty($reg_payments)) {
1158
-            foreach ($payments as $payment) {
1159
-                if (! $payment instanceof EE_Payment) {
1160
-                    continue;
1161
-                } elseif (! isset($existing_reg_payments[$payment->ID()])) {
1162
-                    $existing_reg_payments[$payment->ID()] = array();
1163
-                }
1164
-                foreach ($reg_payments as $reg_payment) {
1165
-                    if ($reg_payment instanceof EE_Registration_Payment
1166
-                        && $reg_payment->payment_ID() === $payment->ID()
1167
-                    ) {
1168
-                        $existing_reg_payments[$payment->ID()][] = $reg_payment->registration_ID();
1169
-                    }
1170
-                }
1171
-            }
1172
-        }
1173
-
1174
-        return $existing_reg_payments;
1175
-    }
1176
-
1177
-
1178
-    /**
1179
-     * _get_registrations_to_apply_payment_to
1180
-     *    generates HTML for displaying a series of checkboxes in the admin payment modal window
1181
-     * which allows the admin to only apply the payment to the specific registrations
1182
-     *
1183
-     * @access protected
1184
-     * @return void
1185
-     * @throws \EE_Error
1186
-     */
1187
-    protected function _get_registrations_to_apply_payment_to()
1188
-    {
1189
-        // we want any registration with an active status (ie: not deleted or cancelled)
1190
-        $query_params                      = array(
1191
-            array(
1192
-                'STS_ID' => array(
1193
-                    'IN',
1194
-                    array(
1195
-                        EEM_Registration::status_id_approved,
1196
-                        EEM_Registration::status_id_pending_payment,
1197
-                        EEM_Registration::status_id_not_approved,
1198
-                    ),
1199
-                ),
1200
-            ),
1201
-        );
1202
-        $registrations_to_apply_payment_to = EEH_HTML::br()
1203
-                                             . EEH_HTML::div(
1204
-                                                 '',
1205
-                                                 'txn-admin-apply-payment-to-registrations-dv',
1206
-                                                 '',
1207
-                                                 'clear: both; margin: 1.5em 0 0; display: none;'
1208
-                                             );
1209
-        $registrations_to_apply_payment_to .= EEH_HTML::br() . EEH_HTML::div('', '', 'admin-primary-mbox-tbl-wrap');
1210
-        $registrations_to_apply_payment_to .= EEH_HTML::table('', '', 'admin-primary-mbox-tbl');
1211
-        $registrations_to_apply_payment_to .= EEH_HTML::thead(
1212
-            EEH_HTML::tr(
1213
-                EEH_HTML::th(esc_html__('ID', 'event_espresso')) .
1214
-                EEH_HTML::th(esc_html__('Registrant', 'event_espresso')) .
1215
-                EEH_HTML::th(esc_html__('Ticket', 'event_espresso')) .
1216
-                EEH_HTML::th(esc_html__('Event', 'event_espresso')) .
1217
-                EEH_HTML::th(esc_html__('Paid', 'event_espresso'), '', 'txn-admin-payment-paid-td jst-cntr') .
1218
-                EEH_HTML::th(esc_html__('Owing', 'event_espresso'), '', 'txn-admin-payment-owing-td jst-cntr') .
1219
-                EEH_HTML::th(esc_html__('Apply', 'event_espresso'), '', 'jst-cntr')
1220
-            )
1221
-        );
1222
-        $registrations_to_apply_payment_to .= EEH_HTML::tbody();
1223
-        // get registrations for TXN
1224
-        $registrations = $this->_transaction->registrations($query_params);
1225
-        $existing_reg_payments = $this->_template_args['existing_reg_payments'];
1226
-        foreach ($registrations as $registration) {
1227
-            if ($registration instanceof EE_Registration) {
1228
-                $attendee_name                     = $registration->attendee() instanceof EE_Attendee
1229
-                    ? $registration->attendee()->full_name()
1230
-                    : esc_html__('Unknown Attendee', 'event_espresso');
1231
-                $owing                             = $registration->final_price() - $registration->paid();
1232
-                $taxable                           = $registration->ticket()->taxable()
1233
-                    ? ' <span class="smaller-text lt-grey-text"> ' . esc_html__('+ tax', 'event_espresso') . '</span>'
1234
-                    : '';
1235
-                $checked = empty($existing_reg_payments) || in_array($registration->ID(), $existing_reg_payments)
1236
-                    ? ' checked="checked"'
1237
-                    : '';
1238
-                $disabled                          = $registration->final_price() > 0 ? '' : ' disabled';
1239
-                $registrations_to_apply_payment_to .= EEH_HTML::tr(
1240
-                    EEH_HTML::td($registration->ID()) .
1241
-                    EEH_HTML::td($attendee_name) .
1242
-                    EEH_HTML::td(
1243
-                        $registration->ticket()->name() . ' : ' . $registration->ticket()->pretty_price() . $taxable
1244
-                    ) .
1245
-                    EEH_HTML::td($registration->event_name()) .
1246
-                    EEH_HTML::td($registration->pretty_paid(), '', 'txn-admin-payment-paid-td jst-cntr') .
1247
-                    EEH_HTML::td(EEH_Template::format_currency($owing), '', 'txn-admin-payment-owing-td jst-cntr') .
1248
-                    EEH_HTML::td(
1249
-                        '<input type="checkbox" value="' . $registration->ID()
1250
-                        . '" name="txn_admin_payment[registrations]"'
1251
-                        . $checked . $disabled . '>',
1252
-                        '',
1253
-                        'jst-cntr'
1254
-                    ),
1255
-                    'apply-payment-registration-row-' . $registration->ID()
1256
-                );
1257
-            }
1258
-        }
1259
-        $registrations_to_apply_payment_to                         .= EEH_HTML::tbodyx();
1260
-        $registrations_to_apply_payment_to                         .= EEH_HTML::tablex();
1261
-        $registrations_to_apply_payment_to                         .= EEH_HTML::divx();
1262
-        $registrations_to_apply_payment_to                         .= EEH_HTML::p(
1263
-            esc_html__(
1264
-                'The payment will only be applied to the registrations that have a check mark in their corresponding check box. Checkboxes for free registrations have been disabled.',
1265
-                'event_espresso'
1266
-            ),
1267
-            '',
1268
-            'clear description'
1269
-        );
1270
-        $registrations_to_apply_payment_to                         .= EEH_HTML::divx();
1271
-        $this->_template_args['registrations_to_apply_payment_to'] = $registrations_to_apply_payment_to;
1272
-    }
1273
-
1274
-
1275
-    /**
1276
-     * _get_reg_status_selection
1277
-     *
1278
-     * @todo   this will need to be adjusted either once MER comes along OR we move default reg status to tickets
1279
-     *         instead of events.
1280
-     * @access protected
1281
-     * @return void
1282
-     * @throws EE_Error
1283
-     */
1284
-    protected function _get_reg_status_selection()
1285
-    {
1286
-        //first get all possible statuses
1287
-        $statuses = EEM_Registration::reg_status_array(array(), true);
1288
-        //let's add a "don't change" option.
1289
-        $status_array['NAN']                                 = esc_html__('Leave the Same', 'event_espresso');
1290
-        $status_array                                        = array_merge($status_array, $statuses);
1291
-        $this->_template_args['status_change_select']        = EEH_Form_Fields::select_input(
1292
-            'txn_reg_status_change[reg_status]',
1293
-            $status_array,
1294
-            'NAN',
1295
-            'id="txn-admin-payment-reg-status-inp"',
1296
-            'txn-reg-status-change-reg-status'
1297
-        );
1298
-        $this->_template_args['delete_status_change_select'] = EEH_Form_Fields::select_input(
1299
-            'delete_txn_reg_status_change[reg_status]',
1300
-            $status_array,
1301
-            'NAN',
1302
-            'delete-txn-admin-payment-reg-status-inp',
1303
-            'delete-txn-reg-status-change-reg-status'
1304
-        );
1305
-    }
1306
-
1307
-
1308
-    /**
1309
-     *    _get_payment_methods
1310
-     * Gets all the payment methods available generally, or the ones that are already
1311
-     * selected on these payments (in case their payment methods are no longer active).
1312
-     * Has the side-effect of updating the template args' payment_methods item
1313
-     *
1314
-     * @access private
1315
-     * @param EE_Payment[] to show on this page
1316
-     * @return void
1317
-     * @throws EE_Error
1318
-     * @throws InvalidArgumentException
1319
-     * @throws InvalidDataTypeException
1320
-     * @throws InvalidInterfaceException
1321
-     * @throws ReflectionException
1322
-     */
1323
-    private function _get_payment_methods($payments = array())
1324
-    {
1325
-        $payment_methods_of_payments = array();
1326
-        foreach ($payments as $payment) {
1327
-            if ($payment instanceof EE_Payment) {
1328
-                $payment_methods_of_payments[] = $payment->get('PMD_ID');
1329
-            }
1330
-        }
1331
-        if ($payment_methods_of_payments) {
1332
-            $query_args = array(
1333
-                array(
1334
-                    'OR*payment_method_for_payment' => array(
1335
-                        'PMD_ID'    => array('IN', $payment_methods_of_payments),
1336
-                        'PMD_scope' => array('LIKE', '%' . EEM_Payment_Method::scope_admin . '%'),
1337
-                    ),
1338
-                ),
1339
-            );
1340
-        } else {
1341
-            $query_args = array(array('PMD_scope' => array('LIKE', '%' . EEM_Payment_Method::scope_admin . '%')));
1342
-        }
1343
-        $this->_template_args['payment_methods'] = EEM_Payment_Method::instance()->get_all($query_args);
1344
-    }
1345
-
1346
-
1347
-    /**
1348
-     * txn_attendees_meta_box
1349
-     *    generates HTML for the Attendees Transaction main meta box
1350
-     *
1351
-     * @access public
1352
-     * @param WP_Post $post
1353
-     * @param array   $metabox
1354
-     * @return void
1355
-     * @throws DomainException
1356
-     * @throws EE_Error
1357
-     */
1358
-    public function txn_attendees_meta_box($post, $metabox = array('args' => array()))
1359
-    {
1360
-
1361
-        /** @noinspection NonSecureExtractUsageInspection */
1362
-        extract($metabox['args']);
1363
-        $this->_template_args['post']            = $post;
1364
-        $this->_template_args['event_attendees'] = array();
1365
-        // process items in cart
1366
-        $line_items = $this->_transaction->get_many_related(
1367
-            'Line_Item',
1368
-            array(array('LIN_type' => 'line-item'))
1369
-        );
1370
-        if (! empty($line_items)) {
1371
-            foreach ($line_items as $item) {
1372
-                if ($item instanceof EE_Line_Item) {
1373
-                    switch ($item->OBJ_type()) {
1374
-                        case 'Event':
1375
-                            break;
1376
-                        case 'Ticket':
1377
-                            $ticket = $item->ticket();
1378
-                            //right now we're only handling tickets here.
1379
-                            //Cause its expected that only tickets will have attendees right?
1380
-                            if (! $ticket instanceof EE_Ticket) {
1381
-                                continue;
1382
-                            }
1383
-                            try {
1384
-                                $event_name = $ticket->get_event_name();
1385
-                            } catch (Exception $e) {
1386
-                                EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1387
-                                $event_name = esc_html__('Unknown Event', 'event_espresso');
1388
-                            }
1389
-                            $event_name   .= ' - ' . $item->get('LIN_name');
1390
-                            $ticket_price = EEH_Template::format_currency($item->get('LIN_unit_price'));
1391
-                            // now get all of the registrations for this transaction that use this ticket
1392
-                            $registrations = $ticket->get_many_related(
1393
-                                'Registration',
1394
-                                array(array('TXN_ID' => $this->_transaction->ID()))
1395
-                            );
1396
-                            foreach ($registrations as $registration) {
1397
-                                if (! $registration instanceof EE_Registration) {
1398
-                                    continue;
1399
-                                }
1400
-                                $this->_template_args['event_attendees'][$registration->ID()]['STS_ID']
1401
-                                    = $registration->status_ID();
1402
-                                $this->_template_args['event_attendees'][$registration->ID()]['att_num']
1403
-                                    = $registration->count();
1404
-                                $this->_template_args['event_attendees'][$registration->ID()]['event_ticket_name']
1405
-                                    = $event_name;
1406
-                                $this->_template_args['event_attendees'][$registration->ID()]['ticket_price']
1407
-                                    = $ticket_price;
1408
-                                // attendee info
1409
-                                $attendee = $registration->get_first_related('Attendee');
1410
-                                if ($attendee instanceof EE_Attendee) {
1411
-                                    $this->_template_args['event_attendees'][$registration->ID()]['att_id']
1412
-                                        = $attendee->ID();
1413
-                                    $this->_template_args['event_attendees'][$registration->ID()]['attendee']
1414
-                                        = $attendee->full_name();
1415
-                                    $this->_template_args['event_attendees'][$registration->ID()]['email']
1416
-                                        = '<a href="mailto:' . $attendee->email() . '?subject=' . $event_name
1417
-                                          . esc_html__(
1418
-                                              ' Event',
1419
-                                              'event_espresso'
1420
-                                          )
1421
-                                          . '">' . $attendee->email() . '</a>';
1422
-                                    $this->_template_args['event_attendees'][$registration->ID()]['address']
1423
-                                        = EEH_Address::format($attendee, 'inline', false, false);
1424
-                                } else {
1425
-                                    $this->_template_args['event_attendees'][$registration->ID()]['att_id']   = '';
1426
-                                    $this->_template_args['event_attendees'][$registration->ID()]['attendee'] = '';
1427
-                                    $this->_template_args['event_attendees'][$registration->ID()]['email']    = '';
1428
-                                    $this->_template_args['event_attendees'][$registration->ID()]['address']  = '';
1429
-                                }
1430
-                            }
1431
-                            break;
1432
-
1433
-                    }
1434
-                }
1435
-            }
1436
-
1437
-            $this->_template_args['transaction_form_url'] = add_query_arg(
1438
-                array(
1439
-                    'action'  => 'edit_transaction',
1440
-                    'process' => 'attendees',
1441
-                ),
1442
-                TXN_ADMIN_URL
1443
-            );
1444
-            echo EEH_Template::display_template(
1445
-                TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_attendees.template.php',
1446
-                $this->_template_args,
1447
-                true
1448
-            );
1449
-
1450
-        } else {
1451
-            echo sprintf(
1452
-                esc_html__(
1453
-                    '%1$sFor some reason, there are no attendees registered for this transaction. Likely the registration was abandoned in process.%2$s',
1454
-                    'event_espresso'
1455
-                ),
1456
-                '<p class="important-notice">',
1457
-                '</p>'
1458
-            );
1459
-        }
1460
-    }
1461
-
1462
-
1463
-    /**
1464
-     * txn_registrant_side_meta_box
1465
-     * generates HTML for the Edit Transaction side meta box
1466
-     *
1467
-     * @access public
1468
-     * @return void
1469
-     * @throws DomainException
1470
-     * @throws EE_Error
1471
-     * @throws InvalidArgumentException
1472
-     * @throws InvalidDataTypeException
1473
-     * @throws InvalidInterfaceException
1474
-     * @throws ReflectionException
1475
-     */
1476
-    public function txn_registrant_side_meta_box()
1477
-    {
1478
-        $primary_att = $this->_transaction->primary_registration() instanceof EE_Registration
1479
-            ? $this->_transaction->primary_registration()->get_first_related('Attendee')
1480
-            : null;
1481
-        if (! $primary_att instanceof EE_Attendee) {
1482
-            $this->_template_args['no_attendee_message'] = esc_html__(
1483
-                'There is no attached contact for this transaction.  The transaction either failed due to an error or was abandoned.',
1484
-                'event_espresso'
1485
-            );
1486
-            $primary_att                                 = EEM_Attendee::instance()->create_default_object();
1487
-        }
1488
-        $this->_template_args['ATT_ID']            = $primary_att->ID();
1489
-        $this->_template_args['prime_reg_fname']   = $primary_att->fname();
1490
-        $this->_template_args['prime_reg_lname']   = $primary_att->lname();
1491
-        $this->_template_args['prime_reg_email']   = $primary_att->email();
1492
-        $this->_template_args['prime_reg_phone']   = $primary_att->phone();
1493
-        $this->_template_args['edit_attendee_url'] = EE_Admin_Page::add_query_args_and_nonce(array(
1494
-            'action' => 'edit_attendee',
1495
-            'post'   => $primary_att->ID(),
1496
-        ), REG_ADMIN_URL);
1497
-        // get formatted address for registrant
1498
-        $this->_template_args['formatted_address'] = EEH_Address::format($primary_att);
1499
-        echo EEH_Template::display_template(
1500
-            TXN_TEMPLATE_PATH . 'txn_admin_details_side_meta_box_registrant.template.php',
1501
-            $this->_template_args,
1502
-            true
1503
-        );
1504
-    }
1505
-
1506
-
1507
-    /**
1508
-     * txn_billing_info_side_meta_box
1509
-     *    generates HTML for the Edit Transaction side meta box
1510
-     *
1511
-     * @access public
1512
-     * @return void
1513
-     * @throws DomainException
1514
-     * @throws EE_Error
1515
-     */
1516
-    public function txn_billing_info_side_meta_box()
1517
-    {
1518
-
1519
-        $this->_template_args['billing_form']     = $this->_transaction->billing_info();
1520
-        $this->_template_args['billing_form_url'] = add_query_arg(
1521
-            array('action' => 'edit_transaction', 'process' => 'billing'),
1522
-            TXN_ADMIN_URL
1523
-        );
1524
-
1525
-        $template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_side_meta_box_billing_info.template.php';
1526
-        echo EEH_Template::display_template($template_path, $this->_template_args, true);/**/
1527
-    }
1528
-
1529
-
1530
-    /**
1531
-     * apply_payments_or_refunds
1532
-     *    registers a payment or refund made towards a transaction
1533
-     *
1534
-     * @access public
1535
-     * @return void
1536
-     * @throws EE_Error
1537
-     * @throws InvalidArgumentException
1538
-     * @throws ReflectionException
1539
-     * @throws RuntimeException
1540
-     * @throws InvalidDataTypeException
1541
-     * @throws InvalidInterfaceException
1542
-     */
1543
-    public function apply_payments_or_refunds()
1544
-    {
1545
-        $json_response_data = array('return_data' => false);
1546
-        $valid_data         = $this->_validate_payment_request_data();
1547
-        $has_access = EE_Registry::instance()->CAP->current_user_can(
1548
-            'ee_edit_payments',
1549
-            'apply_payment_or_refund_from_registration_details'
1550
-        );
1551
-        if (! empty($valid_data) && $has_access) {
1552
-            $PAY_ID = $valid_data['PAY_ID'];
1553
-            //save  the new payment
1554
-            $payment = $this->_create_payment_from_request_data($valid_data);
1555
-            // get the TXN for this payment
1556
-            $transaction = $payment->transaction();
1557
-            // verify transaction
1558
-            if ($transaction instanceof EE_Transaction) {
1559
-                // calculate_total_payments_and_update_status
1560
-                $this->_process_transaction_payments($transaction);
1561
-                $REG_IDs = $this->_get_REG_IDs_to_apply_payment_to($payment);
1562
-                $this->_remove_existing_registration_payments($payment, $PAY_ID);
1563
-                // apply payment to registrations (if applicable)
1564
-                if (! empty($REG_IDs)) {
1565
-                    $this->_update_registration_payments($transaction, $payment, $REG_IDs);
1566
-                    $this->_maybe_send_notifications();
1567
-                    // now process status changes for the same registrations
1568
-                    $this->_process_registration_status_change($transaction, $REG_IDs);
1569
-                }
1570
-                $this->_maybe_send_notifications($payment);
1571
-                //prepare to render page
1572
-                $json_response_data['return_data'] = $this->_build_payment_json_response($payment, $REG_IDs);
1573
-                do_action(
1574
-                    'AHEE__Transactions_Admin_Page__apply_payments_or_refund__after_recording',
1575
-                    $transaction,
1576
-                    $payment
1577
-                );
1578
-            } else {
1579
-                EE_Error::add_error(
1580
-                    esc_html__(
1581
-                        'A valid Transaction for this payment could not be retrieved.',
1582
-                        'event_espresso'
1583
-                    ),
1584
-                    __FILE__,
1585
-                    __FUNCTION__,
1586
-                    __LINE__
1587
-                );
1588
-            }
1589
-        } else {
1590
-            if ($has_access) {
1591
-                EE_Error::add_error(
1592
-                    esc_html__(
1593
-                        'The payment form data could not be processed. Please try again.',
1594
-                        'event_espresso'
1595
-                    ),
1596
-                    __FILE__,
1597
-                    __FUNCTION__,
1598
-                    __LINE__
1599
-                );
1600
-            } else {
1601
-                EE_Error::add_error(
1602
-                    esc_html__(
1603
-                        'You do not have access to apply payments or refunds to a registration.',
1604
-                        'event_espresso'
1605
-                    ),
1606
-                    __FILE__,
1607
-                    __FUNCTION__,
1608
-                    __LINE__
1609
-                );
1610
-            }
1611
-        }
1612
-        $notices              = EE_Error::get_notices(
1613
-            false,
1614
-            false,
1615
-            false
1616
-        );
1617
-        $this->_template_args = array(
1618
-            'data'    => $json_response_data,
1619
-            'error'   => $notices['errors'],
1620
-            'success' => $notices['success'],
1621
-        );
1622
-        $this->_return_json();
1623
-    }
1624
-
1625
-
1626
-    /**
1627
-     * _validate_payment_request_data
1628
-     *
1629
-     * @return array
1630
-     * @throws EE_Error
1631
-     */
1632
-    protected function _validate_payment_request_data()
1633
-    {
1634
-        if (! isset($this->_req_data['txn_admin_payment'])) {
1635
-            return false;
1636
-        }
1637
-        $payment_form = $this->_generate_payment_form_section();
1638
-        try {
1639
-            if ($payment_form->was_submitted()) {
1640
-                $payment_form->receive_form_submission();
1641
-                if (! $payment_form->is_valid()) {
1642
-                    $submission_error_messages = array();
1643
-                    foreach ($payment_form->get_validation_errors_accumulated() as $validation_error) {
1644
-                        if ($validation_error instanceof EE_Validation_Error) {
1645
-                            $submission_error_messages[] = sprintf(
1646
-                                _x('%s : %s', 'Form Section Name : Form Validation Error', 'event_espresso'),
1647
-                                $validation_error->get_form_section()->html_label_text(),
1648
-                                $validation_error->getMessage()
1649
-                            );
1650
-                        }
1651
-                    }
1652
-                    EE_Error::add_error(
1653
-                        implode('<br />', $submission_error_messages),
1654
-                        __FILE__,
1655
-                        __FUNCTION__,
1656
-                        __LINE__
1657
-                    );
1658
-
1659
-                    return array();
1660
-                }
1661
-            }
1662
-        } catch (EE_Error $e) {
1663
-            EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1664
-
1665
-            return array();
1666
-        }
1667
-
1668
-        return $payment_form->valid_data();
1669
-    }
1670
-
1671
-
1672
-    /**
1673
-     * _generate_payment_form_section
1674
-     *
1675
-     * @return EE_Form_Section_Proper
1676
-     * @throws EE_Error
1677
-     */
1678
-    protected function _generate_payment_form_section()
1679
-    {
1680
-        return new EE_Form_Section_Proper(
1681
-            array(
1682
-                'name'        => 'txn_admin_payment',
1683
-                'subsections' => array(
1684
-                    'PAY_ID'          => new EE_Text_Input(
1685
-                        array(
1686
-                            'default'               => 0,
1687
-                            'required'              => false,
1688
-                            'html_label_text'       => esc_html__('Payment ID', 'event_espresso'),
1689
-                            'validation_strategies' => array(new EE_Int_Normalization()),
1690
-                        )
1691
-                    ),
1692
-                    'TXN_ID'          => new EE_Text_Input(
1693
-                        array(
1694
-                            'default'               => 0,
1695
-                            'required'              => true,
1696
-                            'html_label_text'       => esc_html__('Transaction ID', 'event_espresso'),
1697
-                            'validation_strategies' => array(new EE_Int_Normalization()),
1698
-                        )
1699
-                    ),
1700
-                    'type'            => new EE_Text_Input(
1701
-                        array(
1702
-                            'default'               => 1,
1703
-                            'required'              => true,
1704
-                            'html_label_text'       => esc_html__('Payment or Refund', 'event_espresso'),
1705
-                            'validation_strategies' => array(new EE_Int_Normalization()),
1706
-                        )
1707
-                    ),
1708
-                    'amount'          => new EE_Text_Input(
1709
-                        array(
1710
-                            'default'               => 0,
1711
-                            'required'              => true,
1712
-                            'html_label_text'       => esc_html__('Payment amount', 'event_espresso'),
1713
-                            'validation_strategies' => array(new EE_Float_Normalization()),
1714
-                        )
1715
-                    ),
1716
-                    'status'          => new EE_Text_Input(
1717
-                        array(
1718
-                            'default'         => EEM_Payment::status_id_approved,
1719
-                            'required'        => true,
1720
-                            'html_label_text' => esc_html__('Payment status', 'event_espresso'),
1721
-                        )
1722
-                    ),
1723
-                    'PMD_ID'          => new EE_Text_Input(
1724
-                        array(
1725
-                            'default'               => 2,
1726
-                            'required'              => true,
1727
-                            'html_label_text'       => esc_html__('Payment Method', 'event_espresso'),
1728
-                            'validation_strategies' => array(new EE_Int_Normalization()),
1729
-                        )
1730
-                    ),
1731
-                    'date'            => new EE_Text_Input(
1732
-                        array(
1733
-                            'default'         => time(),
1734
-                            'required'        => true,
1735
-                            'html_label_text' => esc_html__('Payment date', 'event_espresso'),
1736
-                        )
1737
-                    ),
1738
-                    'txn_id_chq_nmbr' => new EE_Text_Input(
1739
-                        array(
1740
-                            'default'               => '',
1741
-                            'required'              => false,
1742
-                            'html_label_text'       => esc_html__('Transaction or Cheque Number', 'event_espresso'),
1743
-                            'validation_strategies' => array(
1744
-                                new EE_Max_Length_Validation_Strategy(
1745
-                                    esc_html__('Input too long', 'event_espresso'),
1746
-                                    100
1747
-                                ),
1748
-                            ),
1749
-                        )
1750
-                    ),
1751
-                    'po_number'       => new EE_Text_Input(
1752
-                        array(
1753
-                            'default'               => '',
1754
-                            'required'              => false,
1755
-                            'html_label_text'       => esc_html__('Purchase Order Number', 'event_espresso'),
1756
-                            'validation_strategies' => array(
1757
-                                new EE_Max_Length_Validation_Strategy(
1758
-                                    esc_html__('Input too long', 'event_espresso'),
1759
-                                    100
1760
-                                ),
1761
-                            ),
1762
-                        )
1763
-                    ),
1764
-                    'accounting'      => new EE_Text_Input(
1765
-                        array(
1766
-                            'default'               => '',
1767
-                            'required'              => false,
1768
-                            'html_label_text'       => esc_html__('Extra Field for Accounting', 'event_espresso'),
1769
-                            'validation_strategies' => array(
1770
-                                new EE_Max_Length_Validation_Strategy(
1771
-                                    esc_html__('Input too long', 'event_espresso'),
1772
-                                    100
1773
-                                ),
1774
-                            ),
1775
-                        )
1776
-                    ),
1777
-                ),
1778
-            )
1779
-        );
1780
-    }
1781
-
1782
-
1783
-    /**
1784
-     * _create_payment_from_request_data
1785
-     *
1786
-     * @param array $valid_data
1787
-     * @return EE_Payment
1788
-     * @throws EE_Error
1789
-     */
1790
-    protected function _create_payment_from_request_data($valid_data)
1791
-    {
1792
-        $PAY_ID = $valid_data['PAY_ID'];
1793
-        // get payment amount
1794
-        $amount = $valid_data['amount'] ? abs($valid_data['amount']) : 0;
1795
-        // payments have a type value of 1 and refunds have a type value of -1
1796
-        // so multiplying amount by type will give a positive value for payments, and negative values for refunds
1797
-        $amount = $valid_data['type'] < 0 ? $amount * -1 : $amount;
1798
-        // for some reason the date string coming in has extra spaces between the date and time.  This fixes that.
1799
-        $date    = $valid_data['date']
1800
-            ? preg_replace('/\s+/', ' ', $valid_data['date'])
1801
-            : date('Y-m-d g:i a', current_time('timestamp'));
1802
-        $payment = EE_Payment::new_instance(
1803
-            array(
1804
-                'TXN_ID'              => $valid_data['TXN_ID'],
1805
-                'STS_ID'              => $valid_data['status'],
1806
-                'PAY_timestamp'       => $date,
1807
-                'PAY_source'          => EEM_Payment_Method::scope_admin,
1808
-                'PMD_ID'              => $valid_data['PMD_ID'],
1809
-                'PAY_amount'          => $amount,
1810
-                'PAY_txn_id_chq_nmbr' => $valid_data['txn_id_chq_nmbr'],
1811
-                'PAY_po_number'       => $valid_data['po_number'],
1812
-                'PAY_extra_accntng'   => $valid_data['accounting'],
1813
-                'PAY_details'         => $valid_data,
1814
-                'PAY_ID'              => $PAY_ID,
1815
-            ),
1816
-            '',
1817
-            array('Y-m-d', 'g:i a')
1818
-        );
1819
-
1820
-        if (! $payment->save()) {
1821
-            EE_Error::add_error(
1822
-                sprintf(
1823
-                    esc_html__('Payment %1$d has not been successfully saved to the database.', 'event_espresso'),
1824
-                    $payment->ID()
1825
-                ),
1826
-                __FILE__, __FUNCTION__, __LINE__
1827
-            );
1828
-        }
1829
-
1830
-        return $payment;
1831
-    }
1832
-
1833
-
1834
-    /**
1835
-     * _process_transaction_payments
1836
-     *
1837
-     * @param \EE_Transaction $transaction
1838
-     * @return void
1839
-     * @throws EE_Error
1840
-     * @throws InvalidArgumentException
1841
-     * @throws ReflectionException
1842
-     * @throws InvalidDataTypeException
1843
-     * @throws InvalidInterfaceException
1844
-     */
1845
-    protected function _process_transaction_payments(EE_Transaction $transaction)
1846
-    {
1847
-        /** @type EE_Transaction_Payments $transaction_payments */
1848
-        $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
1849
-        //update the transaction with this payment
1850
-        if ($transaction_payments->calculate_total_payments_and_update_status($transaction)) {
1851
-            EE_Error::add_success(esc_html__(
1852
-                'The payment has been processed successfully.', 'event_espresso'),
1853
-                __FILE__,
1854
-                __FUNCTION__,
1855
-                __LINE__
1856
-            );
1857
-        } else {
1858
-            EE_Error::add_error(
1859
-                esc_html__(
1860
-                    'The payment was processed successfully but the amount paid for the transaction was not updated.',
1861
-                    'event_espresso'
1862
-                )
1863
-                ,
1864
-                __FILE__,
1865
-                __FUNCTION__,
1866
-                __LINE__
1867
-            );
1868
-        }
1869
-    }
1870
-
1871
-
1872
-    /**
1873
-     * _get_REG_IDs_to_apply_payment_to
1874
-     * returns a list of registration IDs that the payment will apply to
1875
-     *
1876
-     * @param \EE_Payment $payment
1877
-     * @return array
1878
-     * @throws EE_Error
1879
-     */
1880
-    protected function _get_REG_IDs_to_apply_payment_to(EE_Payment $payment)
1881
-    {
1882
-        $REG_IDs = array();
1883
-        // grab array of IDs for specific registrations to apply changes to
1884
-        if (isset($this->_req_data['txn_admin_payment']['registrations'])) {
1885
-            $REG_IDs = (array)$this->_req_data['txn_admin_payment']['registrations'];
1886
-        }
1887
-        //nothing specified ? then get all reg IDs
1888
-        if (empty($REG_IDs)) {
1889
-            $registrations = $payment->transaction()->registrations();
1890
-            $REG_IDs       = ! empty($registrations)
1891
-                ? array_keys($registrations)
1892
-                : $this->_get_existing_reg_payment_REG_IDs($payment);
1893
-        }
1894
-
1895
-        // ensure that REG_IDs are integers and NOT strings
1896
-        return array_map('intval', $REG_IDs);
1897
-    }
1898
-
1899
-
1900
-    /**
1901
-     * @return array
1902
-     */
1903
-    public function existing_reg_payment_REG_IDs()
1904
-    {
1905
-        return $this->_existing_reg_payment_REG_IDs;
1906
-    }
1907
-
1908
-
1909
-    /**
1910
-     * @param array $existing_reg_payment_REG_IDs
1911
-     */
1912
-    public function set_existing_reg_payment_REG_IDs($existing_reg_payment_REG_IDs = null)
1913
-    {
1914
-        $this->_existing_reg_payment_REG_IDs = $existing_reg_payment_REG_IDs;
1915
-    }
1916
-
1917
-
1918
-    /**
1919
-     * _get_existing_reg_payment_REG_IDs
1920
-     * returns a list of registration IDs that the payment is currently related to
1921
-     * as recorded in the database
1922
-     *
1923
-     * @param \EE_Payment $payment
1924
-     * @return array
1925
-     * @throws EE_Error
1926
-     */
1927
-    protected function _get_existing_reg_payment_REG_IDs(EE_Payment $payment)
1928
-    {
1929
-        if ($this->existing_reg_payment_REG_IDs() === null) {
1930
-            // let's get any existing reg payment records for this payment
1931
-            $existing_reg_payment_REG_IDs = $payment->get_many_related('Registration');
1932
-            // but we only want the REG IDs, so grab the array keys
1933
-            $existing_reg_payment_REG_IDs = ! empty($existing_reg_payment_REG_IDs)
1934
-                ? array_keys($existing_reg_payment_REG_IDs)
1935
-                : array();
1936
-            $this->set_existing_reg_payment_REG_IDs($existing_reg_payment_REG_IDs);
1937
-        }
1938
-
1939
-        return $this->existing_reg_payment_REG_IDs();
1940
-    }
1941
-
1942
-
1943
-    /**
1944
-     * _remove_existing_registration_payments
1945
-     * this calculates the difference between existing relations
1946
-     * to the supplied payment and the new list registration IDs,
1947
-     * removes any related registrations that no longer apply,
1948
-     * and then updates the registration paid fields
1949
-     *
1950
-     * @param \EE_Payment $payment
1951
-     * @param int         $PAY_ID
1952
-     * @return bool;
1953
-     * @throws EE_Error
1954
-     * @throws InvalidArgumentException
1955
-     * @throws ReflectionException
1956
-     * @throws InvalidDataTypeException
1957
-     * @throws InvalidInterfaceException
1958
-     */
1959
-    protected function _remove_existing_registration_payments(EE_Payment $payment, $PAY_ID = 0)
1960
-    {
1961
-        // newly created payments will have nothing recorded for $PAY_ID
1962
-        if ($PAY_ID == 0) {
1963
-            return false;
1964
-        }
1965
-        $existing_reg_payment_REG_IDs = $this->_get_existing_reg_payment_REG_IDs($payment);
1966
-        if (empty($existing_reg_payment_REG_IDs)) {
1967
-            return false;
1968
-        }
1969
-        /** @type EE_Transaction_Payments $transaction_payments */
1970
-        $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
1971
-
1972
-        return $transaction_payments->delete_registration_payments_and_update_registrations(
1973
-            $payment,
1974
-            array(
1975
-                array(
1976
-                    'PAY_ID' => $payment->ID(),
1977
-                    'REG_ID' => array('IN', $existing_reg_payment_REG_IDs),
1978
-                ),
1979
-            )
1980
-        );
1981
-    }
1982
-
1983
-
1984
-    /**
1985
-     * _update_registration_payments
1986
-     * this applies the payments to the selected registrations
1987
-     * but only if they have not already been paid for
1988
-     *
1989
-     * @param  EE_Transaction $transaction
1990
-     * @param \EE_Payment     $payment
1991
-     * @param array           $REG_IDs
1992
-     * @return void
1993
-     * @throws EE_Error
1994
-     * @throws InvalidArgumentException
1995
-     * @throws ReflectionException
1996
-     * @throws RuntimeException
1997
-     * @throws InvalidDataTypeException
1998
-     * @throws InvalidInterfaceException
1999
-     */
2000
-    protected function _update_registration_payments(
2001
-        EE_Transaction $transaction,
2002
-        EE_Payment $payment,
2003
-        $REG_IDs = array()
2004
-    ) {
2005
-        // we can pass our own custom set of registrations to EE_Payment_Processor::process_registration_payments()
2006
-        // so let's do that using our set of REG_IDs from the form
2007
-        $registration_query_where_params = array(
2008
-            'REG_ID' => array('IN', $REG_IDs),
2009
-        );
2010
-        // but add in some conditions regarding payment,
2011
-        // so that we don't apply payments to registrations that are free or have already been paid for
2012
-        // but ONLY if the payment is NOT a refund ( ie: the payment amount is not negative )
2013
-        if (! $payment->is_a_refund()) {
2014
-            $registration_query_where_params['REG_final_price']  = array('!=', 0);
2015
-            $registration_query_where_params['REG_final_price*'] = array('!=', 'REG_paid', true);
2016
-        }
2017
-        $registrations = $transaction->registrations(array($registration_query_where_params));
2018
-        if (! empty($registrations)) {
2019
-            /** @type EE_Payment_Processor $payment_processor */
2020
-            $payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
2021
-            $payment_processor->process_registration_payments($transaction, $payment, $registrations);
2022
-        }
2023
-    }
2024
-
2025
-
2026
-    /**
2027
-     * _process_registration_status_change
2028
-     * This processes requested registration status changes for all the registrations
2029
-     * on a given transaction and (optionally) sends out notifications for the changes.
2030
-     *
2031
-     * @param  EE_Transaction $transaction
2032
-     * @param array           $REG_IDs
2033
-     * @return bool
2034
-     * @throws EE_Error
2035
-     * @throws InvalidArgumentException
2036
-     * @throws ReflectionException
2037
-     * @throws InvalidDataTypeException
2038
-     * @throws InvalidInterfaceException
2039
-     */
2040
-    protected function _process_registration_status_change(EE_Transaction $transaction, $REG_IDs = array())
2041
-    {
2042
-        // first if there is no change in status then we get out.
2043
-        if (
2044
-            ! isset($this->_req_data['txn_reg_status_change']['reg_status'])
2045
-            || $this->_req_data['txn_reg_status_change']['reg_status'] === 'NAN'
2046
-        ) {
2047
-            //no error message, no change requested, just nothing to do man.
2048
-            return false;
2049
-        }
2050
-        /** @type EE_Transaction_Processor $transaction_processor */
2051
-        $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
2052
-
2053
-        // made it here dude?  Oh WOW.  K, let's take care of changing the statuses
2054
-        return $transaction_processor->manually_update_registration_statuses(
2055
-            $transaction,
2056
-            sanitize_text_field($this->_req_data['txn_reg_status_change']['reg_status']),
2057
-            array(array('REG_ID' => array('IN', $REG_IDs)))
2058
-        );
2059
-    }
2060
-
2061
-
2062
-    /**
2063
-     * _build_payment_json_response
2064
-     *
2065
-     * @access public
2066
-     * @param \EE_Payment $payment
2067
-     * @param array       $REG_IDs
2068
-     * @param bool | null $delete_txn_reg_status_change
2069
-     * @return array
2070
-     * @throws EE_Error
2071
-     * @throws InvalidArgumentException
2072
-     * @throws InvalidDataTypeException
2073
-     * @throws InvalidInterfaceException
2074
-     * @throws ReflectionException
2075
-     */
2076
-    protected function _build_payment_json_response(
2077
-        EE_Payment $payment,
2078
-        $REG_IDs = array(),
2079
-        $delete_txn_reg_status_change = null
2080
-    ) {
2081
-        // was the payment deleted ?
2082
-        if (is_bool($delete_txn_reg_status_change)) {
2083
-            return array(
2084
-                'PAY_ID'                       => $payment->ID(),
2085
-                'amount'                       => $payment->amount(),
2086
-                'total_paid'                   => $payment->transaction()->paid(),
2087
-                'txn_status'                   => $payment->transaction()->status_ID(),
2088
-                'pay_status'                   => $payment->STS_ID(),
2089
-                'registrations'                => $this->_registration_payment_data_array($REG_IDs),
2090
-                'delete_txn_reg_status_change' => $delete_txn_reg_status_change,
2091
-            );
2092
-        } else {
2093
-            $this->_get_payment_status_array();
2094
-
2095
-            return array(
2096
-                'amount'           => $payment->amount(),
2097
-                'total_paid'       => $payment->transaction()->paid(),
2098
-                'txn_status'       => $payment->transaction()->status_ID(),
2099
-                'pay_status'       => $payment->STS_ID(),
2100
-                'PAY_ID'           => $payment->ID(),
2101
-                'STS_ID'           => $payment->STS_ID(),
2102
-                'status'           => self::$_pay_status[$payment->STS_ID()],
2103
-                'date'             => $payment->timestamp('Y-m-d', 'h:i a'),
2104
-                'method'           => strtoupper($payment->source()),
2105
-                'PM_ID'            => $payment->payment_method() ? $payment->payment_method()->ID() : 1,
2106
-                'gateway'          => $payment->payment_method()
2107
-                    ? $payment->payment_method()->admin_name()
2108
-                    : esc_html__("Unknown", 'event_espresso'),
2109
-                'gateway_response' => $payment->gateway_response(),
2110
-                'txn_id_chq_nmbr'  => $payment->txn_id_chq_nmbr(),
2111
-                'po_number'        => $payment->po_number(),
2112
-                'extra_accntng'    => $payment->extra_accntng(),
2113
-                'registrations'    => $this->_registration_payment_data_array($REG_IDs),
2114
-            );
2115
-        }
2116
-    }
2117
-
2118
-
2119
-    /**
2120
-     * delete_payment
2121
-     *    delete a payment or refund made towards a transaction
2122
-     *
2123
-     * @access public
2124
-     * @return void
2125
-     * @throws EE_Error
2126
-     * @throws InvalidArgumentException
2127
-     * @throws ReflectionException
2128
-     * @throws InvalidDataTypeException
2129
-     * @throws InvalidInterfaceException
2130
-     */
2131
-    public function delete_payment()
2132
-    {
2133
-        $json_response_data = array('return_data' => false);
2134
-        $PAY_ID             = isset($this->_req_data['delete_txn_admin_payment']['PAY_ID'])
2135
-            ? absint($this->_req_data['delete_txn_admin_payment']['PAY_ID'])
2136
-            : 0;
2137
-        $can_delete = EE_Registry::instance()->CAP->current_user_can(
2138
-            'ee_delete_payments',
2139
-            'delete_payment_from_registration_details'
2140
-        );
2141
-        if ($PAY_ID && $can_delete) {
2142
-            $delete_txn_reg_status_change = isset($this->_req_data['delete_txn_reg_status_change'])
2143
-                ? $this->_req_data['delete_txn_reg_status_change']
2144
-                : false;
2145
-            $payment                      = EEM_Payment::instance()->get_one_by_ID($PAY_ID);
2146
-            if ($payment instanceof EE_Payment) {
2147
-                $REG_IDs = $this->_get_existing_reg_payment_REG_IDs($payment);
2148
-                /** @type EE_Transaction_Payments $transaction_payments */
2149
-                $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
2150
-                if ($transaction_payments->delete_payment_and_update_transaction($payment)) {
2151
-                    $json_response_data['return_data'] = $this->_build_payment_json_response(
2152
-                        $payment,
2153
-                        $REG_IDs,
2154
-                        $delete_txn_reg_status_change
2155
-                    );
2156
-                    if ($delete_txn_reg_status_change) {
2157
-                        $this->_req_data['txn_reg_status_change'] = $delete_txn_reg_status_change;
2158
-                        //MAKE sure we also add the delete_txn_req_status_change to the
2159
-                        //$_REQUEST global because that's how messages will be looking for it.
2160
-                        $_REQUEST['txn_reg_status_change'] = $delete_txn_reg_status_change;
2161
-                        $this->_maybe_send_notifications();
2162
-                        $this->_process_registration_status_change($payment->transaction(), $REG_IDs);
2163
-                    }
2164
-                }
2165
-            } else {
2166
-                EE_Error::add_error(
2167
-                    esc_html__('Valid Payment data could not be retrieved from the database.', 'event_espresso'),
2168
-                    __FILE__, __FUNCTION__, __LINE__
2169
-                );
2170
-            }
2171
-        } else {
2172
-            if ($can_delete) {
2173
-                EE_Error::add_error(
2174
-                    esc_html__(
2175
-                        'A valid Payment ID was not received, therefore payment form data could not be loaded.',
2176
-                        'event_espresso'
2177
-                    ),
2178
-                    __FILE__, __FUNCTION__, __LINE__
2179
-                );
2180
-            } else {
2181
-                EE_Error::add_error(
2182
-                    esc_html__(
2183
-                        'You do not have access to delete a payment.',
2184
-                        'event_espresso'
2185
-                    ),
2186
-                    __FILE__,
2187
-                    __FUNCTION__,
2188
-                    __LINE__
2189
-                );
2190
-            }
2191
-        }
2192
-        $notices              = EE_Error::get_notices(false, false, false);
2193
-        $this->_template_args = array(
2194
-            'data'      => $json_response_data,
2195
-            'success'   => $notices['success'],
2196
-            'error'     => $notices['errors'],
2197
-            'attention' => $notices['attention'],
2198
-        );
2199
-        $this->_return_json();
2200
-    }
2201
-
2202
-
2203
-    /**
2204
-     * _registration_payment_data_array
2205
-     * adds info for 'owing' and 'paid' for each registration to the json response
2206
-     *
2207
-     * @access protected
2208
-     * @param array $REG_IDs
2209
-     * @return array
2210
-     * @throws EE_Error
2211
-     * @throws InvalidArgumentException
2212
-     * @throws InvalidDataTypeException
2213
-     * @throws InvalidInterfaceException
2214
-     * @throws ReflectionException
2215
-     */
2216
-    protected function _registration_payment_data_array($REG_IDs)
2217
-    {
2218
-        $registration_payment_data = array();
2219
-        //if non empty reg_ids lets get an array of registrations and update the values for the apply_payment/refund rows.
2220
-        if (! empty($REG_IDs)) {
2221
-            $registrations = EEM_Registration::instance()->get_all(array(array('REG_ID' => array('IN', $REG_IDs))));
2222
-            foreach ($registrations as $registration) {
2223
-                if ($registration instanceof EE_Registration) {
2224
-                    $registration_payment_data[$registration->ID()] = array(
2225
-                        'paid'  => $registration->pretty_paid(),
2226
-                        'owing' => EEH_Template::format_currency($registration->final_price() - $registration->paid()),
2227
-                    );
2228
-                }
2229
-            }
2230
-        }
2231
-
2232
-        return $registration_payment_data;
2233
-    }
2234
-
2235
-
2236
-    /**
2237
-     * _maybe_send_notifications
2238
-     * determines whether or not the admin has indicated that notifications should be sent.
2239
-     * If so, will toggle a filter switch for delivering registration notices.
2240
-     * If passed an EE_Payment object, then it will trigger payment notifications instead.
2241
-     *
2242
-     * @access protected
2243
-     * @param \EE_Payment | null $payment
2244
-     */
2245
-    protected function _maybe_send_notifications($payment = null)
2246
-    {
2247
-        switch ($payment instanceof EE_Payment) {
2248
-            // payment notifications
2249
-            case true :
2250
-                if (
2251
-                    isset(
2252
-                        $this->_req_data['txn_payments'],
2253
-                        $this->_req_data['txn_payments']['send_notifications']
2254
-                    ) &&
2255
-                    filter_var($this->_req_data['txn_payments']['send_notifications'], FILTER_VALIDATE_BOOLEAN)
2256
-                ) {
2257
-                    $this->_process_payment_notification($payment);
2258
-                }
2259
-                break;
2260
-            // registration notifications
2261
-            case false :
2262
-                if (
2263
-                    isset(
2264
-                        $this->_req_data['txn_reg_status_change'],
2265
-                        $this->_req_data['txn_reg_status_change']['send_notifications']
2266
-                    ) &&
2267
-                    filter_var($this->_req_data['txn_reg_status_change']['send_notifications'], FILTER_VALIDATE_BOOLEAN)
2268
-                ) {
2269
-                    add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true');
2270
-                }
2271
-                break;
2272
-        }
2273
-    }
2274
-
2275
-
2276
-    /**
2277
-     * _send_payment_reminder
2278
-     *    generates HTML for the View Transaction Details Admin page
2279
-     *
2280
-     * @access protected
2281
-     * @return void
2282
-     * @throws EE_Error
2283
-     * @throws InvalidArgumentException
2284
-     * @throws InvalidDataTypeException
2285
-     * @throws InvalidInterfaceException
2286
-     */
2287
-    protected function _send_payment_reminder()
2288
-    {
2289
-        $TXN_ID      = ! empty($this->_req_data['TXN_ID']) ? absint($this->_req_data['TXN_ID']) : false;
2290
-        $transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
2291
-        $query_args  = isset($this->_req_data['redirect_to']) ? array(
2292
-            'action' => $this->_req_data['redirect_to'],
2293
-            'TXN_ID' => $this->_req_data['TXN_ID'],
2294
-        ) : array();
2295
-        do_action(
2296
-            'AHEE__Transactions_Admin_Page___send_payment_reminder__process_admin_payment_reminder',
2297
-            $transaction
2298
-        );
2299
-        $this->_redirect_after_action(
2300
-            false,
2301
-            esc_html__('payment reminder', 'event_espresso'),
2302
-            esc_html__('sent', 'event_espresso'),
2303
-            $query_args,
2304
-            true
2305
-        );
2306
-    }
2307
-
2308
-
2309
-    /**
2310
-     *  get_transactions
2311
-     *    get transactions for given parameters (used by list table)
2312
-     *
2313
-     * @param  int     $perpage how many transactions displayed per page
2314
-     * @param  boolean $count   return the count or objects
2315
-     * @param string   $view
2316
-     * @return mixed int = count || array of transaction objects
2317
-     * @throws EE_Error
2318
-     * @throws InvalidArgumentException
2319
-     * @throws InvalidDataTypeException
2320
-     * @throws InvalidInterfaceException
2321
-     */
2322
-    public function get_transactions($perpage, $count = false, $view = '')
2323
-    {
2324
-
2325
-        $TXN = EEM_Transaction::instance();
2326
-
2327
-        $start_date = isset($this->_req_data['txn-filter-start-date'])
2328
-            ? wp_strip_all_tags($this->_req_data['txn-filter-start-date'])
2329
-            : date(
2330
-                'm/d/Y',
2331
-                strtotime('-10 year')
2332
-            );
2333
-        $end_date   = isset($this->_req_data['txn-filter-end-date'])
2334
-            ? wp_strip_all_tags($this->_req_data['txn-filter-end-date'])
2335
-            : date('m/d/Y');
2336
-
2337
-        //make sure our timestamps start and end right at the boundaries for each day
2338
-        $start_date = date('Y-m-d', strtotime($start_date)) . ' 00:00:00';
2339
-        $end_date   = date('Y-m-d', strtotime($end_date)) . ' 23:59:59';
2340
-
2341
-
2342
-        //convert to timestamps
2343
-        $start_date = strtotime($start_date);
2344
-        $end_date   = strtotime($end_date);
2345
-
2346
-        //makes sure start date is the lowest value and vice versa
2347
-        $start_date = min($start_date, $end_date);
2348
-        $end_date   = max($start_date, $end_date);
2349
-
2350
-        //convert to correct format for query
2351
-        $start_date = EEM_Transaction::instance()->convert_datetime_for_query(
2352
-            'TXN_timestamp',
2353
-            date('Y-m-d H:i:s', $start_date),
2354
-            'Y-m-d H:i:s'
2355
-        );
2356
-        $end_date   = EEM_Transaction::instance()->convert_datetime_for_query(
2357
-            'TXN_timestamp',
2358
-            date('Y-m-d H:i:s', $end_date),
2359
-            'Y-m-d H:i:s'
2360
-        );
2361
-
2362
-
2363
-        //set orderby
2364
-        $this->_req_data['orderby'] = ! empty($this->_req_data['orderby']) ? $this->_req_data['orderby'] : '';
2365
-
2366
-        switch ($this->_req_data['orderby']) {
2367
-            case 'TXN_ID':
2368
-                $orderby = 'TXN_ID';
2369
-                break;
2370
-            case 'ATT_fname':
2371
-                $orderby = 'Registration.Attendee.ATT_fname';
2372
-                break;
2373
-            case 'event_name':
2374
-                $orderby = 'Registration.Event.EVT_name';
2375
-                break;
2376
-            default: //'TXN_timestamp'
2377
-                $orderby = 'TXN_timestamp';
2378
-        }
2379
-
2380
-        $sort         = ! empty($this->_req_data['order']) ? $this->_req_data['order'] : 'DESC';
2381
-        $current_page = ! empty($this->_req_data['paged']) ? $this->_req_data['paged'] : 1;
2382
-        $per_page     = ! empty($perpage) ? $perpage : 10;
2383
-        $per_page     = ! empty($this->_req_data['perpage']) ? $this->_req_data['perpage'] : $per_page;
2384
-
2385
-        $offset = ($current_page - 1) * $per_page;
2386
-        $limit  = array($offset, $per_page);
2387
-
2388
-        $_where = array(
2389
-            'TXN_timestamp'          => array('BETWEEN', array($start_date, $end_date)),
2390
-            'Registration.REG_count' => 1,
2391
-        );
2392
-
2393
-        if (isset($this->_req_data['EVT_ID'])) {
2394
-            $_where['Registration.EVT_ID'] = $this->_req_data['EVT_ID'];
2395
-        }
2396
-
2397
-        if (isset($this->_req_data['s'])) {
2398
-            $search_string = '%' . $this->_req_data['s'] . '%';
2399
-            $_where['OR']  = array(
2400
-                'Registration.Event.EVT_name'         => array('LIKE', $search_string),
2401
-                'Registration.Event.EVT_desc'         => array('LIKE', $search_string),
2402
-                'Registration.Event.EVT_short_desc'   => array('LIKE', $search_string),
2403
-                'Registration.Attendee.ATT_full_name' => array('LIKE', $search_string),
2404
-                'Registration.Attendee.ATT_fname'     => array('LIKE', $search_string),
2405
-                'Registration.Attendee.ATT_lname'     => array('LIKE', $search_string),
2406
-                'Registration.Attendee.ATT_short_bio' => array('LIKE', $search_string),
2407
-                'Registration.Attendee.ATT_email'     => array('LIKE', $search_string),
2408
-                'Registration.Attendee.ATT_address'   => array('LIKE', $search_string),
2409
-                'Registration.Attendee.ATT_address2'  => array('LIKE', $search_string),
2410
-                'Registration.Attendee.ATT_city'      => array('LIKE', $search_string),
2411
-                'Registration.REG_final_price'        => array('LIKE', $search_string),
2412
-                'Registration.REG_code'               => array('LIKE', $search_string),
2413
-                'Registration.REG_count'              => array('LIKE', $search_string),
2414
-                'Registration.REG_group_size'         => array('LIKE', $search_string),
2415
-                'Registration.Ticket.TKT_name'        => array('LIKE', $search_string),
2416
-                'Registration.Ticket.TKT_description' => array('LIKE', $search_string),
2417
-                'Payment.PAY_source'                  => array('LIKE', $search_string),
2418
-                'Payment.Payment_Method.PMD_name'     => array('LIKE', $search_string),
2419
-                'TXN_session_data'                    => array('LIKE', $search_string),
2420
-                'Payment.PAY_txn_id_chq_nmbr'         => array('LIKE', $search_string),
2421
-            );
2422
-        }
2423
-
2424
-        //failed transactions
2425
-        $failed    = (! empty($this->_req_data['status']) && $this->_req_data['status'] === 'failed' && ! $count)
2426
-                     || ($count && $view === 'failed');
2427
-        $abandoned = (! empty($this->_req_data['status']) && $this->_req_data['status'] === 'abandoned' && ! $count)
2428
-                     || ($count && $view === 'abandoned');
2429
-
2430
-        if ($failed) {
2431
-            $_where['STS_ID'] = EEM_Transaction::failed_status_code;
2432
-        } else if ($abandoned) {
2433
-            $_where['STS_ID'] = EEM_Transaction::abandoned_status_code;
2434
-        } else {
2435
-            $_where['STS_ID']  = array('!=', EEM_Transaction::failed_status_code);
2436
-            $_where['STS_ID*'] = array('!=', EEM_Transaction::abandoned_status_code);
2437
-        }
2438
-
2439
-        $query_params = array(
2440
-            $_where,
2441
-            'order_by'                 => array($orderby => $sort),
2442
-            'limit'                    => $limit,
2443
-            'default_where_conditions' => EEM_Base::default_where_conditions_this_only,
2444
-        );
2445
-
2446
-        $transactions = $count
2447
-            ? $TXN->count(array($_where), 'TXN_ID', true)
2448
-            : $TXN->get_all($query_params);
2449
-
2450
-        return $transactions;
2451
-    }
19
+	/**
20
+	 * @var EE_Transaction
21
+	 */
22
+	private $_transaction;
23
+
24
+	/**
25
+	 * @var EE_Session
26
+	 */
27
+	private $_session;
28
+
29
+	/**
30
+	 * @var array $_txn_status
31
+	 */
32
+	private static $_txn_status;
33
+
34
+	/**
35
+	 * @var array $_pay_status
36
+	 */
37
+	private static $_pay_status;
38
+
39
+	/**
40
+	 * @var array $_existing_reg_payment_REG_IDs
41
+	 */
42
+	protected $_existing_reg_payment_REG_IDs = null;
43
+
44
+
45
+	/**
46
+	 * @Constructor
47
+	 * @access public
48
+	 * @param bool $routing
49
+	 * @throws EE_Error
50
+	 * @throws InvalidArgumentException
51
+	 * @throws ReflectionException
52
+	 * @throws InvalidDataTypeException
53
+	 * @throws InvalidInterfaceException
54
+	 */
55
+	public function __construct($routing = true)
56
+	{
57
+		parent::__construct($routing);
58
+	}
59
+
60
+
61
+	/**
62
+	 *    _init_page_props
63
+	 *
64
+	 * @return void
65
+	 */
66
+	protected function _init_page_props()
67
+	{
68
+		$this->page_slug        = TXN_PG_SLUG;
69
+		$this->page_label       = esc_html__('Transactions', 'event_espresso');
70
+		$this->_admin_base_url  = TXN_ADMIN_URL;
71
+		$this->_admin_base_path = TXN_ADMIN;
72
+	}
73
+
74
+
75
+	/**
76
+	 *    _ajax_hooks
77
+	 *
78
+	 * @return void
79
+	 */
80
+	protected function _ajax_hooks()
81
+	{
82
+		add_action('wp_ajax_espresso_apply_payment', array($this, 'apply_payments_or_refunds'));
83
+		add_action('wp_ajax_espresso_apply_refund', array($this, 'apply_payments_or_refunds'));
84
+		add_action('wp_ajax_espresso_delete_payment', array($this, 'delete_payment'));
85
+	}
86
+
87
+
88
+	/**
89
+	 *    _define_page_props
90
+	 *
91
+	 * @return void
92
+	 */
93
+	protected function _define_page_props()
94
+	{
95
+		$this->_admin_page_title = $this->page_label;
96
+		$this->_labels           = array(
97
+			'buttons' => array(
98
+				'add'    => esc_html__('Add New Transaction', 'event_espresso'),
99
+				'edit'   => esc_html__('Edit Transaction', 'event_espresso'),
100
+				'delete' => esc_html__('Delete Transaction', 'event_espresso'),
101
+			),
102
+		);
103
+	}
104
+
105
+
106
+	/**
107
+	 *        grab url requests and route them
108
+	 *
109
+	 * @access private
110
+	 * @return void
111
+	 * @throws EE_Error
112
+	 * @throws InvalidArgumentException
113
+	 * @throws InvalidDataTypeException
114
+	 * @throws InvalidInterfaceException
115
+	 */
116
+	public function _set_page_routes()
117
+	{
118
+
119
+		$this->_set_transaction_status_array();
120
+
121
+		$txn_id = ! empty($this->_req_data['TXN_ID'])
122
+				  && ! is_array($this->_req_data['TXN_ID'])
123
+			? $this->_req_data['TXN_ID']
124
+			: 0;
125
+
126
+		$this->_page_routes = array(
127
+
128
+			'default' => array(
129
+				'func'       => '_transactions_overview_list_table',
130
+				'capability' => 'ee_read_transactions',
131
+			),
132
+
133
+			'view_transaction' => array(
134
+				'func'       => '_transaction_details',
135
+				'capability' => 'ee_read_transaction',
136
+				'obj_id'     => $txn_id,
137
+			),
138
+
139
+			'send_payment_reminder' => array(
140
+				'func'       => '_send_payment_reminder',
141
+				'noheader'   => true,
142
+				'capability' => 'ee_send_message',
143
+			),
144
+
145
+			'espresso_apply_payment' => array(
146
+				'func'       => 'apply_payments_or_refunds',
147
+				'noheader'   => true,
148
+				'capability' => 'ee_edit_payments',
149
+			),
150
+
151
+			'espresso_apply_refund' => array(
152
+				'func'       => 'apply_payments_or_refunds',
153
+				'noheader'   => true,
154
+				'capability' => 'ee_edit_payments',
155
+			),
156
+
157
+			'espresso_delete_payment' => array(
158
+				'func'       => 'delete_payment',
159
+				'noheader'   => true,
160
+				'capability' => 'ee_delete_payments',
161
+			),
162
+
163
+		);
164
+	}
165
+
166
+
167
+	protected function _set_page_config()
168
+	{
169
+		$this->_page_config = array(
170
+			'default'          => array(
171
+				'nav'           => array(
172
+					'label' => esc_html__('Overview', 'event_espresso'),
173
+					'order' => 10,
174
+				),
175
+				'list_table'    => 'EE_Admin_Transactions_List_Table',
176
+				'help_tabs'     => array(
177
+					'transactions_overview_help_tab'                       => array(
178
+						'title'    => esc_html__('Transactions Overview', 'event_espresso'),
179
+						'filename' => 'transactions_overview',
180
+					),
181
+					'transactions_overview_table_column_headings_help_tab' => array(
182
+						'title'    => esc_html__('Transactions Table Column Headings', 'event_espresso'),
183
+						'filename' => 'transactions_overview_table_column_headings',
184
+					),
185
+					'transactions_overview_views_filters_help_tab'         => array(
186
+						'title'    => esc_html__('Transaction Views & Filters & Search', 'event_espresso'),
187
+						'filename' => 'transactions_overview_views_filters_search',
188
+					),
189
+				),
190
+				'help_tour'     => array('Transactions_Overview_Help_Tour'),
191
+				/**
192
+				 * commented out because currently we are not displaying tips for transaction list table status but this
193
+				 * may change in a later iteration so want to keep the code for then.
194
+				 */
195
+				//'qtips' => array( 'Transactions_List_Table_Tips' ),
196
+				'require_nonce' => false,
197
+			),
198
+			'view_transaction' => array(
199
+				'nav'       => array(
200
+					'label'      => esc_html__('View Transaction', 'event_espresso'),
201
+					'order'      => 5,
202
+					'url'        => isset($this->_req_data['TXN_ID'])
203
+						? add_query_arg(array('TXN_ID' => $this->_req_data['TXN_ID']), $this->_current_page_view_url)
204
+						: $this->_admin_base_url,
205
+					'persistent' => false,
206
+				),
207
+				'help_tabs' => array(
208
+					'transactions_view_transaction_help_tab'                                              => array(
209
+						'title'    => esc_html__('View Transaction', 'event_espresso'),
210
+						'filename' => 'transactions_view_transaction',
211
+					),
212
+					'transactions_view_transaction_transaction_details_table_help_tab'                    => array(
213
+						'title'    => esc_html__('Transaction Details Table', 'event_espresso'),
214
+						'filename' => 'transactions_view_transaction_transaction_details_table',
215
+					),
216
+					'transactions_view_transaction_attendees_registered_help_tab'                         => array(
217
+						'title'    => esc_html__('Attendees Registered', 'event_espresso'),
218
+						'filename' => 'transactions_view_transaction_attendees_registered',
219
+					),
220
+					'transactions_view_transaction_views_primary_registrant_billing_information_help_tab' => array(
221
+						'title'    => esc_html__('Primary Registrant & Billing Information', 'event_espresso'),
222
+						'filename' => 'transactions_view_transaction_primary_registrant_billing_information',
223
+					),
224
+				),
225
+				'qtips'     => array('Transaction_Details_Tips'),
226
+				'help_tour' => array('Transaction_Details_Help_Tour'),
227
+				'metaboxes' => array('_transaction_details_metaboxes'),
228
+
229
+				'require_nonce' => false,
230
+			),
231
+		);
232
+	}
233
+
234
+
235
+	/**
236
+	 * The below methods aren't used by this class currently
237
+	 */
238
+	protected function _add_screen_options()
239
+	{
240
+		//noop
241
+	}
242
+
243
+	protected function _add_feature_pointers()
244
+	{
245
+		//noop
246
+	}
247
+
248
+	public function admin_init()
249
+	{
250
+		// IF a registration was JUST added via the admin...
251
+		if (isset(
252
+			$this->_req_data['redirect_from'],
253
+			$this->_req_data['EVT_ID'],
254
+			$this->_req_data['event_name']
255
+		)) {
256
+			// then set a cookie so that we can block any attempts to use
257
+			// the back button as a way to enter another registration.
258
+			setcookie(
259
+				'ee_registration_added',
260
+				$this->_req_data['EVT_ID'], time() + WEEK_IN_SECONDS, '/'
261
+			);
262
+			// and update the global
263
+			$_COOKIE['ee_registration_added'] = $this->_req_data['EVT_ID'];
264
+		}
265
+		EE_Registry::$i18n_js_strings['invalid_server_response'] = esc_html__(
266
+			'An error occurred! Your request may have been processed, but a valid response from the server was not received. Please refresh the page and try again.',
267
+			'event_espresso'
268
+		);
269
+		EE_Registry::$i18n_js_strings['error_occurred']          = esc_html__(
270
+			'An error occurred! Please refresh the page and try again.',
271
+			'event_espresso'
272
+		);
273
+		EE_Registry::$i18n_js_strings['txn_status_array']        = self::$_txn_status;
274
+		EE_Registry::$i18n_js_strings['pay_status_array']        = self::$_pay_status;
275
+		EE_Registry::$i18n_js_strings['payments_total']          = esc_html__('Payments Total', 'event_espresso');
276
+		EE_Registry::$i18n_js_strings['transaction_overpaid']    = esc_html__(
277
+			'This transaction has been overpaid ! Payments Total',
278
+			'event_espresso'
279
+		);
280
+	}
281
+
282
+	public function admin_notices()
283
+	{
284
+		//noop
285
+	}
286
+
287
+	public function admin_footer_scripts()
288
+	{
289
+		//noop
290
+	}
291
+
292
+
293
+	/**
294
+	 * _set_transaction_status_array
295
+	 * sets list of transaction statuses
296
+	 *
297
+	 * @access private
298
+	 * @return void
299
+	 * @throws EE_Error
300
+	 * @throws InvalidArgumentException
301
+	 * @throws InvalidDataTypeException
302
+	 * @throws InvalidInterfaceException
303
+	 */
304
+	private function _set_transaction_status_array()
305
+	{
306
+		self::$_txn_status = EEM_Transaction::instance()->status_array(true);
307
+	}
308
+
309
+
310
+	/**
311
+	 * get_transaction_status_array
312
+	 * return the transaction status array for wp_list_table
313
+	 *
314
+	 * @access public
315
+	 * @return array
316
+	 */
317
+	public function get_transaction_status_array()
318
+	{
319
+		return self::$_txn_status;
320
+	}
321
+
322
+
323
+	/**
324
+	 *    get list of payment statuses
325
+	 *
326
+	 * @access private
327
+	 * @return void
328
+	 * @throws EE_Error
329
+	 * @throws InvalidArgumentException
330
+	 * @throws InvalidDataTypeException
331
+	 * @throws InvalidInterfaceException
332
+	 */
333
+	private function _get_payment_status_array()
334
+	{
335
+		self::$_pay_status                      = EEM_Payment::instance()->status_array(true);
336
+		$this->_template_args['payment_status'] = self::$_pay_status;
337
+
338
+	}
339
+
340
+
341
+	/**
342
+	 *    _add_screen_options_default
343
+	 *
344
+	 * @access protected
345
+	 * @return void
346
+	 * @throws InvalidArgumentException
347
+	 * @throws InvalidDataTypeException
348
+	 * @throws InvalidInterfaceException
349
+	 */
350
+	protected function _add_screen_options_default()
351
+	{
352
+		$this->_per_page_screen_option();
353
+	}
354
+
355
+
356
+	/**
357
+	 * load_scripts_styles
358
+	 *
359
+	 * @access public
360
+	 * @return void
361
+	 */
362
+	public function load_scripts_styles()
363
+	{
364
+		//enqueue style
365
+		wp_register_style(
366
+			'espresso_txn',
367
+			TXN_ASSETS_URL . 'espresso_transactions_admin.css',
368
+			array(),
369
+			EVENT_ESPRESSO_VERSION
370
+		);
371
+		wp_enqueue_style('espresso_txn');
372
+		//scripts
373
+		wp_register_script('espresso_txn', TXN_ASSETS_URL . 'espresso_transactions_admin.js', array(
374
+			'ee_admin_js',
375
+			'ee-datepicker',
376
+			'jquery-ui-datepicker',
377
+			'jquery-ui-draggable',
378
+			'ee-dialog',
379
+			'ee-accounting',
380
+			'ee-serialize-full-array',
381
+		), EVENT_ESPRESSO_VERSION, true);
382
+		wp_enqueue_script('espresso_txn');
383
+	}
384
+
385
+
386
+	/**
387
+	 *    load_scripts_styles_view_transaction
388
+	 *
389
+	 * @access public
390
+	 * @return void
391
+	 */
392
+	public function load_scripts_styles_view_transaction()
393
+	{
394
+		//styles
395
+		wp_enqueue_style('espresso-ui-theme');
396
+	}
397
+
398
+
399
+	/**
400
+	 *    load_scripts_styles_default
401
+	 *
402
+	 * @access public
403
+	 * @return void
404
+	 */
405
+	public function load_scripts_styles_default()
406
+	{
407
+		//styles
408
+		wp_enqueue_style('espresso-ui-theme');
409
+	}
410
+
411
+
412
+	/**
413
+	 *    _set_list_table_views_default
414
+	 *
415
+	 * @access protected
416
+	 * @return void
417
+	 */
418
+	protected function _set_list_table_views_default()
419
+	{
420
+		$this->_views = array(
421
+			'all'       => array(
422
+				'slug'  => 'all',
423
+				'label' => esc_html__('View All Transactions', 'event_espresso'),
424
+				'count' => 0,
425
+			),
426
+			'abandoned' => array(
427
+				'slug'  => 'abandoned',
428
+				'label' => esc_html__('Abandoned Transactions', 'event_espresso'),
429
+				'count' => 0,
430
+			),
431
+			'failed'    => array(
432
+				'slug'  => 'failed',
433
+				'label' => esc_html__('Failed Transactions', 'event_espresso'),
434
+				'count' => 0,
435
+			),
436
+		);
437
+	}
438
+
439
+
440
+	/**
441
+	 * _set_transaction_object
442
+	 * This sets the _transaction property for the transaction details screen
443
+	 *
444
+	 * @access private
445
+	 * @return void
446
+	 * @throws EE_Error
447
+	 * @throws InvalidArgumentException
448
+	 * @throws RuntimeException
449
+	 * @throws InvalidDataTypeException
450
+	 * @throws InvalidInterfaceException
451
+	 * @throws ReflectionException
452
+	 */
453
+	private function _set_transaction_object()
454
+	{
455
+		if ($this->_transaction instanceof EE_Transaction) {
456
+			return;
457
+		} //get out we've already set the object
458
+
459
+		$TXN_ID = ! empty($this->_req_data['TXN_ID'])
460
+			? absint($this->_req_data['TXN_ID'])
461
+			: false;
462
+
463
+		//get transaction object
464
+		$this->_transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
465
+		$this->_session     = $this->_transaction instanceof EE_Transaction
466
+			? $this->_transaction->get('TXN_session_data')
467
+			: null;
468
+		$this->_transaction->verify_abandoned_transaction_status();
469
+
470
+		if (! $this->_transaction instanceof EE_Transaction) {
471
+			$error_msg = sprintf(
472
+				esc_html__(
473
+					'An error occurred and the details for the transaction with the ID # %d could not be retrieved.',
474
+					'event_espresso'
475
+				),
476
+				$TXN_ID
477
+			);
478
+			EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
479
+		}
480
+	}
481
+
482
+
483
+	/**
484
+	 *    _transaction_legend_items
485
+	 *
486
+	 * @access protected
487
+	 * @return array
488
+	 * @throws EE_Error
489
+	 * @throws InvalidArgumentException
490
+	 * @throws ReflectionException
491
+	 * @throws InvalidDataTypeException
492
+	 * @throws InvalidInterfaceException
493
+	 */
494
+	protected function _transaction_legend_items()
495
+	{
496
+		EE_Registry::instance()->load_helper('MSG_Template');
497
+		$items = array();
498
+
499
+		if (EE_Registry::instance()->CAP->current_user_can(
500
+			'ee_read_global_messages',
501
+			'view_filtered_messages'
502
+		)) {
503
+			$related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
504
+			if (is_array($related_for_icon)
505
+				&& isset($related_for_icon['css_class'], $related_for_icon['label'])
506
+			) {
507
+				$items['view_related_messages'] = array(
508
+					'class' => $related_for_icon['css_class'],
509
+					'desc'  => $related_for_icon['label'],
510
+				);
511
+			}
512
+		}
513
+
514
+		$items = apply_filters(
515
+			'FHEE__Transactions_Admin_Page___transaction_legend_items__items',
516
+			array_merge(
517
+				$items,
518
+				array(
519
+					'view_details'          => array(
520
+						'class' => 'dashicons dashicons-cart',
521
+						'desc'  => esc_html__('View Transaction Details', 'event_espresso'),
522
+					),
523
+					'view_invoice'          => array(
524
+						'class' => 'dashicons dashicons-media-spreadsheet',
525
+						'desc'  => esc_html__('View Transaction Invoice', 'event_espresso'),
526
+					),
527
+					'view_receipt'          => array(
528
+						'class' => 'dashicons dashicons-media-default',
529
+						'desc'  => esc_html__('View Transaction Receipt', 'event_espresso'),
530
+					),
531
+					'view_registration'     => array(
532
+						'class' => 'dashicons dashicons-clipboard',
533
+						'desc'  => esc_html__('View Registration Details', 'event_espresso'),
534
+					),
535
+					'payment_overview_link' => array(
536
+						'class' => 'dashicons dashicons-money',
537
+						'desc'  => esc_html__('Make Payment on Frontend', 'event_espresso'),
538
+					),
539
+				)
540
+			)
541
+		);
542
+
543
+		if (EE_Registry::instance()->CAP->current_user_can(
544
+			'ee_send_message',
545
+			'espresso_transactions_send_payment_reminder'
546
+		)) {
547
+			if (EEH_MSG_Template::is_mt_active('payment_reminder')) {
548
+				$items['send_payment_reminder'] = array(
549
+					'class' => 'dashicons dashicons-email-alt',
550
+					'desc'  => esc_html__('Send Payment Reminder', 'event_espresso'),
551
+				);
552
+			} else {
553
+				$items['blank*'] = array(
554
+					'class' => '',
555
+					'desc'  => '',
556
+				);
557
+			}
558
+		} else {
559
+			$items['blank*'] = array(
560
+				'class' => '',
561
+				'desc'  => '',
562
+			);
563
+		}
564
+		$more_items = apply_filters(
565
+			'FHEE__Transactions_Admin_Page___transaction_legend_items__more_items',
566
+			array(
567
+				'overpaid'   => array(
568
+					'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::overpaid_status_code,
569
+					'desc'  => EEH_Template::pretty_status(
570
+						EEM_Transaction::overpaid_status_code,
571
+						false,
572
+						'sentence'
573
+					),
574
+				),
575
+				'complete'   => array(
576
+					'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::complete_status_code,
577
+					'desc'  => EEH_Template::pretty_status(
578
+						EEM_Transaction::complete_status_code,
579
+						false,
580
+						'sentence'
581
+					),
582
+				),
583
+				'incomplete' => array(
584
+					'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::incomplete_status_code,
585
+					'desc'  => EEH_Template::pretty_status(
586
+						EEM_Transaction::incomplete_status_code,
587
+						false,
588
+						'sentence'
589
+					),
590
+				),
591
+				'abandoned'  => array(
592
+					'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::abandoned_status_code,
593
+					'desc'  => EEH_Template::pretty_status(
594
+						EEM_Transaction::abandoned_status_code,
595
+						false,
596
+						'sentence'
597
+					),
598
+				),
599
+				'failed'     => array(
600
+					'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::failed_status_code,
601
+					'desc'  => EEH_Template::pretty_status(
602
+						EEM_Transaction::failed_status_code,
603
+						false,
604
+						'sentence'
605
+					),
606
+				),
607
+			)
608
+		);
609
+
610
+		return array_merge($items, $more_items);
611
+	}
612
+
613
+
614
+	/**
615
+	 *    _transactions_overview_list_table
616
+	 *
617
+	 * @access protected
618
+	 * @return void
619
+	 * @throws DomainException
620
+	 * @throws EE_Error
621
+	 * @throws InvalidArgumentException
622
+	 * @throws InvalidDataTypeException
623
+	 * @throws InvalidInterfaceException
624
+	 * @throws ReflectionException
625
+	 */
626
+	protected function _transactions_overview_list_table()
627
+	{
628
+		$this->_admin_page_title = esc_html__('Transactions', 'event_espresso');
629
+		$event = isset($this->_req_data['EVT_ID'])
630
+			? EEM_Event::instance()->get_one_by_ID($this->_req_data['EVT_ID'])
631
+			: null;
632
+		$this->_template_args['admin_page_header'] = $event instanceof EE_Event
633
+			? sprintf(
634
+				esc_html__(
635
+					'%sViewing Transactions for the Event: %s%s',
636
+					'event_espresso'
637
+				),
638
+				'<h3>',
639
+				'<a href="'
640
+				. EE_Admin_Page::add_query_args_and_nonce(
641
+					array('action' => 'edit', 'post' => $event->ID()),
642
+					EVENTS_ADMIN_URL
643
+				)
644
+				. '" title="'
645
+				. esc_attr__(
646
+					'Click to Edit event',
647
+					'event_espresso'
648
+				)
649
+				. '">' . $event->get('EVT_name') . '</a>',
650
+				'</h3>'
651
+			)
652
+			: '';
653
+		$this->_template_args['after_list_table']  = $this->_display_legend($this->_transaction_legend_items());
654
+		$this->display_admin_list_table_page_with_no_sidebar();
655
+	}
656
+
657
+
658
+	/**
659
+	 *    _transaction_details
660
+	 * generates HTML for the View Transaction Details Admin page
661
+	 *
662
+	 * @access protected
663
+	 * @return void
664
+	 * @throws DomainException
665
+	 * @throws EE_Error
666
+	 * @throws InvalidArgumentException
667
+	 * @throws InvalidDataTypeException
668
+	 * @throws InvalidInterfaceException
669
+	 * @throws RuntimeException
670
+	 * @throws ReflectionException
671
+	 */
672
+	protected function _transaction_details()
673
+	{
674
+		do_action('AHEE__Transactions_Admin_Page__transaction_details__start', $this->_transaction);
675
+
676
+		$this->_set_transaction_status_array();
677
+
678
+		$this->_template_args                      = array();
679
+		$this->_template_args['transactions_page'] = $this->_wp_page_slug;
680
+
681
+		$this->_set_transaction_object();
682
+
683
+		$primary_registration = $this->_transaction->primary_registration();
684
+		$attendee = $primary_registration instanceof EE_Registration
685
+			? $primary_registration->attendee()
686
+			: null;
687
+
688
+		$this->_template_args['txn_nmbr']['value'] = $this->_transaction->ID();
689
+		$this->_template_args['txn_nmbr']['label'] = esc_html__('Transaction Number', 'event_espresso');
690
+
691
+		$this->_template_args['txn_datetime']['value'] = $this->_transaction->get_i18n_datetime('TXN_timestamp');
692
+		$this->_template_args['txn_datetime']['label'] = esc_html__('Date', 'event_espresso');
693
+
694
+		$this->_template_args['txn_status']['value'] = self::$_txn_status[$this->_transaction->get('STS_ID')];
695
+		$this->_template_args['txn_status']['label'] = esc_html__('Transaction Status', 'event_espresso');
696
+		$this->_template_args['txn_status']['class'] = 'status-' . $this->_transaction->get('STS_ID');
697
+
698
+		$this->_template_args['grand_total'] = $this->_transaction->get('TXN_total');
699
+		$this->_template_args['total_paid']  = $this->_transaction->get('TXN_paid');
700
+
701
+		$amount_due = $this->_transaction->get('TXN_total') - $this->_transaction->get('TXN_paid');
702
+		$this->_template_args['amount_due'] = EEH_Template::format_currency(
703
+			$amount_due,
704
+			true
705
+		);
706
+		if (EE_Registry::instance()->CFG->currency->sign_b4) {
707
+			$this->_template_args['amount_due'] = EE_Registry::instance()->CFG->currency->sign
708
+												  . $this->_template_args['amount_due'];
709
+		} else {
710
+			$this->_template_args['amount_due'] .= EE_Registry::instance()->CFG->currency->sign;
711
+		}
712
+		$this->_template_args['amount_due_class'] = '';
713
+
714
+		if ($this->_transaction->get('TXN_paid') == $this->_transaction->get('TXN_total')) {
715
+			// paid in full
716
+			$this->_template_args['amount_due'] = false;
717
+		} elseif ($this->_transaction->get('TXN_paid') > $this->_transaction->get('TXN_total')) {
718
+			// overpaid
719
+			$this->_template_args['amount_due_class'] = 'txn-overview-no-payment-spn';
720
+		} elseif ($this->_transaction->get('TXN_total') > 0
721
+				  && $this->_transaction->get('TXN_paid') > 0
722
+		) {
723
+			// monies owing
724
+			$this->_template_args['amount_due_class'] = 'txn-overview-part-payment-spn';
725
+		} elseif ($this->_transaction->get('TXN_total') > 0
726
+				  && $this->_transaction->get('TXN_paid') == 0
727
+		) {
728
+			// no payments made yet
729
+			$this->_template_args['amount_due_class'] = 'txn-overview-no-payment-spn';
730
+		} elseif ($this->_transaction->get('TXN_total') == 0) {
731
+			// free event
732
+			$this->_template_args['amount_due'] = false;
733
+		}
734
+
735
+		$payment_method = $this->_transaction->payment_method();
736
+
737
+		$this->_template_args['method_of_payment_name'] = $payment_method instanceof EE_Payment_Method
738
+			? $payment_method->admin_name()
739
+			: esc_html__('Unknown', 'event_espresso');
740
+
741
+		$this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
742
+		// link back to overview
743
+		$this->_template_args['txn_overview_url'] = ! empty($_SERVER['HTTP_REFERER'])
744
+			? $_SERVER['HTTP_REFERER']
745
+			: TXN_ADMIN_URL;
746
+
747
+
748
+		// next link
749
+		$next_txn                                 = $this->_transaction->next(
750
+			null,
751
+			array(array('STS_ID' => array('!=', EEM_Transaction::failed_status_code))),
752
+			'TXN_ID'
753
+		);
754
+		$this->_template_args['next_transaction'] = $next_txn
755
+			? $this->_next_link(
756
+				EE_Admin_Page::add_query_args_and_nonce(
757
+					array('action' => 'view_transaction', 'TXN_ID' => $next_txn['TXN_ID']),
758
+					TXN_ADMIN_URL
759
+				),
760
+				'dashicons dashicons-arrow-right ee-icon-size-22'
761
+			)
762
+			: '';
763
+		// previous link
764
+		$previous_txn                                 = $this->_transaction->previous(
765
+			null,
766
+			array(array('STS_ID' => array('!=', EEM_Transaction::failed_status_code))),
767
+			'TXN_ID'
768
+		);
769
+		$this->_template_args['previous_transaction'] = $previous_txn
770
+			? $this->_previous_link(
771
+				EE_Admin_Page::add_query_args_and_nonce(
772
+					array('action' => 'view_transaction', 'TXN_ID' => $previous_txn['TXN_ID']),
773
+					TXN_ADMIN_URL
774
+				),
775
+				'dashicons dashicons-arrow-left ee-icon-size-22'
776
+			)
777
+			: '';
778
+
779
+		// were we just redirected here after adding a new registration ???
780
+		if (isset(
781
+			$this->_req_data['redirect_from'],
782
+			$this->_req_data['EVT_ID'],
783
+			$this->_req_data['event_name']
784
+		)) {
785
+			if (EE_Registry::instance()->CAP->current_user_can(
786
+				'ee_edit_registrations',
787
+				'espresso_registrations_new_registration',
788
+				$this->_req_data['EVT_ID']
789
+			)) {
790
+				$this->_admin_page_title .= '<a id="add-new-registration" class="add-new-h2 button-primary" href="';
791
+				$this->_admin_page_title .= EE_Admin_Page::add_query_args_and_nonce(
792
+					array(
793
+						'page'     => 'espresso_registrations',
794
+						'action'   => 'new_registration',
795
+						'return'   => 'default',
796
+						'TXN_ID'   => $this->_transaction->ID(),
797
+						'event_id' => $this->_req_data['EVT_ID'],
798
+					),
799
+					REG_ADMIN_URL
800
+				);
801
+				$this->_admin_page_title .= '">';
802
+
803
+				$this->_admin_page_title .= sprintf(
804
+					esc_html__('Add Another New Registration to Event: "%1$s" ?', 'event_espresso'),
805
+					htmlentities(urldecode($this->_req_data['event_name']), ENT_QUOTES, 'UTF-8')
806
+				);
807
+				$this->_admin_page_title .= '</a>';
808
+			}
809
+			EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
810
+		}
811
+		// grab messages at the last second
812
+		$this->_template_args['notices'] = EE_Error::get_notices();
813
+		// path to template
814
+		$template_path                             = TXN_TEMPLATE_PATH . 'txn_admin_details_header.template.php';
815
+		$this->_template_args['admin_page_header'] = EEH_Template::display_template(
816
+			$template_path,
817
+			$this->_template_args,
818
+			true
819
+		);
820
+
821
+		// the details template wrapper
822
+		$this->display_admin_page_with_sidebar();
823
+
824
+	}
825
+
826
+
827
+	/**
828
+	 *        _transaction_details_metaboxes
829
+	 *
830
+	 * @access protected
831
+	 * @return void
832
+	 * @throws EE_Error
833
+	 * @throws InvalidArgumentException
834
+	 * @throws InvalidDataTypeException
835
+	 * @throws InvalidInterfaceException
836
+	 * @throws RuntimeException
837
+	 * @throws ReflectionException
838
+	 */
839
+	protected function _transaction_details_metaboxes()
840
+	{
841
+
842
+		$this->_set_transaction_object();
843
+
844
+		add_meta_box(
845
+			'edit-txn-details-mbox',
846
+			esc_html__('Transaction Details', 'event_espresso'),
847
+			array($this, 'txn_details_meta_box'),
848
+			$this->_wp_page_slug,
849
+			'normal',
850
+			'high'
851
+		);
852
+		add_meta_box(
853
+			'edit-txn-attendees-mbox',
854
+			esc_html__('Attendees Registered in this Transaction', 'event_espresso'),
855
+			array($this, 'txn_attendees_meta_box'),
856
+			$this->_wp_page_slug,
857
+			'normal',
858
+			'high',
859
+			array('TXN_ID' => $this->_transaction->ID())
860
+		);
861
+		add_meta_box(
862
+			'edit-txn-registrant-mbox',
863
+			esc_html__('Primary Contact', 'event_espresso'),
864
+			array($this, 'txn_registrant_side_meta_box'),
865
+			$this->_wp_page_slug,
866
+			'side',
867
+			'high'
868
+		);
869
+		add_meta_box(
870
+			'edit-txn-billing-info-mbox',
871
+			esc_html__('Billing Information', 'event_espresso'),
872
+			array($this, 'txn_billing_info_side_meta_box'),
873
+			$this->_wp_page_slug,
874
+			'side',
875
+			'high'
876
+		);
877
+	}
878
+
879
+
880
+	/**
881
+	 * Callback for transaction actions metabox.
882
+	 *
883
+	 * @param EE_Transaction|null $transaction
884
+	 * @throws DomainException
885
+	 * @throws EE_Error
886
+	 * @throws InvalidArgumentException
887
+	 * @throws InvalidDataTypeException
888
+	 * @throws InvalidInterfaceException
889
+	 * @throws ReflectionException
890
+	 * @throws RuntimeException
891
+	 */
892
+	public function getActionButtons(EE_Transaction $transaction = null)
893
+	{
894
+		$content = '';
895
+		$actions = array();
896
+		if (! $transaction instanceof EE_Transaction) {
897
+			return $content;
898
+		}
899
+		/** @var EE_Registration $primary_registration */
900
+		$primary_registration = $transaction->primary_registration();
901
+		$attendee = $primary_registration instanceof EE_Registration
902
+			? $primary_registration->attendee()
903
+			: null;
904
+
905
+		if ($attendee instanceof EE_Attendee
906
+			&& EE_Registry::instance()->CAP->current_user_can(
907
+				'ee_send_message',
908
+				'espresso_transactions_send_payment_reminder'
909
+			)
910
+		) {
911
+			$actions['payment_reminder'] =
912
+				EEH_MSG_Template::is_mt_active('payment_reminder')
913
+				&& $this->_transaction->get('STS_ID') !== EEM_Transaction::complete_status_code
914
+				&& $this->_transaction->get('STS_ID') !== EEM_Transaction::overpaid_status_code
915
+					? EEH_Template::get_button_or_link(
916
+						EE_Admin_Page::add_query_args_and_nonce(
917
+							array(
918
+								'action'      => 'send_payment_reminder',
919
+								'TXN_ID'      => $this->_transaction->ID(),
920
+								'redirect_to' => 'view_transaction',
921
+							),
922
+							TXN_ADMIN_URL
923
+						),
924
+						esc_html__(' Send Payment Reminder', 'event_espresso'),
925
+						'button secondary-button',
926
+						'dashicons dashicons-email-alt'
927
+					)
928
+					: '';
929
+		}
930
+
931
+		if ($primary_registration instanceof EE_Registration
932
+			&& EEH_MSG_Template::is_mt_active('receipt')
933
+		) {
934
+			$actions['receipt'] = EEH_Template::get_button_or_link(
935
+				$primary_registration->receipt_url(),
936
+				esc_html__('View Receipt', 'event_espresso'),
937
+				'button secondary-button',
938
+				'dashicons dashicons-media-default'
939
+			);
940
+		}
941
+
942
+		if ($primary_registration instanceof EE_Registration
943
+			&& EEH_MSG_Template::is_mt_active('invoice')
944
+		) {
945
+			$actions['invoice'] = EEH_Template::get_button_or_link(
946
+				$primary_registration->invoice_url(),
947
+				esc_html__('View Invoice', 'event_espresso'),
948
+				'button secondary-button',
949
+				'dashicons dashicons-media-spreadsheet'
950
+			);
951
+		}
952
+		$actions = array_filter(
953
+			apply_filters('FHEE__Transactions_Admin_Page__getActionButtons__actions', $actions, $transaction)
954
+		);
955
+		if ($actions) {
956
+			$content = '<ul>';
957
+			$content .= '<li>' . implode('</li><li>', $actions) . '</li>';
958
+			$content .= '</uL>';
959
+		}
960
+		return $content;
961
+	}
962
+
963
+
964
+	/**
965
+	 * txn_details_meta_box
966
+	 * generates HTML for the Transaction main meta box
967
+	 *
968
+	 * @return void
969
+	 * @throws DomainException
970
+	 * @throws EE_Error
971
+	 * @throws InvalidArgumentException
972
+	 * @throws InvalidDataTypeException
973
+	 * @throws InvalidInterfaceException
974
+	 * @throws RuntimeException
975
+	 * @throws ReflectionException
976
+	 */
977
+	public function txn_details_meta_box()
978
+	{
979
+		$this->_set_transaction_object();
980
+		$this->_template_args['TXN_ID']   = $this->_transaction->ID();
981
+		$this->_template_args['attendee'] = $this->_transaction->primary_registration() instanceof EE_Registration
982
+			? $this->_transaction->primary_registration()->attendee()
983
+			: null;
984
+		$this->_template_args['can_edit_payments'] = EE_Registry::instance()->CAP->current_user_can(
985
+			'ee_edit_payments',
986
+			'apply_payment_or_refund_from_registration_details'
987
+		);
988
+		$this->_template_args['can_delete_payments'] = EE_Registry::instance()->CAP->current_user_can(
989
+			'ee_delete_payments',
990
+			'delete_payment_from_registration_details'
991
+		);
992
+
993
+		//get line table
994
+		EEH_Autoloader::register_line_item_display_autoloaders();
995
+		$Line_Item_Display                       = new EE_Line_Item_Display(
996
+			'admin_table',
997
+			'EE_Admin_Table_Line_Item_Display_Strategy'
998
+		);
999
+		$this->_template_args['line_item_table'] = $Line_Item_Display->display_line_item(
1000
+			$this->_transaction->total_line_item()
1001
+		);
1002
+		$this->_template_args['REG_code']        = $this->_transaction->get_first_related('Registration')
1003
+																	  ->get('REG_code');
1004
+
1005
+		// process taxes
1006
+		$taxes                         = $this->_transaction->get_many_related(
1007
+			'Line_Item',
1008
+			array(array('LIN_type' => EEM_Line_Item::type_tax))
1009
+		);
1010
+		$this->_template_args['taxes'] = ! empty($taxes) ? $taxes : false;
1011
+
1012
+		$this->_template_args['grand_total']     = EEH_Template::format_currency(
1013
+			$this->_transaction->get('TXN_total'),
1014
+			false,
1015
+			false
1016
+		);
1017
+		$this->_template_args['grand_raw_total'] = $this->_transaction->get('TXN_total');
1018
+		$this->_template_args['TXN_status']      = $this->_transaction->get('STS_ID');
1019
+
1020
+		// process payment details
1021
+		$payments = $this->_transaction->get_many_related('Payment');
1022
+		if (! empty($payments)) {
1023
+			$this->_template_args['payments']              = $payments;
1024
+			$this->_template_args['existing_reg_payments'] = $this->_get_registration_payment_IDs($payments);
1025
+		} else {
1026
+			$this->_template_args['payments']              = false;
1027
+			$this->_template_args['existing_reg_payments'] = array();
1028
+		}
1029
+
1030
+		$this->_template_args['edit_payment_url']   = add_query_arg(array('action' => 'edit_payment'), TXN_ADMIN_URL);
1031
+		$this->_template_args['delete_payment_url'] = add_query_arg(
1032
+			array('action' => 'espresso_delete_payment'),
1033
+			TXN_ADMIN_URL
1034
+		);
1035
+
1036
+		if (isset($txn_details['invoice_number'])) {
1037
+			$this->_template_args['txn_details']['invoice_number']['value'] = $this->_template_args['REG_code'];
1038
+			$this->_template_args['txn_details']['invoice_number']['label'] = esc_html__(
1039
+				'Invoice Number',
1040
+				'event_espresso'
1041
+			);
1042
+		}
1043
+
1044
+		$this->_template_args['txn_details']['registration_session']['value'] = $this->_transaction
1045
+			->get_first_related('Registration')
1046
+			->get('REG_session');
1047
+		$this->_template_args['txn_details']['registration_session']['label'] = esc_html__(
1048
+			'Registration Session',
1049
+			'event_espresso'
1050
+		);
1051
+
1052
+		$this->_template_args['txn_details']['ip_address']['value'] = isset($this->_session['ip_address'])
1053
+			? $this->_session['ip_address']
1054
+			: '';
1055
+		$this->_template_args['txn_details']['ip_address']['label'] = esc_html__(
1056
+			'Transaction placed from IP',
1057
+			'event_espresso'
1058
+		);
1059
+
1060
+		$this->_template_args['txn_details']['user_agent']['value'] = isset($this->_session['user_agent'])
1061
+			? $this->_session['user_agent']
1062
+			: '';
1063
+		$this->_template_args['txn_details']['user_agent']['label'] = esc_html__(
1064
+			'Registrant User Agent',
1065
+			'event_espresso'
1066
+		);
1067
+
1068
+		$reg_steps = '<ul>';
1069
+		foreach ($this->_transaction->reg_steps() as $reg_step => $reg_step_status) {
1070
+			if ($reg_step_status === true) {
1071
+				$reg_steps .= '<li style="color:#70cc50">'
1072
+							  . sprintf(
1073
+								  esc_html__('%1$s : Completed', 'event_espresso'),
1074
+								  ucwords(str_replace('_', ' ', $reg_step))
1075
+							  )
1076
+							  . '</li>';
1077
+			} elseif (is_numeric($reg_step_status) && $reg_step_status !== false) {
1078
+				$reg_steps .= '<li style="color:#2EA2CC">'
1079
+							  . sprintf(
1080
+								  esc_html__('%1$s : Initiated %2$s', 'event_espresso'),
1081
+								  ucwords(str_replace('_', ' ', $reg_step)),
1082
+								  date(
1083
+									  get_option('date_format') . ' ' . get_option('time_format'),
1084
+									  ($reg_step_status + (get_option('gmt_offset') * HOUR_IN_SECONDS))
1085
+								  )
1086
+							  )
1087
+							  . '</li>';
1088
+			} else {
1089
+				$reg_steps .= '<li style="color:#E76700">'
1090
+							  . sprintf(
1091
+								  esc_html__('%1$s : Never Initiated', 'event_espresso'),
1092
+								  ucwords(str_replace('_', ' ', $reg_step))
1093
+							  )
1094
+							  . '</li>';
1095
+			}
1096
+		}
1097
+		$reg_steps                                                 .= '</ul>';
1098
+		$this->_template_args['txn_details']['reg_steps']['value'] = $reg_steps;
1099
+		$this->_template_args['txn_details']['reg_steps']['label'] = esc_html__(
1100
+			'Registration Step Progress',
1101
+			'event_espresso'
1102
+		);
1103
+
1104
+
1105
+		$this->_get_registrations_to_apply_payment_to();
1106
+		$this->_get_payment_methods($payments);
1107
+		$this->_get_payment_status_array();
1108
+		$this->_get_reg_status_selection(); //sets up the template args for the reg status array for the transaction.
1109
+
1110
+		$this->_template_args['transaction_form_url']    = add_query_arg(array(
1111
+			'action'  => 'edit_transaction',
1112
+			'process' => 'transaction',
1113
+		), TXN_ADMIN_URL);
1114
+		$this->_template_args['apply_payment_form_url']  = add_query_arg(array(
1115
+			'page'   => 'espresso_transactions',
1116
+			'action' => 'espresso_apply_payment',
1117
+		), WP_AJAX_URL);
1118
+		$this->_template_args['delete_payment_form_url'] = add_query_arg(array(
1119
+			'page'   => 'espresso_transactions',
1120
+			'action' => 'espresso_delete_payment',
1121
+		), WP_AJAX_URL);
1122
+
1123
+		$this->_template_args['action_buttons'] = $this->getActionButtons($this->_transaction);
1124
+
1125
+		// 'espresso_delete_payment_nonce'
1126
+
1127
+		$template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_txn_details.template.php';
1128
+		echo EEH_Template::display_template($template_path, $this->_template_args, true);
1129
+	}
1130
+
1131
+
1132
+	/**
1133
+	 * _get_registration_payment_IDs
1134
+	 *    generates an array of Payment IDs and their corresponding Registration IDs
1135
+	 *
1136
+	 * @access protected
1137
+	 * @param EE_Payment[] $payments
1138
+	 * @return array
1139
+	 * @throws EE_Error
1140
+	 * @throws InvalidArgumentException
1141
+	 * @throws InvalidDataTypeException
1142
+	 * @throws InvalidInterfaceException
1143
+	 * @throws ReflectionException
1144
+	 */
1145
+	protected function _get_registration_payment_IDs($payments = array())
1146
+	{
1147
+		$existing_reg_payments = array();
1148
+		// get all reg payments for these payments
1149
+		$reg_payments = EEM_Registration_Payment::instance()->get_all(array(
1150
+			array(
1151
+				'PAY_ID' => array(
1152
+					'IN',
1153
+					array_keys($payments),
1154
+				),
1155
+			),
1156
+		));
1157
+		if (! empty($reg_payments)) {
1158
+			foreach ($payments as $payment) {
1159
+				if (! $payment instanceof EE_Payment) {
1160
+					continue;
1161
+				} elseif (! isset($existing_reg_payments[$payment->ID()])) {
1162
+					$existing_reg_payments[$payment->ID()] = array();
1163
+				}
1164
+				foreach ($reg_payments as $reg_payment) {
1165
+					if ($reg_payment instanceof EE_Registration_Payment
1166
+						&& $reg_payment->payment_ID() === $payment->ID()
1167
+					) {
1168
+						$existing_reg_payments[$payment->ID()][] = $reg_payment->registration_ID();
1169
+					}
1170
+				}
1171
+			}
1172
+		}
1173
+
1174
+		return $existing_reg_payments;
1175
+	}
1176
+
1177
+
1178
+	/**
1179
+	 * _get_registrations_to_apply_payment_to
1180
+	 *    generates HTML for displaying a series of checkboxes in the admin payment modal window
1181
+	 * which allows the admin to only apply the payment to the specific registrations
1182
+	 *
1183
+	 * @access protected
1184
+	 * @return void
1185
+	 * @throws \EE_Error
1186
+	 */
1187
+	protected function _get_registrations_to_apply_payment_to()
1188
+	{
1189
+		// we want any registration with an active status (ie: not deleted or cancelled)
1190
+		$query_params                      = array(
1191
+			array(
1192
+				'STS_ID' => array(
1193
+					'IN',
1194
+					array(
1195
+						EEM_Registration::status_id_approved,
1196
+						EEM_Registration::status_id_pending_payment,
1197
+						EEM_Registration::status_id_not_approved,
1198
+					),
1199
+				),
1200
+			),
1201
+		);
1202
+		$registrations_to_apply_payment_to = EEH_HTML::br()
1203
+											 . EEH_HTML::div(
1204
+												 '',
1205
+												 'txn-admin-apply-payment-to-registrations-dv',
1206
+												 '',
1207
+												 'clear: both; margin: 1.5em 0 0; display: none;'
1208
+											 );
1209
+		$registrations_to_apply_payment_to .= EEH_HTML::br() . EEH_HTML::div('', '', 'admin-primary-mbox-tbl-wrap');
1210
+		$registrations_to_apply_payment_to .= EEH_HTML::table('', '', 'admin-primary-mbox-tbl');
1211
+		$registrations_to_apply_payment_to .= EEH_HTML::thead(
1212
+			EEH_HTML::tr(
1213
+				EEH_HTML::th(esc_html__('ID', 'event_espresso')) .
1214
+				EEH_HTML::th(esc_html__('Registrant', 'event_espresso')) .
1215
+				EEH_HTML::th(esc_html__('Ticket', 'event_espresso')) .
1216
+				EEH_HTML::th(esc_html__('Event', 'event_espresso')) .
1217
+				EEH_HTML::th(esc_html__('Paid', 'event_espresso'), '', 'txn-admin-payment-paid-td jst-cntr') .
1218
+				EEH_HTML::th(esc_html__('Owing', 'event_espresso'), '', 'txn-admin-payment-owing-td jst-cntr') .
1219
+				EEH_HTML::th(esc_html__('Apply', 'event_espresso'), '', 'jst-cntr')
1220
+			)
1221
+		);
1222
+		$registrations_to_apply_payment_to .= EEH_HTML::tbody();
1223
+		// get registrations for TXN
1224
+		$registrations = $this->_transaction->registrations($query_params);
1225
+		$existing_reg_payments = $this->_template_args['existing_reg_payments'];
1226
+		foreach ($registrations as $registration) {
1227
+			if ($registration instanceof EE_Registration) {
1228
+				$attendee_name                     = $registration->attendee() instanceof EE_Attendee
1229
+					? $registration->attendee()->full_name()
1230
+					: esc_html__('Unknown Attendee', 'event_espresso');
1231
+				$owing                             = $registration->final_price() - $registration->paid();
1232
+				$taxable                           = $registration->ticket()->taxable()
1233
+					? ' <span class="smaller-text lt-grey-text"> ' . esc_html__('+ tax', 'event_espresso') . '</span>'
1234
+					: '';
1235
+				$checked = empty($existing_reg_payments) || in_array($registration->ID(), $existing_reg_payments)
1236
+					? ' checked="checked"'
1237
+					: '';
1238
+				$disabled                          = $registration->final_price() > 0 ? '' : ' disabled';
1239
+				$registrations_to_apply_payment_to .= EEH_HTML::tr(
1240
+					EEH_HTML::td($registration->ID()) .
1241
+					EEH_HTML::td($attendee_name) .
1242
+					EEH_HTML::td(
1243
+						$registration->ticket()->name() . ' : ' . $registration->ticket()->pretty_price() . $taxable
1244
+					) .
1245
+					EEH_HTML::td($registration->event_name()) .
1246
+					EEH_HTML::td($registration->pretty_paid(), '', 'txn-admin-payment-paid-td jst-cntr') .
1247
+					EEH_HTML::td(EEH_Template::format_currency($owing), '', 'txn-admin-payment-owing-td jst-cntr') .
1248
+					EEH_HTML::td(
1249
+						'<input type="checkbox" value="' . $registration->ID()
1250
+						. '" name="txn_admin_payment[registrations]"'
1251
+						. $checked . $disabled . '>',
1252
+						'',
1253
+						'jst-cntr'
1254
+					),
1255
+					'apply-payment-registration-row-' . $registration->ID()
1256
+				);
1257
+			}
1258
+		}
1259
+		$registrations_to_apply_payment_to                         .= EEH_HTML::tbodyx();
1260
+		$registrations_to_apply_payment_to                         .= EEH_HTML::tablex();
1261
+		$registrations_to_apply_payment_to                         .= EEH_HTML::divx();
1262
+		$registrations_to_apply_payment_to                         .= EEH_HTML::p(
1263
+			esc_html__(
1264
+				'The payment will only be applied to the registrations that have a check mark in their corresponding check box. Checkboxes for free registrations have been disabled.',
1265
+				'event_espresso'
1266
+			),
1267
+			'',
1268
+			'clear description'
1269
+		);
1270
+		$registrations_to_apply_payment_to                         .= EEH_HTML::divx();
1271
+		$this->_template_args['registrations_to_apply_payment_to'] = $registrations_to_apply_payment_to;
1272
+	}
1273
+
1274
+
1275
+	/**
1276
+	 * _get_reg_status_selection
1277
+	 *
1278
+	 * @todo   this will need to be adjusted either once MER comes along OR we move default reg status to tickets
1279
+	 *         instead of events.
1280
+	 * @access protected
1281
+	 * @return void
1282
+	 * @throws EE_Error
1283
+	 */
1284
+	protected function _get_reg_status_selection()
1285
+	{
1286
+		//first get all possible statuses
1287
+		$statuses = EEM_Registration::reg_status_array(array(), true);
1288
+		//let's add a "don't change" option.
1289
+		$status_array['NAN']                                 = esc_html__('Leave the Same', 'event_espresso');
1290
+		$status_array                                        = array_merge($status_array, $statuses);
1291
+		$this->_template_args['status_change_select']        = EEH_Form_Fields::select_input(
1292
+			'txn_reg_status_change[reg_status]',
1293
+			$status_array,
1294
+			'NAN',
1295
+			'id="txn-admin-payment-reg-status-inp"',
1296
+			'txn-reg-status-change-reg-status'
1297
+		);
1298
+		$this->_template_args['delete_status_change_select'] = EEH_Form_Fields::select_input(
1299
+			'delete_txn_reg_status_change[reg_status]',
1300
+			$status_array,
1301
+			'NAN',
1302
+			'delete-txn-admin-payment-reg-status-inp',
1303
+			'delete-txn-reg-status-change-reg-status'
1304
+		);
1305
+	}
1306
+
1307
+
1308
+	/**
1309
+	 *    _get_payment_methods
1310
+	 * Gets all the payment methods available generally, or the ones that are already
1311
+	 * selected on these payments (in case their payment methods are no longer active).
1312
+	 * Has the side-effect of updating the template args' payment_methods item
1313
+	 *
1314
+	 * @access private
1315
+	 * @param EE_Payment[] to show on this page
1316
+	 * @return void
1317
+	 * @throws EE_Error
1318
+	 * @throws InvalidArgumentException
1319
+	 * @throws InvalidDataTypeException
1320
+	 * @throws InvalidInterfaceException
1321
+	 * @throws ReflectionException
1322
+	 */
1323
+	private function _get_payment_methods($payments = array())
1324
+	{
1325
+		$payment_methods_of_payments = array();
1326
+		foreach ($payments as $payment) {
1327
+			if ($payment instanceof EE_Payment) {
1328
+				$payment_methods_of_payments[] = $payment->get('PMD_ID');
1329
+			}
1330
+		}
1331
+		if ($payment_methods_of_payments) {
1332
+			$query_args = array(
1333
+				array(
1334
+					'OR*payment_method_for_payment' => array(
1335
+						'PMD_ID'    => array('IN', $payment_methods_of_payments),
1336
+						'PMD_scope' => array('LIKE', '%' . EEM_Payment_Method::scope_admin . '%'),
1337
+					),
1338
+				),
1339
+			);
1340
+		} else {
1341
+			$query_args = array(array('PMD_scope' => array('LIKE', '%' . EEM_Payment_Method::scope_admin . '%')));
1342
+		}
1343
+		$this->_template_args['payment_methods'] = EEM_Payment_Method::instance()->get_all($query_args);
1344
+	}
1345
+
1346
+
1347
+	/**
1348
+	 * txn_attendees_meta_box
1349
+	 *    generates HTML for the Attendees Transaction main meta box
1350
+	 *
1351
+	 * @access public
1352
+	 * @param WP_Post $post
1353
+	 * @param array   $metabox
1354
+	 * @return void
1355
+	 * @throws DomainException
1356
+	 * @throws EE_Error
1357
+	 */
1358
+	public function txn_attendees_meta_box($post, $metabox = array('args' => array()))
1359
+	{
1360
+
1361
+		/** @noinspection NonSecureExtractUsageInspection */
1362
+		extract($metabox['args']);
1363
+		$this->_template_args['post']            = $post;
1364
+		$this->_template_args['event_attendees'] = array();
1365
+		// process items in cart
1366
+		$line_items = $this->_transaction->get_many_related(
1367
+			'Line_Item',
1368
+			array(array('LIN_type' => 'line-item'))
1369
+		);
1370
+		if (! empty($line_items)) {
1371
+			foreach ($line_items as $item) {
1372
+				if ($item instanceof EE_Line_Item) {
1373
+					switch ($item->OBJ_type()) {
1374
+						case 'Event':
1375
+							break;
1376
+						case 'Ticket':
1377
+							$ticket = $item->ticket();
1378
+							//right now we're only handling tickets here.
1379
+							//Cause its expected that only tickets will have attendees right?
1380
+							if (! $ticket instanceof EE_Ticket) {
1381
+								continue;
1382
+							}
1383
+							try {
1384
+								$event_name = $ticket->get_event_name();
1385
+							} catch (Exception $e) {
1386
+								EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1387
+								$event_name = esc_html__('Unknown Event', 'event_espresso');
1388
+							}
1389
+							$event_name   .= ' - ' . $item->get('LIN_name');
1390
+							$ticket_price = EEH_Template::format_currency($item->get('LIN_unit_price'));
1391
+							// now get all of the registrations for this transaction that use this ticket
1392
+							$registrations = $ticket->get_many_related(
1393
+								'Registration',
1394
+								array(array('TXN_ID' => $this->_transaction->ID()))
1395
+							);
1396
+							foreach ($registrations as $registration) {
1397
+								if (! $registration instanceof EE_Registration) {
1398
+									continue;
1399
+								}
1400
+								$this->_template_args['event_attendees'][$registration->ID()]['STS_ID']
1401
+									= $registration->status_ID();
1402
+								$this->_template_args['event_attendees'][$registration->ID()]['att_num']
1403
+									= $registration->count();
1404
+								$this->_template_args['event_attendees'][$registration->ID()]['event_ticket_name']
1405
+									= $event_name;
1406
+								$this->_template_args['event_attendees'][$registration->ID()]['ticket_price']
1407
+									= $ticket_price;
1408
+								// attendee info
1409
+								$attendee = $registration->get_first_related('Attendee');
1410
+								if ($attendee instanceof EE_Attendee) {
1411
+									$this->_template_args['event_attendees'][$registration->ID()]['att_id']
1412
+										= $attendee->ID();
1413
+									$this->_template_args['event_attendees'][$registration->ID()]['attendee']
1414
+										= $attendee->full_name();
1415
+									$this->_template_args['event_attendees'][$registration->ID()]['email']
1416
+										= '<a href="mailto:' . $attendee->email() . '?subject=' . $event_name
1417
+										  . esc_html__(
1418
+											  ' Event',
1419
+											  'event_espresso'
1420
+										  )
1421
+										  . '">' . $attendee->email() . '</a>';
1422
+									$this->_template_args['event_attendees'][$registration->ID()]['address']
1423
+										= EEH_Address::format($attendee, 'inline', false, false);
1424
+								} else {
1425
+									$this->_template_args['event_attendees'][$registration->ID()]['att_id']   = '';
1426
+									$this->_template_args['event_attendees'][$registration->ID()]['attendee'] = '';
1427
+									$this->_template_args['event_attendees'][$registration->ID()]['email']    = '';
1428
+									$this->_template_args['event_attendees'][$registration->ID()]['address']  = '';
1429
+								}
1430
+							}
1431
+							break;
1432
+
1433
+					}
1434
+				}
1435
+			}
1436
+
1437
+			$this->_template_args['transaction_form_url'] = add_query_arg(
1438
+				array(
1439
+					'action'  => 'edit_transaction',
1440
+					'process' => 'attendees',
1441
+				),
1442
+				TXN_ADMIN_URL
1443
+			);
1444
+			echo EEH_Template::display_template(
1445
+				TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_attendees.template.php',
1446
+				$this->_template_args,
1447
+				true
1448
+			);
1449
+
1450
+		} else {
1451
+			echo sprintf(
1452
+				esc_html__(
1453
+					'%1$sFor some reason, there are no attendees registered for this transaction. Likely the registration was abandoned in process.%2$s',
1454
+					'event_espresso'
1455
+				),
1456
+				'<p class="important-notice">',
1457
+				'</p>'
1458
+			);
1459
+		}
1460
+	}
1461
+
1462
+
1463
+	/**
1464
+	 * txn_registrant_side_meta_box
1465
+	 * generates HTML for the Edit Transaction side meta box
1466
+	 *
1467
+	 * @access public
1468
+	 * @return void
1469
+	 * @throws DomainException
1470
+	 * @throws EE_Error
1471
+	 * @throws InvalidArgumentException
1472
+	 * @throws InvalidDataTypeException
1473
+	 * @throws InvalidInterfaceException
1474
+	 * @throws ReflectionException
1475
+	 */
1476
+	public function txn_registrant_side_meta_box()
1477
+	{
1478
+		$primary_att = $this->_transaction->primary_registration() instanceof EE_Registration
1479
+			? $this->_transaction->primary_registration()->get_first_related('Attendee')
1480
+			: null;
1481
+		if (! $primary_att instanceof EE_Attendee) {
1482
+			$this->_template_args['no_attendee_message'] = esc_html__(
1483
+				'There is no attached contact for this transaction.  The transaction either failed due to an error or was abandoned.',
1484
+				'event_espresso'
1485
+			);
1486
+			$primary_att                                 = EEM_Attendee::instance()->create_default_object();
1487
+		}
1488
+		$this->_template_args['ATT_ID']            = $primary_att->ID();
1489
+		$this->_template_args['prime_reg_fname']   = $primary_att->fname();
1490
+		$this->_template_args['prime_reg_lname']   = $primary_att->lname();
1491
+		$this->_template_args['prime_reg_email']   = $primary_att->email();
1492
+		$this->_template_args['prime_reg_phone']   = $primary_att->phone();
1493
+		$this->_template_args['edit_attendee_url'] = EE_Admin_Page::add_query_args_and_nonce(array(
1494
+			'action' => 'edit_attendee',
1495
+			'post'   => $primary_att->ID(),
1496
+		), REG_ADMIN_URL);
1497
+		// get formatted address for registrant
1498
+		$this->_template_args['formatted_address'] = EEH_Address::format($primary_att);
1499
+		echo EEH_Template::display_template(
1500
+			TXN_TEMPLATE_PATH . 'txn_admin_details_side_meta_box_registrant.template.php',
1501
+			$this->_template_args,
1502
+			true
1503
+		);
1504
+	}
1505
+
1506
+
1507
+	/**
1508
+	 * txn_billing_info_side_meta_box
1509
+	 *    generates HTML for the Edit Transaction side meta box
1510
+	 *
1511
+	 * @access public
1512
+	 * @return void
1513
+	 * @throws DomainException
1514
+	 * @throws EE_Error
1515
+	 */
1516
+	public function txn_billing_info_side_meta_box()
1517
+	{
1518
+
1519
+		$this->_template_args['billing_form']     = $this->_transaction->billing_info();
1520
+		$this->_template_args['billing_form_url'] = add_query_arg(
1521
+			array('action' => 'edit_transaction', 'process' => 'billing'),
1522
+			TXN_ADMIN_URL
1523
+		);
1524
+
1525
+		$template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_side_meta_box_billing_info.template.php';
1526
+		echo EEH_Template::display_template($template_path, $this->_template_args, true);/**/
1527
+	}
1528
+
1529
+
1530
+	/**
1531
+	 * apply_payments_or_refunds
1532
+	 *    registers a payment or refund made towards a transaction
1533
+	 *
1534
+	 * @access public
1535
+	 * @return void
1536
+	 * @throws EE_Error
1537
+	 * @throws InvalidArgumentException
1538
+	 * @throws ReflectionException
1539
+	 * @throws RuntimeException
1540
+	 * @throws InvalidDataTypeException
1541
+	 * @throws InvalidInterfaceException
1542
+	 */
1543
+	public function apply_payments_or_refunds()
1544
+	{
1545
+		$json_response_data = array('return_data' => false);
1546
+		$valid_data         = $this->_validate_payment_request_data();
1547
+		$has_access = EE_Registry::instance()->CAP->current_user_can(
1548
+			'ee_edit_payments',
1549
+			'apply_payment_or_refund_from_registration_details'
1550
+		);
1551
+		if (! empty($valid_data) && $has_access) {
1552
+			$PAY_ID = $valid_data['PAY_ID'];
1553
+			//save  the new payment
1554
+			$payment = $this->_create_payment_from_request_data($valid_data);
1555
+			// get the TXN for this payment
1556
+			$transaction = $payment->transaction();
1557
+			// verify transaction
1558
+			if ($transaction instanceof EE_Transaction) {
1559
+				// calculate_total_payments_and_update_status
1560
+				$this->_process_transaction_payments($transaction);
1561
+				$REG_IDs = $this->_get_REG_IDs_to_apply_payment_to($payment);
1562
+				$this->_remove_existing_registration_payments($payment, $PAY_ID);
1563
+				// apply payment to registrations (if applicable)
1564
+				if (! empty($REG_IDs)) {
1565
+					$this->_update_registration_payments($transaction, $payment, $REG_IDs);
1566
+					$this->_maybe_send_notifications();
1567
+					// now process status changes for the same registrations
1568
+					$this->_process_registration_status_change($transaction, $REG_IDs);
1569
+				}
1570
+				$this->_maybe_send_notifications($payment);
1571
+				//prepare to render page
1572
+				$json_response_data['return_data'] = $this->_build_payment_json_response($payment, $REG_IDs);
1573
+				do_action(
1574
+					'AHEE__Transactions_Admin_Page__apply_payments_or_refund__after_recording',
1575
+					$transaction,
1576
+					$payment
1577
+				);
1578
+			} else {
1579
+				EE_Error::add_error(
1580
+					esc_html__(
1581
+						'A valid Transaction for this payment could not be retrieved.',
1582
+						'event_espresso'
1583
+					),
1584
+					__FILE__,
1585
+					__FUNCTION__,
1586
+					__LINE__
1587
+				);
1588
+			}
1589
+		} else {
1590
+			if ($has_access) {
1591
+				EE_Error::add_error(
1592
+					esc_html__(
1593
+						'The payment form data could not be processed. Please try again.',
1594
+						'event_espresso'
1595
+					),
1596
+					__FILE__,
1597
+					__FUNCTION__,
1598
+					__LINE__
1599
+				);
1600
+			} else {
1601
+				EE_Error::add_error(
1602
+					esc_html__(
1603
+						'You do not have access to apply payments or refunds to a registration.',
1604
+						'event_espresso'
1605
+					),
1606
+					__FILE__,
1607
+					__FUNCTION__,
1608
+					__LINE__
1609
+				);
1610
+			}
1611
+		}
1612
+		$notices              = EE_Error::get_notices(
1613
+			false,
1614
+			false,
1615
+			false
1616
+		);
1617
+		$this->_template_args = array(
1618
+			'data'    => $json_response_data,
1619
+			'error'   => $notices['errors'],
1620
+			'success' => $notices['success'],
1621
+		);
1622
+		$this->_return_json();
1623
+	}
1624
+
1625
+
1626
+	/**
1627
+	 * _validate_payment_request_data
1628
+	 *
1629
+	 * @return array
1630
+	 * @throws EE_Error
1631
+	 */
1632
+	protected function _validate_payment_request_data()
1633
+	{
1634
+		if (! isset($this->_req_data['txn_admin_payment'])) {
1635
+			return false;
1636
+		}
1637
+		$payment_form = $this->_generate_payment_form_section();
1638
+		try {
1639
+			if ($payment_form->was_submitted()) {
1640
+				$payment_form->receive_form_submission();
1641
+				if (! $payment_form->is_valid()) {
1642
+					$submission_error_messages = array();
1643
+					foreach ($payment_form->get_validation_errors_accumulated() as $validation_error) {
1644
+						if ($validation_error instanceof EE_Validation_Error) {
1645
+							$submission_error_messages[] = sprintf(
1646
+								_x('%s : %s', 'Form Section Name : Form Validation Error', 'event_espresso'),
1647
+								$validation_error->get_form_section()->html_label_text(),
1648
+								$validation_error->getMessage()
1649
+							);
1650
+						}
1651
+					}
1652
+					EE_Error::add_error(
1653
+						implode('<br />', $submission_error_messages),
1654
+						__FILE__,
1655
+						__FUNCTION__,
1656
+						__LINE__
1657
+					);
1658
+
1659
+					return array();
1660
+				}
1661
+			}
1662
+		} catch (EE_Error $e) {
1663
+			EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1664
+
1665
+			return array();
1666
+		}
1667
+
1668
+		return $payment_form->valid_data();
1669
+	}
1670
+
1671
+
1672
+	/**
1673
+	 * _generate_payment_form_section
1674
+	 *
1675
+	 * @return EE_Form_Section_Proper
1676
+	 * @throws EE_Error
1677
+	 */
1678
+	protected function _generate_payment_form_section()
1679
+	{
1680
+		return new EE_Form_Section_Proper(
1681
+			array(
1682
+				'name'        => 'txn_admin_payment',
1683
+				'subsections' => array(
1684
+					'PAY_ID'          => new EE_Text_Input(
1685
+						array(
1686
+							'default'               => 0,
1687
+							'required'              => false,
1688
+							'html_label_text'       => esc_html__('Payment ID', 'event_espresso'),
1689
+							'validation_strategies' => array(new EE_Int_Normalization()),
1690
+						)
1691
+					),
1692
+					'TXN_ID'          => new EE_Text_Input(
1693
+						array(
1694
+							'default'               => 0,
1695
+							'required'              => true,
1696
+							'html_label_text'       => esc_html__('Transaction ID', 'event_espresso'),
1697
+							'validation_strategies' => array(new EE_Int_Normalization()),
1698
+						)
1699
+					),
1700
+					'type'            => new EE_Text_Input(
1701
+						array(
1702
+							'default'               => 1,
1703
+							'required'              => true,
1704
+							'html_label_text'       => esc_html__('Payment or Refund', 'event_espresso'),
1705
+							'validation_strategies' => array(new EE_Int_Normalization()),
1706
+						)
1707
+					),
1708
+					'amount'          => new EE_Text_Input(
1709
+						array(
1710
+							'default'               => 0,
1711
+							'required'              => true,
1712
+							'html_label_text'       => esc_html__('Payment amount', 'event_espresso'),
1713
+							'validation_strategies' => array(new EE_Float_Normalization()),
1714
+						)
1715
+					),
1716
+					'status'          => new EE_Text_Input(
1717
+						array(
1718
+							'default'         => EEM_Payment::status_id_approved,
1719
+							'required'        => true,
1720
+							'html_label_text' => esc_html__('Payment status', 'event_espresso'),
1721
+						)
1722
+					),
1723
+					'PMD_ID'          => new EE_Text_Input(
1724
+						array(
1725
+							'default'               => 2,
1726
+							'required'              => true,
1727
+							'html_label_text'       => esc_html__('Payment Method', 'event_espresso'),
1728
+							'validation_strategies' => array(new EE_Int_Normalization()),
1729
+						)
1730
+					),
1731
+					'date'            => new EE_Text_Input(
1732
+						array(
1733
+							'default'         => time(),
1734
+							'required'        => true,
1735
+							'html_label_text' => esc_html__('Payment date', 'event_espresso'),
1736
+						)
1737
+					),
1738
+					'txn_id_chq_nmbr' => new EE_Text_Input(
1739
+						array(
1740
+							'default'               => '',
1741
+							'required'              => false,
1742
+							'html_label_text'       => esc_html__('Transaction or Cheque Number', 'event_espresso'),
1743
+							'validation_strategies' => array(
1744
+								new EE_Max_Length_Validation_Strategy(
1745
+									esc_html__('Input too long', 'event_espresso'),
1746
+									100
1747
+								),
1748
+							),
1749
+						)
1750
+					),
1751
+					'po_number'       => new EE_Text_Input(
1752
+						array(
1753
+							'default'               => '',
1754
+							'required'              => false,
1755
+							'html_label_text'       => esc_html__('Purchase Order Number', 'event_espresso'),
1756
+							'validation_strategies' => array(
1757
+								new EE_Max_Length_Validation_Strategy(
1758
+									esc_html__('Input too long', 'event_espresso'),
1759
+									100
1760
+								),
1761
+							),
1762
+						)
1763
+					),
1764
+					'accounting'      => new EE_Text_Input(
1765
+						array(
1766
+							'default'               => '',
1767
+							'required'              => false,
1768
+							'html_label_text'       => esc_html__('Extra Field for Accounting', 'event_espresso'),
1769
+							'validation_strategies' => array(
1770
+								new EE_Max_Length_Validation_Strategy(
1771
+									esc_html__('Input too long', 'event_espresso'),
1772
+									100
1773
+								),
1774
+							),
1775
+						)
1776
+					),
1777
+				),
1778
+			)
1779
+		);
1780
+	}
1781
+
1782
+
1783
+	/**
1784
+	 * _create_payment_from_request_data
1785
+	 *
1786
+	 * @param array $valid_data
1787
+	 * @return EE_Payment
1788
+	 * @throws EE_Error
1789
+	 */
1790
+	protected function _create_payment_from_request_data($valid_data)
1791
+	{
1792
+		$PAY_ID = $valid_data['PAY_ID'];
1793
+		// get payment amount
1794
+		$amount = $valid_data['amount'] ? abs($valid_data['amount']) : 0;
1795
+		// payments have a type value of 1 and refunds have a type value of -1
1796
+		// so multiplying amount by type will give a positive value for payments, and negative values for refunds
1797
+		$amount = $valid_data['type'] < 0 ? $amount * -1 : $amount;
1798
+		// for some reason the date string coming in has extra spaces between the date and time.  This fixes that.
1799
+		$date    = $valid_data['date']
1800
+			? preg_replace('/\s+/', ' ', $valid_data['date'])
1801
+			: date('Y-m-d g:i a', current_time('timestamp'));
1802
+		$payment = EE_Payment::new_instance(
1803
+			array(
1804
+				'TXN_ID'              => $valid_data['TXN_ID'],
1805
+				'STS_ID'              => $valid_data['status'],
1806
+				'PAY_timestamp'       => $date,
1807
+				'PAY_source'          => EEM_Payment_Method::scope_admin,
1808
+				'PMD_ID'              => $valid_data['PMD_ID'],
1809
+				'PAY_amount'          => $amount,
1810
+				'PAY_txn_id_chq_nmbr' => $valid_data['txn_id_chq_nmbr'],
1811
+				'PAY_po_number'       => $valid_data['po_number'],
1812
+				'PAY_extra_accntng'   => $valid_data['accounting'],
1813
+				'PAY_details'         => $valid_data,
1814
+				'PAY_ID'              => $PAY_ID,
1815
+			),
1816
+			'',
1817
+			array('Y-m-d', 'g:i a')
1818
+		);
1819
+
1820
+		if (! $payment->save()) {
1821
+			EE_Error::add_error(
1822
+				sprintf(
1823
+					esc_html__('Payment %1$d has not been successfully saved to the database.', 'event_espresso'),
1824
+					$payment->ID()
1825
+				),
1826
+				__FILE__, __FUNCTION__, __LINE__
1827
+			);
1828
+		}
1829
+
1830
+		return $payment;
1831
+	}
1832
+
1833
+
1834
+	/**
1835
+	 * _process_transaction_payments
1836
+	 *
1837
+	 * @param \EE_Transaction $transaction
1838
+	 * @return void
1839
+	 * @throws EE_Error
1840
+	 * @throws InvalidArgumentException
1841
+	 * @throws ReflectionException
1842
+	 * @throws InvalidDataTypeException
1843
+	 * @throws InvalidInterfaceException
1844
+	 */
1845
+	protected function _process_transaction_payments(EE_Transaction $transaction)
1846
+	{
1847
+		/** @type EE_Transaction_Payments $transaction_payments */
1848
+		$transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
1849
+		//update the transaction with this payment
1850
+		if ($transaction_payments->calculate_total_payments_and_update_status($transaction)) {
1851
+			EE_Error::add_success(esc_html__(
1852
+				'The payment has been processed successfully.', 'event_espresso'),
1853
+				__FILE__,
1854
+				__FUNCTION__,
1855
+				__LINE__
1856
+			);
1857
+		} else {
1858
+			EE_Error::add_error(
1859
+				esc_html__(
1860
+					'The payment was processed successfully but the amount paid for the transaction was not updated.',
1861
+					'event_espresso'
1862
+				)
1863
+				,
1864
+				__FILE__,
1865
+				__FUNCTION__,
1866
+				__LINE__
1867
+			);
1868
+		}
1869
+	}
1870
+
1871
+
1872
+	/**
1873
+	 * _get_REG_IDs_to_apply_payment_to
1874
+	 * returns a list of registration IDs that the payment will apply to
1875
+	 *
1876
+	 * @param \EE_Payment $payment
1877
+	 * @return array
1878
+	 * @throws EE_Error
1879
+	 */
1880
+	protected function _get_REG_IDs_to_apply_payment_to(EE_Payment $payment)
1881
+	{
1882
+		$REG_IDs = array();
1883
+		// grab array of IDs for specific registrations to apply changes to
1884
+		if (isset($this->_req_data['txn_admin_payment']['registrations'])) {
1885
+			$REG_IDs = (array)$this->_req_data['txn_admin_payment']['registrations'];
1886
+		}
1887
+		//nothing specified ? then get all reg IDs
1888
+		if (empty($REG_IDs)) {
1889
+			$registrations = $payment->transaction()->registrations();
1890
+			$REG_IDs       = ! empty($registrations)
1891
+				? array_keys($registrations)
1892
+				: $this->_get_existing_reg_payment_REG_IDs($payment);
1893
+		}
1894
+
1895
+		// ensure that REG_IDs are integers and NOT strings
1896
+		return array_map('intval', $REG_IDs);
1897
+	}
1898
+
1899
+
1900
+	/**
1901
+	 * @return array
1902
+	 */
1903
+	public function existing_reg_payment_REG_IDs()
1904
+	{
1905
+		return $this->_existing_reg_payment_REG_IDs;
1906
+	}
1907
+
1908
+
1909
+	/**
1910
+	 * @param array $existing_reg_payment_REG_IDs
1911
+	 */
1912
+	public function set_existing_reg_payment_REG_IDs($existing_reg_payment_REG_IDs = null)
1913
+	{
1914
+		$this->_existing_reg_payment_REG_IDs = $existing_reg_payment_REG_IDs;
1915
+	}
1916
+
1917
+
1918
+	/**
1919
+	 * _get_existing_reg_payment_REG_IDs
1920
+	 * returns a list of registration IDs that the payment is currently related to
1921
+	 * as recorded in the database
1922
+	 *
1923
+	 * @param \EE_Payment $payment
1924
+	 * @return array
1925
+	 * @throws EE_Error
1926
+	 */
1927
+	protected function _get_existing_reg_payment_REG_IDs(EE_Payment $payment)
1928
+	{
1929
+		if ($this->existing_reg_payment_REG_IDs() === null) {
1930
+			// let's get any existing reg payment records for this payment
1931
+			$existing_reg_payment_REG_IDs = $payment->get_many_related('Registration');
1932
+			// but we only want the REG IDs, so grab the array keys
1933
+			$existing_reg_payment_REG_IDs = ! empty($existing_reg_payment_REG_IDs)
1934
+				? array_keys($existing_reg_payment_REG_IDs)
1935
+				: array();
1936
+			$this->set_existing_reg_payment_REG_IDs($existing_reg_payment_REG_IDs);
1937
+		}
1938
+
1939
+		return $this->existing_reg_payment_REG_IDs();
1940
+	}
1941
+
1942
+
1943
+	/**
1944
+	 * _remove_existing_registration_payments
1945
+	 * this calculates the difference between existing relations
1946
+	 * to the supplied payment and the new list registration IDs,
1947
+	 * removes any related registrations that no longer apply,
1948
+	 * and then updates the registration paid fields
1949
+	 *
1950
+	 * @param \EE_Payment $payment
1951
+	 * @param int         $PAY_ID
1952
+	 * @return bool;
1953
+	 * @throws EE_Error
1954
+	 * @throws InvalidArgumentException
1955
+	 * @throws ReflectionException
1956
+	 * @throws InvalidDataTypeException
1957
+	 * @throws InvalidInterfaceException
1958
+	 */
1959
+	protected function _remove_existing_registration_payments(EE_Payment $payment, $PAY_ID = 0)
1960
+	{
1961
+		// newly created payments will have nothing recorded for $PAY_ID
1962
+		if ($PAY_ID == 0) {
1963
+			return false;
1964
+		}
1965
+		$existing_reg_payment_REG_IDs = $this->_get_existing_reg_payment_REG_IDs($payment);
1966
+		if (empty($existing_reg_payment_REG_IDs)) {
1967
+			return false;
1968
+		}
1969
+		/** @type EE_Transaction_Payments $transaction_payments */
1970
+		$transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
1971
+
1972
+		return $transaction_payments->delete_registration_payments_and_update_registrations(
1973
+			$payment,
1974
+			array(
1975
+				array(
1976
+					'PAY_ID' => $payment->ID(),
1977
+					'REG_ID' => array('IN', $existing_reg_payment_REG_IDs),
1978
+				),
1979
+			)
1980
+		);
1981
+	}
1982
+
1983
+
1984
+	/**
1985
+	 * _update_registration_payments
1986
+	 * this applies the payments to the selected registrations
1987
+	 * but only if they have not already been paid for
1988
+	 *
1989
+	 * @param  EE_Transaction $transaction
1990
+	 * @param \EE_Payment     $payment
1991
+	 * @param array           $REG_IDs
1992
+	 * @return void
1993
+	 * @throws EE_Error
1994
+	 * @throws InvalidArgumentException
1995
+	 * @throws ReflectionException
1996
+	 * @throws RuntimeException
1997
+	 * @throws InvalidDataTypeException
1998
+	 * @throws InvalidInterfaceException
1999
+	 */
2000
+	protected function _update_registration_payments(
2001
+		EE_Transaction $transaction,
2002
+		EE_Payment $payment,
2003
+		$REG_IDs = array()
2004
+	) {
2005
+		// we can pass our own custom set of registrations to EE_Payment_Processor::process_registration_payments()
2006
+		// so let's do that using our set of REG_IDs from the form
2007
+		$registration_query_where_params = array(
2008
+			'REG_ID' => array('IN', $REG_IDs),
2009
+		);
2010
+		// but add in some conditions regarding payment,
2011
+		// so that we don't apply payments to registrations that are free or have already been paid for
2012
+		// but ONLY if the payment is NOT a refund ( ie: the payment amount is not negative )
2013
+		if (! $payment->is_a_refund()) {
2014
+			$registration_query_where_params['REG_final_price']  = array('!=', 0);
2015
+			$registration_query_where_params['REG_final_price*'] = array('!=', 'REG_paid', true);
2016
+		}
2017
+		$registrations = $transaction->registrations(array($registration_query_where_params));
2018
+		if (! empty($registrations)) {
2019
+			/** @type EE_Payment_Processor $payment_processor */
2020
+			$payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
2021
+			$payment_processor->process_registration_payments($transaction, $payment, $registrations);
2022
+		}
2023
+	}
2024
+
2025
+
2026
+	/**
2027
+	 * _process_registration_status_change
2028
+	 * This processes requested registration status changes for all the registrations
2029
+	 * on a given transaction and (optionally) sends out notifications for the changes.
2030
+	 *
2031
+	 * @param  EE_Transaction $transaction
2032
+	 * @param array           $REG_IDs
2033
+	 * @return bool
2034
+	 * @throws EE_Error
2035
+	 * @throws InvalidArgumentException
2036
+	 * @throws ReflectionException
2037
+	 * @throws InvalidDataTypeException
2038
+	 * @throws InvalidInterfaceException
2039
+	 */
2040
+	protected function _process_registration_status_change(EE_Transaction $transaction, $REG_IDs = array())
2041
+	{
2042
+		// first if there is no change in status then we get out.
2043
+		if (
2044
+			! isset($this->_req_data['txn_reg_status_change']['reg_status'])
2045
+			|| $this->_req_data['txn_reg_status_change']['reg_status'] === 'NAN'
2046
+		) {
2047
+			//no error message, no change requested, just nothing to do man.
2048
+			return false;
2049
+		}
2050
+		/** @type EE_Transaction_Processor $transaction_processor */
2051
+		$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
2052
+
2053
+		// made it here dude?  Oh WOW.  K, let's take care of changing the statuses
2054
+		return $transaction_processor->manually_update_registration_statuses(
2055
+			$transaction,
2056
+			sanitize_text_field($this->_req_data['txn_reg_status_change']['reg_status']),
2057
+			array(array('REG_ID' => array('IN', $REG_IDs)))
2058
+		);
2059
+	}
2060
+
2061
+
2062
+	/**
2063
+	 * _build_payment_json_response
2064
+	 *
2065
+	 * @access public
2066
+	 * @param \EE_Payment $payment
2067
+	 * @param array       $REG_IDs
2068
+	 * @param bool | null $delete_txn_reg_status_change
2069
+	 * @return array
2070
+	 * @throws EE_Error
2071
+	 * @throws InvalidArgumentException
2072
+	 * @throws InvalidDataTypeException
2073
+	 * @throws InvalidInterfaceException
2074
+	 * @throws ReflectionException
2075
+	 */
2076
+	protected function _build_payment_json_response(
2077
+		EE_Payment $payment,
2078
+		$REG_IDs = array(),
2079
+		$delete_txn_reg_status_change = null
2080
+	) {
2081
+		// was the payment deleted ?
2082
+		if (is_bool($delete_txn_reg_status_change)) {
2083
+			return array(
2084
+				'PAY_ID'                       => $payment->ID(),
2085
+				'amount'                       => $payment->amount(),
2086
+				'total_paid'                   => $payment->transaction()->paid(),
2087
+				'txn_status'                   => $payment->transaction()->status_ID(),
2088
+				'pay_status'                   => $payment->STS_ID(),
2089
+				'registrations'                => $this->_registration_payment_data_array($REG_IDs),
2090
+				'delete_txn_reg_status_change' => $delete_txn_reg_status_change,
2091
+			);
2092
+		} else {
2093
+			$this->_get_payment_status_array();
2094
+
2095
+			return array(
2096
+				'amount'           => $payment->amount(),
2097
+				'total_paid'       => $payment->transaction()->paid(),
2098
+				'txn_status'       => $payment->transaction()->status_ID(),
2099
+				'pay_status'       => $payment->STS_ID(),
2100
+				'PAY_ID'           => $payment->ID(),
2101
+				'STS_ID'           => $payment->STS_ID(),
2102
+				'status'           => self::$_pay_status[$payment->STS_ID()],
2103
+				'date'             => $payment->timestamp('Y-m-d', 'h:i a'),
2104
+				'method'           => strtoupper($payment->source()),
2105
+				'PM_ID'            => $payment->payment_method() ? $payment->payment_method()->ID() : 1,
2106
+				'gateway'          => $payment->payment_method()
2107
+					? $payment->payment_method()->admin_name()
2108
+					: esc_html__("Unknown", 'event_espresso'),
2109
+				'gateway_response' => $payment->gateway_response(),
2110
+				'txn_id_chq_nmbr'  => $payment->txn_id_chq_nmbr(),
2111
+				'po_number'        => $payment->po_number(),
2112
+				'extra_accntng'    => $payment->extra_accntng(),
2113
+				'registrations'    => $this->_registration_payment_data_array($REG_IDs),
2114
+			);
2115
+		}
2116
+	}
2117
+
2118
+
2119
+	/**
2120
+	 * delete_payment
2121
+	 *    delete a payment or refund made towards a transaction
2122
+	 *
2123
+	 * @access public
2124
+	 * @return void
2125
+	 * @throws EE_Error
2126
+	 * @throws InvalidArgumentException
2127
+	 * @throws ReflectionException
2128
+	 * @throws InvalidDataTypeException
2129
+	 * @throws InvalidInterfaceException
2130
+	 */
2131
+	public function delete_payment()
2132
+	{
2133
+		$json_response_data = array('return_data' => false);
2134
+		$PAY_ID             = isset($this->_req_data['delete_txn_admin_payment']['PAY_ID'])
2135
+			? absint($this->_req_data['delete_txn_admin_payment']['PAY_ID'])
2136
+			: 0;
2137
+		$can_delete = EE_Registry::instance()->CAP->current_user_can(
2138
+			'ee_delete_payments',
2139
+			'delete_payment_from_registration_details'
2140
+		);
2141
+		if ($PAY_ID && $can_delete) {
2142
+			$delete_txn_reg_status_change = isset($this->_req_data['delete_txn_reg_status_change'])
2143
+				? $this->_req_data['delete_txn_reg_status_change']
2144
+				: false;
2145
+			$payment                      = EEM_Payment::instance()->get_one_by_ID($PAY_ID);
2146
+			if ($payment instanceof EE_Payment) {
2147
+				$REG_IDs = $this->_get_existing_reg_payment_REG_IDs($payment);
2148
+				/** @type EE_Transaction_Payments $transaction_payments */
2149
+				$transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
2150
+				if ($transaction_payments->delete_payment_and_update_transaction($payment)) {
2151
+					$json_response_data['return_data'] = $this->_build_payment_json_response(
2152
+						$payment,
2153
+						$REG_IDs,
2154
+						$delete_txn_reg_status_change
2155
+					);
2156
+					if ($delete_txn_reg_status_change) {
2157
+						$this->_req_data['txn_reg_status_change'] = $delete_txn_reg_status_change;
2158
+						//MAKE sure we also add the delete_txn_req_status_change to the
2159
+						//$_REQUEST global because that's how messages will be looking for it.
2160
+						$_REQUEST['txn_reg_status_change'] = $delete_txn_reg_status_change;
2161
+						$this->_maybe_send_notifications();
2162
+						$this->_process_registration_status_change($payment->transaction(), $REG_IDs);
2163
+					}
2164
+				}
2165
+			} else {
2166
+				EE_Error::add_error(
2167
+					esc_html__('Valid Payment data could not be retrieved from the database.', 'event_espresso'),
2168
+					__FILE__, __FUNCTION__, __LINE__
2169
+				);
2170
+			}
2171
+		} else {
2172
+			if ($can_delete) {
2173
+				EE_Error::add_error(
2174
+					esc_html__(
2175
+						'A valid Payment ID was not received, therefore payment form data could not be loaded.',
2176
+						'event_espresso'
2177
+					),
2178
+					__FILE__, __FUNCTION__, __LINE__
2179
+				);
2180
+			} else {
2181
+				EE_Error::add_error(
2182
+					esc_html__(
2183
+						'You do not have access to delete a payment.',
2184
+						'event_espresso'
2185
+					),
2186
+					__FILE__,
2187
+					__FUNCTION__,
2188
+					__LINE__
2189
+				);
2190
+			}
2191
+		}
2192
+		$notices              = EE_Error::get_notices(false, false, false);
2193
+		$this->_template_args = array(
2194
+			'data'      => $json_response_data,
2195
+			'success'   => $notices['success'],
2196
+			'error'     => $notices['errors'],
2197
+			'attention' => $notices['attention'],
2198
+		);
2199
+		$this->_return_json();
2200
+	}
2201
+
2202
+
2203
+	/**
2204
+	 * _registration_payment_data_array
2205
+	 * adds info for 'owing' and 'paid' for each registration to the json response
2206
+	 *
2207
+	 * @access protected
2208
+	 * @param array $REG_IDs
2209
+	 * @return array
2210
+	 * @throws EE_Error
2211
+	 * @throws InvalidArgumentException
2212
+	 * @throws InvalidDataTypeException
2213
+	 * @throws InvalidInterfaceException
2214
+	 * @throws ReflectionException
2215
+	 */
2216
+	protected function _registration_payment_data_array($REG_IDs)
2217
+	{
2218
+		$registration_payment_data = array();
2219
+		//if non empty reg_ids lets get an array of registrations and update the values for the apply_payment/refund rows.
2220
+		if (! empty($REG_IDs)) {
2221
+			$registrations = EEM_Registration::instance()->get_all(array(array('REG_ID' => array('IN', $REG_IDs))));
2222
+			foreach ($registrations as $registration) {
2223
+				if ($registration instanceof EE_Registration) {
2224
+					$registration_payment_data[$registration->ID()] = array(
2225
+						'paid'  => $registration->pretty_paid(),
2226
+						'owing' => EEH_Template::format_currency($registration->final_price() - $registration->paid()),
2227
+					);
2228
+				}
2229
+			}
2230
+		}
2231
+
2232
+		return $registration_payment_data;
2233
+	}
2234
+
2235
+
2236
+	/**
2237
+	 * _maybe_send_notifications
2238
+	 * determines whether or not the admin has indicated that notifications should be sent.
2239
+	 * If so, will toggle a filter switch for delivering registration notices.
2240
+	 * If passed an EE_Payment object, then it will trigger payment notifications instead.
2241
+	 *
2242
+	 * @access protected
2243
+	 * @param \EE_Payment | null $payment
2244
+	 */
2245
+	protected function _maybe_send_notifications($payment = null)
2246
+	{
2247
+		switch ($payment instanceof EE_Payment) {
2248
+			// payment notifications
2249
+			case true :
2250
+				if (
2251
+					isset(
2252
+						$this->_req_data['txn_payments'],
2253
+						$this->_req_data['txn_payments']['send_notifications']
2254
+					) &&
2255
+					filter_var($this->_req_data['txn_payments']['send_notifications'], FILTER_VALIDATE_BOOLEAN)
2256
+				) {
2257
+					$this->_process_payment_notification($payment);
2258
+				}
2259
+				break;
2260
+			// registration notifications
2261
+			case false :
2262
+				if (
2263
+					isset(
2264
+						$this->_req_data['txn_reg_status_change'],
2265
+						$this->_req_data['txn_reg_status_change']['send_notifications']
2266
+					) &&
2267
+					filter_var($this->_req_data['txn_reg_status_change']['send_notifications'], FILTER_VALIDATE_BOOLEAN)
2268
+				) {
2269
+					add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true');
2270
+				}
2271
+				break;
2272
+		}
2273
+	}
2274
+
2275
+
2276
+	/**
2277
+	 * _send_payment_reminder
2278
+	 *    generates HTML for the View Transaction Details Admin page
2279
+	 *
2280
+	 * @access protected
2281
+	 * @return void
2282
+	 * @throws EE_Error
2283
+	 * @throws InvalidArgumentException
2284
+	 * @throws InvalidDataTypeException
2285
+	 * @throws InvalidInterfaceException
2286
+	 */
2287
+	protected function _send_payment_reminder()
2288
+	{
2289
+		$TXN_ID      = ! empty($this->_req_data['TXN_ID']) ? absint($this->_req_data['TXN_ID']) : false;
2290
+		$transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
2291
+		$query_args  = isset($this->_req_data['redirect_to']) ? array(
2292
+			'action' => $this->_req_data['redirect_to'],
2293
+			'TXN_ID' => $this->_req_data['TXN_ID'],
2294
+		) : array();
2295
+		do_action(
2296
+			'AHEE__Transactions_Admin_Page___send_payment_reminder__process_admin_payment_reminder',
2297
+			$transaction
2298
+		);
2299
+		$this->_redirect_after_action(
2300
+			false,
2301
+			esc_html__('payment reminder', 'event_espresso'),
2302
+			esc_html__('sent', 'event_espresso'),
2303
+			$query_args,
2304
+			true
2305
+		);
2306
+	}
2307
+
2308
+
2309
+	/**
2310
+	 *  get_transactions
2311
+	 *    get transactions for given parameters (used by list table)
2312
+	 *
2313
+	 * @param  int     $perpage how many transactions displayed per page
2314
+	 * @param  boolean $count   return the count or objects
2315
+	 * @param string   $view
2316
+	 * @return mixed int = count || array of transaction objects
2317
+	 * @throws EE_Error
2318
+	 * @throws InvalidArgumentException
2319
+	 * @throws InvalidDataTypeException
2320
+	 * @throws InvalidInterfaceException
2321
+	 */
2322
+	public function get_transactions($perpage, $count = false, $view = '')
2323
+	{
2324
+
2325
+		$TXN = EEM_Transaction::instance();
2326
+
2327
+		$start_date = isset($this->_req_data['txn-filter-start-date'])
2328
+			? wp_strip_all_tags($this->_req_data['txn-filter-start-date'])
2329
+			: date(
2330
+				'm/d/Y',
2331
+				strtotime('-10 year')
2332
+			);
2333
+		$end_date   = isset($this->_req_data['txn-filter-end-date'])
2334
+			? wp_strip_all_tags($this->_req_data['txn-filter-end-date'])
2335
+			: date('m/d/Y');
2336
+
2337
+		//make sure our timestamps start and end right at the boundaries for each day
2338
+		$start_date = date('Y-m-d', strtotime($start_date)) . ' 00:00:00';
2339
+		$end_date   = date('Y-m-d', strtotime($end_date)) . ' 23:59:59';
2340
+
2341
+
2342
+		//convert to timestamps
2343
+		$start_date = strtotime($start_date);
2344
+		$end_date   = strtotime($end_date);
2345
+
2346
+		//makes sure start date is the lowest value and vice versa
2347
+		$start_date = min($start_date, $end_date);
2348
+		$end_date   = max($start_date, $end_date);
2349
+
2350
+		//convert to correct format for query
2351
+		$start_date = EEM_Transaction::instance()->convert_datetime_for_query(
2352
+			'TXN_timestamp',
2353
+			date('Y-m-d H:i:s', $start_date),
2354
+			'Y-m-d H:i:s'
2355
+		);
2356
+		$end_date   = EEM_Transaction::instance()->convert_datetime_for_query(
2357
+			'TXN_timestamp',
2358
+			date('Y-m-d H:i:s', $end_date),
2359
+			'Y-m-d H:i:s'
2360
+		);
2361
+
2362
+
2363
+		//set orderby
2364
+		$this->_req_data['orderby'] = ! empty($this->_req_data['orderby']) ? $this->_req_data['orderby'] : '';
2365
+
2366
+		switch ($this->_req_data['orderby']) {
2367
+			case 'TXN_ID':
2368
+				$orderby = 'TXN_ID';
2369
+				break;
2370
+			case 'ATT_fname':
2371
+				$orderby = 'Registration.Attendee.ATT_fname';
2372
+				break;
2373
+			case 'event_name':
2374
+				$orderby = 'Registration.Event.EVT_name';
2375
+				break;
2376
+			default: //'TXN_timestamp'
2377
+				$orderby = 'TXN_timestamp';
2378
+		}
2379
+
2380
+		$sort         = ! empty($this->_req_data['order']) ? $this->_req_data['order'] : 'DESC';
2381
+		$current_page = ! empty($this->_req_data['paged']) ? $this->_req_data['paged'] : 1;
2382
+		$per_page     = ! empty($perpage) ? $perpage : 10;
2383
+		$per_page     = ! empty($this->_req_data['perpage']) ? $this->_req_data['perpage'] : $per_page;
2384
+
2385
+		$offset = ($current_page - 1) * $per_page;
2386
+		$limit  = array($offset, $per_page);
2387
+
2388
+		$_where = array(
2389
+			'TXN_timestamp'          => array('BETWEEN', array($start_date, $end_date)),
2390
+			'Registration.REG_count' => 1,
2391
+		);
2392
+
2393
+		if (isset($this->_req_data['EVT_ID'])) {
2394
+			$_where['Registration.EVT_ID'] = $this->_req_data['EVT_ID'];
2395
+		}
2396
+
2397
+		if (isset($this->_req_data['s'])) {
2398
+			$search_string = '%' . $this->_req_data['s'] . '%';
2399
+			$_where['OR']  = array(
2400
+				'Registration.Event.EVT_name'         => array('LIKE', $search_string),
2401
+				'Registration.Event.EVT_desc'         => array('LIKE', $search_string),
2402
+				'Registration.Event.EVT_short_desc'   => array('LIKE', $search_string),
2403
+				'Registration.Attendee.ATT_full_name' => array('LIKE', $search_string),
2404
+				'Registration.Attendee.ATT_fname'     => array('LIKE', $search_string),
2405
+				'Registration.Attendee.ATT_lname'     => array('LIKE', $search_string),
2406
+				'Registration.Attendee.ATT_short_bio' => array('LIKE', $search_string),
2407
+				'Registration.Attendee.ATT_email'     => array('LIKE', $search_string),
2408
+				'Registration.Attendee.ATT_address'   => array('LIKE', $search_string),
2409
+				'Registration.Attendee.ATT_address2'  => array('LIKE', $search_string),
2410
+				'Registration.Attendee.ATT_city'      => array('LIKE', $search_string),
2411
+				'Registration.REG_final_price'        => array('LIKE', $search_string),
2412
+				'Registration.REG_code'               => array('LIKE', $search_string),
2413
+				'Registration.REG_count'              => array('LIKE', $search_string),
2414
+				'Registration.REG_group_size'         => array('LIKE', $search_string),
2415
+				'Registration.Ticket.TKT_name'        => array('LIKE', $search_string),
2416
+				'Registration.Ticket.TKT_description' => array('LIKE', $search_string),
2417
+				'Payment.PAY_source'                  => array('LIKE', $search_string),
2418
+				'Payment.Payment_Method.PMD_name'     => array('LIKE', $search_string),
2419
+				'TXN_session_data'                    => array('LIKE', $search_string),
2420
+				'Payment.PAY_txn_id_chq_nmbr'         => array('LIKE', $search_string),
2421
+			);
2422
+		}
2423
+
2424
+		//failed transactions
2425
+		$failed    = (! empty($this->_req_data['status']) && $this->_req_data['status'] === 'failed' && ! $count)
2426
+					 || ($count && $view === 'failed');
2427
+		$abandoned = (! empty($this->_req_data['status']) && $this->_req_data['status'] === 'abandoned' && ! $count)
2428
+					 || ($count && $view === 'abandoned');
2429
+
2430
+		if ($failed) {
2431
+			$_where['STS_ID'] = EEM_Transaction::failed_status_code;
2432
+		} else if ($abandoned) {
2433
+			$_where['STS_ID'] = EEM_Transaction::abandoned_status_code;
2434
+		} else {
2435
+			$_where['STS_ID']  = array('!=', EEM_Transaction::failed_status_code);
2436
+			$_where['STS_ID*'] = array('!=', EEM_Transaction::abandoned_status_code);
2437
+		}
2438
+
2439
+		$query_params = array(
2440
+			$_where,
2441
+			'order_by'                 => array($orderby => $sort),
2442
+			'limit'                    => $limit,
2443
+			'default_where_conditions' => EEM_Base::default_where_conditions_this_only,
2444
+		);
2445
+
2446
+		$transactions = $count
2447
+			? $TXN->count(array($_where), 'TXN_ID', true)
2448
+			: $TXN->get_all($query_params);
2449
+
2450
+		return $transactions;
2451
+	}
2452 2452
 }
Please login to merge, or discard this patch.
Spacing   +81 added lines, -81 removed lines patch added patch discarded remove patch
@@ -266,7 +266,7 @@  discard block
 block discarded – undo
266 266
             'An error occurred! Your request may have been processed, but a valid response from the server was not received. Please refresh the page and try again.',
267 267
             'event_espresso'
268 268
         );
269
-        EE_Registry::$i18n_js_strings['error_occurred']          = esc_html__(
269
+        EE_Registry::$i18n_js_strings['error_occurred'] = esc_html__(
270 270
             'An error occurred! Please refresh the page and try again.',
271 271
             'event_espresso'
272 272
         );
@@ -364,13 +364,13 @@  discard block
 block discarded – undo
364 364
         //enqueue style
365 365
         wp_register_style(
366 366
             'espresso_txn',
367
-            TXN_ASSETS_URL . 'espresso_transactions_admin.css',
367
+            TXN_ASSETS_URL.'espresso_transactions_admin.css',
368 368
             array(),
369 369
             EVENT_ESPRESSO_VERSION
370 370
         );
371 371
         wp_enqueue_style('espresso_txn');
372 372
         //scripts
373
-        wp_register_script('espresso_txn', TXN_ASSETS_URL . 'espresso_transactions_admin.js', array(
373
+        wp_register_script('espresso_txn', TXN_ASSETS_URL.'espresso_transactions_admin.js', array(
374 374
             'ee_admin_js',
375 375
             'ee-datepicker',
376 376
             'jquery-ui-datepicker',
@@ -467,7 +467,7 @@  discard block
 block discarded – undo
467 467
             : null;
468 468
         $this->_transaction->verify_abandoned_transaction_status();
469 469
 
470
-        if (! $this->_transaction instanceof EE_Transaction) {
470
+        if ( ! $this->_transaction instanceof EE_Transaction) {
471 471
             $error_msg = sprintf(
472 472
                 esc_html__(
473 473
                     'An error occurred and the details for the transaction with the ID # %d could not be retrieved.',
@@ -565,7 +565,7 @@  discard block
 block discarded – undo
565 565
             'FHEE__Transactions_Admin_Page___transaction_legend_items__more_items',
566 566
             array(
567 567
                 'overpaid'   => array(
568
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::overpaid_status_code,
568
+                    'class' => 'ee-status-legend ee-status-legend-'.EEM_Transaction::overpaid_status_code,
569 569
                     'desc'  => EEH_Template::pretty_status(
570 570
                         EEM_Transaction::overpaid_status_code,
571 571
                         false,
@@ -573,7 +573,7 @@  discard block
 block discarded – undo
573 573
                     ),
574 574
                 ),
575 575
                 'complete'   => array(
576
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::complete_status_code,
576
+                    'class' => 'ee-status-legend ee-status-legend-'.EEM_Transaction::complete_status_code,
577 577
                     'desc'  => EEH_Template::pretty_status(
578 578
                         EEM_Transaction::complete_status_code,
579 579
                         false,
@@ -581,7 +581,7 @@  discard block
 block discarded – undo
581 581
                     ),
582 582
                 ),
583 583
                 'incomplete' => array(
584
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::incomplete_status_code,
584
+                    'class' => 'ee-status-legend ee-status-legend-'.EEM_Transaction::incomplete_status_code,
585 585
                     'desc'  => EEH_Template::pretty_status(
586 586
                         EEM_Transaction::incomplete_status_code,
587 587
                         false,
@@ -589,7 +589,7 @@  discard block
 block discarded – undo
589 589
                     ),
590 590
                 ),
591 591
                 'abandoned'  => array(
592
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::abandoned_status_code,
592
+                    'class' => 'ee-status-legend ee-status-legend-'.EEM_Transaction::abandoned_status_code,
593 593
                     'desc'  => EEH_Template::pretty_status(
594 594
                         EEM_Transaction::abandoned_status_code,
595 595
                         false,
@@ -597,7 +597,7 @@  discard block
 block discarded – undo
597 597
                     ),
598 598
                 ),
599 599
                 'failed'     => array(
600
-                    'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::failed_status_code,
600
+                    'class' => 'ee-status-legend ee-status-legend-'.EEM_Transaction::failed_status_code,
601 601
                     'desc'  => EEH_Template::pretty_status(
602 602
                         EEM_Transaction::failed_status_code,
603 603
                         false,
@@ -646,11 +646,11 @@  discard block
 block discarded – undo
646 646
                     'Click to Edit event',
647 647
                     'event_espresso'
648 648
                 )
649
-                . '">' . $event->get('EVT_name') . '</a>',
649
+                . '">'.$event->get('EVT_name').'</a>',
650 650
                 '</h3>'
651 651
             )
652 652
             : '';
653
-        $this->_template_args['after_list_table']  = $this->_display_legend($this->_transaction_legend_items());
653
+        $this->_template_args['after_list_table'] = $this->_display_legend($this->_transaction_legend_items());
654 654
         $this->display_admin_list_table_page_with_no_sidebar();
655 655
     }
656 656
 
@@ -693,7 +693,7 @@  discard block
 block discarded – undo
693 693
 
694 694
         $this->_template_args['txn_status']['value'] = self::$_txn_status[$this->_transaction->get('STS_ID')];
695 695
         $this->_template_args['txn_status']['label'] = esc_html__('Transaction Status', 'event_espresso');
696
-        $this->_template_args['txn_status']['class'] = 'status-' . $this->_transaction->get('STS_ID');
696
+        $this->_template_args['txn_status']['class'] = 'status-'.$this->_transaction->get('STS_ID');
697 697
 
698 698
         $this->_template_args['grand_total'] = $this->_transaction->get('TXN_total');
699 699
         $this->_template_args['total_paid']  = $this->_transaction->get('TXN_paid');
@@ -746,7 +746,7 @@  discard block
 block discarded – undo
746 746
 
747 747
 
748 748
         // next link
749
-        $next_txn                                 = $this->_transaction->next(
749
+        $next_txn = $this->_transaction->next(
750 750
             null,
751 751
             array(array('STS_ID' => array('!=', EEM_Transaction::failed_status_code))),
752 752
             'TXN_ID'
@@ -761,7 +761,7 @@  discard block
 block discarded – undo
761 761
             )
762 762
             : '';
763 763
         // previous link
764
-        $previous_txn                                 = $this->_transaction->previous(
764
+        $previous_txn = $this->_transaction->previous(
765 765
             null,
766 766
             array(array('STS_ID' => array('!=', EEM_Transaction::failed_status_code))),
767 767
             'TXN_ID'
@@ -811,7 +811,7 @@  discard block
 block discarded – undo
811 811
         // grab messages at the last second
812 812
         $this->_template_args['notices'] = EE_Error::get_notices();
813 813
         // path to template
814
-        $template_path                             = TXN_TEMPLATE_PATH . 'txn_admin_details_header.template.php';
814
+        $template_path                             = TXN_TEMPLATE_PATH.'txn_admin_details_header.template.php';
815 815
         $this->_template_args['admin_page_header'] = EEH_Template::display_template(
816 816
             $template_path,
817 817
             $this->_template_args,
@@ -893,7 +893,7 @@  discard block
 block discarded – undo
893 893
     {
894 894
         $content = '';
895 895
         $actions = array();
896
-        if (! $transaction instanceof EE_Transaction) {
896
+        if ( ! $transaction instanceof EE_Transaction) {
897 897
             return $content;
898 898
         }
899 899
         /** @var EE_Registration $primary_registration */
@@ -954,7 +954,7 @@  discard block
 block discarded – undo
954 954
         );
955 955
         if ($actions) {
956 956
             $content = '<ul>';
957
-            $content .= '<li>' . implode('</li><li>', $actions) . '</li>';
957
+            $content .= '<li>'.implode('</li><li>', $actions).'</li>';
958 958
             $content .= '</uL>';
959 959
         }
960 960
         return $content;
@@ -992,7 +992,7 @@  discard block
 block discarded – undo
992 992
 
993 993
         //get line table
994 994
         EEH_Autoloader::register_line_item_display_autoloaders();
995
-        $Line_Item_Display                       = new EE_Line_Item_Display(
995
+        $Line_Item_Display = new EE_Line_Item_Display(
996 996
             'admin_table',
997 997
             'EE_Admin_Table_Line_Item_Display_Strategy'
998 998
         );
@@ -1003,13 +1003,13 @@  discard block
 block discarded – undo
1003 1003
                                                                       ->get('REG_code');
1004 1004
 
1005 1005
         // process taxes
1006
-        $taxes                         = $this->_transaction->get_many_related(
1006
+        $taxes = $this->_transaction->get_many_related(
1007 1007
             'Line_Item',
1008 1008
             array(array('LIN_type' => EEM_Line_Item::type_tax))
1009 1009
         );
1010 1010
         $this->_template_args['taxes'] = ! empty($taxes) ? $taxes : false;
1011 1011
 
1012
-        $this->_template_args['grand_total']     = EEH_Template::format_currency(
1012
+        $this->_template_args['grand_total'] = EEH_Template::format_currency(
1013 1013
             $this->_transaction->get('TXN_total'),
1014 1014
             false,
1015 1015
             false
@@ -1019,7 +1019,7 @@  discard block
 block discarded – undo
1019 1019
 
1020 1020
         // process payment details
1021 1021
         $payments = $this->_transaction->get_many_related('Payment');
1022
-        if (! empty($payments)) {
1022
+        if ( ! empty($payments)) {
1023 1023
             $this->_template_args['payments']              = $payments;
1024 1024
             $this->_template_args['existing_reg_payments'] = $this->_get_registration_payment_IDs($payments);
1025 1025
         } else {
@@ -1080,7 +1080,7 @@  discard block
 block discarded – undo
1080 1080
                                   esc_html__('%1$s : Initiated %2$s', 'event_espresso'),
1081 1081
                                   ucwords(str_replace('_', ' ', $reg_step)),
1082 1082
                                   date(
1083
-                                      get_option('date_format') . ' ' . get_option('time_format'),
1083
+                                      get_option('date_format').' '.get_option('time_format'),
1084 1084
                                       ($reg_step_status + (get_option('gmt_offset') * HOUR_IN_SECONDS))
1085 1085
                                   )
1086 1086
                               )
@@ -1094,7 +1094,7 @@  discard block
 block discarded – undo
1094 1094
                               . '</li>';
1095 1095
             }
1096 1096
         }
1097
-        $reg_steps                                                 .= '</ul>';
1097
+        $reg_steps .= '</ul>';
1098 1098
         $this->_template_args['txn_details']['reg_steps']['value'] = $reg_steps;
1099 1099
         $this->_template_args['txn_details']['reg_steps']['label'] = esc_html__(
1100 1100
             'Registration Step Progress',
@@ -1107,11 +1107,11 @@  discard block
 block discarded – undo
1107 1107
         $this->_get_payment_status_array();
1108 1108
         $this->_get_reg_status_selection(); //sets up the template args for the reg status array for the transaction.
1109 1109
 
1110
-        $this->_template_args['transaction_form_url']    = add_query_arg(array(
1110
+        $this->_template_args['transaction_form_url'] = add_query_arg(array(
1111 1111
             'action'  => 'edit_transaction',
1112 1112
             'process' => 'transaction',
1113 1113
         ), TXN_ADMIN_URL);
1114
-        $this->_template_args['apply_payment_form_url']  = add_query_arg(array(
1114
+        $this->_template_args['apply_payment_form_url'] = add_query_arg(array(
1115 1115
             'page'   => 'espresso_transactions',
1116 1116
             'action' => 'espresso_apply_payment',
1117 1117
         ), WP_AJAX_URL);
@@ -1124,7 +1124,7 @@  discard block
 block discarded – undo
1124 1124
 
1125 1125
         // 'espresso_delete_payment_nonce'
1126 1126
 
1127
-        $template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_txn_details.template.php';
1127
+        $template_path = TXN_TEMPLATE_PATH.'txn_admin_details_main_meta_box_txn_details.template.php';
1128 1128
         echo EEH_Template::display_template($template_path, $this->_template_args, true);
1129 1129
     }
1130 1130
 
@@ -1154,11 +1154,11 @@  discard block
 block discarded – undo
1154 1154
                 ),
1155 1155
             ),
1156 1156
         ));
1157
-        if (! empty($reg_payments)) {
1157
+        if ( ! empty($reg_payments)) {
1158 1158
             foreach ($payments as $payment) {
1159
-                if (! $payment instanceof EE_Payment) {
1159
+                if ( ! $payment instanceof EE_Payment) {
1160 1160
                     continue;
1161
-                } elseif (! isset($existing_reg_payments[$payment->ID()])) {
1161
+                } elseif ( ! isset($existing_reg_payments[$payment->ID()])) {
1162 1162
                     $existing_reg_payments[$payment->ID()] = array();
1163 1163
                 }
1164 1164
                 foreach ($reg_payments as $reg_payment) {
@@ -1187,7 +1187,7 @@  discard block
 block discarded – undo
1187 1187
     protected function _get_registrations_to_apply_payment_to()
1188 1188
     {
1189 1189
         // we want any registration with an active status (ie: not deleted or cancelled)
1190
-        $query_params                      = array(
1190
+        $query_params = array(
1191 1191
             array(
1192 1192
                 'STS_ID' => array(
1193 1193
                     'IN',
@@ -1206,16 +1206,16 @@  discard block
 block discarded – undo
1206 1206
                                                  '',
1207 1207
                                                  'clear: both; margin: 1.5em 0 0; display: none;'
1208 1208
                                              );
1209
-        $registrations_to_apply_payment_to .= EEH_HTML::br() . EEH_HTML::div('', '', 'admin-primary-mbox-tbl-wrap');
1209
+        $registrations_to_apply_payment_to .= EEH_HTML::br().EEH_HTML::div('', '', 'admin-primary-mbox-tbl-wrap');
1210 1210
         $registrations_to_apply_payment_to .= EEH_HTML::table('', '', 'admin-primary-mbox-tbl');
1211 1211
         $registrations_to_apply_payment_to .= EEH_HTML::thead(
1212 1212
             EEH_HTML::tr(
1213
-                EEH_HTML::th(esc_html__('ID', 'event_espresso')) .
1214
-                EEH_HTML::th(esc_html__('Registrant', 'event_espresso')) .
1215
-                EEH_HTML::th(esc_html__('Ticket', 'event_espresso')) .
1216
-                EEH_HTML::th(esc_html__('Event', 'event_espresso')) .
1217
-                EEH_HTML::th(esc_html__('Paid', 'event_espresso'), '', 'txn-admin-payment-paid-td jst-cntr') .
1218
-                EEH_HTML::th(esc_html__('Owing', 'event_espresso'), '', 'txn-admin-payment-owing-td jst-cntr') .
1213
+                EEH_HTML::th(esc_html__('ID', 'event_espresso')).
1214
+                EEH_HTML::th(esc_html__('Registrant', 'event_espresso')).
1215
+                EEH_HTML::th(esc_html__('Ticket', 'event_espresso')).
1216
+                EEH_HTML::th(esc_html__('Event', 'event_espresso')).
1217
+                EEH_HTML::th(esc_html__('Paid', 'event_espresso'), '', 'txn-admin-payment-paid-td jst-cntr').
1218
+                EEH_HTML::th(esc_html__('Owing', 'event_espresso'), '', 'txn-admin-payment-owing-td jst-cntr').
1219 1219
                 EEH_HTML::th(esc_html__('Apply', 'event_espresso'), '', 'jst-cntr')
1220 1220
             )
1221 1221
         );
@@ -1230,29 +1230,29 @@  discard block
 block discarded – undo
1230 1230
                     : esc_html__('Unknown Attendee', 'event_espresso');
1231 1231
                 $owing                             = $registration->final_price() - $registration->paid();
1232 1232
                 $taxable                           = $registration->ticket()->taxable()
1233
-                    ? ' <span class="smaller-text lt-grey-text"> ' . esc_html__('+ tax', 'event_espresso') . '</span>'
1233
+                    ? ' <span class="smaller-text lt-grey-text"> '.esc_html__('+ tax', 'event_espresso').'</span>'
1234 1234
                     : '';
1235 1235
                 $checked = empty($existing_reg_payments) || in_array($registration->ID(), $existing_reg_payments)
1236 1236
                     ? ' checked="checked"'
1237 1237
                     : '';
1238
-                $disabled                          = $registration->final_price() > 0 ? '' : ' disabled';
1238
+                $disabled = $registration->final_price() > 0 ? '' : ' disabled';
1239 1239
                 $registrations_to_apply_payment_to .= EEH_HTML::tr(
1240
-                    EEH_HTML::td($registration->ID()) .
1241
-                    EEH_HTML::td($attendee_name) .
1240
+                    EEH_HTML::td($registration->ID()).
1241
+                    EEH_HTML::td($attendee_name).
1242 1242
                     EEH_HTML::td(
1243
-                        $registration->ticket()->name() . ' : ' . $registration->ticket()->pretty_price() . $taxable
1244
-                    ) .
1245
-                    EEH_HTML::td($registration->event_name()) .
1246
-                    EEH_HTML::td($registration->pretty_paid(), '', 'txn-admin-payment-paid-td jst-cntr') .
1247
-                    EEH_HTML::td(EEH_Template::format_currency($owing), '', 'txn-admin-payment-owing-td jst-cntr') .
1243
+                        $registration->ticket()->name().' : '.$registration->ticket()->pretty_price().$taxable
1244
+                    ).
1245
+                    EEH_HTML::td($registration->event_name()).
1246
+                    EEH_HTML::td($registration->pretty_paid(), '', 'txn-admin-payment-paid-td jst-cntr').
1247
+                    EEH_HTML::td(EEH_Template::format_currency($owing), '', 'txn-admin-payment-owing-td jst-cntr').
1248 1248
                     EEH_HTML::td(
1249
-                        '<input type="checkbox" value="' . $registration->ID()
1249
+                        '<input type="checkbox" value="'.$registration->ID()
1250 1250
                         . '" name="txn_admin_payment[registrations]"'
1251
-                        . $checked . $disabled . '>',
1251
+                        . $checked.$disabled.'>',
1252 1252
                         '',
1253 1253
                         'jst-cntr'
1254 1254
                     ),
1255
-                    'apply-payment-registration-row-' . $registration->ID()
1255
+                    'apply-payment-registration-row-'.$registration->ID()
1256 1256
                 );
1257 1257
             }
1258 1258
         }
@@ -1267,7 +1267,7 @@  discard block
 block discarded – undo
1267 1267
             '',
1268 1268
             'clear description'
1269 1269
         );
1270
-        $registrations_to_apply_payment_to                         .= EEH_HTML::divx();
1270
+        $registrations_to_apply_payment_to .= EEH_HTML::divx();
1271 1271
         $this->_template_args['registrations_to_apply_payment_to'] = $registrations_to_apply_payment_to;
1272 1272
     }
1273 1273
 
@@ -1333,12 +1333,12 @@  discard block
 block discarded – undo
1333 1333
                 array(
1334 1334
                     'OR*payment_method_for_payment' => array(
1335 1335
                         'PMD_ID'    => array('IN', $payment_methods_of_payments),
1336
-                        'PMD_scope' => array('LIKE', '%' . EEM_Payment_Method::scope_admin . '%'),
1336
+                        'PMD_scope' => array('LIKE', '%'.EEM_Payment_Method::scope_admin.'%'),
1337 1337
                     ),
1338 1338
                 ),
1339 1339
             );
1340 1340
         } else {
1341
-            $query_args = array(array('PMD_scope' => array('LIKE', '%' . EEM_Payment_Method::scope_admin . '%')));
1341
+            $query_args = array(array('PMD_scope' => array('LIKE', '%'.EEM_Payment_Method::scope_admin.'%')));
1342 1342
         }
1343 1343
         $this->_template_args['payment_methods'] = EEM_Payment_Method::instance()->get_all($query_args);
1344 1344
     }
@@ -1367,7 +1367,7 @@  discard block
 block discarded – undo
1367 1367
             'Line_Item',
1368 1368
             array(array('LIN_type' => 'line-item'))
1369 1369
         );
1370
-        if (! empty($line_items)) {
1370
+        if ( ! empty($line_items)) {
1371 1371
             foreach ($line_items as $item) {
1372 1372
                 if ($item instanceof EE_Line_Item) {
1373 1373
                     switch ($item->OBJ_type()) {
@@ -1377,7 +1377,7 @@  discard block
 block discarded – undo
1377 1377
                             $ticket = $item->ticket();
1378 1378
                             //right now we're only handling tickets here.
1379 1379
                             //Cause its expected that only tickets will have attendees right?
1380
-                            if (! $ticket instanceof EE_Ticket) {
1380
+                            if ( ! $ticket instanceof EE_Ticket) {
1381 1381
                                 continue;
1382 1382
                             }
1383 1383
                             try {
@@ -1386,7 +1386,7 @@  discard block
 block discarded – undo
1386 1386
                                 EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__);
1387 1387
                                 $event_name = esc_html__('Unknown Event', 'event_espresso');
1388 1388
                             }
1389
-                            $event_name   .= ' - ' . $item->get('LIN_name');
1389
+                            $event_name   .= ' - '.$item->get('LIN_name');
1390 1390
                             $ticket_price = EEH_Template::format_currency($item->get('LIN_unit_price'));
1391 1391
                             // now get all of the registrations for this transaction that use this ticket
1392 1392
                             $registrations = $ticket->get_many_related(
@@ -1394,7 +1394,7 @@  discard block
 block discarded – undo
1394 1394
                                 array(array('TXN_ID' => $this->_transaction->ID()))
1395 1395
                             );
1396 1396
                             foreach ($registrations as $registration) {
1397
-                                if (! $registration instanceof EE_Registration) {
1397
+                                if ( ! $registration instanceof EE_Registration) {
1398 1398
                                     continue;
1399 1399
                                 }
1400 1400
                                 $this->_template_args['event_attendees'][$registration->ID()]['STS_ID']
@@ -1413,12 +1413,12 @@  discard block
 block discarded – undo
1413 1413
                                     $this->_template_args['event_attendees'][$registration->ID()]['attendee']
1414 1414
                                         = $attendee->full_name();
1415 1415
                                     $this->_template_args['event_attendees'][$registration->ID()]['email']
1416
-                                        = '<a href="mailto:' . $attendee->email() . '?subject=' . $event_name
1416
+                                        = '<a href="mailto:'.$attendee->email().'?subject='.$event_name
1417 1417
                                           . esc_html__(
1418 1418
                                               ' Event',
1419 1419
                                               'event_espresso'
1420 1420
                                           )
1421
-                                          . '">' . $attendee->email() . '</a>';
1421
+                                          . '">'.$attendee->email().'</a>';
1422 1422
                                     $this->_template_args['event_attendees'][$registration->ID()]['address']
1423 1423
                                         = EEH_Address::format($attendee, 'inline', false, false);
1424 1424
                                 } else {
@@ -1442,7 +1442,7 @@  discard block
 block discarded – undo
1442 1442
                 TXN_ADMIN_URL
1443 1443
             );
1444 1444
             echo EEH_Template::display_template(
1445
-                TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_attendees.template.php',
1445
+                TXN_TEMPLATE_PATH.'txn_admin_details_main_meta_box_attendees.template.php',
1446 1446
                 $this->_template_args,
1447 1447
                 true
1448 1448
             );
@@ -1478,12 +1478,12 @@  discard block
 block discarded – undo
1478 1478
         $primary_att = $this->_transaction->primary_registration() instanceof EE_Registration
1479 1479
             ? $this->_transaction->primary_registration()->get_first_related('Attendee')
1480 1480
             : null;
1481
-        if (! $primary_att instanceof EE_Attendee) {
1481
+        if ( ! $primary_att instanceof EE_Attendee) {
1482 1482
             $this->_template_args['no_attendee_message'] = esc_html__(
1483 1483
                 'There is no attached contact for this transaction.  The transaction either failed due to an error or was abandoned.',
1484 1484
                 'event_espresso'
1485 1485
             );
1486
-            $primary_att                                 = EEM_Attendee::instance()->create_default_object();
1486
+            $primary_att = EEM_Attendee::instance()->create_default_object();
1487 1487
         }
1488 1488
         $this->_template_args['ATT_ID']            = $primary_att->ID();
1489 1489
         $this->_template_args['prime_reg_fname']   = $primary_att->fname();
@@ -1497,7 +1497,7 @@  discard block
 block discarded – undo
1497 1497
         // get formatted address for registrant
1498 1498
         $this->_template_args['formatted_address'] = EEH_Address::format($primary_att);
1499 1499
         echo EEH_Template::display_template(
1500
-            TXN_TEMPLATE_PATH . 'txn_admin_details_side_meta_box_registrant.template.php',
1500
+            TXN_TEMPLATE_PATH.'txn_admin_details_side_meta_box_registrant.template.php',
1501 1501
             $this->_template_args,
1502 1502
             true
1503 1503
         );
@@ -1522,8 +1522,8 @@  discard block
 block discarded – undo
1522 1522
             TXN_ADMIN_URL
1523 1523
         );
1524 1524
 
1525
-        $template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_side_meta_box_billing_info.template.php';
1526
-        echo EEH_Template::display_template($template_path, $this->_template_args, true);/**/
1525
+        $template_path = TXN_TEMPLATE_PATH.'txn_admin_details_side_meta_box_billing_info.template.php';
1526
+        echo EEH_Template::display_template($template_path, $this->_template_args, true); /**/
1527 1527
     }
1528 1528
 
1529 1529
 
@@ -1548,7 +1548,7 @@  discard block
 block discarded – undo
1548 1548
             'ee_edit_payments',
1549 1549
             'apply_payment_or_refund_from_registration_details'
1550 1550
         );
1551
-        if (! empty($valid_data) && $has_access) {
1551
+        if ( ! empty($valid_data) && $has_access) {
1552 1552
             $PAY_ID = $valid_data['PAY_ID'];
1553 1553
             //save  the new payment
1554 1554
             $payment = $this->_create_payment_from_request_data($valid_data);
@@ -1561,7 +1561,7 @@  discard block
 block discarded – undo
1561 1561
                 $REG_IDs = $this->_get_REG_IDs_to_apply_payment_to($payment);
1562 1562
                 $this->_remove_existing_registration_payments($payment, $PAY_ID);
1563 1563
                 // apply payment to registrations (if applicable)
1564
-                if (! empty($REG_IDs)) {
1564
+                if ( ! empty($REG_IDs)) {
1565 1565
                     $this->_update_registration_payments($transaction, $payment, $REG_IDs);
1566 1566
                     $this->_maybe_send_notifications();
1567 1567
                     // now process status changes for the same registrations
@@ -1609,7 +1609,7 @@  discard block
 block discarded – undo
1609 1609
                 );
1610 1610
             }
1611 1611
         }
1612
-        $notices              = EE_Error::get_notices(
1612
+        $notices = EE_Error::get_notices(
1613 1613
             false,
1614 1614
             false,
1615 1615
             false
@@ -1631,14 +1631,14 @@  discard block
 block discarded – undo
1631 1631
      */
1632 1632
     protected function _validate_payment_request_data()
1633 1633
     {
1634
-        if (! isset($this->_req_data['txn_admin_payment'])) {
1634
+        if ( ! isset($this->_req_data['txn_admin_payment'])) {
1635 1635
             return false;
1636 1636
         }
1637 1637
         $payment_form = $this->_generate_payment_form_section();
1638 1638
         try {
1639 1639
             if ($payment_form->was_submitted()) {
1640 1640
                 $payment_form->receive_form_submission();
1641
-                if (! $payment_form->is_valid()) {
1641
+                if ( ! $payment_form->is_valid()) {
1642 1642
                     $submission_error_messages = array();
1643 1643
                     foreach ($payment_form->get_validation_errors_accumulated() as $validation_error) {
1644 1644
                         if ($validation_error instanceof EE_Validation_Error) {
@@ -1817,7 +1817,7 @@  discard block
 block discarded – undo
1817 1817
             array('Y-m-d', 'g:i a')
1818 1818
         );
1819 1819
 
1820
-        if (! $payment->save()) {
1820
+        if ( ! $payment->save()) {
1821 1821
             EE_Error::add_error(
1822 1822
                 sprintf(
1823 1823
                     esc_html__('Payment %1$d has not been successfully saved to the database.', 'event_espresso'),
@@ -1882,7 +1882,7 @@  discard block
 block discarded – undo
1882 1882
         $REG_IDs = array();
1883 1883
         // grab array of IDs for specific registrations to apply changes to
1884 1884
         if (isset($this->_req_data['txn_admin_payment']['registrations'])) {
1885
-            $REG_IDs = (array)$this->_req_data['txn_admin_payment']['registrations'];
1885
+            $REG_IDs = (array) $this->_req_data['txn_admin_payment']['registrations'];
1886 1886
         }
1887 1887
         //nothing specified ? then get all reg IDs
1888 1888
         if (empty($REG_IDs)) {
@@ -2010,12 +2010,12 @@  discard block
 block discarded – undo
2010 2010
         // but add in some conditions regarding payment,
2011 2011
         // so that we don't apply payments to registrations that are free or have already been paid for
2012 2012
         // but ONLY if the payment is NOT a refund ( ie: the payment amount is not negative )
2013
-        if (! $payment->is_a_refund()) {
2013
+        if ( ! $payment->is_a_refund()) {
2014 2014
             $registration_query_where_params['REG_final_price']  = array('!=', 0);
2015 2015
             $registration_query_where_params['REG_final_price*'] = array('!=', 'REG_paid', true);
2016 2016
         }
2017 2017
         $registrations = $transaction->registrations(array($registration_query_where_params));
2018
-        if (! empty($registrations)) {
2018
+        if ( ! empty($registrations)) {
2019 2019
             /** @type EE_Payment_Processor $payment_processor */
2020 2020
             $payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
2021 2021
             $payment_processor->process_registration_payments($transaction, $payment, $registrations);
@@ -2217,7 +2217,7 @@  discard block
 block discarded – undo
2217 2217
     {
2218 2218
         $registration_payment_data = array();
2219 2219
         //if non empty reg_ids lets get an array of registrations and update the values for the apply_payment/refund rows.
2220
-        if (! empty($REG_IDs)) {
2220
+        if ( ! empty($REG_IDs)) {
2221 2221
             $registrations = EEM_Registration::instance()->get_all(array(array('REG_ID' => array('IN', $REG_IDs))));
2222 2222
             foreach ($registrations as $registration) {
2223 2223
                 if ($registration instanceof EE_Registration) {
@@ -2330,13 +2330,13 @@  discard block
 block discarded – undo
2330 2330
                 'm/d/Y',
2331 2331
                 strtotime('-10 year')
2332 2332
             );
2333
-        $end_date   = isset($this->_req_data['txn-filter-end-date'])
2333
+        $end_date = isset($this->_req_data['txn-filter-end-date'])
2334 2334
             ? wp_strip_all_tags($this->_req_data['txn-filter-end-date'])
2335 2335
             : date('m/d/Y');
2336 2336
 
2337 2337
         //make sure our timestamps start and end right at the boundaries for each day
2338
-        $start_date = date('Y-m-d', strtotime($start_date)) . ' 00:00:00';
2339
-        $end_date   = date('Y-m-d', strtotime($end_date)) . ' 23:59:59';
2338
+        $start_date = date('Y-m-d', strtotime($start_date)).' 00:00:00';
2339
+        $end_date   = date('Y-m-d', strtotime($end_date)).' 23:59:59';
2340 2340
 
2341 2341
 
2342 2342
         //convert to timestamps
@@ -2353,7 +2353,7 @@  discard block
 block discarded – undo
2353 2353
             date('Y-m-d H:i:s', $start_date),
2354 2354
             'Y-m-d H:i:s'
2355 2355
         );
2356
-        $end_date   = EEM_Transaction::instance()->convert_datetime_for_query(
2356
+        $end_date = EEM_Transaction::instance()->convert_datetime_for_query(
2357 2357
             'TXN_timestamp',
2358 2358
             date('Y-m-d H:i:s', $end_date),
2359 2359
             'Y-m-d H:i:s'
@@ -2395,7 +2395,7 @@  discard block
 block discarded – undo
2395 2395
         }
2396 2396
 
2397 2397
         if (isset($this->_req_data['s'])) {
2398
-            $search_string = '%' . $this->_req_data['s'] . '%';
2398
+            $search_string = '%'.$this->_req_data['s'].'%';
2399 2399
             $_where['OR']  = array(
2400 2400
                 'Registration.Event.EVT_name'         => array('LIKE', $search_string),
2401 2401
                 'Registration.Event.EVT_desc'         => array('LIKE', $search_string),
@@ -2422,9 +2422,9 @@  discard block
 block discarded – undo
2422 2422
         }
2423 2423
 
2424 2424
         //failed transactions
2425
-        $failed    = (! empty($this->_req_data['status']) && $this->_req_data['status'] === 'failed' && ! $count)
2425
+        $failed    = ( ! empty($this->_req_data['status']) && $this->_req_data['status'] === 'failed' && ! $count)
2426 2426
                      || ($count && $view === 'failed');
2427
-        $abandoned = (! empty($this->_req_data['status']) && $this->_req_data['status'] === 'abandoned' && ! $count)
2427
+        $abandoned = ( ! empty($this->_req_data['status']) && $this->_req_data['status'] === 'abandoned' && ! $count)
2428 2428
                      || ($count && $view === 'abandoned');
2429 2429
 
2430 2430
         if ($failed) {
Please login to merge, or discard this patch.
core/request_stack/EE_Request.core.php 1 patch
Indentation   +363 added lines, -363 removed lines patch added patch discarded remove patch
@@ -22,369 +22,369 @@
 block discarded – undo
22 22
 class EE_Request implements LegacyRequestInterface, InterminableInterface
23 23
 {
24 24
 
25
-    /**
26
-     * @var RequestInterface $request
27
-     */
28
-    private $request;
29
-
30
-    /**
31
-     * whether current request is for the admin but NOT via AJAX
32
-     *
33
-     * @var boolean $admin
34
-     */
35
-    public $admin = false;
36
-
37
-    /**
38
-     * whether current request is via AJAX
39
-     *
40
-     * @var boolean $ajax
41
-     */
42
-    public $ajax = false;
43
-
44
-    /**
45
-     * whether current request is via AJAX from the frontend of the site
46
-     *
47
-     * @var boolean $front_ajax
48
-     */
49
-    public $front_ajax = false;
50
-
51
-
52
-    /**
53
-     * @deprecated 4.9.53
54
-     * @param array $get
55
-     * @param array $post
56
-     * @param array $cookie
57
-     * @param array $server
58
-     */
59
-    public function __construct(
60
-        array $get = array(),
61
-        array $post = array(),
62
-        array $cookie = array(),
63
-        array $server = array()
64
-    ) {
65
-    }
66
-
67
-
68
-    /**
69
-     * @return RequestInterface
70
-     * @throws InvalidArgumentException
71
-     * @throws InvalidInterfaceException
72
-     * @throws InvalidDataTypeException
73
-     */
74
-    private function request()
75
-    {
76
-        if($this->request instanceof RequestInterface){
77
-            return $this->request;
78
-        }
79
-        $loader = LoaderFactory::getLoader();
80
-        $this->request = $loader->getShared('EventEspresso\core\services\request\RequestInterface');
81
-        return $this->request;
82
-    }
83
-
84
-
85
-    /**
86
-     * @param RequestInterface $request
87
-     */
88
-    public function setRequest(RequestInterface $request)
89
-    {
90
-        $this->request = $request;
91
-    }
92
-
93
-
94
-
95
-    /**
96
-     * @deprecated 4.9.53
97
-     * @return array
98
-     * @throws InvalidArgumentException
99
-     * @throws InvalidDataTypeException
100
-     * @throws InvalidInterfaceException
101
-     */
102
-    public function get_params()
103
-    {
104
-        return $this->request()->getParams();
105
-    }
106
-
107
-
108
-
109
-    /**
110
-     * @deprecated 4.9.53
111
-     * @return array
112
-     * @throws InvalidArgumentException
113
-     * @throws InvalidDataTypeException
114
-     * @throws InvalidInterfaceException
115
-     */
116
-    public function post_params()
117
-    {
118
-        return $this->request()->postParams();
119
-    }
120
-
121
-
122
-
123
-    /**
124
-     * @deprecated 4.9.53
125
-     * @return array
126
-     * @throws InvalidArgumentException
127
-     * @throws InvalidDataTypeException
128
-     * @throws InvalidInterfaceException
129
-     */
130
-    public function cookie_params()
131
-    {
132
-        return $this->request()->cookieParams();
133
-    }
134
-
135
-
136
-    /**
137
-     * @deprecated 4.9.53
138
-     * @return array
139
-     * @throws InvalidArgumentException
140
-     * @throws InvalidDataTypeException
141
-     * @throws InvalidInterfaceException
142
-     */
143
-    public function server_params()
144
-    {
145
-        return $this->request()->serverParams();
146
-    }
147
-
148
-
149
-
150
-    /**
151
-     * returns contents of $_REQUEST
152
-     *
153
-     * @deprecated 4.9.53
154
-     * @return array
155
-     * @throws InvalidArgumentException
156
-     * @throws InvalidDataTypeException
157
-     * @throws InvalidInterfaceException
158
-     */
159
-    public function params()
160
-    {
161
-        return $this->request()->requestParams();
162
-    }
163
-
164
-
165
-
166
-    /**
167
-     * @deprecated 4.9.53
168
-     * @param      $key
169
-     * @param      $value
170
-     * @param bool $override_ee
171
-     * @return void
172
-     * @throws InvalidArgumentException
173
-     * @throws InvalidDataTypeException
174
-     * @throws InvalidInterfaceException
175
-     */
176
-    public function set($key, $value, $override_ee = false)
177
-    {
178
-        $this->request()->setRequestParam($key, $value, $override_ee);
179
-    }
180
-
181
-
182
-
183
-    /**
184
-     * returns   the value for a request param if the given key exists
185
-     *
186
-     * @deprecated 4.9.53
187
-     * @param      $key
188
-     * @param null $default
189
-     * @return mixed
190
-     * @throws InvalidArgumentException
191
-     * @throws InvalidDataTypeException
192
-     * @throws InvalidInterfaceException
193
-     */
194
-    public function get($key, $default = null)
195
-    {
196
-        return $this->request()->getRequestParam($key, $default);
197
-    }
198
-
199
-
200
-
201
-    /**
202
-     * check if param exists
203
-     *
204
-     * @deprecated 4.9.53
205
-     * @param $key
206
-     * @return bool
207
-     * @throws InvalidArgumentException
208
-     * @throws InvalidDataTypeException
209
-     * @throws InvalidInterfaceException
210
-     */
211
-    public function is_set($key)
212
-    {
213
-        return $this->request()->requestParamIsSet($key);
214
-    }
215
-
216
-
217
-    /**
218
-     * remove param
219
-     *
220
-     * @deprecated 4.9.53
221
-     * @param      $key
222
-     * @param bool $unset_from_global_too
223
-     * @throws InvalidArgumentException
224
-     * @throws InvalidDataTypeException
225
-     * @throws InvalidInterfaceException
226
-     */
227
-    public function un_set($key, $unset_from_global_too = false)
228
-    {
229
-        $this->request()->unSetRequestParam($key, $unset_from_global_too);
230
-    }
231
-
232
-
233
-
234
-    /**
235
-     * @deprecated 4.9.53
236
-     * @return string
237
-     * @throws InvalidArgumentException
238
-     * @throws InvalidDataTypeException
239
-     * @throws InvalidInterfaceException
240
-     */
241
-    public function ip_address()
242
-    {
243
-        return $this->request()->ipAddress();
244
-    }
245
-
246
-
247
-    /**
248
-     * @deprecated 4.9.53
249
-     * @return bool
250
-     * @throws InvalidArgumentException
251
-     * @throws InvalidDataTypeException
252
-     * @throws InvalidInterfaceException
253
-     */
254
-    public function isAdmin()
255
-    {
256
-        return $this->request()->isAdmin();
257
-    }
258
-
259
-
260
-    /**
261
-     * @deprecated 4.9.53
262
-     * @return mixed
263
-     * @throws InvalidArgumentException
264
-     * @throws InvalidDataTypeException
265
-     * @throws InvalidInterfaceException
266
-     */
267
-    public function isAjax()
268
-    {
269
-        return $this->request()->isAjax();
270
-    }
271
-
272
-
273
-    /**
274
-     * @deprecated 4.9.53
275
-     * @return mixed
276
-     * @throws InvalidArgumentException
277
-     * @throws InvalidDataTypeException
278
-     * @throws InvalidInterfaceException
279
-     */
280
-    public function isFrontAjax()
281
-    {
282
-        return $this->request()->isFrontAjax();
283
-    }
284
-
285
-
286
-    /**
287
-     * @deprecated 4.9.53
288
-     * @return mixed|string
289
-     * @throws InvalidArgumentException
290
-     * @throws InvalidDataTypeException
291
-     * @throws InvalidInterfaceException
292
-     */
293
-    public function requestUri()
294
-    {
295
-        return $this->request()->requestUri();
296
-    }
297
-
298
-
299
-    /**
300
-     * @deprecated 4.9.53
301
-     * @return string
302
-     * @throws InvalidArgumentException
303
-     * @throws InvalidDataTypeException
304
-     * @throws InvalidInterfaceException
305
-     */
306
-    public function userAgent()
307
-    {
308
-        return $this->request()->userAgent();
309
-    }
310
-
311
-
312
-    /**
313
-     * @deprecated 4.9.53
314
-     * @param string $user_agent
315
-     * @throws InvalidArgumentException
316
-     * @throws InvalidDataTypeException
317
-     * @throws InvalidInterfaceException
318
-     */
319
-    public function setUserAgent($user_agent = '')
320
-    {
321
-        $this->request()->setUserAgent($user_agent);
322
-    }
323
-
324
-
325
-    /**
326
-     * @deprecated 4.9.53
327
-     * @return bool
328
-     * @throws InvalidArgumentException
329
-     * @throws InvalidDataTypeException
330
-     * @throws InvalidInterfaceException
331
-     */
332
-    public function isBot()
333
-    {
334
-        return $this->request()->isBot();
335
-    }
336
-
337
-
338
-    /**
339
-     * @deprecated 4.9.53
340
-     * @param bool $is_bot
341
-     * @throws InvalidArgumentException
342
-     * @throws InvalidDataTypeException
343
-     * @throws InvalidInterfaceException
344
-     */
345
-    public function setIsBot($is_bot)
346
-    {
347
-        $this->request()->setIsBot($is_bot);
348
-    }
349
-
350
-
351
-    /**
352
-     * check if a request parameter exists whose key that matches the supplied wildcard pattern
353
-     * and return the value for the first match found
354
-     * wildcards can be either of the following:
355
-     *      ? to represent a single character of any type
356
-     *      * to represent one or more characters of any type
357
-     *
358
-     * @param string     $pattern
359
-     * @param null|mixed $default
360
-     * @return false|int
361
-     * @throws InvalidArgumentException
362
-     * @throws InvalidInterfaceException
363
-     * @throws InvalidDataTypeException
364
-     */
365
-    public function getMatch($pattern, $default = null)
366
-    {
367
-        return $this->request()->getMatch($pattern, $default);
368
-    }
369
-
370
-
371
-    /**
372
-     * check if a request parameter exists whose key matches the supplied wildcard pattern
373
-     * wildcards can be either of the following:
374
-     *      ? to represent a single character of any type
375
-     *      * to represent one or more characters of any type
376
-     * returns true if a match is found or false if not
377
-     *
378
-     * @param string $pattern
379
-     * @return false|int
380
-     * @throws InvalidArgumentException
381
-     * @throws InvalidInterfaceException
382
-     * @throws InvalidDataTypeException
383
-     */
384
-    public function matches($pattern)
385
-    {
386
-        return $this->request()->matches($pattern);
387
-    }
25
+	/**
26
+	 * @var RequestInterface $request
27
+	 */
28
+	private $request;
29
+
30
+	/**
31
+	 * whether current request is for the admin but NOT via AJAX
32
+	 *
33
+	 * @var boolean $admin
34
+	 */
35
+	public $admin = false;
36
+
37
+	/**
38
+	 * whether current request is via AJAX
39
+	 *
40
+	 * @var boolean $ajax
41
+	 */
42
+	public $ajax = false;
43
+
44
+	/**
45
+	 * whether current request is via AJAX from the frontend of the site
46
+	 *
47
+	 * @var boolean $front_ajax
48
+	 */
49
+	public $front_ajax = false;
50
+
51
+
52
+	/**
53
+	 * @deprecated 4.9.53
54
+	 * @param array $get
55
+	 * @param array $post
56
+	 * @param array $cookie
57
+	 * @param array $server
58
+	 */
59
+	public function __construct(
60
+		array $get = array(),
61
+		array $post = array(),
62
+		array $cookie = array(),
63
+		array $server = array()
64
+	) {
65
+	}
66
+
67
+
68
+	/**
69
+	 * @return RequestInterface
70
+	 * @throws InvalidArgumentException
71
+	 * @throws InvalidInterfaceException
72
+	 * @throws InvalidDataTypeException
73
+	 */
74
+	private function request()
75
+	{
76
+		if($this->request instanceof RequestInterface){
77
+			return $this->request;
78
+		}
79
+		$loader = LoaderFactory::getLoader();
80
+		$this->request = $loader->getShared('EventEspresso\core\services\request\RequestInterface');
81
+		return $this->request;
82
+	}
83
+
84
+
85
+	/**
86
+	 * @param RequestInterface $request
87
+	 */
88
+	public function setRequest(RequestInterface $request)
89
+	{
90
+		$this->request = $request;
91
+	}
92
+
93
+
94
+
95
+	/**
96
+	 * @deprecated 4.9.53
97
+	 * @return array
98
+	 * @throws InvalidArgumentException
99
+	 * @throws InvalidDataTypeException
100
+	 * @throws InvalidInterfaceException
101
+	 */
102
+	public function get_params()
103
+	{
104
+		return $this->request()->getParams();
105
+	}
106
+
107
+
108
+
109
+	/**
110
+	 * @deprecated 4.9.53
111
+	 * @return array
112
+	 * @throws InvalidArgumentException
113
+	 * @throws InvalidDataTypeException
114
+	 * @throws InvalidInterfaceException
115
+	 */
116
+	public function post_params()
117
+	{
118
+		return $this->request()->postParams();
119
+	}
120
+
121
+
122
+
123
+	/**
124
+	 * @deprecated 4.9.53
125
+	 * @return array
126
+	 * @throws InvalidArgumentException
127
+	 * @throws InvalidDataTypeException
128
+	 * @throws InvalidInterfaceException
129
+	 */
130
+	public function cookie_params()
131
+	{
132
+		return $this->request()->cookieParams();
133
+	}
134
+
135
+
136
+	/**
137
+	 * @deprecated 4.9.53
138
+	 * @return array
139
+	 * @throws InvalidArgumentException
140
+	 * @throws InvalidDataTypeException
141
+	 * @throws InvalidInterfaceException
142
+	 */
143
+	public function server_params()
144
+	{
145
+		return $this->request()->serverParams();
146
+	}
147
+
148
+
149
+
150
+	/**
151
+	 * returns contents of $_REQUEST
152
+	 *
153
+	 * @deprecated 4.9.53
154
+	 * @return array
155
+	 * @throws InvalidArgumentException
156
+	 * @throws InvalidDataTypeException
157
+	 * @throws InvalidInterfaceException
158
+	 */
159
+	public function params()
160
+	{
161
+		return $this->request()->requestParams();
162
+	}
163
+
164
+
165
+
166
+	/**
167
+	 * @deprecated 4.9.53
168
+	 * @param      $key
169
+	 * @param      $value
170
+	 * @param bool $override_ee
171
+	 * @return void
172
+	 * @throws InvalidArgumentException
173
+	 * @throws InvalidDataTypeException
174
+	 * @throws InvalidInterfaceException
175
+	 */
176
+	public function set($key, $value, $override_ee = false)
177
+	{
178
+		$this->request()->setRequestParam($key, $value, $override_ee);
179
+	}
180
+
181
+
182
+
183
+	/**
184
+	 * returns   the value for a request param if the given key exists
185
+	 *
186
+	 * @deprecated 4.9.53
187
+	 * @param      $key
188
+	 * @param null $default
189
+	 * @return mixed
190
+	 * @throws InvalidArgumentException
191
+	 * @throws InvalidDataTypeException
192
+	 * @throws InvalidInterfaceException
193
+	 */
194
+	public function get($key, $default = null)
195
+	{
196
+		return $this->request()->getRequestParam($key, $default);
197
+	}
198
+
199
+
200
+
201
+	/**
202
+	 * check if param exists
203
+	 *
204
+	 * @deprecated 4.9.53
205
+	 * @param $key
206
+	 * @return bool
207
+	 * @throws InvalidArgumentException
208
+	 * @throws InvalidDataTypeException
209
+	 * @throws InvalidInterfaceException
210
+	 */
211
+	public function is_set($key)
212
+	{
213
+		return $this->request()->requestParamIsSet($key);
214
+	}
215
+
216
+
217
+	/**
218
+	 * remove param
219
+	 *
220
+	 * @deprecated 4.9.53
221
+	 * @param      $key
222
+	 * @param bool $unset_from_global_too
223
+	 * @throws InvalidArgumentException
224
+	 * @throws InvalidDataTypeException
225
+	 * @throws InvalidInterfaceException
226
+	 */
227
+	public function un_set($key, $unset_from_global_too = false)
228
+	{
229
+		$this->request()->unSetRequestParam($key, $unset_from_global_too);
230
+	}
231
+
232
+
233
+
234
+	/**
235
+	 * @deprecated 4.9.53
236
+	 * @return string
237
+	 * @throws InvalidArgumentException
238
+	 * @throws InvalidDataTypeException
239
+	 * @throws InvalidInterfaceException
240
+	 */
241
+	public function ip_address()
242
+	{
243
+		return $this->request()->ipAddress();
244
+	}
245
+
246
+
247
+	/**
248
+	 * @deprecated 4.9.53
249
+	 * @return bool
250
+	 * @throws InvalidArgumentException
251
+	 * @throws InvalidDataTypeException
252
+	 * @throws InvalidInterfaceException
253
+	 */
254
+	public function isAdmin()
255
+	{
256
+		return $this->request()->isAdmin();
257
+	}
258
+
259
+
260
+	/**
261
+	 * @deprecated 4.9.53
262
+	 * @return mixed
263
+	 * @throws InvalidArgumentException
264
+	 * @throws InvalidDataTypeException
265
+	 * @throws InvalidInterfaceException
266
+	 */
267
+	public function isAjax()
268
+	{
269
+		return $this->request()->isAjax();
270
+	}
271
+
272
+
273
+	/**
274
+	 * @deprecated 4.9.53
275
+	 * @return mixed
276
+	 * @throws InvalidArgumentException
277
+	 * @throws InvalidDataTypeException
278
+	 * @throws InvalidInterfaceException
279
+	 */
280
+	public function isFrontAjax()
281
+	{
282
+		return $this->request()->isFrontAjax();
283
+	}
284
+
285
+
286
+	/**
287
+	 * @deprecated 4.9.53
288
+	 * @return mixed|string
289
+	 * @throws InvalidArgumentException
290
+	 * @throws InvalidDataTypeException
291
+	 * @throws InvalidInterfaceException
292
+	 */
293
+	public function requestUri()
294
+	{
295
+		return $this->request()->requestUri();
296
+	}
297
+
298
+
299
+	/**
300
+	 * @deprecated 4.9.53
301
+	 * @return string
302
+	 * @throws InvalidArgumentException
303
+	 * @throws InvalidDataTypeException
304
+	 * @throws InvalidInterfaceException
305
+	 */
306
+	public function userAgent()
307
+	{
308
+		return $this->request()->userAgent();
309
+	}
310
+
311
+
312
+	/**
313
+	 * @deprecated 4.9.53
314
+	 * @param string $user_agent
315
+	 * @throws InvalidArgumentException
316
+	 * @throws InvalidDataTypeException
317
+	 * @throws InvalidInterfaceException
318
+	 */
319
+	public function setUserAgent($user_agent = '')
320
+	{
321
+		$this->request()->setUserAgent($user_agent);
322
+	}
323
+
324
+
325
+	/**
326
+	 * @deprecated 4.9.53
327
+	 * @return bool
328
+	 * @throws InvalidArgumentException
329
+	 * @throws InvalidDataTypeException
330
+	 * @throws InvalidInterfaceException
331
+	 */
332
+	public function isBot()
333
+	{
334
+		return $this->request()->isBot();
335
+	}
336
+
337
+
338
+	/**
339
+	 * @deprecated 4.9.53
340
+	 * @param bool $is_bot
341
+	 * @throws InvalidArgumentException
342
+	 * @throws InvalidDataTypeException
343
+	 * @throws InvalidInterfaceException
344
+	 */
345
+	public function setIsBot($is_bot)
346
+	{
347
+		$this->request()->setIsBot($is_bot);
348
+	}
349
+
350
+
351
+	/**
352
+	 * check if a request parameter exists whose key that matches the supplied wildcard pattern
353
+	 * and return the value for the first match found
354
+	 * wildcards can be either of the following:
355
+	 *      ? to represent a single character of any type
356
+	 *      * to represent one or more characters of any type
357
+	 *
358
+	 * @param string     $pattern
359
+	 * @param null|mixed $default
360
+	 * @return false|int
361
+	 * @throws InvalidArgumentException
362
+	 * @throws InvalidInterfaceException
363
+	 * @throws InvalidDataTypeException
364
+	 */
365
+	public function getMatch($pattern, $default = null)
366
+	{
367
+		return $this->request()->getMatch($pattern, $default);
368
+	}
369
+
370
+
371
+	/**
372
+	 * check if a request parameter exists whose key matches the supplied wildcard pattern
373
+	 * wildcards can be either of the following:
374
+	 *      ? to represent a single character of any type
375
+	 *      * to represent one or more characters of any type
376
+	 * returns true if a match is found or false if not
377
+	 *
378
+	 * @param string $pattern
379
+	 * @return false|int
380
+	 * @throws InvalidArgumentException
381
+	 * @throws InvalidInterfaceException
382
+	 * @throws InvalidDataTypeException
383
+	 */
384
+	public function matches($pattern)
385
+	{
386
+		return $this->request()->matches($pattern);
387
+	}
388 388
 
389 389
 
390 390
 }
Please login to merge, or discard this patch.
core/services/Benchmark.php 2 patches
Indentation   +328 added lines, -328 removed lines patch added patch discarded remove patch
@@ -20,334 +20,334 @@
 block discarded – undo
20 20
 class Benchmark
21 21
 {
22 22
 
23
-    /**
24
-     * @var string $output
25
-     */
26
-    private static $output;
27
-
28
-    /**
29
-     * @var array $start_times array containing the start time for the timers
30
-     */
31
-    private static $start_times;
32
-
33
-    /**
34
-     * @var array $times array containing all the timer'd times, which can be outputted via show_times()
35
-     */
36
-    private static $times = array();
37
-
38
-    /**
39
-     * @var array $memory_usage
40
-     */
41
-    protected static $memory_usage = array();
42
-
43
-
44
-    /**
45
-     * @param string $output
46
-     * @param bool   $formatted
47
-     */
48
-    public static function addOutput($output, $formatted = true)
49
-    {
50
-        Benchmark::$output .= $formatted
51
-            ? "<br />{$output}"
52
-            : "\n{$output}";
53
-    }
54
-
55
-
56
-    /**
57
-     * @return void
58
-     */
59
-    public static function resetOutput()
60
-    {
61
-        Benchmark::$output = '';
62
-    }
63
-
64
-    /**
65
-     * whether to benchmark code or not
66
-     */
67
-    public static function doNotRun()
68
-    {
69
-        return ! WP_DEBUG || (defined('DOING_AJAX') && DOING_AJAX);
70
-    }
71
-
72
-
73
-
74
-    /**
75
-     * resetTimes
76
-     */
77
-    public static function resetTimes()
78
-    {
79
-        Benchmark::$times = array();
80
-    }
81
-
82
-
83
-
84
-    /**
85
-     * Add Benchmark::startTimer() before a block of code you want to measure the performance of
86
-     *
87
-     * @param null $timer_name
88
-     */
89
-    public static function startTimer($timer_name = null)
90
-    {
91
-        if (Benchmark::doNotRun()) {
92
-            return;
93
-        }
94
-        $timer_name = $timer_name !== '' ? $timer_name : get_called_class();
95
-        Benchmark::$start_times[$timer_name] = microtime(true);
96
-    }
97
-
98
-
99
-
100
-    /**
101
-     * Add Benchmark::stopTimer() after a block of code you want to measure the performance of
102
-     *
103
-     * @param string $timer_name
104
-     */
105
-    public static function stopTimer($timer_name = '')
106
-    {
107
-        if (Benchmark::doNotRun()) {
108
-            return;
109
-        }
110
-        $timer_name = $timer_name !== '' ? $timer_name : get_called_class();
111
-        if (isset(Benchmark::$start_times[$timer_name])) {
112
-            $start_time = Benchmark::$start_times[$timer_name];
113
-            unset(Benchmark::$start_times[$timer_name]);
114
-        } else {
115
-            $start_time = array_pop(Benchmark::$start_times);
116
-        }
117
-        Benchmark::$times[$timer_name] = number_format(microtime(true) - $start_time, 8);
118
-    }
119
-
120
-
121
-
122
-    /**
123
-     * Measure the memory usage by PHP so far.
124
-     *
125
-     * @param string  $label      The label to show for this time eg "Start of calling Some_Class::some_function"
126
-     * @param boolean $output_now whether to echo now, or wait until EEH_Debug_Tools::show_times() is called
127
-     * @param bool    $formatted
128
-     * @return void
129
-     */
130
-    public static function measureMemory($label = 'memory usage', $output_now = false, $formatted = true)
131
-    {
132
-        if (Benchmark::doNotRun()) {
133
-            return;
134
-        }
135
-        $memory_used = Benchmark::convert(memory_get_usage(true));
136
-        Benchmark::$memory_usage[$label] = $memory_used;
137
-        if ($output_now) {
138
-            echo $formatted
139
-                ? "<br>{$label} : {$memory_used}"
140
-                : "\n {$label} : {$memory_used}";
141
-        }
142
-    }
143
-
144
-
145
-
146
-    /**
147
-     * will display the benchmarking results at shutdown
148
-     *
149
-     * @param bool $formatted
150
-     * @return void
151
-     */
152
-    public static function displayResultsAtShutdown($formatted = true)
153
-    {
154
-        Benchmark::resetOutput();
155
-        add_action(
156
-            'shutdown',
157
-            function () use ($formatted) {
158
-                Benchmark::displayResults(true, $formatted);
159
-            }
160
-        );
161
-    }
162
-
163
-
164
-
165
-    /**
166
-     * will display the benchmarking results at shutdown
167
-     *
168
-     * @param string $filepath
169
-     * @param bool   $formatted
170
-     * @param bool   $append
171
-     * @return void
172
-     */
173
-    public static function writeResultsAtShutdown($filepath = '', $formatted = true, $append = true)
174
-    {
175
-        Benchmark::resetOutput();
176
-        add_action(
177
-            'shutdown',
178
-            function () use ($filepath, $formatted, $append) {
179
-                Benchmark::writeResultsToFile($filepath, $formatted, $append);
180
-            }
181
-        );
182
-    }
183
-
184
-
185
-
186
-    /**
187
-     * @param bool $formatted
188
-     * @return string
189
-     */
190
-    private static function generateResults($formatted = true)
191
-    {
192
-        if (Benchmark::doNotRun()) {
193
-            return '';
194
-        }
195
-        if (! empty(Benchmark::$times)) {
196
-            $total = 0;
197
-            Benchmark::$output .= $formatted
198
-                ? '<span style="color:#999999; font-size:.8em;">( time in milliseconds )</span><br />'
199
-                : '';
200
-            foreach (Benchmark::$times as $timer_name => $total_time) {
201
-                Benchmark::$output .= Benchmark::formatTime($timer_name, $total_time, $formatted);
202
-                Benchmark::$output .= $formatted ? '<br />'  : "\n";
203
-                $total += $total_time;
204
-            }
205
-            if($formatted) {
206
-                Benchmark::$output .= '<br />';
207
-                Benchmark::$output .= '<h4>TOTAL TIME</h4>';
208
-                Benchmark::$output .= Benchmark::formatTime('', $total, $formatted);
209
-                Benchmark::$output .= '<span style="color:#999999; font-size:.8em;"> milliseconds</span><br />';
210
-                Benchmark::$output .= '<br />';
211
-                Benchmark::$output .= '<h5>Performance scale (from best to worse)</h5>';
212
-                Benchmark::$output .= '<span style="color:mediumpurple">Like wow! How about a Scooby snack?</span><br />';
213
-                Benchmark::$output .= '<span style="color:deepskyblue">Like...no way man!</span><br />';
214
-                Benchmark::$output .= '<span style="color:limegreen">Like...groovy!</span><br />';
215
-                Benchmark::$output .= '<span style="color:gold">Ruh Oh</span><br />';
216
-                Benchmark::$output .= '<span style="color:darkorange">Zoinks!</span><br />';
217
-                Benchmark::$output .= '<span style="color:red">Like...HEEELLLP</span><br />';
218
-            }
219
-        }
220
-        if (! empty(Benchmark::$memory_usage)) {
221
-            Benchmark::$output .= $formatted
222
-                ? '<h5>Memory</h5>'
223
-                : "\nMemory";
224
-            foreach (Benchmark::$memory_usage as $label => $memory_usage) {
225
-                Benchmark::$output .= $formatted
226
-                    ? "<br />{$memory_usage} : {$label}"
227
-                    : "\n{$memory_usage} : {$label}";
228
-            }
229
-        }
230
-        if (empty(Benchmark::$output)) {
231
-            return '';
232
-        }
233
-        Benchmark::$output = $formatted
234
-            ? '<div style="border:1px solid #dddddd; background-color:#ffffff;'
235
-              . (is_admin()
236
-                ? ' margin:2em 2em 2em 180px;'
237
-                : ' margin:2em;')
238
-              . ' padding:2em;">'
239
-              . '<h4>BENCHMARKING</h4>'
240
-              . Benchmark::$output
241
-              . '</div>'
242
-            : Benchmark::$output;
243
-        return Benchmark::$output;
244
-    }
245
-
246
-
247
-
248
-    /**
249
-     * @param bool $echo
250
-     * @param bool $formatted
251
-     * @return string
252
-     */
253
-    public static function displayResults($echo = true, $formatted = true)
254
-    {
255
-        $results = Benchmark::generateResults($formatted);
256
-        if ($echo) {
257
-            echo $results;
258
-            $results = '';
259
-        }
260
-        return $results;
261
-    }
262
-
263
-
264
-    /**
265
-     * @param string $filepath
266
-     * @param bool   $formatted
267
-     * @param bool   $append
268
-     * @throws EE_Error
269
-     */
270
-    public static function writeResultsToFile($filepath = '', $formatted = true, $append = true)
271
-    {
272
-        $filepath = ! empty($filepath) && is_readable(dirname($filepath))
273
-            ? $filepath
274
-            : '';
275
-        if( empty($filepath)) {
276
-            $filepath = EVENT_ESPRESSO_UPLOAD_DIR . 'logs/benchmarking-' . date('Y-m-d') . '.html';
277
-        }
278
-        EEH_File::ensure_file_exists_and_is_writable($filepath);
279
-        file_put_contents(
280
-            $filepath,
281
-            "\n" . date('Y-m-d H:i:s') . Benchmark::generateResults($formatted),
282
-            $append ? FILE_APPEND | LOCK_EX : LOCK_EX
283
-        );
284
-    }
285
-
286
-
287
-
288
-    /**
289
-     * Converts a measure of memory bytes into the most logical units (eg kb, mb, etc)
290
-     *
291
-     * @param int $size
292
-     * @return string
293
-     */
294
-    public static function convert($size)
295
-    {
296
-        $unit = array('b', 'kb', 'mb', 'gb', 'tb', 'pb');
297
-        return round(
298
-            $size / pow(1024, $i = floor(log($size, 1024))),
299
-            2
300
-        ) . ' ' . $unit[absint($i)];
301
-    }
302
-
303
-
304
-
305
-    /**
306
-     * @param string $timer_name
307
-     * @param float  $total_time
308
-     * @param bool   $formatted
309
-     * @return string
310
-     */
311
-    public static function formatTime($timer_name, $total_time, $formatted = true)
312
-    {
313
-        $total_time *= 1000;
314
-        switch ($total_time) {
315
-            case $total_time > 12500 :
316
-                $color = 'red';
317
-                $bold = 'bold';
318
-                break;
319
-            case $total_time > 2500 :
320
-                $color = 'darkorange';
321
-                $bold = 'bold';
322
-                break;
323
-            case $total_time > 500 :
324
-                $color = 'gold';
325
-                $bold = 'bold';
326
-                break;
327
-            case $total_time > 100 :
328
-                $color = 'limegreen';
329
-                $bold = 'normal';
330
-                break;
331
-            case $total_time > 20 :
332
-                $color = 'deepskyblue';
333
-                $bold = 'normal';
334
-                break;
335
-            default :
336
-                $color = 'mediumpurple';
337
-                $bold = 'normal';
338
-                break;
339
-        }
340
-        return $formatted
341
-            ? '<span style="min-width: 10px; margin:0 1em; color:'
342
-               . $color
343
-               . '; font-weight:'
344
-               . $bold
345
-               . '; font-size:1.2em;">'
346
-               . str_pad(number_format($total_time, 3), 9, '0', STR_PAD_LEFT)
347
-               . '</span> '
348
-               . $timer_name
349
-            :  str_pad(number_format($total_time, 3), 9, '0', STR_PAD_LEFT);
350
-    }
23
+	/**
24
+	 * @var string $output
25
+	 */
26
+	private static $output;
27
+
28
+	/**
29
+	 * @var array $start_times array containing the start time for the timers
30
+	 */
31
+	private static $start_times;
32
+
33
+	/**
34
+	 * @var array $times array containing all the timer'd times, which can be outputted via show_times()
35
+	 */
36
+	private static $times = array();
37
+
38
+	/**
39
+	 * @var array $memory_usage
40
+	 */
41
+	protected static $memory_usage = array();
42
+
43
+
44
+	/**
45
+	 * @param string $output
46
+	 * @param bool   $formatted
47
+	 */
48
+	public static function addOutput($output, $formatted = true)
49
+	{
50
+		Benchmark::$output .= $formatted
51
+			? "<br />{$output}"
52
+			: "\n{$output}";
53
+	}
54
+
55
+
56
+	/**
57
+	 * @return void
58
+	 */
59
+	public static function resetOutput()
60
+	{
61
+		Benchmark::$output = '';
62
+	}
63
+
64
+	/**
65
+	 * whether to benchmark code or not
66
+	 */
67
+	public static function doNotRun()
68
+	{
69
+		return ! WP_DEBUG || (defined('DOING_AJAX') && DOING_AJAX);
70
+	}
71
+
72
+
73
+
74
+	/**
75
+	 * resetTimes
76
+	 */
77
+	public static function resetTimes()
78
+	{
79
+		Benchmark::$times = array();
80
+	}
81
+
82
+
83
+
84
+	/**
85
+	 * Add Benchmark::startTimer() before a block of code you want to measure the performance of
86
+	 *
87
+	 * @param null $timer_name
88
+	 */
89
+	public static function startTimer($timer_name = null)
90
+	{
91
+		if (Benchmark::doNotRun()) {
92
+			return;
93
+		}
94
+		$timer_name = $timer_name !== '' ? $timer_name : get_called_class();
95
+		Benchmark::$start_times[$timer_name] = microtime(true);
96
+	}
97
+
98
+
99
+
100
+	/**
101
+	 * Add Benchmark::stopTimer() after a block of code you want to measure the performance of
102
+	 *
103
+	 * @param string $timer_name
104
+	 */
105
+	public static function stopTimer($timer_name = '')
106
+	{
107
+		if (Benchmark::doNotRun()) {
108
+			return;
109
+		}
110
+		$timer_name = $timer_name !== '' ? $timer_name : get_called_class();
111
+		if (isset(Benchmark::$start_times[$timer_name])) {
112
+			$start_time = Benchmark::$start_times[$timer_name];
113
+			unset(Benchmark::$start_times[$timer_name]);
114
+		} else {
115
+			$start_time = array_pop(Benchmark::$start_times);
116
+		}
117
+		Benchmark::$times[$timer_name] = number_format(microtime(true) - $start_time, 8);
118
+	}
119
+
120
+
121
+
122
+	/**
123
+	 * Measure the memory usage by PHP so far.
124
+	 *
125
+	 * @param string  $label      The label to show for this time eg "Start of calling Some_Class::some_function"
126
+	 * @param boolean $output_now whether to echo now, or wait until EEH_Debug_Tools::show_times() is called
127
+	 * @param bool    $formatted
128
+	 * @return void
129
+	 */
130
+	public static function measureMemory($label = 'memory usage', $output_now = false, $formatted = true)
131
+	{
132
+		if (Benchmark::doNotRun()) {
133
+			return;
134
+		}
135
+		$memory_used = Benchmark::convert(memory_get_usage(true));
136
+		Benchmark::$memory_usage[$label] = $memory_used;
137
+		if ($output_now) {
138
+			echo $formatted
139
+				? "<br>{$label} : {$memory_used}"
140
+				: "\n {$label} : {$memory_used}";
141
+		}
142
+	}
143
+
144
+
145
+
146
+	/**
147
+	 * will display the benchmarking results at shutdown
148
+	 *
149
+	 * @param bool $formatted
150
+	 * @return void
151
+	 */
152
+	public static function displayResultsAtShutdown($formatted = true)
153
+	{
154
+		Benchmark::resetOutput();
155
+		add_action(
156
+			'shutdown',
157
+			function () use ($formatted) {
158
+				Benchmark::displayResults(true, $formatted);
159
+			}
160
+		);
161
+	}
162
+
163
+
164
+
165
+	/**
166
+	 * will display the benchmarking results at shutdown
167
+	 *
168
+	 * @param string $filepath
169
+	 * @param bool   $formatted
170
+	 * @param bool   $append
171
+	 * @return void
172
+	 */
173
+	public static function writeResultsAtShutdown($filepath = '', $formatted = true, $append = true)
174
+	{
175
+		Benchmark::resetOutput();
176
+		add_action(
177
+			'shutdown',
178
+			function () use ($filepath, $formatted, $append) {
179
+				Benchmark::writeResultsToFile($filepath, $formatted, $append);
180
+			}
181
+		);
182
+	}
183
+
184
+
185
+
186
+	/**
187
+	 * @param bool $formatted
188
+	 * @return string
189
+	 */
190
+	private static function generateResults($formatted = true)
191
+	{
192
+		if (Benchmark::doNotRun()) {
193
+			return '';
194
+		}
195
+		if (! empty(Benchmark::$times)) {
196
+			$total = 0;
197
+			Benchmark::$output .= $formatted
198
+				? '<span style="color:#999999; font-size:.8em;">( time in milliseconds )</span><br />'
199
+				: '';
200
+			foreach (Benchmark::$times as $timer_name => $total_time) {
201
+				Benchmark::$output .= Benchmark::formatTime($timer_name, $total_time, $formatted);
202
+				Benchmark::$output .= $formatted ? '<br />'  : "\n";
203
+				$total += $total_time;
204
+			}
205
+			if($formatted) {
206
+				Benchmark::$output .= '<br />';
207
+				Benchmark::$output .= '<h4>TOTAL TIME</h4>';
208
+				Benchmark::$output .= Benchmark::formatTime('', $total, $formatted);
209
+				Benchmark::$output .= '<span style="color:#999999; font-size:.8em;"> milliseconds</span><br />';
210
+				Benchmark::$output .= '<br />';
211
+				Benchmark::$output .= '<h5>Performance scale (from best to worse)</h5>';
212
+				Benchmark::$output .= '<span style="color:mediumpurple">Like wow! How about a Scooby snack?</span><br />';
213
+				Benchmark::$output .= '<span style="color:deepskyblue">Like...no way man!</span><br />';
214
+				Benchmark::$output .= '<span style="color:limegreen">Like...groovy!</span><br />';
215
+				Benchmark::$output .= '<span style="color:gold">Ruh Oh</span><br />';
216
+				Benchmark::$output .= '<span style="color:darkorange">Zoinks!</span><br />';
217
+				Benchmark::$output .= '<span style="color:red">Like...HEEELLLP</span><br />';
218
+			}
219
+		}
220
+		if (! empty(Benchmark::$memory_usage)) {
221
+			Benchmark::$output .= $formatted
222
+				? '<h5>Memory</h5>'
223
+				: "\nMemory";
224
+			foreach (Benchmark::$memory_usage as $label => $memory_usage) {
225
+				Benchmark::$output .= $formatted
226
+					? "<br />{$memory_usage} : {$label}"
227
+					: "\n{$memory_usage} : {$label}";
228
+			}
229
+		}
230
+		if (empty(Benchmark::$output)) {
231
+			return '';
232
+		}
233
+		Benchmark::$output = $formatted
234
+			? '<div style="border:1px solid #dddddd; background-color:#ffffff;'
235
+			  . (is_admin()
236
+				? ' margin:2em 2em 2em 180px;'
237
+				: ' margin:2em;')
238
+			  . ' padding:2em;">'
239
+			  . '<h4>BENCHMARKING</h4>'
240
+			  . Benchmark::$output
241
+			  . '</div>'
242
+			: Benchmark::$output;
243
+		return Benchmark::$output;
244
+	}
245
+
246
+
247
+
248
+	/**
249
+	 * @param bool $echo
250
+	 * @param bool $formatted
251
+	 * @return string
252
+	 */
253
+	public static function displayResults($echo = true, $formatted = true)
254
+	{
255
+		$results = Benchmark::generateResults($formatted);
256
+		if ($echo) {
257
+			echo $results;
258
+			$results = '';
259
+		}
260
+		return $results;
261
+	}
262
+
263
+
264
+	/**
265
+	 * @param string $filepath
266
+	 * @param bool   $formatted
267
+	 * @param bool   $append
268
+	 * @throws EE_Error
269
+	 */
270
+	public static function writeResultsToFile($filepath = '', $formatted = true, $append = true)
271
+	{
272
+		$filepath = ! empty($filepath) && is_readable(dirname($filepath))
273
+			? $filepath
274
+			: '';
275
+		if( empty($filepath)) {
276
+			$filepath = EVENT_ESPRESSO_UPLOAD_DIR . 'logs/benchmarking-' . date('Y-m-d') . '.html';
277
+		}
278
+		EEH_File::ensure_file_exists_and_is_writable($filepath);
279
+		file_put_contents(
280
+			$filepath,
281
+			"\n" . date('Y-m-d H:i:s') . Benchmark::generateResults($formatted),
282
+			$append ? FILE_APPEND | LOCK_EX : LOCK_EX
283
+		);
284
+	}
285
+
286
+
287
+
288
+	/**
289
+	 * Converts a measure of memory bytes into the most logical units (eg kb, mb, etc)
290
+	 *
291
+	 * @param int $size
292
+	 * @return string
293
+	 */
294
+	public static function convert($size)
295
+	{
296
+		$unit = array('b', 'kb', 'mb', 'gb', 'tb', 'pb');
297
+		return round(
298
+			$size / pow(1024, $i = floor(log($size, 1024))),
299
+			2
300
+		) . ' ' . $unit[absint($i)];
301
+	}
302
+
303
+
304
+
305
+	/**
306
+	 * @param string $timer_name
307
+	 * @param float  $total_time
308
+	 * @param bool   $formatted
309
+	 * @return string
310
+	 */
311
+	public static function formatTime($timer_name, $total_time, $formatted = true)
312
+	{
313
+		$total_time *= 1000;
314
+		switch ($total_time) {
315
+			case $total_time > 12500 :
316
+				$color = 'red';
317
+				$bold = 'bold';
318
+				break;
319
+			case $total_time > 2500 :
320
+				$color = 'darkorange';
321
+				$bold = 'bold';
322
+				break;
323
+			case $total_time > 500 :
324
+				$color = 'gold';
325
+				$bold = 'bold';
326
+				break;
327
+			case $total_time > 100 :
328
+				$color = 'limegreen';
329
+				$bold = 'normal';
330
+				break;
331
+			case $total_time > 20 :
332
+				$color = 'deepskyblue';
333
+				$bold = 'normal';
334
+				break;
335
+			default :
336
+				$color = 'mediumpurple';
337
+				$bold = 'normal';
338
+				break;
339
+		}
340
+		return $formatted
341
+			? '<span style="min-width: 10px; margin:0 1em; color:'
342
+			   . $color
343
+			   . '; font-weight:'
344
+			   . $bold
345
+			   . '; font-size:1.2em;">'
346
+			   . str_pad(number_format($total_time, 3), 9, '0', STR_PAD_LEFT)
347
+			   . '</span> '
348
+			   . $timer_name
349
+			:  str_pad(number_format($total_time, 3), 9, '0', STR_PAD_LEFT);
350
+	}
351 351
 
352 352
 
353 353
 
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -154,7 +154,7 @@  discard block
 block discarded – undo
154 154
         Benchmark::resetOutput();
155 155
         add_action(
156 156
             'shutdown',
157
-            function () use ($formatted) {
157
+            function() use ($formatted) {
158 158
                 Benchmark::displayResults(true, $formatted);
159 159
             }
160 160
         );
@@ -175,7 +175,7 @@  discard block
 block discarded – undo
175 175
         Benchmark::resetOutput();
176 176
         add_action(
177 177
             'shutdown',
178
-            function () use ($filepath, $formatted, $append) {
178
+            function() use ($filepath, $formatted, $append) {
179 179
                 Benchmark::writeResultsToFile($filepath, $formatted, $append);
180 180
             }
181 181
         );
@@ -192,17 +192,17 @@  discard block
 block discarded – undo
192 192
         if (Benchmark::doNotRun()) {
193 193
             return '';
194 194
         }
195
-        if (! empty(Benchmark::$times)) {
195
+        if ( ! empty(Benchmark::$times)) {
196 196
             $total = 0;
197 197
             Benchmark::$output .= $formatted
198 198
                 ? '<span style="color:#999999; font-size:.8em;">( time in milliseconds )</span><br />'
199 199
                 : '';
200 200
             foreach (Benchmark::$times as $timer_name => $total_time) {
201 201
                 Benchmark::$output .= Benchmark::formatTime($timer_name, $total_time, $formatted);
202
-                Benchmark::$output .= $formatted ? '<br />'  : "\n";
202
+                Benchmark::$output .= $formatted ? '<br />' : "\n";
203 203
                 $total += $total_time;
204 204
             }
205
-            if($formatted) {
205
+            if ($formatted) {
206 206
                 Benchmark::$output .= '<br />';
207 207
                 Benchmark::$output .= '<h4>TOTAL TIME</h4>';
208 208
                 Benchmark::$output .= Benchmark::formatTime('', $total, $formatted);
@@ -217,7 +217,7 @@  discard block
 block discarded – undo
217 217
                 Benchmark::$output .= '<span style="color:red">Like...HEEELLLP</span><br />';
218 218
             }
219 219
         }
220
-        if (! empty(Benchmark::$memory_usage)) {
220
+        if ( ! empty(Benchmark::$memory_usage)) {
221 221
             Benchmark::$output .= $formatted
222 222
                 ? '<h5>Memory</h5>'
223 223
                 : "\nMemory";
@@ -272,13 +272,13 @@  discard block
 block discarded – undo
272 272
         $filepath = ! empty($filepath) && is_readable(dirname($filepath))
273 273
             ? $filepath
274 274
             : '';
275
-        if( empty($filepath)) {
276
-            $filepath = EVENT_ESPRESSO_UPLOAD_DIR . 'logs/benchmarking-' . date('Y-m-d') . '.html';
275
+        if (empty($filepath)) {
276
+            $filepath = EVENT_ESPRESSO_UPLOAD_DIR.'logs/benchmarking-'.date('Y-m-d').'.html';
277 277
         }
278 278
         EEH_File::ensure_file_exists_and_is_writable($filepath);
279 279
         file_put_contents(
280 280
             $filepath,
281
-            "\n" . date('Y-m-d H:i:s') . Benchmark::generateResults($formatted),
281
+            "\n".date('Y-m-d H:i:s').Benchmark::generateResults($formatted),
282 282
             $append ? FILE_APPEND | LOCK_EX : LOCK_EX
283 283
         );
284 284
     }
@@ -297,7 +297,7 @@  discard block
 block discarded – undo
297 297
         return round(
298 298
             $size / pow(1024, $i = floor(log($size, 1024))),
299 299
             2
300
-        ) . ' ' . $unit[absint($i)];
300
+        ).' '.$unit[absint($i)];
301 301
     }
302 302
 
303 303
 
Please login to merge, or discard this patch.
core/EE_Encryption.core.php 2 patches
Indentation   +686 added lines, -686 removed lines patch added patch discarded remove patch
@@ -19,692 +19,692 @@
 block discarded – undo
19 19
 class EE_Encryption implements InterminableInterface
20 20
 {
21 21
 
22
-    /**
23
-     * key used for saving the encryption key to the wp_options table
24
-     */
25
-    const ENCRYPTION_OPTION_KEY = 'ee_encryption_key';
26
-
27
-    /**
28
-     * the OPENSSL cipher method used
29
-     */
30
-    const OPENSSL_CIPHER_METHOD = 'AES-128-CBC';
31
-
32
-    /**
33
-     * WP "options_name" used to store a verified available cipher method
34
-     */
35
-    const OPENSSL_CIPHER_METHOD_OPTION_NAME = 'ee_openssl_cipher_method';
36
-
37
-    /**
38
-     * the OPENSSL digest method used
39
-     */
40
-    const OPENSSL_DIGEST_METHOD = 'sha512';
41
-
42
-    /**
43
-     * separates the encrypted text from the initialization vector
44
-     */
45
-    const OPENSSL_IV_DELIMITER = ':iv:';
46
-
47
-    /**
48
-     * appended to text encrypted using the acme encryption
49
-     */
50
-    const ACME_ENCRYPTION_FLAG = '::ae';
51
-
52
-
53
-
54
-    /**
55
-     * instance of the EE_Encryption object
56
-     */
57
-    protected static $_instance;
58
-
59
-    /**
60
-     * @var string $_encryption_key
61
-     */
62
-    protected $_encryption_key;
63
-
64
-    /**
65
-     * @var string $cipher_method
66
-     */
67
-    private $cipher_method = '';
68
-
69
-    /**
70
-     * @var array $cipher_methods
71
-     */
72
-    private $cipher_methods = array();
73
-
74
-    /**
75
-     * @var array $digest_methods
76
-     */
77
-    private $digest_methods = array();
78
-
79
-    /**
80
-     * @var boolean $_use_openssl_encrypt
81
-     */
82
-    protected $_use_openssl_encrypt = false;
83
-
84
-    /**
85
-     * @var boolean $_use_mcrypt
86
-     */
87
-    protected $_use_mcrypt = false;
88
-
89
-    /**
90
-     * @var boolean $_use_base64_encode
91
-     */
92
-    protected $_use_base64_encode = false;
93
-
94
-
95
-
96
-    /**
97
-     * protected constructor to prevent direct creation
98
-     */
99
-    protected function __construct()
100
-    {
101
-        if (! defined('ESPRESSO_ENCRYPT')) {
102
-            define('ESPRESSO_ENCRYPT', true);
103
-        }
104
-        if (extension_loaded('openssl')) {
105
-            $this->_use_openssl_encrypt = true;
106
-        } else if (extension_loaded('mcrypt')) {
107
-            $this->_use_mcrypt = true;
108
-        }
109
-        if (function_exists('base64_encode')) {
110
-            $this->_use_base64_encode = true;
111
-        }
112
-    }
113
-
114
-
115
-
116
-    /**
117
-     * singleton method used to instantiate class object
118
-     *
119
-     * @return EE_Encryption
120
-     */
121
-    public static function instance()
122
-    {
123
-        // check if class object is instantiated
124
-        if (! EE_Encryption::$_instance instanceof EE_Encryption) {
125
-            EE_Encryption::$_instance = new self();
126
-        }
127
-        return EE_Encryption::$_instance;
128
-    }
129
-
130
-
131
-
132
-    /**
133
-     * get encryption key
134
-     *
135
-     * @return string
136
-     */
137
-    public function get_encryption_key()
138
-    {
139
-        // if encryption key has not been set
140
-        if (empty($this->_encryption_key)) {
141
-            // retrieve encryption_key from db
142
-            $this->_encryption_key = get_option(EE_Encryption::ENCRYPTION_OPTION_KEY, '');
143
-            // WHAT?? No encryption_key in the db ??
144
-            if ($this->_encryption_key === '') {
145
-                // let's make one. And md5 it to make it just the right size for a key
146
-                $new_key = md5($this->generate_random_string());
147
-                // now save it to the db for later
148
-                add_option(EE_Encryption::ENCRYPTION_OPTION_KEY, $new_key);
149
-                // here's the key - FINALLY !
150
-                $this->_encryption_key = $new_key;
151
-            }
152
-        }
153
-        return $this->_encryption_key;
154
-    }
155
-
156
-
157
-
158
-    /**
159
-     * encrypts data
160
-     *
161
-     * @param string $text_string - the text to be encrypted
162
-     * @return string
163
-     * @throws RuntimeException
164
-     */
165
-    public function encrypt($text_string = '')
166
-    {
167
-        // you give me nothing??? GET OUT !
168
-        if (empty($text_string)) {
169
-            return $text_string;
170
-        }
171
-        if ($this->_use_openssl_encrypt) {
172
-            $encrypted_text = $this->openssl_encrypt($text_string);
173
-        } else {
174
-            $encrypted_text = $this->acme_encrypt($text_string);
175
-        }
176
-        return $encrypted_text;
177
-    }
178
-
179
-
180
-
181
-    /**
182
-     * decrypts data
183
-     *
184
-     * @param string $encrypted_text - the text to be decrypted
185
-     * @return string
186
-     * @throws RuntimeException
187
-     */
188
-    public function decrypt($encrypted_text = '')
189
-    {
190
-        // you give me nothing??? GET OUT !
191
-        if (empty($encrypted_text)) {
192
-            return $encrypted_text;
193
-        }
194
-        // if PHP's mcrypt functions are installed then we'll use them
195
-        if ($this->_use_openssl_encrypt) {
196
-            $decrypted_text = $this->openssl_decrypt($encrypted_text);
197
-        } else {
198
-            $decrypted_text = $this->acme_decrypt($encrypted_text);
199
-        }
200
-        return $decrypted_text;
201
-    }
202
-
203
-
204
-
205
-    /**
206
-     * encodes string with PHP's base64 encoding
207
-     *
208
-     * @see http://php.net/manual/en/function.base64-encode.php
209
-     * @param string $text_string the text to be encoded
210
-     * @return string
211
-     */
212
-    public function base64_string_encode($text_string = '')
213
-    {
214
-        // you give me nothing??? GET OUT !
215
-        if (empty($text_string) || ! $this->_use_base64_encode) {
216
-            return $text_string;
217
-        }
218
-        // encode
219
-        return base64_encode($text_string);
220
-    }
221
-
222
-
223
-    /**
224
-     * decodes string that has been encoded with PHP's base64 encoding
225
-     *
226
-     * @see http://php.net/manual/en/function.base64-encode.php
227
-     * @param string $encoded_string the text to be decoded
228
-     * @return string
229
-     * @throws RuntimeException
230
-     */
231
-    public function base64_string_decode($encoded_string = '')
232
-    {
233
-        // you give me nothing??? GET OUT !
234
-        if (empty($encoded_string) || ! $this->valid_base_64($encoded_string)) {
235
-            return $encoded_string;
236
-        }
237
-        // decode
238
-        $decoded_string = base64_decode($encoded_string);
239
-        if ($decoded_string === false) {
240
-            throw new RuntimeException(
241
-                esc_html__('Base 64 decoding failed.', 'event_espresso')
242
-            );
243
-        }
244
-        return $decoded_string;
245
-    }
246
-
247
-
248
-
249
-    /**
250
-     * encodes  url string with PHP's base64 encoding
251
-     *
252
-     * @see http://php.net/manual/en/function.base64-encode.php
253
-     * @param string $text_string the text to be encoded
254
-     * @return string
255
-     */
256
-    public function base64_url_encode($text_string = '')
257
-    {
258
-        // you give me nothing??? GET OUT !
259
-        if (empty($text_string) || ! $this->_use_base64_encode) {
260
-            return $text_string;
261
-        }
262
-        // encode
263
-        $encoded_string = base64_encode($text_string);
264
-        // remove chars to make encoding more URL friendly
265
-        return strtr($encoded_string, '+/=', '-_,');
266
-    }
267
-
268
-
269
-    /**
270
-     * decodes  url string that has been encoded with PHP's base64 encoding
271
-     *
272
-     * @see http://php.net/manual/en/function.base64-encode.php
273
-     * @param string $encoded_string the text to be decoded
274
-     * @return string
275
-     * @throws RuntimeException
276
-     */
277
-    public function base64_url_decode($encoded_string = '')
278
-    {
279
-        // you give me nothing??? GET OUT !
280
-        if (empty($encoded_string) || ! $this->valid_base_64($encoded_string)) {
281
-            return $encoded_string;
282
-        }
283
-        // replace previously removed characters
284
-        $encoded_string = strtr($encoded_string, '-_,', '+/=');
285
-        // decode
286
-        $decoded_string = base64_decode($encoded_string);
287
-        if ($decoded_string === false) {
288
-            throw new RuntimeException(
289
-                esc_html__('Base 64 decoding failed.', 'event_espresso')
290
-            );
291
-        }
292
-        return $decoded_string;
293
-    }
294
-
295
-
296
-    /**
297
-     * encrypts data using PHP's openssl functions
298
-     *
299
-     * @param string $text_string the text to be encrypted
300
-     * @param string $cipher_method
301
-     * @param string $encryption_key
302
-     * @return string
303
-     * @throws RuntimeException
304
-     */
305
-    protected function openssl_encrypt(
306
-        $text_string = '',
307
-        $cipher_method = EE_Encryption::OPENSSL_CIPHER_METHOD,
308
-        $encryption_key = ''
309
-    ) {
310
-        // you give me nothing??? GET OUT !
311
-        if (empty($text_string)) {
312
-            return $text_string;
313
-        }
314
-        $this->cipher_method = $this->getCipherMethod($cipher_method);
315
-        // get initialization vector size
316
-        $iv_size = openssl_cipher_iv_length($this->cipher_method);
317
-        // generate initialization vector.
318
-        // The second parameter ("crypto_strong") is passed by reference,
319
-        // and is used to determines if the algorithm used was "cryptographically strong"
320
-        // openssl_random_pseudo_bytes() will toggle it to either true or false
321
-        $iv = openssl_random_pseudo_bytes($iv_size, $is_strong);
322
-        if ($iv === false || $is_strong === false) {
323
-            throw new RuntimeException(
324
-                esc_html__('Failed to generate OpenSSL initialization vector.', 'event_espresso')
325
-            );
326
-        }
327
-        // encrypt it
328
-        $encrypted_text = openssl_encrypt(
329
-            $text_string,
330
-            $this->cipher_method,
331
-            $this->getDigestHashValue(EE_Encryption::OPENSSL_DIGEST_METHOD, $encryption_key),
332
-            0,
333
-            $iv
334
-        );
335
-        // append the initialization vector
336
-        $encrypted_text .= EE_Encryption::OPENSSL_IV_DELIMITER . $iv;
337
-        // trim and maybe encode
338
-        return $this->_use_base64_encode
339
-            ? trim(base64_encode($encrypted_text))
340
-            : trim($encrypted_text);
341
-    }
342
-
343
-
344
-
345
-    /**
346
-     * Returns a cipher method that has been verified to work.
347
-     * First checks if the cached cipher has been set already and if so, returns that.
348
-     * Then tests the incoming default and returns that if it's good.
349
-     * If not, then it retrieves the previously tested and saved cipher method.
350
-     * But if that doesn't exist, then calls getAvailableCipherMethod()
351
-     * to see what is available on the server, and returns the results.
352
-     *
353
-     * @param string $cipher_method
354
-     * @return string
355
-     * @throws RuntimeException
356
-     */
357
-    protected function getCipherMethod($cipher_method = EE_Encryption::OPENSSL_CIPHER_METHOD)
358
-    {
359
-        if($this->cipher_method !== ''){
360
-            return $this->cipher_method;
361
-        }
362
-        // verify that the default cipher method can produce an initialization vector
363
-        if (openssl_cipher_iv_length($cipher_method) === false) {
364
-            // nope? okay let's get what we found in the past to work
365
-            $cipher_method = get_option(EE_Encryption::OPENSSL_CIPHER_METHOD_OPTION_NAME, '');
366
-            // oops... haven't tested available cipher methods yet
367
-            if($cipher_method === '' || openssl_cipher_iv_length($cipher_method) === false) {
368
-                $cipher_method = $this->getAvailableCipherMethod($cipher_method);
369
-            }
370
-        }
371
-        return $cipher_method;
372
-    }
373
-
374
-
375
-
376
-    /**
377
-     * @param string $cipher_method
378
-     * @return string
379
-     * @throws \RuntimeException
380
-     */
381
-    protected function getAvailableCipherMethod($cipher_method)
382
-    {
383
-        // verify that the incoming cipher method can produce an initialization vector
384
-        if (openssl_cipher_iv_length($cipher_method) === false) {
385
-            // nope? then check the next cipher in the list of available cipher methods
386
-            $cipher_method = next($this->cipher_methods);
387
-            // what? there's no list? then generate that list and cache it,
388
-            if (empty($this->cipher_methods)) {
389
-                $this->cipher_methods = openssl_get_cipher_methods();
390
-                // then grab the first item from the list
391
-                $cipher_method = reset($this->cipher_methods);
392
-            }
393
-            if($cipher_method === false){
394
-                throw new RuntimeException(
395
-                    esc_html__(
396
-                        'OpenSSL support appears to be enabled on the server, but no cipher methods are available. Please contact the server administrator.',
397
-                        'event_espresso'
398
-                    )
399
-                );
400
-            }
401
-            // verify that the next cipher method works
402
-            return $this->getAvailableCipherMethod($cipher_method);
403
-        }
404
-        // if we've gotten this far, then we found an available cipher method that works
405
-        // so save that for next time
406
-        update_option(
407
-            EE_Encryption::OPENSSL_CIPHER_METHOD_OPTION_NAME,
408
-            $cipher_method
409
-        );
410
-        return $cipher_method;
411
-    }
412
-
413
-
414
-    /**
415
-     * decrypts data that has been encrypted with PHP's openssl functions
416
-     *
417
-     * @param string $encrypted_text the text to be decrypted
418
-     * @param string $cipher_method
419
-     * @param string $encryption_key
420
-     * @return string
421
-     * @throws RuntimeException
422
-     */
423
-    protected function openssl_decrypt(
424
-        $encrypted_text = '',
425
-        $cipher_method = EE_Encryption::OPENSSL_CIPHER_METHOD,
426
-        $encryption_key = ''
427
-    ) {
428
-        // you give me nothing??? GET OUT !
429
-        if (empty($encrypted_text)) {
430
-            return $encrypted_text;
431
-        }
432
-        // decode
433
-        $encrypted_text = $this->valid_base_64($encrypted_text)
434
-            ? $this->base64_url_decode($encrypted_text)
435
-            : $encrypted_text;
436
-        $encrypted_components = explode(
437
-            EE_Encryption::OPENSSL_IV_DELIMITER,
438
-            $encrypted_text,
439
-            2
440
-        );
441
-        // check that iv exists, and if not, maybe text was encoded using mcrypt?
442
-        if ($this->_use_mcrypt && ! isset($encrypted_components[1])) {
443
-            return $this->m_decrypt($encrypted_text);
444
-        }
445
-        // decrypt it
446
-        $decrypted_text = openssl_decrypt(
447
-            $encrypted_components[0],
448
-            $this->getCipherMethod($cipher_method),
449
-            $this->getDigestHashValue(EE_Encryption::OPENSSL_DIGEST_METHOD,$encryption_key),
450
-            0,
451
-            $encrypted_components[1]
452
-        );
453
-        $decrypted_text = trim($decrypted_text);
454
-        return $decrypted_text;
455
-    }
456
-
457
-
458
-    /**
459
-     * Computes the digest hash value using the specified digest method.
460
-     * If that digest method fails to produce a valid hash value,
461
-     * then we'll grab the next digest method and recursively try again until something works.
462
-     *
463
-     * @param string $digest_method
464
-     * @param string $encryption_key
465
-     * @return string
466
-     * @throws RuntimeException
467
-     */
468
-    protected function getDigestHashValue($digest_method = EE_Encryption::OPENSSL_DIGEST_METHOD, $encryption_key = ''){
469
-        $encryption_key = $encryption_key !== ''
470
-            ? $encryption_key
471
-            : $this->get_encryption_key();
472
-        $digest_hash_value = openssl_digest($encryption_key, $digest_method);
473
-        if ($digest_hash_value === false) {
474
-            return $this->getDigestHashValue($this->getDigestMethod());
475
-        }
476
-        return $digest_hash_value;
477
-    }
478
-
479
-
480
-
481
-    /**
482
-     * Returns the NEXT element in the $digest_methods array.
483
-     * If the $digest_methods array is empty, then we populate it
484
-     * with the available values returned from openssl_get_md_methods().
485
-     *
486
-     * @return string
487
-     * @throws \RuntimeException
488
-     */
489
-    protected function getDigestMethod(){
490
-        $digest_method = prev($this->digest_methods);
491
-        if (empty($this->digest_methods)) {
492
-            $this->digest_methods = openssl_get_md_methods();
493
-            $digest_method = end($this->digest_methods);
494
-        }
495
-        if ($digest_method === false) {
496
-            throw new RuntimeException(
497
-                esc_html__(
498
-                    'OpenSSL support appears to be enabled on the server, but no digest methods are available. Please contact the server administrator.',
499
-                    'event_espresso'
500
-                )
501
-            );
502
-        }
503
-        return $digest_method;
504
-    }
505
-
506
-
507
-    /**
508
-     * encrypts data for acme servers that didn't bother to install PHP mcrypt
509
-     *
510
-     * @see http://stackoverflow.com/questions/800922/how-to-encrypt-string-without-mcrypt-library-in-php
511
-     * @param string $text_string the text to be decrypted
512
-     * @return string
513
-     */
514
-    protected function acme_encrypt($text_string = '')
515
-    {
516
-        // you give me nothing??? GET OUT !
517
-        if (empty($text_string)) {
518
-            return $text_string;
519
-        }
520
-        $key_bits = str_split(
521
-            str_pad(
522
-                '',
523
-                strlen($text_string),
524
-                $this->get_encryption_key(),
525
-                STR_PAD_RIGHT
526
-            )
527
-        );
528
-        $string_bits = str_split($text_string);
529
-        foreach ($string_bits as $k => $v) {
530
-            $temp = ord($v) + ord($key_bits[$k]);
531
-            $string_bits[$k] = chr($temp > 255 ? ($temp - 256) : $temp);
532
-        }
533
-        $encrypted_text = implode('', $string_bits);
534
-        $encrypted_text .= EE_Encryption::ACME_ENCRYPTION_FLAG;
535
-        return $this->_use_base64_encode
536
-            ? base64_encode($encrypted_text)
537
-            : $encrypted_text;
538
-    }
539
-
540
-
541
-
542
-    /**
543
-     * decrypts data for acme servers that didn't bother to install PHP mcrypt
544
-     *
545
-     * @see http://stackoverflow.com/questions/800922/how-to-encrypt-string-without-mcrypt-library-in-php
546
-     * @param string $encrypted_text the text to be decrypted
547
-     * @return string
548
-     * @throws RuntimeException
549
-     */
550
-    protected function acme_decrypt($encrypted_text = '')
551
-    {
552
-        // you give me nothing??? GET OUT !
553
-        if (empty($encrypted_text)) {
554
-            return $encrypted_text;
555
-        }
556
-        // decode the data ?
557
-        $encrypted_text = $this->valid_base_64($encrypted_text)
558
-            ? $this->base64_url_decode($encrypted_text)
559
-            : $encrypted_text;
560
-        if (
561
-            $this->_use_mcrypt
562
-            && strpos($encrypted_text, EE_Encryption::ACME_ENCRYPTION_FLAG) === false
563
-        ){
564
-            return $this->m_decrypt($encrypted_text);
565
-        }
566
-        $encrypted_text = substr($encrypted_text, 0, -4);
567
-        $key_bits = str_split(
568
-            str_pad(
569
-                '',
570
-                strlen($encrypted_text),
571
-                $this->get_encryption_key(),
572
-                STR_PAD_RIGHT
573
-            )
574
-        );
575
-        $string_bits = str_split($encrypted_text);
576
-        foreach ($string_bits as $k => $v) {
577
-            $temp = ord($v) - ord($key_bits[$k]);
578
-            $string_bits[$k] = chr($temp < 0 ? ($temp + 256) : $temp);
579
-        }
580
-        return implode('', $string_bits);
581
-    }
582
-
583
-
584
-
585
-    /**
586
-     * @see http://stackoverflow.com/questions/2556345/detect-base64-encoding-in-php#30231906
587
-     * @param $string
588
-     * @return bool
589
-     */
590
-    protected function valid_base_64($string)
591
-    {
592
-        // ensure data is a string
593
-        if (! is_string($string) || ! $this->_use_base64_encode) {
594
-            return false;
595
-        }
596
-        $decoded = base64_decode($string, true);
597
-        // Check if there is no invalid character in string
598
-        if (! preg_match('/^[a-zA-Z0-9\/\r\n+]*={0,2}$/', $string)) {
599
-            return false;
600
-        }
601
-        // Decode the string in strict mode and send the response
602
-        if (! base64_decode($string, true)) {
603
-            return false;
604
-        }
605
-        // Encode and compare it to original one
606
-        return base64_encode($decoded) === $string;
607
-    }
608
-
609
-
610
-
611
-    /**
612
-     * generate random string
613
-     *
614
-     * @see http://stackoverflow.com/questions/637278/what-is-the-best-way-to-generate-a-random-key-within-php
615
-     * @param int $length number of characters for random string
616
-     * @return string
617
-     */
618
-    public function generate_random_string($length = 40)
619
-    {
620
-        $iterations = ceil($length / 40);
621
-        $random_string = '';
622
-        for ($i = 0; $i < $iterations; $i++) {
623
-            $random_string .= sha1(microtime(true) . mt_rand(10000, 90000));
624
-        }
625
-        $random_string = substr($random_string, 0, $length);
626
-        return $random_string;
627
-    }
628
-
629
-
630
-
631
-    /**
632
-     * encrypts data using PHP's mcrypt functions
633
-     *
634
-     * @deprecated 4.9.39
635
-     * @param string $text_string
636
-     * @internal   param $string - the text to be encrypted
637
-     * @return string
638
-     * @throws RuntimeException
639
-     */
640
-    protected function m_encrypt($text_string = '')
641
-    {
642
-        // you give me nothing??? GET OUT !
643
-        if (empty($text_string)) {
644
-            return $text_string;
645
-        }
646
-        // get the initialization vector size
647
-        $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
648
-        // initialization vector
649
-        $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
650
-        if ($iv === false) {
651
-            throw new RuntimeException(
652
-                esc_html__('Failed to generate mcrypt initialization vector.', 'event_espresso')
653
-            );
654
-        }
655
-        // encrypt it
656
-        $encrypted_text = mcrypt_encrypt(
657
-            MCRYPT_RIJNDAEL_256,
658
-            $this->get_encryption_key(),
659
-            $text_string,
660
-            MCRYPT_MODE_ECB,
661
-            $iv
662
-        );
663
-        // trim and maybe encode
664
-        return $this->_use_base64_encode
665
-            ? trim(base64_encode($encrypted_text))
666
-            : trim($encrypted_text);
667
-    }
668
-
669
-
670
-
671
-    /**
672
-     * decrypts data that has been encrypted with PHP's mcrypt functions
673
-     *
674
-     * @deprecated 4.9.39
675
-     * @param string $encrypted_text the text to be decrypted
676
-     * @return string
677
-     * @throws RuntimeException
678
-     */
679
-    protected function m_decrypt($encrypted_text = '')
680
-    {
681
-        // you give me nothing??? GET OUT !
682
-        if (empty($encrypted_text)) {
683
-            return $encrypted_text;
684
-        }
685
-        // decode
686
-        $encrypted_text = $this->valid_base_64($encrypted_text)
687
-            ? $this->base64_url_decode($encrypted_text)
688
-            : $encrypted_text;
689
-        // get the initialization vector size
690
-        $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
691
-        $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
692
-        if ($iv === false) {
693
-            throw new RuntimeException(
694
-                esc_html__('Failed to generate mcrypt initialization vector.', 'event_espresso')
695
-            );
696
-        }
697
-        // decrypt it
698
-        $decrypted_text = mcrypt_decrypt(
699
-            MCRYPT_RIJNDAEL_256,
700
-            $this->get_encryption_key(),
701
-            $encrypted_text,
702
-            MCRYPT_MODE_ECB,
703
-            $iv
704
-        );
705
-        $decrypted_text = trim($decrypted_text);
706
-        return $decrypted_text;
707
-    }
22
+	/**
23
+	 * key used for saving the encryption key to the wp_options table
24
+	 */
25
+	const ENCRYPTION_OPTION_KEY = 'ee_encryption_key';
26
+
27
+	/**
28
+	 * the OPENSSL cipher method used
29
+	 */
30
+	const OPENSSL_CIPHER_METHOD = 'AES-128-CBC';
31
+
32
+	/**
33
+	 * WP "options_name" used to store a verified available cipher method
34
+	 */
35
+	const OPENSSL_CIPHER_METHOD_OPTION_NAME = 'ee_openssl_cipher_method';
36
+
37
+	/**
38
+	 * the OPENSSL digest method used
39
+	 */
40
+	const OPENSSL_DIGEST_METHOD = 'sha512';
41
+
42
+	/**
43
+	 * separates the encrypted text from the initialization vector
44
+	 */
45
+	const OPENSSL_IV_DELIMITER = ':iv:';
46
+
47
+	/**
48
+	 * appended to text encrypted using the acme encryption
49
+	 */
50
+	const ACME_ENCRYPTION_FLAG = '::ae';
51
+
52
+
53
+
54
+	/**
55
+	 * instance of the EE_Encryption object
56
+	 */
57
+	protected static $_instance;
58
+
59
+	/**
60
+	 * @var string $_encryption_key
61
+	 */
62
+	protected $_encryption_key;
63
+
64
+	/**
65
+	 * @var string $cipher_method
66
+	 */
67
+	private $cipher_method = '';
68
+
69
+	/**
70
+	 * @var array $cipher_methods
71
+	 */
72
+	private $cipher_methods = array();
73
+
74
+	/**
75
+	 * @var array $digest_methods
76
+	 */
77
+	private $digest_methods = array();
78
+
79
+	/**
80
+	 * @var boolean $_use_openssl_encrypt
81
+	 */
82
+	protected $_use_openssl_encrypt = false;
83
+
84
+	/**
85
+	 * @var boolean $_use_mcrypt
86
+	 */
87
+	protected $_use_mcrypt = false;
88
+
89
+	/**
90
+	 * @var boolean $_use_base64_encode
91
+	 */
92
+	protected $_use_base64_encode = false;
93
+
94
+
95
+
96
+	/**
97
+	 * protected constructor to prevent direct creation
98
+	 */
99
+	protected function __construct()
100
+	{
101
+		if (! defined('ESPRESSO_ENCRYPT')) {
102
+			define('ESPRESSO_ENCRYPT', true);
103
+		}
104
+		if (extension_loaded('openssl')) {
105
+			$this->_use_openssl_encrypt = true;
106
+		} else if (extension_loaded('mcrypt')) {
107
+			$this->_use_mcrypt = true;
108
+		}
109
+		if (function_exists('base64_encode')) {
110
+			$this->_use_base64_encode = true;
111
+		}
112
+	}
113
+
114
+
115
+
116
+	/**
117
+	 * singleton method used to instantiate class object
118
+	 *
119
+	 * @return EE_Encryption
120
+	 */
121
+	public static function instance()
122
+	{
123
+		// check if class object is instantiated
124
+		if (! EE_Encryption::$_instance instanceof EE_Encryption) {
125
+			EE_Encryption::$_instance = new self();
126
+		}
127
+		return EE_Encryption::$_instance;
128
+	}
129
+
130
+
131
+
132
+	/**
133
+	 * get encryption key
134
+	 *
135
+	 * @return string
136
+	 */
137
+	public function get_encryption_key()
138
+	{
139
+		// if encryption key has not been set
140
+		if (empty($this->_encryption_key)) {
141
+			// retrieve encryption_key from db
142
+			$this->_encryption_key = get_option(EE_Encryption::ENCRYPTION_OPTION_KEY, '');
143
+			// WHAT?? No encryption_key in the db ??
144
+			if ($this->_encryption_key === '') {
145
+				// let's make one. And md5 it to make it just the right size for a key
146
+				$new_key = md5($this->generate_random_string());
147
+				// now save it to the db for later
148
+				add_option(EE_Encryption::ENCRYPTION_OPTION_KEY, $new_key);
149
+				// here's the key - FINALLY !
150
+				$this->_encryption_key = $new_key;
151
+			}
152
+		}
153
+		return $this->_encryption_key;
154
+	}
155
+
156
+
157
+
158
+	/**
159
+	 * encrypts data
160
+	 *
161
+	 * @param string $text_string - the text to be encrypted
162
+	 * @return string
163
+	 * @throws RuntimeException
164
+	 */
165
+	public function encrypt($text_string = '')
166
+	{
167
+		// you give me nothing??? GET OUT !
168
+		if (empty($text_string)) {
169
+			return $text_string;
170
+		}
171
+		if ($this->_use_openssl_encrypt) {
172
+			$encrypted_text = $this->openssl_encrypt($text_string);
173
+		} else {
174
+			$encrypted_text = $this->acme_encrypt($text_string);
175
+		}
176
+		return $encrypted_text;
177
+	}
178
+
179
+
180
+
181
+	/**
182
+	 * decrypts data
183
+	 *
184
+	 * @param string $encrypted_text - the text to be decrypted
185
+	 * @return string
186
+	 * @throws RuntimeException
187
+	 */
188
+	public function decrypt($encrypted_text = '')
189
+	{
190
+		// you give me nothing??? GET OUT !
191
+		if (empty($encrypted_text)) {
192
+			return $encrypted_text;
193
+		}
194
+		// if PHP's mcrypt functions are installed then we'll use them
195
+		if ($this->_use_openssl_encrypt) {
196
+			$decrypted_text = $this->openssl_decrypt($encrypted_text);
197
+		} else {
198
+			$decrypted_text = $this->acme_decrypt($encrypted_text);
199
+		}
200
+		return $decrypted_text;
201
+	}
202
+
203
+
204
+
205
+	/**
206
+	 * encodes string with PHP's base64 encoding
207
+	 *
208
+	 * @see http://php.net/manual/en/function.base64-encode.php
209
+	 * @param string $text_string the text to be encoded
210
+	 * @return string
211
+	 */
212
+	public function base64_string_encode($text_string = '')
213
+	{
214
+		// you give me nothing??? GET OUT !
215
+		if (empty($text_string) || ! $this->_use_base64_encode) {
216
+			return $text_string;
217
+		}
218
+		// encode
219
+		return base64_encode($text_string);
220
+	}
221
+
222
+
223
+	/**
224
+	 * decodes string that has been encoded with PHP's base64 encoding
225
+	 *
226
+	 * @see http://php.net/manual/en/function.base64-encode.php
227
+	 * @param string $encoded_string the text to be decoded
228
+	 * @return string
229
+	 * @throws RuntimeException
230
+	 */
231
+	public function base64_string_decode($encoded_string = '')
232
+	{
233
+		// you give me nothing??? GET OUT !
234
+		if (empty($encoded_string) || ! $this->valid_base_64($encoded_string)) {
235
+			return $encoded_string;
236
+		}
237
+		// decode
238
+		$decoded_string = base64_decode($encoded_string);
239
+		if ($decoded_string === false) {
240
+			throw new RuntimeException(
241
+				esc_html__('Base 64 decoding failed.', 'event_espresso')
242
+			);
243
+		}
244
+		return $decoded_string;
245
+	}
246
+
247
+
248
+
249
+	/**
250
+	 * encodes  url string with PHP's base64 encoding
251
+	 *
252
+	 * @see http://php.net/manual/en/function.base64-encode.php
253
+	 * @param string $text_string the text to be encoded
254
+	 * @return string
255
+	 */
256
+	public function base64_url_encode($text_string = '')
257
+	{
258
+		// you give me nothing??? GET OUT !
259
+		if (empty($text_string) || ! $this->_use_base64_encode) {
260
+			return $text_string;
261
+		}
262
+		// encode
263
+		$encoded_string = base64_encode($text_string);
264
+		// remove chars to make encoding more URL friendly
265
+		return strtr($encoded_string, '+/=', '-_,');
266
+	}
267
+
268
+
269
+	/**
270
+	 * decodes  url string that has been encoded with PHP's base64 encoding
271
+	 *
272
+	 * @see http://php.net/manual/en/function.base64-encode.php
273
+	 * @param string $encoded_string the text to be decoded
274
+	 * @return string
275
+	 * @throws RuntimeException
276
+	 */
277
+	public function base64_url_decode($encoded_string = '')
278
+	{
279
+		// you give me nothing??? GET OUT !
280
+		if (empty($encoded_string) || ! $this->valid_base_64($encoded_string)) {
281
+			return $encoded_string;
282
+		}
283
+		// replace previously removed characters
284
+		$encoded_string = strtr($encoded_string, '-_,', '+/=');
285
+		// decode
286
+		$decoded_string = base64_decode($encoded_string);
287
+		if ($decoded_string === false) {
288
+			throw new RuntimeException(
289
+				esc_html__('Base 64 decoding failed.', 'event_espresso')
290
+			);
291
+		}
292
+		return $decoded_string;
293
+	}
294
+
295
+
296
+	/**
297
+	 * encrypts data using PHP's openssl functions
298
+	 *
299
+	 * @param string $text_string the text to be encrypted
300
+	 * @param string $cipher_method
301
+	 * @param string $encryption_key
302
+	 * @return string
303
+	 * @throws RuntimeException
304
+	 */
305
+	protected function openssl_encrypt(
306
+		$text_string = '',
307
+		$cipher_method = EE_Encryption::OPENSSL_CIPHER_METHOD,
308
+		$encryption_key = ''
309
+	) {
310
+		// you give me nothing??? GET OUT !
311
+		if (empty($text_string)) {
312
+			return $text_string;
313
+		}
314
+		$this->cipher_method = $this->getCipherMethod($cipher_method);
315
+		// get initialization vector size
316
+		$iv_size = openssl_cipher_iv_length($this->cipher_method);
317
+		// generate initialization vector.
318
+		// The second parameter ("crypto_strong") is passed by reference,
319
+		// and is used to determines if the algorithm used was "cryptographically strong"
320
+		// openssl_random_pseudo_bytes() will toggle it to either true or false
321
+		$iv = openssl_random_pseudo_bytes($iv_size, $is_strong);
322
+		if ($iv === false || $is_strong === false) {
323
+			throw new RuntimeException(
324
+				esc_html__('Failed to generate OpenSSL initialization vector.', 'event_espresso')
325
+			);
326
+		}
327
+		// encrypt it
328
+		$encrypted_text = openssl_encrypt(
329
+			$text_string,
330
+			$this->cipher_method,
331
+			$this->getDigestHashValue(EE_Encryption::OPENSSL_DIGEST_METHOD, $encryption_key),
332
+			0,
333
+			$iv
334
+		);
335
+		// append the initialization vector
336
+		$encrypted_text .= EE_Encryption::OPENSSL_IV_DELIMITER . $iv;
337
+		// trim and maybe encode
338
+		return $this->_use_base64_encode
339
+			? trim(base64_encode($encrypted_text))
340
+			: trim($encrypted_text);
341
+	}
342
+
343
+
344
+
345
+	/**
346
+	 * Returns a cipher method that has been verified to work.
347
+	 * First checks if the cached cipher has been set already and if so, returns that.
348
+	 * Then tests the incoming default and returns that if it's good.
349
+	 * If not, then it retrieves the previously tested and saved cipher method.
350
+	 * But if that doesn't exist, then calls getAvailableCipherMethod()
351
+	 * to see what is available on the server, and returns the results.
352
+	 *
353
+	 * @param string $cipher_method
354
+	 * @return string
355
+	 * @throws RuntimeException
356
+	 */
357
+	protected function getCipherMethod($cipher_method = EE_Encryption::OPENSSL_CIPHER_METHOD)
358
+	{
359
+		if($this->cipher_method !== ''){
360
+			return $this->cipher_method;
361
+		}
362
+		// verify that the default cipher method can produce an initialization vector
363
+		if (openssl_cipher_iv_length($cipher_method) === false) {
364
+			// nope? okay let's get what we found in the past to work
365
+			$cipher_method = get_option(EE_Encryption::OPENSSL_CIPHER_METHOD_OPTION_NAME, '');
366
+			// oops... haven't tested available cipher methods yet
367
+			if($cipher_method === '' || openssl_cipher_iv_length($cipher_method) === false) {
368
+				$cipher_method = $this->getAvailableCipherMethod($cipher_method);
369
+			}
370
+		}
371
+		return $cipher_method;
372
+	}
373
+
374
+
375
+
376
+	/**
377
+	 * @param string $cipher_method
378
+	 * @return string
379
+	 * @throws \RuntimeException
380
+	 */
381
+	protected function getAvailableCipherMethod($cipher_method)
382
+	{
383
+		// verify that the incoming cipher method can produce an initialization vector
384
+		if (openssl_cipher_iv_length($cipher_method) === false) {
385
+			// nope? then check the next cipher in the list of available cipher methods
386
+			$cipher_method = next($this->cipher_methods);
387
+			// what? there's no list? then generate that list and cache it,
388
+			if (empty($this->cipher_methods)) {
389
+				$this->cipher_methods = openssl_get_cipher_methods();
390
+				// then grab the first item from the list
391
+				$cipher_method = reset($this->cipher_methods);
392
+			}
393
+			if($cipher_method === false){
394
+				throw new RuntimeException(
395
+					esc_html__(
396
+						'OpenSSL support appears to be enabled on the server, but no cipher methods are available. Please contact the server administrator.',
397
+						'event_espresso'
398
+					)
399
+				);
400
+			}
401
+			// verify that the next cipher method works
402
+			return $this->getAvailableCipherMethod($cipher_method);
403
+		}
404
+		// if we've gotten this far, then we found an available cipher method that works
405
+		// so save that for next time
406
+		update_option(
407
+			EE_Encryption::OPENSSL_CIPHER_METHOD_OPTION_NAME,
408
+			$cipher_method
409
+		);
410
+		return $cipher_method;
411
+	}
412
+
413
+
414
+	/**
415
+	 * decrypts data that has been encrypted with PHP's openssl functions
416
+	 *
417
+	 * @param string $encrypted_text the text to be decrypted
418
+	 * @param string $cipher_method
419
+	 * @param string $encryption_key
420
+	 * @return string
421
+	 * @throws RuntimeException
422
+	 */
423
+	protected function openssl_decrypt(
424
+		$encrypted_text = '',
425
+		$cipher_method = EE_Encryption::OPENSSL_CIPHER_METHOD,
426
+		$encryption_key = ''
427
+	) {
428
+		// you give me nothing??? GET OUT !
429
+		if (empty($encrypted_text)) {
430
+			return $encrypted_text;
431
+		}
432
+		// decode
433
+		$encrypted_text = $this->valid_base_64($encrypted_text)
434
+			? $this->base64_url_decode($encrypted_text)
435
+			: $encrypted_text;
436
+		$encrypted_components = explode(
437
+			EE_Encryption::OPENSSL_IV_DELIMITER,
438
+			$encrypted_text,
439
+			2
440
+		);
441
+		// check that iv exists, and if not, maybe text was encoded using mcrypt?
442
+		if ($this->_use_mcrypt && ! isset($encrypted_components[1])) {
443
+			return $this->m_decrypt($encrypted_text);
444
+		}
445
+		// decrypt it
446
+		$decrypted_text = openssl_decrypt(
447
+			$encrypted_components[0],
448
+			$this->getCipherMethod($cipher_method),
449
+			$this->getDigestHashValue(EE_Encryption::OPENSSL_DIGEST_METHOD,$encryption_key),
450
+			0,
451
+			$encrypted_components[1]
452
+		);
453
+		$decrypted_text = trim($decrypted_text);
454
+		return $decrypted_text;
455
+	}
456
+
457
+
458
+	/**
459
+	 * Computes the digest hash value using the specified digest method.
460
+	 * If that digest method fails to produce a valid hash value,
461
+	 * then we'll grab the next digest method and recursively try again until something works.
462
+	 *
463
+	 * @param string $digest_method
464
+	 * @param string $encryption_key
465
+	 * @return string
466
+	 * @throws RuntimeException
467
+	 */
468
+	protected function getDigestHashValue($digest_method = EE_Encryption::OPENSSL_DIGEST_METHOD, $encryption_key = ''){
469
+		$encryption_key = $encryption_key !== ''
470
+			? $encryption_key
471
+			: $this->get_encryption_key();
472
+		$digest_hash_value = openssl_digest($encryption_key, $digest_method);
473
+		if ($digest_hash_value === false) {
474
+			return $this->getDigestHashValue($this->getDigestMethod());
475
+		}
476
+		return $digest_hash_value;
477
+	}
478
+
479
+
480
+
481
+	/**
482
+	 * Returns the NEXT element in the $digest_methods array.
483
+	 * If the $digest_methods array is empty, then we populate it
484
+	 * with the available values returned from openssl_get_md_methods().
485
+	 *
486
+	 * @return string
487
+	 * @throws \RuntimeException
488
+	 */
489
+	protected function getDigestMethod(){
490
+		$digest_method = prev($this->digest_methods);
491
+		if (empty($this->digest_methods)) {
492
+			$this->digest_methods = openssl_get_md_methods();
493
+			$digest_method = end($this->digest_methods);
494
+		}
495
+		if ($digest_method === false) {
496
+			throw new RuntimeException(
497
+				esc_html__(
498
+					'OpenSSL support appears to be enabled on the server, but no digest methods are available. Please contact the server administrator.',
499
+					'event_espresso'
500
+				)
501
+			);
502
+		}
503
+		return $digest_method;
504
+	}
505
+
506
+
507
+	/**
508
+	 * encrypts data for acme servers that didn't bother to install PHP mcrypt
509
+	 *
510
+	 * @see http://stackoverflow.com/questions/800922/how-to-encrypt-string-without-mcrypt-library-in-php
511
+	 * @param string $text_string the text to be decrypted
512
+	 * @return string
513
+	 */
514
+	protected function acme_encrypt($text_string = '')
515
+	{
516
+		// you give me nothing??? GET OUT !
517
+		if (empty($text_string)) {
518
+			return $text_string;
519
+		}
520
+		$key_bits = str_split(
521
+			str_pad(
522
+				'',
523
+				strlen($text_string),
524
+				$this->get_encryption_key(),
525
+				STR_PAD_RIGHT
526
+			)
527
+		);
528
+		$string_bits = str_split($text_string);
529
+		foreach ($string_bits as $k => $v) {
530
+			$temp = ord($v) + ord($key_bits[$k]);
531
+			$string_bits[$k] = chr($temp > 255 ? ($temp - 256) : $temp);
532
+		}
533
+		$encrypted_text = implode('', $string_bits);
534
+		$encrypted_text .= EE_Encryption::ACME_ENCRYPTION_FLAG;
535
+		return $this->_use_base64_encode
536
+			? base64_encode($encrypted_text)
537
+			: $encrypted_text;
538
+	}
539
+
540
+
541
+
542
+	/**
543
+	 * decrypts data for acme servers that didn't bother to install PHP mcrypt
544
+	 *
545
+	 * @see http://stackoverflow.com/questions/800922/how-to-encrypt-string-without-mcrypt-library-in-php
546
+	 * @param string $encrypted_text the text to be decrypted
547
+	 * @return string
548
+	 * @throws RuntimeException
549
+	 */
550
+	protected function acme_decrypt($encrypted_text = '')
551
+	{
552
+		// you give me nothing??? GET OUT !
553
+		if (empty($encrypted_text)) {
554
+			return $encrypted_text;
555
+		}
556
+		// decode the data ?
557
+		$encrypted_text = $this->valid_base_64($encrypted_text)
558
+			? $this->base64_url_decode($encrypted_text)
559
+			: $encrypted_text;
560
+		if (
561
+			$this->_use_mcrypt
562
+			&& strpos($encrypted_text, EE_Encryption::ACME_ENCRYPTION_FLAG) === false
563
+		){
564
+			return $this->m_decrypt($encrypted_text);
565
+		}
566
+		$encrypted_text = substr($encrypted_text, 0, -4);
567
+		$key_bits = str_split(
568
+			str_pad(
569
+				'',
570
+				strlen($encrypted_text),
571
+				$this->get_encryption_key(),
572
+				STR_PAD_RIGHT
573
+			)
574
+		);
575
+		$string_bits = str_split($encrypted_text);
576
+		foreach ($string_bits as $k => $v) {
577
+			$temp = ord($v) - ord($key_bits[$k]);
578
+			$string_bits[$k] = chr($temp < 0 ? ($temp + 256) : $temp);
579
+		}
580
+		return implode('', $string_bits);
581
+	}
582
+
583
+
584
+
585
+	/**
586
+	 * @see http://stackoverflow.com/questions/2556345/detect-base64-encoding-in-php#30231906
587
+	 * @param $string
588
+	 * @return bool
589
+	 */
590
+	protected function valid_base_64($string)
591
+	{
592
+		// ensure data is a string
593
+		if (! is_string($string) || ! $this->_use_base64_encode) {
594
+			return false;
595
+		}
596
+		$decoded = base64_decode($string, true);
597
+		// Check if there is no invalid character in string
598
+		if (! preg_match('/^[a-zA-Z0-9\/\r\n+]*={0,2}$/', $string)) {
599
+			return false;
600
+		}
601
+		// Decode the string in strict mode and send the response
602
+		if (! base64_decode($string, true)) {
603
+			return false;
604
+		}
605
+		// Encode and compare it to original one
606
+		return base64_encode($decoded) === $string;
607
+	}
608
+
609
+
610
+
611
+	/**
612
+	 * generate random string
613
+	 *
614
+	 * @see http://stackoverflow.com/questions/637278/what-is-the-best-way-to-generate-a-random-key-within-php
615
+	 * @param int $length number of characters for random string
616
+	 * @return string
617
+	 */
618
+	public function generate_random_string($length = 40)
619
+	{
620
+		$iterations = ceil($length / 40);
621
+		$random_string = '';
622
+		for ($i = 0; $i < $iterations; $i++) {
623
+			$random_string .= sha1(microtime(true) . mt_rand(10000, 90000));
624
+		}
625
+		$random_string = substr($random_string, 0, $length);
626
+		return $random_string;
627
+	}
628
+
629
+
630
+
631
+	/**
632
+	 * encrypts data using PHP's mcrypt functions
633
+	 *
634
+	 * @deprecated 4.9.39
635
+	 * @param string $text_string
636
+	 * @internal   param $string - the text to be encrypted
637
+	 * @return string
638
+	 * @throws RuntimeException
639
+	 */
640
+	protected function m_encrypt($text_string = '')
641
+	{
642
+		// you give me nothing??? GET OUT !
643
+		if (empty($text_string)) {
644
+			return $text_string;
645
+		}
646
+		// get the initialization vector size
647
+		$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
648
+		// initialization vector
649
+		$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
650
+		if ($iv === false) {
651
+			throw new RuntimeException(
652
+				esc_html__('Failed to generate mcrypt initialization vector.', 'event_espresso')
653
+			);
654
+		}
655
+		// encrypt it
656
+		$encrypted_text = mcrypt_encrypt(
657
+			MCRYPT_RIJNDAEL_256,
658
+			$this->get_encryption_key(),
659
+			$text_string,
660
+			MCRYPT_MODE_ECB,
661
+			$iv
662
+		);
663
+		// trim and maybe encode
664
+		return $this->_use_base64_encode
665
+			? trim(base64_encode($encrypted_text))
666
+			: trim($encrypted_text);
667
+	}
668
+
669
+
670
+
671
+	/**
672
+	 * decrypts data that has been encrypted with PHP's mcrypt functions
673
+	 *
674
+	 * @deprecated 4.9.39
675
+	 * @param string $encrypted_text the text to be decrypted
676
+	 * @return string
677
+	 * @throws RuntimeException
678
+	 */
679
+	protected function m_decrypt($encrypted_text = '')
680
+	{
681
+		// you give me nothing??? GET OUT !
682
+		if (empty($encrypted_text)) {
683
+			return $encrypted_text;
684
+		}
685
+		// decode
686
+		$encrypted_text = $this->valid_base_64($encrypted_text)
687
+			? $this->base64_url_decode($encrypted_text)
688
+			: $encrypted_text;
689
+		// get the initialization vector size
690
+		$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB);
691
+		$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
692
+		if ($iv === false) {
693
+			throw new RuntimeException(
694
+				esc_html__('Failed to generate mcrypt initialization vector.', 'event_espresso')
695
+			);
696
+		}
697
+		// decrypt it
698
+		$decrypted_text = mcrypt_decrypt(
699
+			MCRYPT_RIJNDAEL_256,
700
+			$this->get_encryption_key(),
701
+			$encrypted_text,
702
+			MCRYPT_MODE_ECB,
703
+			$iv
704
+		);
705
+		$decrypted_text = trim($decrypted_text);
706
+		return $decrypted_text;
707
+	}
708 708
 
709 709
 }
710 710
 /* End of file EE_Encryption.class.php */
Please login to merge, or discard this patch.
Spacing   +14 added lines, -14 removed lines patch added patch discarded remove patch
@@ -98,7 +98,7 @@  discard block
 block discarded – undo
98 98
      */
99 99
     protected function __construct()
100 100
     {
101
-        if (! defined('ESPRESSO_ENCRYPT')) {
101
+        if ( ! defined('ESPRESSO_ENCRYPT')) {
102 102
             define('ESPRESSO_ENCRYPT', true);
103 103
         }
104 104
         if (extension_loaded('openssl')) {
@@ -121,7 +121,7 @@  discard block
 block discarded – undo
121 121
     public static function instance()
122 122
     {
123 123
         // check if class object is instantiated
124
-        if (! EE_Encryption::$_instance instanceof EE_Encryption) {
124
+        if ( ! EE_Encryption::$_instance instanceof EE_Encryption) {
125 125
             EE_Encryption::$_instance = new self();
126 126
         }
127 127
         return EE_Encryption::$_instance;
@@ -333,7 +333,7 @@  discard block
 block discarded – undo
333 333
             $iv
334 334
         );
335 335
         // append the initialization vector
336
-        $encrypted_text .= EE_Encryption::OPENSSL_IV_DELIMITER . $iv;
336
+        $encrypted_text .= EE_Encryption::OPENSSL_IV_DELIMITER.$iv;
337 337
         // trim and maybe encode
338 338
         return $this->_use_base64_encode
339 339
             ? trim(base64_encode($encrypted_text))
@@ -356,7 +356,7 @@  discard block
 block discarded – undo
356 356
      */
357 357
     protected function getCipherMethod($cipher_method = EE_Encryption::OPENSSL_CIPHER_METHOD)
358 358
     {
359
-        if($this->cipher_method !== ''){
359
+        if ($this->cipher_method !== '') {
360 360
             return $this->cipher_method;
361 361
         }
362 362
         // verify that the default cipher method can produce an initialization vector
@@ -364,7 +364,7 @@  discard block
 block discarded – undo
364 364
             // nope? okay let's get what we found in the past to work
365 365
             $cipher_method = get_option(EE_Encryption::OPENSSL_CIPHER_METHOD_OPTION_NAME, '');
366 366
             // oops... haven't tested available cipher methods yet
367
-            if($cipher_method === '' || openssl_cipher_iv_length($cipher_method) === false) {
367
+            if ($cipher_method === '' || openssl_cipher_iv_length($cipher_method) === false) {
368 368
                 $cipher_method = $this->getAvailableCipherMethod($cipher_method);
369 369
             }
370 370
         }
@@ -390,7 +390,7 @@  discard block
 block discarded – undo
390 390
                 // then grab the first item from the list
391 391
                 $cipher_method = reset($this->cipher_methods);
392 392
             }
393
-            if($cipher_method === false){
393
+            if ($cipher_method === false) {
394 394
                 throw new RuntimeException(
395 395
                     esc_html__(
396 396
                         'OpenSSL support appears to be enabled on the server, but no cipher methods are available. Please contact the server administrator.',
@@ -446,7 +446,7 @@  discard block
 block discarded – undo
446 446
         $decrypted_text = openssl_decrypt(
447 447
             $encrypted_components[0],
448 448
             $this->getCipherMethod($cipher_method),
449
-            $this->getDigestHashValue(EE_Encryption::OPENSSL_DIGEST_METHOD,$encryption_key),
449
+            $this->getDigestHashValue(EE_Encryption::OPENSSL_DIGEST_METHOD, $encryption_key),
450 450
             0,
451 451
             $encrypted_components[1]
452 452
         );
@@ -465,7 +465,7 @@  discard block
 block discarded – undo
465 465
      * @return string
466 466
      * @throws RuntimeException
467 467
      */
468
-    protected function getDigestHashValue($digest_method = EE_Encryption::OPENSSL_DIGEST_METHOD, $encryption_key = ''){
468
+    protected function getDigestHashValue($digest_method = EE_Encryption::OPENSSL_DIGEST_METHOD, $encryption_key = '') {
469 469
         $encryption_key = $encryption_key !== ''
470 470
             ? $encryption_key
471 471
             : $this->get_encryption_key();
@@ -486,7 +486,7 @@  discard block
 block discarded – undo
486 486
      * @return string
487 487
      * @throws \RuntimeException
488 488
      */
489
-    protected function getDigestMethod(){
489
+    protected function getDigestMethod() {
490 490
         $digest_method = prev($this->digest_methods);
491 491
         if (empty($this->digest_methods)) {
492 492
             $this->digest_methods = openssl_get_md_methods();
@@ -560,7 +560,7 @@  discard block
 block discarded – undo
560 560
         if (
561 561
             $this->_use_mcrypt
562 562
             && strpos($encrypted_text, EE_Encryption::ACME_ENCRYPTION_FLAG) === false
563
-        ){
563
+        ) {
564 564
             return $this->m_decrypt($encrypted_text);
565 565
         }
566 566
         $encrypted_text = substr($encrypted_text, 0, -4);
@@ -590,16 +590,16 @@  discard block
 block discarded – undo
590 590
     protected function valid_base_64($string)
591 591
     {
592 592
         // ensure data is a string
593
-        if (! is_string($string) || ! $this->_use_base64_encode) {
593
+        if ( ! is_string($string) || ! $this->_use_base64_encode) {
594 594
             return false;
595 595
         }
596 596
         $decoded = base64_decode($string, true);
597 597
         // Check if there is no invalid character in string
598
-        if (! preg_match('/^[a-zA-Z0-9\/\r\n+]*={0,2}$/', $string)) {
598
+        if ( ! preg_match('/^[a-zA-Z0-9\/\r\n+]*={0,2}$/', $string)) {
599 599
             return false;
600 600
         }
601 601
         // Decode the string in strict mode and send the response
602
-        if (! base64_decode($string, true)) {
602
+        if ( ! base64_decode($string, true)) {
603 603
             return false;
604 604
         }
605 605
         // Encode and compare it to original one
@@ -620,7 +620,7 @@  discard block
 block discarded – undo
620 620
         $iterations = ceil($length / 40);
621 621
         $random_string = '';
622 622
         for ($i = 0; $i < $iterations; $i++) {
623
-            $random_string .= sha1(microtime(true) . mt_rand(10000, 90000));
623
+            $random_string .= sha1(microtime(true).mt_rand(10000, 90000));
624 624
         }
625 625
         $random_string = substr($random_string, 0, $length);
626 626
         return $random_string;
Please login to merge, or discard this patch.
modules/ticket_sales_monitor/EED_Ticket_Sales_Monitor.module.php 2 patches
Indentation   +1066 added lines, -1066 removed lines patch added patch discarded remove patch
@@ -24,1073 +24,1073 @@
 block discarded – undo
24 24
 class EED_Ticket_Sales_Monitor extends EED_Module
25 25
 {
26 26
 
27
-    const debug = false;    //	true false
28
-
29
-    private static $nl = '';
30
-
31
-    /**
32
-     * an array of raw ticket data from EED_Ticket_Selector
33
-     *
34
-     * @var array $ticket_selections
35
-     */
36
-    protected $ticket_selections = array();
37
-
38
-    /**
39
-     * the raw ticket data from EED_Ticket_Selector is organized in rows
40
-     * according to how they are displayed in the actual Ticket_Selector
41
-     * this tracks the current row being processed
42
-     *
43
-     * @var int $current_row
44
-     */
45
-    protected $current_row = 0;
46
-
47
-    /**
48
-     * an array for tracking names of tickets that have sold out
49
-     *
50
-     * @var array $sold_out_tickets
51
-     */
52
-    protected $sold_out_tickets = array();
53
-
54
-    /**
55
-     * an array for tracking names of tickets that have had their quantities reduced
56
-     *
57
-     * @var array $decremented_tickets
58
-     */
59
-    protected $decremented_tickets = array();
60
-
61
-
62
-
63
-    /**
64
-     * set_hooks - for hooking into EE Core, other modules, etc
65
-     *
66
-     * @return    void
67
-     */
68
-    public static function set_hooks()
69
-    {
70
-        self::$nl = defined('EE_TESTS_DIR')? "\n" : '<br />';
71
-        // release tickets for expired carts
72
-        add_action(
73
-            'EED_Ticket_Selector__process_ticket_selections__before',
74
-            array('EED_Ticket_Sales_Monitor', 'release_tickets_for_expired_carts'),
75
-            1
76
-        );
77
-        // check ticket reserves AFTER MER does it's check (hence priority 20)
78
-        add_filter(
79
-            'FHEE__EE_Ticket_Selector___add_ticket_to_cart__ticket_qty',
80
-            array('EED_Ticket_Sales_Monitor', 'validate_ticket_sale'),
81
-            20,
82
-            3
83
-        );
84
-        // add notices for sold out tickets
85
-        add_action(
86
-            'AHEE__EE_Ticket_Selector__process_ticket_selections__after_tickets_added_to_cart',
87
-            array('EED_Ticket_Sales_Monitor', 'post_notices'),
88
-            10
89
-        );
90
-        // handle ticket quantities adjusted in cart
91
-        //add_action(
92
-        //	'FHEE__EED_Multi_Event_Registration__adjust_line_item_quantity__line_item_quantity_updated',
93
-        //	array( 'EED_Ticket_Sales_Monitor', 'ticket_quantity_updated' ),
94
-        //	10, 2
95
-        //);
96
-        // handle tickets deleted from cart
97
-        add_action(
98
-            'FHEE__EED_Multi_Event_Registration__delete_ticket__ticket_removed_from_cart',
99
-            array('EED_Ticket_Sales_Monitor', 'ticket_removed_from_cart'),
100
-            10,
101
-            2
102
-        );
103
-        // handle emptied carts
104
-        add_action(
105
-            'AHEE__EE_Session__reset_cart__before_reset',
106
-            array('EED_Ticket_Sales_Monitor', 'session_cart_reset'),
107
-            10,
108
-            1
109
-        );
110
-        add_action(
111
-            'AHEE__EED_Multi_Event_Registration__empty_event_cart__before_delete_cart',
112
-            array('EED_Ticket_Sales_Monitor', 'session_cart_reset'),
113
-            10,
114
-            1
115
-        );
116
-        // handle cancelled registrations
117
-        add_action(
118
-            'AHEE__EE_Session__reset_checkout__before_reset',
119
-            array('EED_Ticket_Sales_Monitor', 'session_checkout_reset'),
120
-            10,
121
-            1
122
-        );
123
-        // cron tasks
124
-        add_action(
125
-            'AHEE__EE_Cron_Tasks__process_expired_transactions__abandoned_transaction',
126
-            array('EED_Ticket_Sales_Monitor', 'process_abandoned_transactions'),
127
-            10,
128
-            1
129
-        );
130
-        add_action(
131
-            'AHEE__EE_Cron_Tasks__process_expired_transactions__incomplete_transaction',
132
-            array('EED_Ticket_Sales_Monitor', 'process_abandoned_transactions'),
133
-            10,
134
-            1
135
-        );
136
-        add_action(
137
-            'AHEE__EE_Cron_Tasks__process_expired_transactions__failed_transaction',
138
-            array('EED_Ticket_Sales_Monitor', 'process_failed_transactions'),
139
-            10,
140
-            1
141
-        );
142
-    }
143
-
144
-
145
-
146
-    /**
147
-     * set_hooks_admin - for hooking into EE Admin Core, other modules, etc
148
-     *
149
-     * @return void
150
-     */
151
-    public static function set_hooks_admin()
152
-    {
153
-        EED_Ticket_Sales_Monitor::set_hooks();
154
-    }
155
-
156
-
157
-
158
-    /**
159
-     * @return EED_Ticket_Sales_Monitor|EED_Module
160
-     */
161
-    public static function instance()
162
-    {
163
-        return parent::get_instance(__CLASS__);
164
-    }
165
-
166
-
167
-
168
-    /**
169
-     * @param WP_Query $WP_Query
170
-     * @return    void
171
-     */
172
-    public function run($WP_Query)
173
-    {
174
-    }
175
-
176
-
177
-
178
-    /********************************** PRE_TICKET_SALES  **********************************/
179
-
180
-
181
-
182
-    /**
183
-     * Retrieves grand totals from the line items that have no TXN ID
184
-     * and timestamps less than the current time minus the session lifespan.
185
-     * These are carts that have been abandoned before the "registrant" even attempted to checkout.
186
-     * We're going to release the tickets for these line items before attempting to add more to the cart.
187
-     *
188
-     * @return void
189
-     * @throws DomainException
190
-     * @throws EE_Error
191
-     * @throws InvalidArgumentException
192
-     * @throws InvalidDataTypeException
193
-     * @throws InvalidInterfaceException
194
-     * @throws UnexpectedEntityException
195
-     */
196
-    public static function release_tickets_for_expired_carts()
197
-    {
198
-        if (self::debug) {
199
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '()';
200
-        }
201
-        do_action('AHEE__EED_Ticket_Sales_Monitor__release_tickets_for_expired_carts__begin');
202
-        $expired_ticket_IDs = array();
203
-        /** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */
204
-        $session_lifespan = LoaderFactory::getLoader()->getShared(
205
-            'EventEspresso\core\domain\values\session\SessionLifespan'
206
-        );
207
-        $timestamp = $session_lifespan->expiration();
208
-        $expired_ticket_line_items = EEM_Line_Item::instance()->getTicketLineItemsForExpiredCarts($timestamp);
209
-        if (self::debug) {
210
-            echo self::$nl . ' . time(): ' . time();
211
-            echo self::$nl . ' . time() as date: ' . date('Y-m-d H:i a');
212
-            echo self::$nl . ' . session expiration: ' . $session_lifespan->expiration();
213
-            echo self::$nl . ' . session expiration as date: ' . date('Y-m-d H:i a', $session_lifespan->expiration());
214
-            echo self::$nl . ' . timestamp: ' . $timestamp;
215
-            echo self::$nl . ' . $expired_ticket_line_items: ' . count($expired_ticket_line_items);
216
-        }
217
-        if (! empty($expired_ticket_line_items)) {
218
-            foreach ($expired_ticket_line_items as $expired_ticket_line_item) {
219
-                if (! $expired_ticket_line_item instanceof EE_Line_Item) {
220
-                    continue;
221
-                }
222
-                $expired_ticket_IDs[ $expired_ticket_line_item->OBJ_ID() ] = $expired_ticket_line_item->OBJ_ID();
223
-                if (self::debug) {
224
-                    echo self::$nl . ' . $expired_ticket_line_item->OBJ_ID(): ' . $expired_ticket_line_item->OBJ_ID();
225
-                    echo self::$nl . ' . $expired_ticket_line_item->timestamp(): ' . date('Y-m-d h:i a',
226
-                            $expired_ticket_line_item->timestamp(true));
227
-                }
228
-            }
229
-            if (! empty($expired_ticket_IDs)) {
230
-                EED_Ticket_Sales_Monitor::release_reservations_for_tickets(
231
-                    \EEM_Ticket::instance()->get_tickets_with_IDs($expired_ticket_IDs),
232
-                    array(),
233
-                    __FUNCTION__
234
-                );
235
-                // now  let's get rid of expired line items so that they can't interfere with tracking
236
-                EED_Ticket_Sales_Monitor::clear_expired_line_items_with_no_transaction($timestamp);
237
-            }
238
-        }
239
-        do_action(
240
-            'AHEE__EED_Ticket_Sales_Monitor__release_tickets_for_expired_carts__end',
241
-            $expired_ticket_IDs,
242
-            $expired_ticket_line_items
243
-        );
244
-    }
245
-
246
-
247
-
248
-    /********************************** VALIDATE_TICKET_SALE  **********************************/
249
-
250
-
251
-
252
-    /**
253
-     * callback for 'FHEE__EED_Ticket_Selector__process_ticket_selections__valid_post_data'
254
-     *
255
-     * @param int       $qty
256
-     * @param EE_Ticket $ticket
257
-     * @return bool
258
-     * @throws UnexpectedEntityException
259
-     * @throws EE_Error
260
-     */
261
-    public static function validate_ticket_sale($qty = 1, EE_Ticket $ticket)
262
-    {
263
-        $qty = absint($qty);
264
-        if ($qty > 0) {
265
-            $qty = EED_Ticket_Sales_Monitor::instance()->_validate_ticket_sale($ticket, $qty);
266
-        }
267
-        if (self::debug) {
268
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '()';
269
-            echo self::$nl . self::$nl . '<b> RETURNED QTY: ' . $qty . '</b>';
270
-        }
271
-        return $qty;
272
-    }
273
-
274
-
275
-
276
-    /**
277
-     * checks whether an individual ticket is available for purchase based on datetime, and ticket details
278
-     *
279
-     * @param   EE_Ticket $ticket
280
-     * @param int         $qty
281
-     * @return int
282
-     * @throws UnexpectedEntityException
283
-     * @throws EE_Error
284
-     */
285
-    protected function _validate_ticket_sale(EE_Ticket $ticket, $qty = 1)
286
-    {
287
-        if (self::debug) {
288
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
289
-        }
290
-        if (! $ticket instanceof EE_Ticket) {
291
-            return 0;
292
-        }
293
-        if (self::debug) {
294
-            echo self::$nl . '<b> . ticket->ID: ' . $ticket->ID() . '</b>';
295
-            echo self::$nl . ' . original ticket->reserved: ' . $ticket->reserved();
296
-        }
297
-        $ticket->refresh_from_db();
298
-        // first let's determine the ticket availability based on sales
299
-        $available = $ticket->qty('saleable');
300
-        if (self::debug) {
301
-            echo self::$nl . ' . . . ticket->qty: ' . $ticket->qty();
302
-            echo self::$nl . ' . . . ticket->sold: ' . $ticket->sold();
303
-            echo self::$nl . ' . . . ticket->reserved: ' . $ticket->reserved();
304
-            echo self::$nl . ' . . . ticket->qty(saleable): ' . $ticket->qty('saleable');
305
-            echo self::$nl . ' . . . available: ' . $available;
306
-        }
307
-        if ($available < 1) {
308
-            $this->_ticket_sold_out($ticket);
309
-            return 0;
310
-        }
311
-        if (self::debug) {
312
-            echo self::$nl . ' . . . qty: ' . $qty;
313
-        }
314
-        if ($available < $qty) {
315
-            $qty = $available;
316
-            if (self::debug) {
317
-                echo self::$nl . ' . . . QTY ADJUSTED: ' . $qty;
318
-            }
319
-            $this->_ticket_quantity_decremented($ticket);
320
-        }
321
-        $this->_reserve_ticket($ticket, $qty);
322
-        return $qty;
323
-    }
324
-
325
-
326
-
327
-    /**
328
-     * increments ticket reserved based on quantity passed
329
-     *
330
-     * @param    EE_Ticket $ticket
331
-     * @param int          $quantity
332
-     * @return bool
333
-     * @throws EE_Error
334
-     */
335
-    protected function _reserve_ticket(EE_Ticket $ticket, $quantity = 1)
336
-    {
337
-        if (self::debug) {
338
-            echo self::$nl . self::$nl . ' . . . INCREASE RESERVED: ' . $quantity;
339
-        }
340
-        $ticket->increase_reserved($quantity, 'TicketSalesMonitor:'. __LINE__);
341
-        return $ticket->save();
342
-    }
343
-
344
-
345
-
346
-    /**
347
-     * @param  EE_Ticket $ticket
348
-     * @param  int       $quantity
349
-     * @return bool
350
-     * @throws EE_Error
351
-     */
352
-    protected function _release_reserved_ticket(EE_Ticket $ticket, $quantity = 1)
353
-    {
354
-        if (self::debug) {
355
-            echo self::$nl . ' . . . ticket->ID: ' . $ticket->ID();
356
-            echo self::$nl . ' . . . ticket->reserved: ' . $ticket->reserved();
357
-        }
358
-        $ticket->decrease_reserved($quantity, true, 'TicketSalesMonitor:'. __LINE__);
359
-        if (self::debug) {
360
-            echo self::$nl . ' . . . ticket->reserved: ' . $ticket->reserved();
361
-        }
362
-        return $ticket->save() ? 1 : 0;
363
-    }
364
-
365
-
366
-
367
-    /**
368
-     * removes quantities within the ticket selector based on zero ticket availability
369
-     *
370
-     * @param    EE_Ticket $ticket
371
-     * @return    void
372
-     * @throws UnexpectedEntityException
373
-     * @throws EE_Error
374
-     */
375
-    protected function _ticket_sold_out(EE_Ticket $ticket)
376
-    {
377
-        if (self::debug) {
378
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
379
-            echo self::$nl . ' . . ticket->name: ' . $this->_get_ticket_and_event_name($ticket);
380
-        }
381
-        $this->sold_out_tickets[] = $this->_get_ticket_and_event_name($ticket);
382
-    }
383
-
384
-
385
-
386
-    /**
387
-     * adjusts quantities within the ticket selector based on decreased ticket availability
388
-     *
389
-     * @param    EE_Ticket $ticket
390
-     * @return void
391
-     * @throws UnexpectedEntityException
392
-     * @throws EE_Error
393
-     */
394
-    protected function _ticket_quantity_decremented(EE_Ticket $ticket)
395
-    {
396
-        if (self::debug) {
397
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
398
-            echo self::$nl . ' . . ticket->name: ' . $this->_get_ticket_and_event_name($ticket);
399
-        }
400
-        $this->decremented_tickets[] = $this->_get_ticket_and_event_name($ticket);
401
-    }
402
-
403
-
404
-
405
-    /**
406
-     * builds string out of ticket and event name
407
-     *
408
-     * @param    EE_Ticket $ticket
409
-     * @return string
410
-     * @throws UnexpectedEntityException
411
-     * @throws EE_Error
412
-     */
413
-    protected function _get_ticket_and_event_name(EE_Ticket $ticket)
414
-    {
415
-        $event = $ticket->get_related_event();
416
-        if ($event instanceof EE_Event) {
417
-            $ticket_name = sprintf(
418
-                _x('%1$s for %2$s', 'ticket name for event name', 'event_espresso'),
419
-                $ticket->name(),
420
-                $event->name()
421
-            );
422
-        } else {
423
-            $ticket_name = $ticket->name();
424
-        }
425
-        return $ticket_name;
426
-    }
427
-
428
-
429
-
430
-    /********************************** EVENT CART  **********************************/
431
-
432
-
433
-
434
-    /**
435
-     * releases or reserves ticket(s) based on quantity passed
436
-     *
437
-     * @param  EE_Line_Item $line_item
438
-     * @param  int          $quantity
439
-     * @return void
440
-     * @throws EE_Error
441
-     * @throws InvalidArgumentException
442
-     * @throws InvalidDataTypeException
443
-     * @throws InvalidInterfaceException
444
-     */
445
-    public static function ticket_quantity_updated(EE_Line_Item $line_item, $quantity = 1)
446
-    {
447
-        $ticket = EEM_Ticket::instance()->get_one_by_ID(absint($line_item->OBJ_ID()));
448
-        if ($ticket instanceof EE_Ticket) {
449
-            $ticket->add_extra_meta(
450
-                EE_Ticket::META_KEY_TICKET_RESERVATIONS,
451
-                __LINE__ . ') ' . __METHOD__ . '()'
452
-            );
453
-            if ($quantity > 0) {
454
-                EED_Ticket_Sales_Monitor::instance()->_reserve_ticket($ticket, $quantity);
455
-            } else {
456
-                EED_Ticket_Sales_Monitor::instance()->_release_reserved_ticket($ticket, $quantity);
457
-            }
458
-        }
459
-    }
460
-
461
-
462
-
463
-    /**
464
-     * releases reserved ticket(s) based on quantity passed
465
-     *
466
-     * @param  EE_Ticket $ticket
467
-     * @param  int       $quantity
468
-     * @return void
469
-     * @throws EE_Error
470
-     */
471
-    public static function ticket_removed_from_cart(EE_Ticket $ticket, $quantity = 1)
472
-    {
473
-        $ticket->add_extra_meta(
474
-            EE_Ticket::META_KEY_TICKET_RESERVATIONS,
475
-            __LINE__ . ') ' . __METHOD__ . '()'
476
-        );
477
-        EED_Ticket_Sales_Monitor::instance()->_release_reserved_ticket($ticket, $quantity);
478
-    }
479
-
480
-
481
-
482
-    /********************************** POST_NOTICES  **********************************/
483
-
484
-
485
-
486
-    /**
487
-     * @return void
488
-     * @throws EE_Error
489
-     * @throws InvalidArgumentException
490
-     * @throws ReflectionException
491
-     * @throws InvalidDataTypeException
492
-     * @throws InvalidInterfaceException
493
-     */
494
-    public static function post_notices()
495
-    {
496
-        EED_Ticket_Sales_Monitor::instance()->_post_notices();
497
-    }
498
-
499
-
500
-
501
-    /**
502
-     * @return void
503
-     * @throws EE_Error
504
-     * @throws InvalidArgumentException
505
-     * @throws ReflectionException
506
-     * @throws InvalidDataTypeException
507
-     * @throws InvalidInterfaceException
508
-     */
509
-    protected function _post_notices()
510
-    {
511
-        if (self::debug) {
512
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
513
-        }
514
-        $refresh_msg    = '';
515
-        $none_added_msg = '';
516
-        if (defined('DOING_AJAX') && DOING_AJAX) {
517
-            $refresh_msg    = __(
518
-                'Please refresh the page to view updated ticket quantities.',
519
-                'event_espresso'
520
-            );
521
-            $none_added_msg = __('No tickets were added for the event.', 'event_espresso');
522
-        }
523
-        if (! empty($this->sold_out_tickets)) {
524
-            EE_Error::add_attention(
525
-                sprintf(
526
-                    apply_filters(
527
-                        'FHEE__EED_Ticket_Sales_Monitor___post_notices__sold_out_tickets_notice',
528
-                        __(
529
-                            'We\'re sorry...%1$sThe following items have sold out since you first viewed this page, and can no longer be registered for:%1$s%1$s%2$s%1$s%1$sPlease note that availability can change at any time due to cancellations, so please check back again later if registration for this event(s) is important to you.%1$s%1$s%3$s%1$s%4$s%1$s',
530
-                            'event_espresso'
531
-                        )
532
-                    ),
533
-                    '<br />',
534
-                    implode('<br />', $this->sold_out_tickets),
535
-                    $none_added_msg,
536
-                    $refresh_msg
537
-                )
538
-            );
539
-            // alter code flow in the Ticket Selector for better UX
540
-            add_filter('FHEE__EED_Ticket_Selector__process_ticket_selections__tckts_slctd', '__return_true');
541
-            add_filter('FHEE__EED_Ticket_Selector__process_ticket_selections__success', '__return_false');
542
-            $this->sold_out_tickets = array();
543
-            // and reset the cart
544
-            EED_Ticket_Sales_Monitor::session_cart_reset(EE_Registry::instance()->SSN);
545
-        }
546
-        if (! empty($this->decremented_tickets)) {
547
-            EE_Error::add_attention(
548
-                sprintf(
549
-                    apply_filters(
550
-                        'FHEE__EED_Ticket_Sales_Monitor___ticket_quantity_decremented__notice',
551
-                        __(
552
-                            'We\'re sorry...%1$sDue to sales that have occurred since you first viewed the last page, the following items have had their quantities adjusted to match the current available amount:%1$s%1$s%2$s%1$s%1$sPlease note that availability can change at any time due to cancellations, so please check back again later if registration for this event(s) is important to you.%1$s%1$s%3$s%1$s%4$s%1$s',
553
-                            'event_espresso'
554
-                        )
555
-                    ),
556
-                    '<br />',
557
-                    implode('<br />', $this->decremented_tickets),
558
-                    $none_added_msg,
559
-                    $refresh_msg
560
-                )
561
-            );
562
-            $this->decremented_tickets = array();
563
-        }
564
-    }
565
-
566
-
567
-
568
-    /********************************** RELEASE_ALL_RESERVED_TICKETS_FOR_TRANSACTION  **********************************/
569
-
570
-
571
-
572
-    /**
573
-     * releases reserved tickets for all registrations of an EE_Transaction
574
-     * by default, will NOT release tickets for finalized transactions
575
-     *
576
-     * @param    EE_Transaction $transaction
577
-     * @return int
578
-     * @throws EE_Error
579
-     * @throws InvalidSessionDataException
580
-     */
581
-    protected function _release_all_reserved_tickets_for_transaction(EE_Transaction $transaction)
582
-    {
583
-        if (self::debug) {
584
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
585
-            echo self::$nl . ' . transaction->ID: ' . $transaction->ID();
586
-            echo self::$nl . ' . TXN status_ID: ' . $transaction->status_ID();
587
-        }
588
-        // check if 'finalize_registration' step has been completed...
589
-        $finalized = $transaction->reg_step_completed('finalize_registration');
590
-        if (self::debug) {
591
-            // DEBUG LOG
592
-            EEH_Debug_Tools::log(
593
-                __CLASS__,
594
-                __FUNCTION__,
595
-                __LINE__,
596
-                array('finalized' => $finalized),
597
-                false,
598
-                'EE_Transaction: ' . $transaction->ID()
599
-            );
600
-        }
601
-        // how many tickets were released
602
-        $count = 0;
603
-        if (self::debug) {
604
-            echo self::$nl . ' . . . TXN finalized: ' . $finalized;
605
-        }
606
-        $release_tickets_with_TXN_status = array(
607
-            EEM_Transaction::failed_status_code,
608
-            EEM_Transaction::abandoned_status_code,
609
-            EEM_Transaction::incomplete_status_code,
610
-        );
611
-        $events = array();
612
-        // if the session is getting cleared BEFORE the TXN has been finalized or the transaction is not completed
613
-        if (! $finalized || in_array($transaction->status_ID(), $release_tickets_with_TXN_status, true)) {
614
-            // cancel any reserved tickets for registrations that were not approved
615
-            $registrations = $transaction->registrations();
616
-            if (self::debug) {
617
-                echo self::$nl . ' . . . # registrations: ' . count($registrations);
618
-                $reg    = reset($registrations);
619
-                $ticket = $reg->ticket();
620
-                if ($ticket instanceof EE_Ticket) {
621
-                    $ticket->add_extra_meta(
622
-                        EE_Ticket::META_KEY_TICKET_RESERVATIONS,
623
-                        __LINE__ . ') Release All Tickets TXN:' . $transaction->ID()
624
-                    );
625
-                }
626
-            }
627
-            if (! empty($registrations)) {
628
-                foreach ($registrations as $registration) {
629
-                    if (
630
-                        $registration instanceof EE_Registration
631
-                        && $this->_release_reserved_ticket_for_registration($registration, $transaction)
632
-                    ) {
633
-                        $count++;
634
-                        $events[ $registration->event_ID() ] = $registration->event();
635
-                    }
636
-                }
637
-            }
638
-        }
639
-        if ($events !== array()) {
640
-            foreach ($events as $event) {
641
-                /** @var EE_Event $event */
642
-                $event->perform_sold_out_status_check();
643
-            }
644
-        }
645
-        return $count;
646
-    }
647
-
648
-
649
-
650
-    /**
651
-     * releases reserved tickets for an EE_Registration
652
-     * by default, will NOT release tickets for APPROVED registrations
653
-     *
654
-     * @param EE_Registration $registration
655
-     * @param EE_Transaction  $transaction
656
-     * @return int
657
-     * @throws EE_Error
658
-     */
659
-    protected function _release_reserved_ticket_for_registration(
660
-        EE_Registration $registration,
661
-        EE_Transaction $transaction
662
-    ) {
663
-        $STS_ID = $transaction->status_ID();
664
-        if (self::debug) {
665
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
666
-            echo self::$nl . ' . . registration->ID: ' . $registration->ID();
667
-            echo self::$nl . ' . . registration->status_ID: ' . $registration->status_ID();
668
-            echo self::$nl . ' . . transaction->status_ID(): ' . $STS_ID;
669
-        }
670
-        if (
671
-            // release Tickets for Failed Transactions and Abandoned Transactions
672
-            $STS_ID === EEM_Transaction::failed_status_code
673
-            || $STS_ID === EEM_Transaction::abandoned_status_code
674
-            || (
675
-                // also release Tickets for Incomplete Transactions, but ONLY if the Registrations are NOT Approved
676
-                $STS_ID === EEM_Transaction::incomplete_status_code
677
-                && $registration->status_ID() !== EEM_Registration::status_id_approved
678
-            )
679
-        ) {
680
-            if (self::debug) {
681
-                echo self::$nl . self::$nl . ' . . RELEASE RESERVED TICKET';
682
-                $rsrvd = $registration->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true);
683
-                echo self::$nl . ' . . . registration HAS_RESERVED_TICKET_KEY: ';
684
-                var_dump($rsrvd);
685
-            }
686
-            $registration->release_reserved_ticket(true, 'TicketSalesMonitor:'. __LINE__);
687
-            return 1;
688
-        }
689
-        return 0;
690
-    }
691
-
692
-
693
-
694
-    /********************************** SESSION_CART_RESET  **********************************/
695
-
696
-
697
-
698
-    /**
699
-     * callback hooked into 'AHEE__EE_Session__reset_cart__before_reset'
700
-     *
701
-     * @param EE_Session $session
702
-     * @return void
703
-     * @throws EE_Error
704
-     * @throws InvalidArgumentException
705
-     * @throws ReflectionException
706
-     * @throws InvalidDataTypeException
707
-     * @throws InvalidInterfaceException
708
-     */
709
-    public static function session_cart_reset(EE_Session $session)
710
-    {
711
-        if (self::debug) {
712
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
713
-        }
714
-        // first check of the session has a valid Checkout object
715
-        $checkout = $session->checkout();
716
-        if ($checkout instanceof EE_Checkout) {
717
-            // and use that to clear ticket reservations because it will update the associated registration meta data
718
-            EED_Ticket_Sales_Monitor::instance()->_session_checkout_reset($checkout);
719
-            return;
720
-        }
721
-        $cart = $session->cart();
722
-        if ($cart instanceof EE_Cart) {
723
-            if (self::debug) {
724
-                echo self::$nl . self::$nl . ' cart instance of EE_Cart: ';
725
-            }
726
-            EED_Ticket_Sales_Monitor::instance()->_session_cart_reset($cart, $session);
727
-        } else {
728
-            if (self::debug) {
729
-                echo self::$nl . self::$nl . ' invalid EE_Cart: ';
730
-                var_export($cart, true);
731
-            }
732
-        }
733
-    }
734
-
735
-
736
-
737
-    /**
738
-     * releases reserved tickets in the EE_Cart
739
-     *
740
-     * @param EE_Cart $cart
741
-     * @return void
742
-     * @throws EE_Error
743
-     * @throws InvalidArgumentException
744
-     * @throws ReflectionException
745
-     * @throws InvalidDataTypeException
746
-     * @throws InvalidInterfaceException
747
-     */
748
-    protected function _session_cart_reset(EE_Cart $cart, EE_Session $session)
749
-    {
750
-        if (self::debug) {
751
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
752
-        }
753
-        EE_Registry::instance()->load_helper('Line_Item');
754
-        $ticket_line_items = $cart->get_tickets();
755
-        if (empty($ticket_line_items)) {
756
-            return;
757
-        }
758
-        foreach ($ticket_line_items as $ticket_line_item) {
759
-            if (self::debug) {
760
-                echo self::$nl . ' . ticket_line_item->ID(): ' . $ticket_line_item->ID();
761
-            }
762
-            if ($ticket_line_item instanceof EE_Line_Item && $ticket_line_item->OBJ_type() === 'Ticket') {
763
-                if (self::debug) {
764
-                    echo self::$nl . ' . . ticket_line_item->OBJ_ID(): ' . $ticket_line_item->OBJ_ID();
765
-                }
766
-                $ticket = EEM_Ticket::instance()->get_one_by_ID($ticket_line_item->OBJ_ID());
767
-                if ($ticket instanceof EE_Ticket) {
768
-                    if (self::debug) {
769
-                        echo self::$nl . ' . . ticket->ID(): ' . $ticket->ID();
770
-                        echo self::$nl . ' . . ticket_line_item->quantity(): ' . $ticket_line_item->quantity();
771
-                    }
772
-                    $ticket->add_extra_meta(
773
-                        EE_Ticket::META_KEY_TICKET_RESERVATIONS,
774
-                        __LINE__ . ') ' . __METHOD__ . '() SID = ' . $session->id()
775
-                    );
776
-                    $this->_release_reserved_ticket($ticket, $ticket_line_item->quantity());
777
-                }
778
-            }
779
-        }
780
-        if (self::debug) {
781
-            echo self::$nl . self::$nl . ' RESET COMPLETED ';
782
-        }
783
-    }
784
-
785
-
786
-
787
-    /********************************** SESSION_CHECKOUT_RESET  **********************************/
788
-
789
-
790
-
791
-    /**
792
-     * callback hooked into 'AHEE__EE_Session__reset_checkout__before_reset'
793
-     *
794
-     * @param EE_Session $session
795
-     * @return void
796
-     * @throws EE_Error
797
-     * @throws InvalidSessionDataException
798
-     */
799
-    public static function session_checkout_reset(EE_Session $session)
800
-    {
801
-        $checkout = $session->checkout();
802
-        if ($checkout instanceof EE_Checkout) {
803
-            EED_Ticket_Sales_Monitor::instance()->_session_checkout_reset($checkout);
804
-        }
805
-    }
806
-
807
-
808
-
809
-    /**
810
-     * releases reserved tickets for the EE_Checkout->transaction
811
-     *
812
-     * @param EE_Checkout $checkout
813
-     * @return void
814
-     * @throws EE_Error
815
-     * @throws InvalidSessionDataException
816
-     */
817
-    protected function _session_checkout_reset(EE_Checkout $checkout)
818
-    {
819
-        if (self::debug) {
820
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
821
-        }
822
-        // we want to release the each registration's reserved tickets if the session was cleared, but not if this is a revisit
823
-        if ($checkout->revisit || ! $checkout->transaction instanceof EE_Transaction) {
824
-            return;
825
-        }
826
-        $this->_release_all_reserved_tickets_for_transaction($checkout->transaction);
827
-    }
828
-
829
-
830
-
831
-    /********************************** SESSION_EXPIRED_RESET  **********************************/
832
-
833
-
834
-
835
-    /**
836
-     * @param    EE_Session $session
837
-     * @return    void
838
-     */
839
-    public static function session_expired_reset(EE_Session $session)
840
-    {
841
-    }
842
-
843
-
844
-
845
-    /********************************** PROCESS_ABANDONED_TRANSACTIONS  **********************************/
846
-
847
-
848
-
849
-    /**
850
-     * releases reserved tickets for all registrations of an ABANDONED EE_Transaction
851
-     * by default, will NOT release tickets for free transactions, or any that have received a payment
852
-     *
853
-     * @param EE_Transaction $transaction
854
-     * @return void
855
-     * @throws EE_Error
856
-     * @throws InvalidSessionDataException
857
-     */
858
-    public static function process_abandoned_transactions(EE_Transaction $transaction)
859
-    {
860
-        // is this TXN free or has any money been paid towards this TXN? If so, then leave it alone
861
-        if ($transaction->is_free() || $transaction->paid() > 0) {
862
-            if (self::debug) {
863
-                // DEBUG LOG
864
-                EEH_Debug_Tools::log(
865
-                    __CLASS__,
866
-                    __FUNCTION__,
867
-                    __LINE__,
868
-                    array($transaction),
869
-                    false,
870
-                    'EE_Transaction: ' . $transaction->ID()
871
-                );
872
-            }
873
-            return;
874
-        }
875
-        // have their been any successful payments made ?
876
-        $payments = $transaction->payments();
877
-        foreach ($payments as $payment) {
878
-            if ($payment instanceof EE_Payment && $payment->status() === EEM_Payment::status_id_approved) {
879
-                if (self::debug) {
880
-                    // DEBUG LOG
881
-                    EEH_Debug_Tools::log(
882
-                        __CLASS__,
883
-                        __FUNCTION__,
884
-                        __LINE__,
885
-                        array($payment),
886
-                        false,
887
-                        'EE_Transaction: ' . $transaction->ID()
888
-                    );
889
-                }
890
-                return;
891
-            }
892
-        }
893
-        // since you haven't even attempted to pay for your ticket...
894
-        EED_Ticket_Sales_Monitor::instance()->_release_all_reserved_tickets_for_transaction($transaction);
895
-    }
896
-
897
-
898
-
899
-    /********************************** PROCESS_FAILED_TRANSACTIONS  **********************************/
900
-
901
-
902
-
903
-    /**
904
-     * releases reserved tickets for absolutely ALL registrations of a FAILED EE_Transaction
905
-     *
906
-     * @param EE_Transaction $transaction
907
-     * @return void
908
-     * @throws EE_Error
909
-     * @throws InvalidSessionDataException
910
-     */
911
-    public static function process_failed_transactions(EE_Transaction $transaction)
912
-    {
913
-        // since you haven't even attempted to pay for your ticket...
914
-        EED_Ticket_Sales_Monitor::instance()->_release_all_reserved_tickets_for_transaction($transaction);
915
-    }
916
-
917
-
918
-
919
-    /********************************** RESET RESERVATION COUNTS  *********************************/
920
-
921
-
922
-
923
-    /**
924
-     * Resets all ticket and datetime reserved counts to zero
925
-     * Tickets that are currently associated with a Transaction that is in progress
926
-     *
927
-     * @throws EE_Error
928
-     * @throws DomainException
929
-     * @throws InvalidDataTypeException
930
-     * @throws InvalidInterfaceException
931
-     * @throws InvalidArgumentException
932
-     * @throws UnexpectedEntityException
933
-     */
934
-    public static function reset_reservation_counts()
935
-    {
936
-        /** @var EE_Line_Item[] $valid_reserved_tickets */
937
-        $valid_reserved_tickets = array();
938
-        /** @var EE_Transaction[] $transactions_not_in_progress */
939
-        $transactions_not_in_progress = EEM_Transaction::instance()->get_transactions_not_in_progress();
940
-        foreach ($transactions_not_in_progress as $transaction) {
941
-            // if this TXN has been fully completed, then skip it
942
-            if ($transaction->reg_step_completed('finalize_registration')) {
943
-                continue;
944
-            }
945
-            $total_line_item = $transaction->total_line_item();
946
-            // $transaction_in_progress->line
947
-            if (! $total_line_item instanceof EE_Line_Item) {
948
-                throw new DomainException(
949
-                    esc_html__(
950
-                        'Transaction does not have a valid Total Line Item associated with it.',
951
-                        'event_espresso'
952
-                    )
953
-                );
954
-            }
955
-            $valid_reserved_tickets += EED_Ticket_Sales_Monitor::get_ticket_line_items_for_grand_total(
956
-                $total_line_item
957
-            );
958
-        }
959
-        $total_line_items = EEM_Line_Item::instance()->get_total_line_items_for_active_carts();
960
-        foreach ($total_line_items as $total_line_item) {
961
-            $valid_reserved_tickets += EED_Ticket_Sales_Monitor::get_ticket_line_items_for_grand_total(
962
-                $total_line_item
963
-            );
964
-        }
965
-        $tickets_with_reservations = EEM_Ticket::instance()->get_tickets_with_reservations();
966
-        return EED_Ticket_Sales_Monitor::release_reservations_for_tickets(
967
-            $tickets_with_reservations,
968
-            $valid_reserved_tickets,
969
-            __FUNCTION__
970
-        );
971
-    }
972
-
973
-
974
-
975
-    /**
976
-     * @param EE_Line_Item $total_line_item
977
-     * @return EE_Line_Item[]
978
-     */
979
-    private static function get_ticket_line_items_for_grand_total(EE_Line_Item $total_line_item)
980
-    {
981
-        /** @var EE_Line_Item[] $valid_reserved_tickets */
982
-        $valid_reserved_tickets = array();
983
-        $ticket_line_items      = EEH_Line_Item::get_ticket_line_items($total_line_item);
984
-        foreach ($ticket_line_items as $ticket_line_item) {
985
-            if ($ticket_line_item instanceof EE_Line_Item) {
986
-                $valid_reserved_tickets[] = $ticket_line_item;
987
-            }
988
-        }
989
-        return $valid_reserved_tickets;
990
-    }
991
-
992
-
993
-
994
-    /**
995
-     * @param EE_Ticket[]    $tickets_with_reservations
996
-     * @param EE_Line_Item[] $valid_reserved_ticket_line_items
997
-     * @return int
998
-     * @throws UnexpectedEntityException
999
-     * @throws DomainException
1000
-     * @throws EE_Error
1001
-     */
1002
-    private static function release_reservations_for_tickets(
1003
-        array $tickets_with_reservations,
1004
-        array $valid_reserved_ticket_line_items = array(),
1005
-        $source
1006
-    ) {
1007
-        if (self::debug) {
1008
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '()';
1009
-        }
1010
-        $total_tickets_released = 0;
1011
-        $sold_out_events = array();
1012
-        foreach ($tickets_with_reservations as $ticket_with_reservations) {
1013
-            if (! $ticket_with_reservations instanceof EE_Ticket) {
1014
-                continue;
1015
-            }
1016
-            $reserved_qty = $ticket_with_reservations->reserved();
1017
-            if (self::debug) {
1018
-                echo self::$nl . ' . $ticket_with_reservations->ID(): ' . $ticket_with_reservations->ID();
1019
-                echo self::$nl . ' . $reserved_qty: ' . $reserved_qty;
1020
-            }
1021
-            foreach ($valid_reserved_ticket_line_items as $valid_reserved_ticket_line_item) {
1022
-                if (
1023
-                    $valid_reserved_ticket_line_item instanceof EE_Line_Item
1024
-                    && $valid_reserved_ticket_line_item->OBJ_ID() === $ticket_with_reservations->ID()
1025
-                ) {
1026
-                    if (self::debug) {
1027
-                        echo self::$nl . ' . $valid_reserved_ticket_line_item->quantity(): ' . $valid_reserved_ticket_line_item->quantity();
1028
-                    }
1029
-                    $reserved_qty -= $valid_reserved_ticket_line_item->quantity();
1030
-                }
1031
-            }
1032
-            if ($reserved_qty > 0) {
1033
-                $ticket_with_reservations->add_extra_meta(
1034
-                    EE_Ticket::META_KEY_TICKET_RESERVATIONS,
1035
-                    __LINE__ . ') ' . $source . '()'
1036
-                );
1037
-                $ticket_with_reservations->decrease_reserved($reserved_qty, true, 'TicketSalesMonitor:'. __LINE__);
1038
-                $ticket_with_reservations->save();
1039
-                $total_tickets_released += $reserved_qty;
1040
-                $event = $ticket_with_reservations->get_related_event();
1041
-                // track sold out events
1042
-                if ($event instanceof EE_Event && $event->is_sold_out()) {
1043
-                    $sold_out_events[] = $event;
1044
-                }
1045
-            }
1046
-        }
1047
-        if (self::debug) {
1048
-            echo self::$nl . ' . $total_tickets_released: ' . $total_tickets_released;
1049
-        }
1050
-        // double check whether sold out events should remain sold out after releasing tickets
1051
-        if($sold_out_events !== array()){
1052
-            foreach ($sold_out_events as $sold_out_event) {
1053
-                /** @var EE_Event $sold_out_event */
1054
-                $sold_out_event->perform_sold_out_status_check();
1055
-            }
1056
-        }
1057
-        return $total_tickets_released;
1058
-    }
1059
-
1060
-
1061
-
1062
-    /********************************** SHUTDOWN  **********************************/
1063
-
1064
-
1065
-
1066
-    /**
1067
-     * @param int $timestamp
1068
-     * @return false|int
1069
-     * @throws EE_Error
1070
-     * @throws InvalidArgumentException
1071
-     * @throws InvalidDataTypeException
1072
-     * @throws InvalidInterfaceException
1073
-     */
1074
-    public static function clear_expired_line_items_with_no_transaction($timestamp = 0)
1075
-    {
1076
-       /** @type WPDB $wpdb */
1077
-        global $wpdb;
1078
-        if (! absint($timestamp)) {
1079
-            /** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */
1080
-            $session_lifespan = LoaderFactory::getLoader()->getShared(
1081
-                'EventEspresso\core\domain\values\session\SessionLifespan'
1082
-            );
1083
-            $timestamp = $session_lifespan->expiration();
1084
-        }
1085
-         return $wpdb->query(
1086
-            $wpdb->prepare(
1087
-                'DELETE FROM ' . EEM_Line_Item::instance()->table() . '
27
+	const debug = false;    //	true false
28
+
29
+	private static $nl = '';
30
+
31
+	/**
32
+	 * an array of raw ticket data from EED_Ticket_Selector
33
+	 *
34
+	 * @var array $ticket_selections
35
+	 */
36
+	protected $ticket_selections = array();
37
+
38
+	/**
39
+	 * the raw ticket data from EED_Ticket_Selector is organized in rows
40
+	 * according to how they are displayed in the actual Ticket_Selector
41
+	 * this tracks the current row being processed
42
+	 *
43
+	 * @var int $current_row
44
+	 */
45
+	protected $current_row = 0;
46
+
47
+	/**
48
+	 * an array for tracking names of tickets that have sold out
49
+	 *
50
+	 * @var array $sold_out_tickets
51
+	 */
52
+	protected $sold_out_tickets = array();
53
+
54
+	/**
55
+	 * an array for tracking names of tickets that have had their quantities reduced
56
+	 *
57
+	 * @var array $decremented_tickets
58
+	 */
59
+	protected $decremented_tickets = array();
60
+
61
+
62
+
63
+	/**
64
+	 * set_hooks - for hooking into EE Core, other modules, etc
65
+	 *
66
+	 * @return    void
67
+	 */
68
+	public static function set_hooks()
69
+	{
70
+		self::$nl = defined('EE_TESTS_DIR')? "\n" : '<br />';
71
+		// release tickets for expired carts
72
+		add_action(
73
+			'EED_Ticket_Selector__process_ticket_selections__before',
74
+			array('EED_Ticket_Sales_Monitor', 'release_tickets_for_expired_carts'),
75
+			1
76
+		);
77
+		// check ticket reserves AFTER MER does it's check (hence priority 20)
78
+		add_filter(
79
+			'FHEE__EE_Ticket_Selector___add_ticket_to_cart__ticket_qty',
80
+			array('EED_Ticket_Sales_Monitor', 'validate_ticket_sale'),
81
+			20,
82
+			3
83
+		);
84
+		// add notices for sold out tickets
85
+		add_action(
86
+			'AHEE__EE_Ticket_Selector__process_ticket_selections__after_tickets_added_to_cart',
87
+			array('EED_Ticket_Sales_Monitor', 'post_notices'),
88
+			10
89
+		);
90
+		// handle ticket quantities adjusted in cart
91
+		//add_action(
92
+		//	'FHEE__EED_Multi_Event_Registration__adjust_line_item_quantity__line_item_quantity_updated',
93
+		//	array( 'EED_Ticket_Sales_Monitor', 'ticket_quantity_updated' ),
94
+		//	10, 2
95
+		//);
96
+		// handle tickets deleted from cart
97
+		add_action(
98
+			'FHEE__EED_Multi_Event_Registration__delete_ticket__ticket_removed_from_cart',
99
+			array('EED_Ticket_Sales_Monitor', 'ticket_removed_from_cart'),
100
+			10,
101
+			2
102
+		);
103
+		// handle emptied carts
104
+		add_action(
105
+			'AHEE__EE_Session__reset_cart__before_reset',
106
+			array('EED_Ticket_Sales_Monitor', 'session_cart_reset'),
107
+			10,
108
+			1
109
+		);
110
+		add_action(
111
+			'AHEE__EED_Multi_Event_Registration__empty_event_cart__before_delete_cart',
112
+			array('EED_Ticket_Sales_Monitor', 'session_cart_reset'),
113
+			10,
114
+			1
115
+		);
116
+		// handle cancelled registrations
117
+		add_action(
118
+			'AHEE__EE_Session__reset_checkout__before_reset',
119
+			array('EED_Ticket_Sales_Monitor', 'session_checkout_reset'),
120
+			10,
121
+			1
122
+		);
123
+		// cron tasks
124
+		add_action(
125
+			'AHEE__EE_Cron_Tasks__process_expired_transactions__abandoned_transaction',
126
+			array('EED_Ticket_Sales_Monitor', 'process_abandoned_transactions'),
127
+			10,
128
+			1
129
+		);
130
+		add_action(
131
+			'AHEE__EE_Cron_Tasks__process_expired_transactions__incomplete_transaction',
132
+			array('EED_Ticket_Sales_Monitor', 'process_abandoned_transactions'),
133
+			10,
134
+			1
135
+		);
136
+		add_action(
137
+			'AHEE__EE_Cron_Tasks__process_expired_transactions__failed_transaction',
138
+			array('EED_Ticket_Sales_Monitor', 'process_failed_transactions'),
139
+			10,
140
+			1
141
+		);
142
+	}
143
+
144
+
145
+
146
+	/**
147
+	 * set_hooks_admin - for hooking into EE Admin Core, other modules, etc
148
+	 *
149
+	 * @return void
150
+	 */
151
+	public static function set_hooks_admin()
152
+	{
153
+		EED_Ticket_Sales_Monitor::set_hooks();
154
+	}
155
+
156
+
157
+
158
+	/**
159
+	 * @return EED_Ticket_Sales_Monitor|EED_Module
160
+	 */
161
+	public static function instance()
162
+	{
163
+		return parent::get_instance(__CLASS__);
164
+	}
165
+
166
+
167
+
168
+	/**
169
+	 * @param WP_Query $WP_Query
170
+	 * @return    void
171
+	 */
172
+	public function run($WP_Query)
173
+	{
174
+	}
175
+
176
+
177
+
178
+	/********************************** PRE_TICKET_SALES  **********************************/
179
+
180
+
181
+
182
+	/**
183
+	 * Retrieves grand totals from the line items that have no TXN ID
184
+	 * and timestamps less than the current time minus the session lifespan.
185
+	 * These are carts that have been abandoned before the "registrant" even attempted to checkout.
186
+	 * We're going to release the tickets for these line items before attempting to add more to the cart.
187
+	 *
188
+	 * @return void
189
+	 * @throws DomainException
190
+	 * @throws EE_Error
191
+	 * @throws InvalidArgumentException
192
+	 * @throws InvalidDataTypeException
193
+	 * @throws InvalidInterfaceException
194
+	 * @throws UnexpectedEntityException
195
+	 */
196
+	public static function release_tickets_for_expired_carts()
197
+	{
198
+		if (self::debug) {
199
+			echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '()';
200
+		}
201
+		do_action('AHEE__EED_Ticket_Sales_Monitor__release_tickets_for_expired_carts__begin');
202
+		$expired_ticket_IDs = array();
203
+		/** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */
204
+		$session_lifespan = LoaderFactory::getLoader()->getShared(
205
+			'EventEspresso\core\domain\values\session\SessionLifespan'
206
+		);
207
+		$timestamp = $session_lifespan->expiration();
208
+		$expired_ticket_line_items = EEM_Line_Item::instance()->getTicketLineItemsForExpiredCarts($timestamp);
209
+		if (self::debug) {
210
+			echo self::$nl . ' . time(): ' . time();
211
+			echo self::$nl . ' . time() as date: ' . date('Y-m-d H:i a');
212
+			echo self::$nl . ' . session expiration: ' . $session_lifespan->expiration();
213
+			echo self::$nl . ' . session expiration as date: ' . date('Y-m-d H:i a', $session_lifespan->expiration());
214
+			echo self::$nl . ' . timestamp: ' . $timestamp;
215
+			echo self::$nl . ' . $expired_ticket_line_items: ' . count($expired_ticket_line_items);
216
+		}
217
+		if (! empty($expired_ticket_line_items)) {
218
+			foreach ($expired_ticket_line_items as $expired_ticket_line_item) {
219
+				if (! $expired_ticket_line_item instanceof EE_Line_Item) {
220
+					continue;
221
+				}
222
+				$expired_ticket_IDs[ $expired_ticket_line_item->OBJ_ID() ] = $expired_ticket_line_item->OBJ_ID();
223
+				if (self::debug) {
224
+					echo self::$nl . ' . $expired_ticket_line_item->OBJ_ID(): ' . $expired_ticket_line_item->OBJ_ID();
225
+					echo self::$nl . ' . $expired_ticket_line_item->timestamp(): ' . date('Y-m-d h:i a',
226
+							$expired_ticket_line_item->timestamp(true));
227
+				}
228
+			}
229
+			if (! empty($expired_ticket_IDs)) {
230
+				EED_Ticket_Sales_Monitor::release_reservations_for_tickets(
231
+					\EEM_Ticket::instance()->get_tickets_with_IDs($expired_ticket_IDs),
232
+					array(),
233
+					__FUNCTION__
234
+				);
235
+				// now  let's get rid of expired line items so that they can't interfere with tracking
236
+				EED_Ticket_Sales_Monitor::clear_expired_line_items_with_no_transaction($timestamp);
237
+			}
238
+		}
239
+		do_action(
240
+			'AHEE__EED_Ticket_Sales_Monitor__release_tickets_for_expired_carts__end',
241
+			$expired_ticket_IDs,
242
+			$expired_ticket_line_items
243
+		);
244
+	}
245
+
246
+
247
+
248
+	/********************************** VALIDATE_TICKET_SALE  **********************************/
249
+
250
+
251
+
252
+	/**
253
+	 * callback for 'FHEE__EED_Ticket_Selector__process_ticket_selections__valid_post_data'
254
+	 *
255
+	 * @param int       $qty
256
+	 * @param EE_Ticket $ticket
257
+	 * @return bool
258
+	 * @throws UnexpectedEntityException
259
+	 * @throws EE_Error
260
+	 */
261
+	public static function validate_ticket_sale($qty = 1, EE_Ticket $ticket)
262
+	{
263
+		$qty = absint($qty);
264
+		if ($qty > 0) {
265
+			$qty = EED_Ticket_Sales_Monitor::instance()->_validate_ticket_sale($ticket, $qty);
266
+		}
267
+		if (self::debug) {
268
+			echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '()';
269
+			echo self::$nl . self::$nl . '<b> RETURNED QTY: ' . $qty . '</b>';
270
+		}
271
+		return $qty;
272
+	}
273
+
274
+
275
+
276
+	/**
277
+	 * checks whether an individual ticket is available for purchase based on datetime, and ticket details
278
+	 *
279
+	 * @param   EE_Ticket $ticket
280
+	 * @param int         $qty
281
+	 * @return int
282
+	 * @throws UnexpectedEntityException
283
+	 * @throws EE_Error
284
+	 */
285
+	protected function _validate_ticket_sale(EE_Ticket $ticket, $qty = 1)
286
+	{
287
+		if (self::debug) {
288
+			echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
289
+		}
290
+		if (! $ticket instanceof EE_Ticket) {
291
+			return 0;
292
+		}
293
+		if (self::debug) {
294
+			echo self::$nl . '<b> . ticket->ID: ' . $ticket->ID() . '</b>';
295
+			echo self::$nl . ' . original ticket->reserved: ' . $ticket->reserved();
296
+		}
297
+		$ticket->refresh_from_db();
298
+		// first let's determine the ticket availability based on sales
299
+		$available = $ticket->qty('saleable');
300
+		if (self::debug) {
301
+			echo self::$nl . ' . . . ticket->qty: ' . $ticket->qty();
302
+			echo self::$nl . ' . . . ticket->sold: ' . $ticket->sold();
303
+			echo self::$nl . ' . . . ticket->reserved: ' . $ticket->reserved();
304
+			echo self::$nl . ' . . . ticket->qty(saleable): ' . $ticket->qty('saleable');
305
+			echo self::$nl . ' . . . available: ' . $available;
306
+		}
307
+		if ($available < 1) {
308
+			$this->_ticket_sold_out($ticket);
309
+			return 0;
310
+		}
311
+		if (self::debug) {
312
+			echo self::$nl . ' . . . qty: ' . $qty;
313
+		}
314
+		if ($available < $qty) {
315
+			$qty = $available;
316
+			if (self::debug) {
317
+				echo self::$nl . ' . . . QTY ADJUSTED: ' . $qty;
318
+			}
319
+			$this->_ticket_quantity_decremented($ticket);
320
+		}
321
+		$this->_reserve_ticket($ticket, $qty);
322
+		return $qty;
323
+	}
324
+
325
+
326
+
327
+	/**
328
+	 * increments ticket reserved based on quantity passed
329
+	 *
330
+	 * @param    EE_Ticket $ticket
331
+	 * @param int          $quantity
332
+	 * @return bool
333
+	 * @throws EE_Error
334
+	 */
335
+	protected function _reserve_ticket(EE_Ticket $ticket, $quantity = 1)
336
+	{
337
+		if (self::debug) {
338
+			echo self::$nl . self::$nl . ' . . . INCREASE RESERVED: ' . $quantity;
339
+		}
340
+		$ticket->increase_reserved($quantity, 'TicketSalesMonitor:'. __LINE__);
341
+		return $ticket->save();
342
+	}
343
+
344
+
345
+
346
+	/**
347
+	 * @param  EE_Ticket $ticket
348
+	 * @param  int       $quantity
349
+	 * @return bool
350
+	 * @throws EE_Error
351
+	 */
352
+	protected function _release_reserved_ticket(EE_Ticket $ticket, $quantity = 1)
353
+	{
354
+		if (self::debug) {
355
+			echo self::$nl . ' . . . ticket->ID: ' . $ticket->ID();
356
+			echo self::$nl . ' . . . ticket->reserved: ' . $ticket->reserved();
357
+		}
358
+		$ticket->decrease_reserved($quantity, true, 'TicketSalesMonitor:'. __LINE__);
359
+		if (self::debug) {
360
+			echo self::$nl . ' . . . ticket->reserved: ' . $ticket->reserved();
361
+		}
362
+		return $ticket->save() ? 1 : 0;
363
+	}
364
+
365
+
366
+
367
+	/**
368
+	 * removes quantities within the ticket selector based on zero ticket availability
369
+	 *
370
+	 * @param    EE_Ticket $ticket
371
+	 * @return    void
372
+	 * @throws UnexpectedEntityException
373
+	 * @throws EE_Error
374
+	 */
375
+	protected function _ticket_sold_out(EE_Ticket $ticket)
376
+	{
377
+		if (self::debug) {
378
+			echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
379
+			echo self::$nl . ' . . ticket->name: ' . $this->_get_ticket_and_event_name($ticket);
380
+		}
381
+		$this->sold_out_tickets[] = $this->_get_ticket_and_event_name($ticket);
382
+	}
383
+
384
+
385
+
386
+	/**
387
+	 * adjusts quantities within the ticket selector based on decreased ticket availability
388
+	 *
389
+	 * @param    EE_Ticket $ticket
390
+	 * @return void
391
+	 * @throws UnexpectedEntityException
392
+	 * @throws EE_Error
393
+	 */
394
+	protected function _ticket_quantity_decremented(EE_Ticket $ticket)
395
+	{
396
+		if (self::debug) {
397
+			echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
398
+			echo self::$nl . ' . . ticket->name: ' . $this->_get_ticket_and_event_name($ticket);
399
+		}
400
+		$this->decremented_tickets[] = $this->_get_ticket_and_event_name($ticket);
401
+	}
402
+
403
+
404
+
405
+	/**
406
+	 * builds string out of ticket and event name
407
+	 *
408
+	 * @param    EE_Ticket $ticket
409
+	 * @return string
410
+	 * @throws UnexpectedEntityException
411
+	 * @throws EE_Error
412
+	 */
413
+	protected function _get_ticket_and_event_name(EE_Ticket $ticket)
414
+	{
415
+		$event = $ticket->get_related_event();
416
+		if ($event instanceof EE_Event) {
417
+			$ticket_name = sprintf(
418
+				_x('%1$s for %2$s', 'ticket name for event name', 'event_espresso'),
419
+				$ticket->name(),
420
+				$event->name()
421
+			);
422
+		} else {
423
+			$ticket_name = $ticket->name();
424
+		}
425
+		return $ticket_name;
426
+	}
427
+
428
+
429
+
430
+	/********************************** EVENT CART  **********************************/
431
+
432
+
433
+
434
+	/**
435
+	 * releases or reserves ticket(s) based on quantity passed
436
+	 *
437
+	 * @param  EE_Line_Item $line_item
438
+	 * @param  int          $quantity
439
+	 * @return void
440
+	 * @throws EE_Error
441
+	 * @throws InvalidArgumentException
442
+	 * @throws InvalidDataTypeException
443
+	 * @throws InvalidInterfaceException
444
+	 */
445
+	public static function ticket_quantity_updated(EE_Line_Item $line_item, $quantity = 1)
446
+	{
447
+		$ticket = EEM_Ticket::instance()->get_one_by_ID(absint($line_item->OBJ_ID()));
448
+		if ($ticket instanceof EE_Ticket) {
449
+			$ticket->add_extra_meta(
450
+				EE_Ticket::META_KEY_TICKET_RESERVATIONS,
451
+				__LINE__ . ') ' . __METHOD__ . '()'
452
+			);
453
+			if ($quantity > 0) {
454
+				EED_Ticket_Sales_Monitor::instance()->_reserve_ticket($ticket, $quantity);
455
+			} else {
456
+				EED_Ticket_Sales_Monitor::instance()->_release_reserved_ticket($ticket, $quantity);
457
+			}
458
+		}
459
+	}
460
+
461
+
462
+
463
+	/**
464
+	 * releases reserved ticket(s) based on quantity passed
465
+	 *
466
+	 * @param  EE_Ticket $ticket
467
+	 * @param  int       $quantity
468
+	 * @return void
469
+	 * @throws EE_Error
470
+	 */
471
+	public static function ticket_removed_from_cart(EE_Ticket $ticket, $quantity = 1)
472
+	{
473
+		$ticket->add_extra_meta(
474
+			EE_Ticket::META_KEY_TICKET_RESERVATIONS,
475
+			__LINE__ . ') ' . __METHOD__ . '()'
476
+		);
477
+		EED_Ticket_Sales_Monitor::instance()->_release_reserved_ticket($ticket, $quantity);
478
+	}
479
+
480
+
481
+
482
+	/********************************** POST_NOTICES  **********************************/
483
+
484
+
485
+
486
+	/**
487
+	 * @return void
488
+	 * @throws EE_Error
489
+	 * @throws InvalidArgumentException
490
+	 * @throws ReflectionException
491
+	 * @throws InvalidDataTypeException
492
+	 * @throws InvalidInterfaceException
493
+	 */
494
+	public static function post_notices()
495
+	{
496
+		EED_Ticket_Sales_Monitor::instance()->_post_notices();
497
+	}
498
+
499
+
500
+
501
+	/**
502
+	 * @return void
503
+	 * @throws EE_Error
504
+	 * @throws InvalidArgumentException
505
+	 * @throws ReflectionException
506
+	 * @throws InvalidDataTypeException
507
+	 * @throws InvalidInterfaceException
508
+	 */
509
+	protected function _post_notices()
510
+	{
511
+		if (self::debug) {
512
+			echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
513
+		}
514
+		$refresh_msg    = '';
515
+		$none_added_msg = '';
516
+		if (defined('DOING_AJAX') && DOING_AJAX) {
517
+			$refresh_msg    = __(
518
+				'Please refresh the page to view updated ticket quantities.',
519
+				'event_espresso'
520
+			);
521
+			$none_added_msg = __('No tickets were added for the event.', 'event_espresso');
522
+		}
523
+		if (! empty($this->sold_out_tickets)) {
524
+			EE_Error::add_attention(
525
+				sprintf(
526
+					apply_filters(
527
+						'FHEE__EED_Ticket_Sales_Monitor___post_notices__sold_out_tickets_notice',
528
+						__(
529
+							'We\'re sorry...%1$sThe following items have sold out since you first viewed this page, and can no longer be registered for:%1$s%1$s%2$s%1$s%1$sPlease note that availability can change at any time due to cancellations, so please check back again later if registration for this event(s) is important to you.%1$s%1$s%3$s%1$s%4$s%1$s',
530
+							'event_espresso'
531
+						)
532
+					),
533
+					'<br />',
534
+					implode('<br />', $this->sold_out_tickets),
535
+					$none_added_msg,
536
+					$refresh_msg
537
+				)
538
+			);
539
+			// alter code flow in the Ticket Selector for better UX
540
+			add_filter('FHEE__EED_Ticket_Selector__process_ticket_selections__tckts_slctd', '__return_true');
541
+			add_filter('FHEE__EED_Ticket_Selector__process_ticket_selections__success', '__return_false');
542
+			$this->sold_out_tickets = array();
543
+			// and reset the cart
544
+			EED_Ticket_Sales_Monitor::session_cart_reset(EE_Registry::instance()->SSN);
545
+		}
546
+		if (! empty($this->decremented_tickets)) {
547
+			EE_Error::add_attention(
548
+				sprintf(
549
+					apply_filters(
550
+						'FHEE__EED_Ticket_Sales_Monitor___ticket_quantity_decremented__notice',
551
+						__(
552
+							'We\'re sorry...%1$sDue to sales that have occurred since you first viewed the last page, the following items have had their quantities adjusted to match the current available amount:%1$s%1$s%2$s%1$s%1$sPlease note that availability can change at any time due to cancellations, so please check back again later if registration for this event(s) is important to you.%1$s%1$s%3$s%1$s%4$s%1$s',
553
+							'event_espresso'
554
+						)
555
+					),
556
+					'<br />',
557
+					implode('<br />', $this->decremented_tickets),
558
+					$none_added_msg,
559
+					$refresh_msg
560
+				)
561
+			);
562
+			$this->decremented_tickets = array();
563
+		}
564
+	}
565
+
566
+
567
+
568
+	/********************************** RELEASE_ALL_RESERVED_TICKETS_FOR_TRANSACTION  **********************************/
569
+
570
+
571
+
572
+	/**
573
+	 * releases reserved tickets for all registrations of an EE_Transaction
574
+	 * by default, will NOT release tickets for finalized transactions
575
+	 *
576
+	 * @param    EE_Transaction $transaction
577
+	 * @return int
578
+	 * @throws EE_Error
579
+	 * @throws InvalidSessionDataException
580
+	 */
581
+	protected function _release_all_reserved_tickets_for_transaction(EE_Transaction $transaction)
582
+	{
583
+		if (self::debug) {
584
+			echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
585
+			echo self::$nl . ' . transaction->ID: ' . $transaction->ID();
586
+			echo self::$nl . ' . TXN status_ID: ' . $transaction->status_ID();
587
+		}
588
+		// check if 'finalize_registration' step has been completed...
589
+		$finalized = $transaction->reg_step_completed('finalize_registration');
590
+		if (self::debug) {
591
+			// DEBUG LOG
592
+			EEH_Debug_Tools::log(
593
+				__CLASS__,
594
+				__FUNCTION__,
595
+				__LINE__,
596
+				array('finalized' => $finalized),
597
+				false,
598
+				'EE_Transaction: ' . $transaction->ID()
599
+			);
600
+		}
601
+		// how many tickets were released
602
+		$count = 0;
603
+		if (self::debug) {
604
+			echo self::$nl . ' . . . TXN finalized: ' . $finalized;
605
+		}
606
+		$release_tickets_with_TXN_status = array(
607
+			EEM_Transaction::failed_status_code,
608
+			EEM_Transaction::abandoned_status_code,
609
+			EEM_Transaction::incomplete_status_code,
610
+		);
611
+		$events = array();
612
+		// if the session is getting cleared BEFORE the TXN has been finalized or the transaction is not completed
613
+		if (! $finalized || in_array($transaction->status_ID(), $release_tickets_with_TXN_status, true)) {
614
+			// cancel any reserved tickets for registrations that were not approved
615
+			$registrations = $transaction->registrations();
616
+			if (self::debug) {
617
+				echo self::$nl . ' . . . # registrations: ' . count($registrations);
618
+				$reg    = reset($registrations);
619
+				$ticket = $reg->ticket();
620
+				if ($ticket instanceof EE_Ticket) {
621
+					$ticket->add_extra_meta(
622
+						EE_Ticket::META_KEY_TICKET_RESERVATIONS,
623
+						__LINE__ . ') Release All Tickets TXN:' . $transaction->ID()
624
+					);
625
+				}
626
+			}
627
+			if (! empty($registrations)) {
628
+				foreach ($registrations as $registration) {
629
+					if (
630
+						$registration instanceof EE_Registration
631
+						&& $this->_release_reserved_ticket_for_registration($registration, $transaction)
632
+					) {
633
+						$count++;
634
+						$events[ $registration->event_ID() ] = $registration->event();
635
+					}
636
+				}
637
+			}
638
+		}
639
+		if ($events !== array()) {
640
+			foreach ($events as $event) {
641
+				/** @var EE_Event $event */
642
+				$event->perform_sold_out_status_check();
643
+			}
644
+		}
645
+		return $count;
646
+	}
647
+
648
+
649
+
650
+	/**
651
+	 * releases reserved tickets for an EE_Registration
652
+	 * by default, will NOT release tickets for APPROVED registrations
653
+	 *
654
+	 * @param EE_Registration $registration
655
+	 * @param EE_Transaction  $transaction
656
+	 * @return int
657
+	 * @throws EE_Error
658
+	 */
659
+	protected function _release_reserved_ticket_for_registration(
660
+		EE_Registration $registration,
661
+		EE_Transaction $transaction
662
+	) {
663
+		$STS_ID = $transaction->status_ID();
664
+		if (self::debug) {
665
+			echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
666
+			echo self::$nl . ' . . registration->ID: ' . $registration->ID();
667
+			echo self::$nl . ' . . registration->status_ID: ' . $registration->status_ID();
668
+			echo self::$nl . ' . . transaction->status_ID(): ' . $STS_ID;
669
+		}
670
+		if (
671
+			// release Tickets for Failed Transactions and Abandoned Transactions
672
+			$STS_ID === EEM_Transaction::failed_status_code
673
+			|| $STS_ID === EEM_Transaction::abandoned_status_code
674
+			|| (
675
+				// also release Tickets for Incomplete Transactions, but ONLY if the Registrations are NOT Approved
676
+				$STS_ID === EEM_Transaction::incomplete_status_code
677
+				&& $registration->status_ID() !== EEM_Registration::status_id_approved
678
+			)
679
+		) {
680
+			if (self::debug) {
681
+				echo self::$nl . self::$nl . ' . . RELEASE RESERVED TICKET';
682
+				$rsrvd = $registration->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true);
683
+				echo self::$nl . ' . . . registration HAS_RESERVED_TICKET_KEY: ';
684
+				var_dump($rsrvd);
685
+			}
686
+			$registration->release_reserved_ticket(true, 'TicketSalesMonitor:'. __LINE__);
687
+			return 1;
688
+		}
689
+		return 0;
690
+	}
691
+
692
+
693
+
694
+	/********************************** SESSION_CART_RESET  **********************************/
695
+
696
+
697
+
698
+	/**
699
+	 * callback hooked into 'AHEE__EE_Session__reset_cart__before_reset'
700
+	 *
701
+	 * @param EE_Session $session
702
+	 * @return void
703
+	 * @throws EE_Error
704
+	 * @throws InvalidArgumentException
705
+	 * @throws ReflectionException
706
+	 * @throws InvalidDataTypeException
707
+	 * @throws InvalidInterfaceException
708
+	 */
709
+	public static function session_cart_reset(EE_Session $session)
710
+	{
711
+		if (self::debug) {
712
+			echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
713
+		}
714
+		// first check of the session has a valid Checkout object
715
+		$checkout = $session->checkout();
716
+		if ($checkout instanceof EE_Checkout) {
717
+			// and use that to clear ticket reservations because it will update the associated registration meta data
718
+			EED_Ticket_Sales_Monitor::instance()->_session_checkout_reset($checkout);
719
+			return;
720
+		}
721
+		$cart = $session->cart();
722
+		if ($cart instanceof EE_Cart) {
723
+			if (self::debug) {
724
+				echo self::$nl . self::$nl . ' cart instance of EE_Cart: ';
725
+			}
726
+			EED_Ticket_Sales_Monitor::instance()->_session_cart_reset($cart, $session);
727
+		} else {
728
+			if (self::debug) {
729
+				echo self::$nl . self::$nl . ' invalid EE_Cart: ';
730
+				var_export($cart, true);
731
+			}
732
+		}
733
+	}
734
+
735
+
736
+
737
+	/**
738
+	 * releases reserved tickets in the EE_Cart
739
+	 *
740
+	 * @param EE_Cart $cart
741
+	 * @return void
742
+	 * @throws EE_Error
743
+	 * @throws InvalidArgumentException
744
+	 * @throws ReflectionException
745
+	 * @throws InvalidDataTypeException
746
+	 * @throws InvalidInterfaceException
747
+	 */
748
+	protected function _session_cart_reset(EE_Cart $cart, EE_Session $session)
749
+	{
750
+		if (self::debug) {
751
+			echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
752
+		}
753
+		EE_Registry::instance()->load_helper('Line_Item');
754
+		$ticket_line_items = $cart->get_tickets();
755
+		if (empty($ticket_line_items)) {
756
+			return;
757
+		}
758
+		foreach ($ticket_line_items as $ticket_line_item) {
759
+			if (self::debug) {
760
+				echo self::$nl . ' . ticket_line_item->ID(): ' . $ticket_line_item->ID();
761
+			}
762
+			if ($ticket_line_item instanceof EE_Line_Item && $ticket_line_item->OBJ_type() === 'Ticket') {
763
+				if (self::debug) {
764
+					echo self::$nl . ' . . ticket_line_item->OBJ_ID(): ' . $ticket_line_item->OBJ_ID();
765
+				}
766
+				$ticket = EEM_Ticket::instance()->get_one_by_ID($ticket_line_item->OBJ_ID());
767
+				if ($ticket instanceof EE_Ticket) {
768
+					if (self::debug) {
769
+						echo self::$nl . ' . . ticket->ID(): ' . $ticket->ID();
770
+						echo self::$nl . ' . . ticket_line_item->quantity(): ' . $ticket_line_item->quantity();
771
+					}
772
+					$ticket->add_extra_meta(
773
+						EE_Ticket::META_KEY_TICKET_RESERVATIONS,
774
+						__LINE__ . ') ' . __METHOD__ . '() SID = ' . $session->id()
775
+					);
776
+					$this->_release_reserved_ticket($ticket, $ticket_line_item->quantity());
777
+				}
778
+			}
779
+		}
780
+		if (self::debug) {
781
+			echo self::$nl . self::$nl . ' RESET COMPLETED ';
782
+		}
783
+	}
784
+
785
+
786
+
787
+	/********************************** SESSION_CHECKOUT_RESET  **********************************/
788
+
789
+
790
+
791
+	/**
792
+	 * callback hooked into 'AHEE__EE_Session__reset_checkout__before_reset'
793
+	 *
794
+	 * @param EE_Session $session
795
+	 * @return void
796
+	 * @throws EE_Error
797
+	 * @throws InvalidSessionDataException
798
+	 */
799
+	public static function session_checkout_reset(EE_Session $session)
800
+	{
801
+		$checkout = $session->checkout();
802
+		if ($checkout instanceof EE_Checkout) {
803
+			EED_Ticket_Sales_Monitor::instance()->_session_checkout_reset($checkout);
804
+		}
805
+	}
806
+
807
+
808
+
809
+	/**
810
+	 * releases reserved tickets for the EE_Checkout->transaction
811
+	 *
812
+	 * @param EE_Checkout $checkout
813
+	 * @return void
814
+	 * @throws EE_Error
815
+	 * @throws InvalidSessionDataException
816
+	 */
817
+	protected function _session_checkout_reset(EE_Checkout $checkout)
818
+	{
819
+		if (self::debug) {
820
+			echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
821
+		}
822
+		// we want to release the each registration's reserved tickets if the session was cleared, but not if this is a revisit
823
+		if ($checkout->revisit || ! $checkout->transaction instanceof EE_Transaction) {
824
+			return;
825
+		}
826
+		$this->_release_all_reserved_tickets_for_transaction($checkout->transaction);
827
+	}
828
+
829
+
830
+
831
+	/********************************** SESSION_EXPIRED_RESET  **********************************/
832
+
833
+
834
+
835
+	/**
836
+	 * @param    EE_Session $session
837
+	 * @return    void
838
+	 */
839
+	public static function session_expired_reset(EE_Session $session)
840
+	{
841
+	}
842
+
843
+
844
+
845
+	/********************************** PROCESS_ABANDONED_TRANSACTIONS  **********************************/
846
+
847
+
848
+
849
+	/**
850
+	 * releases reserved tickets for all registrations of an ABANDONED EE_Transaction
851
+	 * by default, will NOT release tickets for free transactions, or any that have received a payment
852
+	 *
853
+	 * @param EE_Transaction $transaction
854
+	 * @return void
855
+	 * @throws EE_Error
856
+	 * @throws InvalidSessionDataException
857
+	 */
858
+	public static function process_abandoned_transactions(EE_Transaction $transaction)
859
+	{
860
+		// is this TXN free or has any money been paid towards this TXN? If so, then leave it alone
861
+		if ($transaction->is_free() || $transaction->paid() > 0) {
862
+			if (self::debug) {
863
+				// DEBUG LOG
864
+				EEH_Debug_Tools::log(
865
+					__CLASS__,
866
+					__FUNCTION__,
867
+					__LINE__,
868
+					array($transaction),
869
+					false,
870
+					'EE_Transaction: ' . $transaction->ID()
871
+				);
872
+			}
873
+			return;
874
+		}
875
+		// have their been any successful payments made ?
876
+		$payments = $transaction->payments();
877
+		foreach ($payments as $payment) {
878
+			if ($payment instanceof EE_Payment && $payment->status() === EEM_Payment::status_id_approved) {
879
+				if (self::debug) {
880
+					// DEBUG LOG
881
+					EEH_Debug_Tools::log(
882
+						__CLASS__,
883
+						__FUNCTION__,
884
+						__LINE__,
885
+						array($payment),
886
+						false,
887
+						'EE_Transaction: ' . $transaction->ID()
888
+					);
889
+				}
890
+				return;
891
+			}
892
+		}
893
+		// since you haven't even attempted to pay for your ticket...
894
+		EED_Ticket_Sales_Monitor::instance()->_release_all_reserved_tickets_for_transaction($transaction);
895
+	}
896
+
897
+
898
+
899
+	/********************************** PROCESS_FAILED_TRANSACTIONS  **********************************/
900
+
901
+
902
+
903
+	/**
904
+	 * releases reserved tickets for absolutely ALL registrations of a FAILED EE_Transaction
905
+	 *
906
+	 * @param EE_Transaction $transaction
907
+	 * @return void
908
+	 * @throws EE_Error
909
+	 * @throws InvalidSessionDataException
910
+	 */
911
+	public static function process_failed_transactions(EE_Transaction $transaction)
912
+	{
913
+		// since you haven't even attempted to pay for your ticket...
914
+		EED_Ticket_Sales_Monitor::instance()->_release_all_reserved_tickets_for_transaction($transaction);
915
+	}
916
+
917
+
918
+
919
+	/********************************** RESET RESERVATION COUNTS  *********************************/
920
+
921
+
922
+
923
+	/**
924
+	 * Resets all ticket and datetime reserved counts to zero
925
+	 * Tickets that are currently associated with a Transaction that is in progress
926
+	 *
927
+	 * @throws EE_Error
928
+	 * @throws DomainException
929
+	 * @throws InvalidDataTypeException
930
+	 * @throws InvalidInterfaceException
931
+	 * @throws InvalidArgumentException
932
+	 * @throws UnexpectedEntityException
933
+	 */
934
+	public static function reset_reservation_counts()
935
+	{
936
+		/** @var EE_Line_Item[] $valid_reserved_tickets */
937
+		$valid_reserved_tickets = array();
938
+		/** @var EE_Transaction[] $transactions_not_in_progress */
939
+		$transactions_not_in_progress = EEM_Transaction::instance()->get_transactions_not_in_progress();
940
+		foreach ($transactions_not_in_progress as $transaction) {
941
+			// if this TXN has been fully completed, then skip it
942
+			if ($transaction->reg_step_completed('finalize_registration')) {
943
+				continue;
944
+			}
945
+			$total_line_item = $transaction->total_line_item();
946
+			// $transaction_in_progress->line
947
+			if (! $total_line_item instanceof EE_Line_Item) {
948
+				throw new DomainException(
949
+					esc_html__(
950
+						'Transaction does not have a valid Total Line Item associated with it.',
951
+						'event_espresso'
952
+					)
953
+				);
954
+			}
955
+			$valid_reserved_tickets += EED_Ticket_Sales_Monitor::get_ticket_line_items_for_grand_total(
956
+				$total_line_item
957
+			);
958
+		}
959
+		$total_line_items = EEM_Line_Item::instance()->get_total_line_items_for_active_carts();
960
+		foreach ($total_line_items as $total_line_item) {
961
+			$valid_reserved_tickets += EED_Ticket_Sales_Monitor::get_ticket_line_items_for_grand_total(
962
+				$total_line_item
963
+			);
964
+		}
965
+		$tickets_with_reservations = EEM_Ticket::instance()->get_tickets_with_reservations();
966
+		return EED_Ticket_Sales_Monitor::release_reservations_for_tickets(
967
+			$tickets_with_reservations,
968
+			$valid_reserved_tickets,
969
+			__FUNCTION__
970
+		);
971
+	}
972
+
973
+
974
+
975
+	/**
976
+	 * @param EE_Line_Item $total_line_item
977
+	 * @return EE_Line_Item[]
978
+	 */
979
+	private static function get_ticket_line_items_for_grand_total(EE_Line_Item $total_line_item)
980
+	{
981
+		/** @var EE_Line_Item[] $valid_reserved_tickets */
982
+		$valid_reserved_tickets = array();
983
+		$ticket_line_items      = EEH_Line_Item::get_ticket_line_items($total_line_item);
984
+		foreach ($ticket_line_items as $ticket_line_item) {
985
+			if ($ticket_line_item instanceof EE_Line_Item) {
986
+				$valid_reserved_tickets[] = $ticket_line_item;
987
+			}
988
+		}
989
+		return $valid_reserved_tickets;
990
+	}
991
+
992
+
993
+
994
+	/**
995
+	 * @param EE_Ticket[]    $tickets_with_reservations
996
+	 * @param EE_Line_Item[] $valid_reserved_ticket_line_items
997
+	 * @return int
998
+	 * @throws UnexpectedEntityException
999
+	 * @throws DomainException
1000
+	 * @throws EE_Error
1001
+	 */
1002
+	private static function release_reservations_for_tickets(
1003
+		array $tickets_with_reservations,
1004
+		array $valid_reserved_ticket_line_items = array(),
1005
+		$source
1006
+	) {
1007
+		if (self::debug) {
1008
+			echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '()';
1009
+		}
1010
+		$total_tickets_released = 0;
1011
+		$sold_out_events = array();
1012
+		foreach ($tickets_with_reservations as $ticket_with_reservations) {
1013
+			if (! $ticket_with_reservations instanceof EE_Ticket) {
1014
+				continue;
1015
+			}
1016
+			$reserved_qty = $ticket_with_reservations->reserved();
1017
+			if (self::debug) {
1018
+				echo self::$nl . ' . $ticket_with_reservations->ID(): ' . $ticket_with_reservations->ID();
1019
+				echo self::$nl . ' . $reserved_qty: ' . $reserved_qty;
1020
+			}
1021
+			foreach ($valid_reserved_ticket_line_items as $valid_reserved_ticket_line_item) {
1022
+				if (
1023
+					$valid_reserved_ticket_line_item instanceof EE_Line_Item
1024
+					&& $valid_reserved_ticket_line_item->OBJ_ID() === $ticket_with_reservations->ID()
1025
+				) {
1026
+					if (self::debug) {
1027
+						echo self::$nl . ' . $valid_reserved_ticket_line_item->quantity(): ' . $valid_reserved_ticket_line_item->quantity();
1028
+					}
1029
+					$reserved_qty -= $valid_reserved_ticket_line_item->quantity();
1030
+				}
1031
+			}
1032
+			if ($reserved_qty > 0) {
1033
+				$ticket_with_reservations->add_extra_meta(
1034
+					EE_Ticket::META_KEY_TICKET_RESERVATIONS,
1035
+					__LINE__ . ') ' . $source . '()'
1036
+				);
1037
+				$ticket_with_reservations->decrease_reserved($reserved_qty, true, 'TicketSalesMonitor:'. __LINE__);
1038
+				$ticket_with_reservations->save();
1039
+				$total_tickets_released += $reserved_qty;
1040
+				$event = $ticket_with_reservations->get_related_event();
1041
+				// track sold out events
1042
+				if ($event instanceof EE_Event && $event->is_sold_out()) {
1043
+					$sold_out_events[] = $event;
1044
+				}
1045
+			}
1046
+		}
1047
+		if (self::debug) {
1048
+			echo self::$nl . ' . $total_tickets_released: ' . $total_tickets_released;
1049
+		}
1050
+		// double check whether sold out events should remain sold out after releasing tickets
1051
+		if($sold_out_events !== array()){
1052
+			foreach ($sold_out_events as $sold_out_event) {
1053
+				/** @var EE_Event $sold_out_event */
1054
+				$sold_out_event->perform_sold_out_status_check();
1055
+			}
1056
+		}
1057
+		return $total_tickets_released;
1058
+	}
1059
+
1060
+
1061
+
1062
+	/********************************** SHUTDOWN  **********************************/
1063
+
1064
+
1065
+
1066
+	/**
1067
+	 * @param int $timestamp
1068
+	 * @return false|int
1069
+	 * @throws EE_Error
1070
+	 * @throws InvalidArgumentException
1071
+	 * @throws InvalidDataTypeException
1072
+	 * @throws InvalidInterfaceException
1073
+	 */
1074
+	public static function clear_expired_line_items_with_no_transaction($timestamp = 0)
1075
+	{
1076
+	   /** @type WPDB $wpdb */
1077
+		global $wpdb;
1078
+		if (! absint($timestamp)) {
1079
+			/** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */
1080
+			$session_lifespan = LoaderFactory::getLoader()->getShared(
1081
+				'EventEspresso\core\domain\values\session\SessionLifespan'
1082
+			);
1083
+			$timestamp = $session_lifespan->expiration();
1084
+		}
1085
+		 return $wpdb->query(
1086
+			$wpdb->prepare(
1087
+				'DELETE FROM ' . EEM_Line_Item::instance()->table() . '
1088 1088
                 WHERE TXN_ID = 0 AND LIN_timestamp <= %s',
1089
-                // use GMT time because that's what LIN_timestamps are in
1090
-                date('Y-m-d H:i:s', $timestamp)
1091
-            )
1092
-        );
1093
-    }
1089
+				// use GMT time because that's what LIN_timestamps are in
1090
+				date('Y-m-d H:i:s', $timestamp)
1091
+			)
1092
+		);
1093
+	}
1094 1094
 
1095 1095
 }
1096 1096
 // End of file EED_Ticket_Sales_Monitor.module.php
Please login to merge, or discard this patch.
Spacing   +86 added lines, -86 removed lines patch added patch discarded remove patch
@@ -24,7 +24,7 @@  discard block
 block discarded – undo
24 24
 class EED_Ticket_Sales_Monitor extends EED_Module
25 25
 {
26 26
 
27
-    const debug = false;    //	true false
27
+    const debug = false; //	true false
28 28
 
29 29
     private static $nl = '';
30 30
 
@@ -67,7 +67,7 @@  discard block
 block discarded – undo
67 67
      */
68 68
     public static function set_hooks()
69 69
     {
70
-        self::$nl = defined('EE_TESTS_DIR')? "\n" : '<br />';
70
+        self::$nl = defined('EE_TESTS_DIR') ? "\n" : '<br />';
71 71
         // release tickets for expired carts
72 72
         add_action(
73 73
             'EED_Ticket_Selector__process_ticket_selections__before',
@@ -196,7 +196,7 @@  discard block
 block discarded – undo
196 196
     public static function release_tickets_for_expired_carts()
197 197
     {
198 198
         if (self::debug) {
199
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '()';
199
+            echo self::$nl.self::$nl.__LINE__.') '.__METHOD__.'()';
200 200
         }
201 201
         do_action('AHEE__EED_Ticket_Sales_Monitor__release_tickets_for_expired_carts__begin');
202 202
         $expired_ticket_IDs = array();
@@ -207,26 +207,26 @@  discard block
 block discarded – undo
207 207
         $timestamp = $session_lifespan->expiration();
208 208
         $expired_ticket_line_items = EEM_Line_Item::instance()->getTicketLineItemsForExpiredCarts($timestamp);
209 209
         if (self::debug) {
210
-            echo self::$nl . ' . time(): ' . time();
211
-            echo self::$nl . ' . time() as date: ' . date('Y-m-d H:i a');
212
-            echo self::$nl . ' . session expiration: ' . $session_lifespan->expiration();
213
-            echo self::$nl . ' . session expiration as date: ' . date('Y-m-d H:i a', $session_lifespan->expiration());
214
-            echo self::$nl . ' . timestamp: ' . $timestamp;
215
-            echo self::$nl . ' . $expired_ticket_line_items: ' . count($expired_ticket_line_items);
210
+            echo self::$nl.' . time(): '.time();
211
+            echo self::$nl.' . time() as date: '.date('Y-m-d H:i a');
212
+            echo self::$nl.' . session expiration: '.$session_lifespan->expiration();
213
+            echo self::$nl.' . session expiration as date: '.date('Y-m-d H:i a', $session_lifespan->expiration());
214
+            echo self::$nl.' . timestamp: '.$timestamp;
215
+            echo self::$nl.' . $expired_ticket_line_items: '.count($expired_ticket_line_items);
216 216
         }
217
-        if (! empty($expired_ticket_line_items)) {
217
+        if ( ! empty($expired_ticket_line_items)) {
218 218
             foreach ($expired_ticket_line_items as $expired_ticket_line_item) {
219
-                if (! $expired_ticket_line_item instanceof EE_Line_Item) {
219
+                if ( ! $expired_ticket_line_item instanceof EE_Line_Item) {
220 220
                     continue;
221 221
                 }
222
-                $expired_ticket_IDs[ $expired_ticket_line_item->OBJ_ID() ] = $expired_ticket_line_item->OBJ_ID();
222
+                $expired_ticket_IDs[$expired_ticket_line_item->OBJ_ID()] = $expired_ticket_line_item->OBJ_ID();
223 223
                 if (self::debug) {
224
-                    echo self::$nl . ' . $expired_ticket_line_item->OBJ_ID(): ' . $expired_ticket_line_item->OBJ_ID();
225
-                    echo self::$nl . ' . $expired_ticket_line_item->timestamp(): ' . date('Y-m-d h:i a',
224
+                    echo self::$nl.' . $expired_ticket_line_item->OBJ_ID(): '.$expired_ticket_line_item->OBJ_ID();
225
+                    echo self::$nl.' . $expired_ticket_line_item->timestamp(): '.date('Y-m-d h:i a',
226 226
                             $expired_ticket_line_item->timestamp(true));
227 227
                 }
228 228
             }
229
-            if (! empty($expired_ticket_IDs)) {
229
+            if ( ! empty($expired_ticket_IDs)) {
230 230
                 EED_Ticket_Sales_Monitor::release_reservations_for_tickets(
231 231
                     \EEM_Ticket::instance()->get_tickets_with_IDs($expired_ticket_IDs),
232 232
                     array(),
@@ -265,8 +265,8 @@  discard block
 block discarded – undo
265 265
             $qty = EED_Ticket_Sales_Monitor::instance()->_validate_ticket_sale($ticket, $qty);
266 266
         }
267 267
         if (self::debug) {
268
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '()';
269
-            echo self::$nl . self::$nl . '<b> RETURNED QTY: ' . $qty . '</b>';
268
+            echo self::$nl.self::$nl.__LINE__.') '.__METHOD__.'()';
269
+            echo self::$nl.self::$nl.'<b> RETURNED QTY: '.$qty.'</b>';
270 270
         }
271 271
         return $qty;
272 272
     }
@@ -285,36 +285,36 @@  discard block
 block discarded – undo
285 285
     protected function _validate_ticket_sale(EE_Ticket $ticket, $qty = 1)
286 286
     {
287 287
         if (self::debug) {
288
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
288
+            echo self::$nl.self::$nl.__LINE__.') '.__METHOD__.'() ';
289 289
         }
290
-        if (! $ticket instanceof EE_Ticket) {
290
+        if ( ! $ticket instanceof EE_Ticket) {
291 291
             return 0;
292 292
         }
293 293
         if (self::debug) {
294
-            echo self::$nl . '<b> . ticket->ID: ' . $ticket->ID() . '</b>';
295
-            echo self::$nl . ' . original ticket->reserved: ' . $ticket->reserved();
294
+            echo self::$nl.'<b> . ticket->ID: '.$ticket->ID().'</b>';
295
+            echo self::$nl.' . original ticket->reserved: '.$ticket->reserved();
296 296
         }
297 297
         $ticket->refresh_from_db();
298 298
         // first let's determine the ticket availability based on sales
299 299
         $available = $ticket->qty('saleable');
300 300
         if (self::debug) {
301
-            echo self::$nl . ' . . . ticket->qty: ' . $ticket->qty();
302
-            echo self::$nl . ' . . . ticket->sold: ' . $ticket->sold();
303
-            echo self::$nl . ' . . . ticket->reserved: ' . $ticket->reserved();
304
-            echo self::$nl . ' . . . ticket->qty(saleable): ' . $ticket->qty('saleable');
305
-            echo self::$nl . ' . . . available: ' . $available;
301
+            echo self::$nl.' . . . ticket->qty: '.$ticket->qty();
302
+            echo self::$nl.' . . . ticket->sold: '.$ticket->sold();
303
+            echo self::$nl.' . . . ticket->reserved: '.$ticket->reserved();
304
+            echo self::$nl.' . . . ticket->qty(saleable): '.$ticket->qty('saleable');
305
+            echo self::$nl.' . . . available: '.$available;
306 306
         }
307 307
         if ($available < 1) {
308 308
             $this->_ticket_sold_out($ticket);
309 309
             return 0;
310 310
         }
311 311
         if (self::debug) {
312
-            echo self::$nl . ' . . . qty: ' . $qty;
312
+            echo self::$nl.' . . . qty: '.$qty;
313 313
         }
314 314
         if ($available < $qty) {
315 315
             $qty = $available;
316 316
             if (self::debug) {
317
-                echo self::$nl . ' . . . QTY ADJUSTED: ' . $qty;
317
+                echo self::$nl.' . . . QTY ADJUSTED: '.$qty;
318 318
             }
319 319
             $this->_ticket_quantity_decremented($ticket);
320 320
         }
@@ -335,9 +335,9 @@  discard block
 block discarded – undo
335 335
     protected function _reserve_ticket(EE_Ticket $ticket, $quantity = 1)
336 336
     {
337 337
         if (self::debug) {
338
-            echo self::$nl . self::$nl . ' . . . INCREASE RESERVED: ' . $quantity;
338
+            echo self::$nl.self::$nl.' . . . INCREASE RESERVED: '.$quantity;
339 339
         }
340
-        $ticket->increase_reserved($quantity, 'TicketSalesMonitor:'. __LINE__);
340
+        $ticket->increase_reserved($quantity, 'TicketSalesMonitor:'.__LINE__);
341 341
         return $ticket->save();
342 342
     }
343 343
 
@@ -352,12 +352,12 @@  discard block
 block discarded – undo
352 352
     protected function _release_reserved_ticket(EE_Ticket $ticket, $quantity = 1)
353 353
     {
354 354
         if (self::debug) {
355
-            echo self::$nl . ' . . . ticket->ID: ' . $ticket->ID();
356
-            echo self::$nl . ' . . . ticket->reserved: ' . $ticket->reserved();
355
+            echo self::$nl.' . . . ticket->ID: '.$ticket->ID();
356
+            echo self::$nl.' . . . ticket->reserved: '.$ticket->reserved();
357 357
         }
358
-        $ticket->decrease_reserved($quantity, true, 'TicketSalesMonitor:'. __LINE__);
358
+        $ticket->decrease_reserved($quantity, true, 'TicketSalesMonitor:'.__LINE__);
359 359
         if (self::debug) {
360
-            echo self::$nl . ' . . . ticket->reserved: ' . $ticket->reserved();
360
+            echo self::$nl.' . . . ticket->reserved: '.$ticket->reserved();
361 361
         }
362 362
         return $ticket->save() ? 1 : 0;
363 363
     }
@@ -375,8 +375,8 @@  discard block
 block discarded – undo
375 375
     protected function _ticket_sold_out(EE_Ticket $ticket)
376 376
     {
377 377
         if (self::debug) {
378
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
379
-            echo self::$nl . ' . . ticket->name: ' . $this->_get_ticket_and_event_name($ticket);
378
+            echo self::$nl.self::$nl.__LINE__.') '.__METHOD__.'() ';
379
+            echo self::$nl.' . . ticket->name: '.$this->_get_ticket_and_event_name($ticket);
380 380
         }
381 381
         $this->sold_out_tickets[] = $this->_get_ticket_and_event_name($ticket);
382 382
     }
@@ -394,8 +394,8 @@  discard block
 block discarded – undo
394 394
     protected function _ticket_quantity_decremented(EE_Ticket $ticket)
395 395
     {
396 396
         if (self::debug) {
397
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
398
-            echo self::$nl . ' . . ticket->name: ' . $this->_get_ticket_and_event_name($ticket);
397
+            echo self::$nl.self::$nl.__LINE__.') '.__METHOD__.'() ';
398
+            echo self::$nl.' . . ticket->name: '.$this->_get_ticket_and_event_name($ticket);
399 399
         }
400 400
         $this->decremented_tickets[] = $this->_get_ticket_and_event_name($ticket);
401 401
     }
@@ -448,7 +448,7 @@  discard block
 block discarded – undo
448 448
         if ($ticket instanceof EE_Ticket) {
449 449
             $ticket->add_extra_meta(
450 450
                 EE_Ticket::META_KEY_TICKET_RESERVATIONS,
451
-                __LINE__ . ') ' . __METHOD__ . '()'
451
+                __LINE__.') '.__METHOD__.'()'
452 452
             );
453 453
             if ($quantity > 0) {
454 454
                 EED_Ticket_Sales_Monitor::instance()->_reserve_ticket($ticket, $quantity);
@@ -472,7 +472,7 @@  discard block
 block discarded – undo
472 472
     {
473 473
         $ticket->add_extra_meta(
474 474
             EE_Ticket::META_KEY_TICKET_RESERVATIONS,
475
-            __LINE__ . ') ' . __METHOD__ . '()'
475
+            __LINE__.') '.__METHOD__.'()'
476 476
         );
477 477
         EED_Ticket_Sales_Monitor::instance()->_release_reserved_ticket($ticket, $quantity);
478 478
     }
@@ -509,18 +509,18 @@  discard block
 block discarded – undo
509 509
     protected function _post_notices()
510 510
     {
511 511
         if (self::debug) {
512
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
512
+            echo self::$nl.self::$nl.__LINE__.') '.__METHOD__.'() ';
513 513
         }
514 514
         $refresh_msg    = '';
515 515
         $none_added_msg = '';
516 516
         if (defined('DOING_AJAX') && DOING_AJAX) {
517
-            $refresh_msg    = __(
517
+            $refresh_msg = __(
518 518
                 'Please refresh the page to view updated ticket quantities.',
519 519
                 'event_espresso'
520 520
             );
521 521
             $none_added_msg = __('No tickets were added for the event.', 'event_espresso');
522 522
         }
523
-        if (! empty($this->sold_out_tickets)) {
523
+        if ( ! empty($this->sold_out_tickets)) {
524 524
             EE_Error::add_attention(
525 525
                 sprintf(
526 526
                     apply_filters(
@@ -543,7 +543,7 @@  discard block
 block discarded – undo
543 543
             // and reset the cart
544 544
             EED_Ticket_Sales_Monitor::session_cart_reset(EE_Registry::instance()->SSN);
545 545
         }
546
-        if (! empty($this->decremented_tickets)) {
546
+        if ( ! empty($this->decremented_tickets)) {
547 547
             EE_Error::add_attention(
548 548
                 sprintf(
549 549
                     apply_filters(
@@ -581,9 +581,9 @@  discard block
 block discarded – undo
581 581
     protected function _release_all_reserved_tickets_for_transaction(EE_Transaction $transaction)
582 582
     {
583 583
         if (self::debug) {
584
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
585
-            echo self::$nl . ' . transaction->ID: ' . $transaction->ID();
586
-            echo self::$nl . ' . TXN status_ID: ' . $transaction->status_ID();
584
+            echo self::$nl.self::$nl.__LINE__.') '.__METHOD__.'() ';
585
+            echo self::$nl.' . transaction->ID: '.$transaction->ID();
586
+            echo self::$nl.' . TXN status_ID: '.$transaction->status_ID();
587 587
         }
588 588
         // check if 'finalize_registration' step has been completed...
589 589
         $finalized = $transaction->reg_step_completed('finalize_registration');
@@ -595,13 +595,13 @@  discard block
 block discarded – undo
595 595
                 __LINE__,
596 596
                 array('finalized' => $finalized),
597 597
                 false,
598
-                'EE_Transaction: ' . $transaction->ID()
598
+                'EE_Transaction: '.$transaction->ID()
599 599
             );
600 600
         }
601 601
         // how many tickets were released
602 602
         $count = 0;
603 603
         if (self::debug) {
604
-            echo self::$nl . ' . . . TXN finalized: ' . $finalized;
604
+            echo self::$nl.' . . . TXN finalized: '.$finalized;
605 605
         }
606 606
         $release_tickets_with_TXN_status = array(
607 607
             EEM_Transaction::failed_status_code,
@@ -610,28 +610,28 @@  discard block
 block discarded – undo
610 610
         );
611 611
         $events = array();
612 612
         // if the session is getting cleared BEFORE the TXN has been finalized or the transaction is not completed
613
-        if (! $finalized || in_array($transaction->status_ID(), $release_tickets_with_TXN_status, true)) {
613
+        if ( ! $finalized || in_array($transaction->status_ID(), $release_tickets_with_TXN_status, true)) {
614 614
             // cancel any reserved tickets for registrations that were not approved
615 615
             $registrations = $transaction->registrations();
616 616
             if (self::debug) {
617
-                echo self::$nl . ' . . . # registrations: ' . count($registrations);
617
+                echo self::$nl.' . . . # registrations: '.count($registrations);
618 618
                 $reg    = reset($registrations);
619 619
                 $ticket = $reg->ticket();
620 620
                 if ($ticket instanceof EE_Ticket) {
621 621
                     $ticket->add_extra_meta(
622 622
                         EE_Ticket::META_KEY_TICKET_RESERVATIONS,
623
-                        __LINE__ . ') Release All Tickets TXN:' . $transaction->ID()
623
+                        __LINE__.') Release All Tickets TXN:'.$transaction->ID()
624 624
                     );
625 625
                 }
626 626
             }
627
-            if (! empty($registrations)) {
627
+            if ( ! empty($registrations)) {
628 628
                 foreach ($registrations as $registration) {
629 629
                     if (
630 630
                         $registration instanceof EE_Registration
631 631
                         && $this->_release_reserved_ticket_for_registration($registration, $transaction)
632 632
                     ) {
633 633
                         $count++;
634
-                        $events[ $registration->event_ID() ] = $registration->event();
634
+                        $events[$registration->event_ID()] = $registration->event();
635 635
                     }
636 636
                 }
637 637
             }
@@ -662,10 +662,10 @@  discard block
 block discarded – undo
662 662
     ) {
663 663
         $STS_ID = $transaction->status_ID();
664 664
         if (self::debug) {
665
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
666
-            echo self::$nl . ' . . registration->ID: ' . $registration->ID();
667
-            echo self::$nl . ' . . registration->status_ID: ' . $registration->status_ID();
668
-            echo self::$nl . ' . . transaction->status_ID(): ' . $STS_ID;
665
+            echo self::$nl.self::$nl.__LINE__.') '.__METHOD__.'() ';
666
+            echo self::$nl.' . . registration->ID: '.$registration->ID();
667
+            echo self::$nl.' . . registration->status_ID: '.$registration->status_ID();
668
+            echo self::$nl.' . . transaction->status_ID(): '.$STS_ID;
669 669
         }
670 670
         if (
671 671
             // release Tickets for Failed Transactions and Abandoned Transactions
@@ -678,12 +678,12 @@  discard block
 block discarded – undo
678 678
             )
679 679
         ) {
680 680
             if (self::debug) {
681
-                echo self::$nl . self::$nl . ' . . RELEASE RESERVED TICKET';
681
+                echo self::$nl.self::$nl.' . . RELEASE RESERVED TICKET';
682 682
                 $rsrvd = $registration->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true);
683
-                echo self::$nl . ' . . . registration HAS_RESERVED_TICKET_KEY: ';
683
+                echo self::$nl.' . . . registration HAS_RESERVED_TICKET_KEY: ';
684 684
                 var_dump($rsrvd);
685 685
             }
686
-            $registration->release_reserved_ticket(true, 'TicketSalesMonitor:'. __LINE__);
686
+            $registration->release_reserved_ticket(true, 'TicketSalesMonitor:'.__LINE__);
687 687
             return 1;
688 688
         }
689 689
         return 0;
@@ -709,7 +709,7 @@  discard block
 block discarded – undo
709 709
     public static function session_cart_reset(EE_Session $session)
710 710
     {
711 711
         if (self::debug) {
712
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
712
+            echo self::$nl.self::$nl.__LINE__.') '.__METHOD__.'() ';
713 713
         }
714 714
         // first check of the session has a valid Checkout object
715 715
         $checkout = $session->checkout();
@@ -721,12 +721,12 @@  discard block
 block discarded – undo
721 721
         $cart = $session->cart();
722 722
         if ($cart instanceof EE_Cart) {
723 723
             if (self::debug) {
724
-                echo self::$nl . self::$nl . ' cart instance of EE_Cart: ';
724
+                echo self::$nl.self::$nl.' cart instance of EE_Cart: ';
725 725
             }
726 726
             EED_Ticket_Sales_Monitor::instance()->_session_cart_reset($cart, $session);
727 727
         } else {
728 728
             if (self::debug) {
729
-                echo self::$nl . self::$nl . ' invalid EE_Cart: ';
729
+                echo self::$nl.self::$nl.' invalid EE_Cart: ';
730 730
                 var_export($cart, true);
731 731
             }
732 732
         }
@@ -748,7 +748,7 @@  discard block
 block discarded – undo
748 748
     protected function _session_cart_reset(EE_Cart $cart, EE_Session $session)
749 749
     {
750 750
         if (self::debug) {
751
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
751
+            echo self::$nl.self::$nl.__LINE__.') '.__METHOD__.'() ';
752 752
         }
753 753
         EE_Registry::instance()->load_helper('Line_Item');
754 754
         $ticket_line_items = $cart->get_tickets();
@@ -757,28 +757,28 @@  discard block
 block discarded – undo
757 757
         }
758 758
         foreach ($ticket_line_items as $ticket_line_item) {
759 759
             if (self::debug) {
760
-                echo self::$nl . ' . ticket_line_item->ID(): ' . $ticket_line_item->ID();
760
+                echo self::$nl.' . ticket_line_item->ID(): '.$ticket_line_item->ID();
761 761
             }
762 762
             if ($ticket_line_item instanceof EE_Line_Item && $ticket_line_item->OBJ_type() === 'Ticket') {
763 763
                 if (self::debug) {
764
-                    echo self::$nl . ' . . ticket_line_item->OBJ_ID(): ' . $ticket_line_item->OBJ_ID();
764
+                    echo self::$nl.' . . ticket_line_item->OBJ_ID(): '.$ticket_line_item->OBJ_ID();
765 765
                 }
766 766
                 $ticket = EEM_Ticket::instance()->get_one_by_ID($ticket_line_item->OBJ_ID());
767 767
                 if ($ticket instanceof EE_Ticket) {
768 768
                     if (self::debug) {
769
-                        echo self::$nl . ' . . ticket->ID(): ' . $ticket->ID();
770
-                        echo self::$nl . ' . . ticket_line_item->quantity(): ' . $ticket_line_item->quantity();
769
+                        echo self::$nl.' . . ticket->ID(): '.$ticket->ID();
770
+                        echo self::$nl.' . . ticket_line_item->quantity(): '.$ticket_line_item->quantity();
771 771
                     }
772 772
                     $ticket->add_extra_meta(
773 773
                         EE_Ticket::META_KEY_TICKET_RESERVATIONS,
774
-                        __LINE__ . ') ' . __METHOD__ . '() SID = ' . $session->id()
774
+                        __LINE__.') '.__METHOD__.'() SID = '.$session->id()
775 775
                     );
776 776
                     $this->_release_reserved_ticket($ticket, $ticket_line_item->quantity());
777 777
                 }
778 778
             }
779 779
         }
780 780
         if (self::debug) {
781
-            echo self::$nl . self::$nl . ' RESET COMPLETED ';
781
+            echo self::$nl.self::$nl.' RESET COMPLETED ';
782 782
         }
783 783
     }
784 784
 
@@ -817,7 +817,7 @@  discard block
 block discarded – undo
817 817
     protected function _session_checkout_reset(EE_Checkout $checkout)
818 818
     {
819 819
         if (self::debug) {
820
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '() ';
820
+            echo self::$nl.self::$nl.__LINE__.') '.__METHOD__.'() ';
821 821
         }
822 822
         // we want to release the each registration's reserved tickets if the session was cleared, but not if this is a revisit
823 823
         if ($checkout->revisit || ! $checkout->transaction instanceof EE_Transaction) {
@@ -867,7 +867,7 @@  discard block
 block discarded – undo
867 867
                     __LINE__,
868 868
                     array($transaction),
869 869
                     false,
870
-                    'EE_Transaction: ' . $transaction->ID()
870
+                    'EE_Transaction: '.$transaction->ID()
871 871
                 );
872 872
             }
873 873
             return;
@@ -884,7 +884,7 @@  discard block
 block discarded – undo
884 884
                         __LINE__,
885 885
                         array($payment),
886 886
                         false,
887
-                        'EE_Transaction: ' . $transaction->ID()
887
+                        'EE_Transaction: '.$transaction->ID()
888 888
                     );
889 889
                 }
890 890
                 return;
@@ -944,7 +944,7 @@  discard block
 block discarded – undo
944 944
             }
945 945
             $total_line_item = $transaction->total_line_item();
946 946
             // $transaction_in_progress->line
947
-            if (! $total_line_item instanceof EE_Line_Item) {
947
+            if ( ! $total_line_item instanceof EE_Line_Item) {
948 948
                 throw new DomainException(
949 949
                     esc_html__(
950 950
                         'Transaction does not have a valid Total Line Item associated with it.',
@@ -1005,18 +1005,18 @@  discard block
 block discarded – undo
1005 1005
         $source
1006 1006
     ) {
1007 1007
         if (self::debug) {
1008
-            echo self::$nl . self::$nl . __LINE__ . ') ' . __METHOD__ . '()';
1008
+            echo self::$nl.self::$nl.__LINE__.') '.__METHOD__.'()';
1009 1009
         }
1010 1010
         $total_tickets_released = 0;
1011 1011
         $sold_out_events = array();
1012 1012
         foreach ($tickets_with_reservations as $ticket_with_reservations) {
1013
-            if (! $ticket_with_reservations instanceof EE_Ticket) {
1013
+            if ( ! $ticket_with_reservations instanceof EE_Ticket) {
1014 1014
                 continue;
1015 1015
             }
1016 1016
             $reserved_qty = $ticket_with_reservations->reserved();
1017 1017
             if (self::debug) {
1018
-                echo self::$nl . ' . $ticket_with_reservations->ID(): ' . $ticket_with_reservations->ID();
1019
-                echo self::$nl . ' . $reserved_qty: ' . $reserved_qty;
1018
+                echo self::$nl.' . $ticket_with_reservations->ID(): '.$ticket_with_reservations->ID();
1019
+                echo self::$nl.' . $reserved_qty: '.$reserved_qty;
1020 1020
             }
1021 1021
             foreach ($valid_reserved_ticket_line_items as $valid_reserved_ticket_line_item) {
1022 1022
                 if (
@@ -1024,7 +1024,7 @@  discard block
 block discarded – undo
1024 1024
                     && $valid_reserved_ticket_line_item->OBJ_ID() === $ticket_with_reservations->ID()
1025 1025
                 ) {
1026 1026
                     if (self::debug) {
1027
-                        echo self::$nl . ' . $valid_reserved_ticket_line_item->quantity(): ' . $valid_reserved_ticket_line_item->quantity();
1027
+                        echo self::$nl.' . $valid_reserved_ticket_line_item->quantity(): '.$valid_reserved_ticket_line_item->quantity();
1028 1028
                     }
1029 1029
                     $reserved_qty -= $valid_reserved_ticket_line_item->quantity();
1030 1030
                 }
@@ -1032,9 +1032,9 @@  discard block
 block discarded – undo
1032 1032
             if ($reserved_qty > 0) {
1033 1033
                 $ticket_with_reservations->add_extra_meta(
1034 1034
                     EE_Ticket::META_KEY_TICKET_RESERVATIONS,
1035
-                    __LINE__ . ') ' . $source . '()'
1035
+                    __LINE__.') '.$source.'()'
1036 1036
                 );
1037
-                $ticket_with_reservations->decrease_reserved($reserved_qty, true, 'TicketSalesMonitor:'. __LINE__);
1037
+                $ticket_with_reservations->decrease_reserved($reserved_qty, true, 'TicketSalesMonitor:'.__LINE__);
1038 1038
                 $ticket_with_reservations->save();
1039 1039
                 $total_tickets_released += $reserved_qty;
1040 1040
                 $event = $ticket_with_reservations->get_related_event();
@@ -1045,10 +1045,10 @@  discard block
 block discarded – undo
1045 1045
             }
1046 1046
         }
1047 1047
         if (self::debug) {
1048
-            echo self::$nl . ' . $total_tickets_released: ' . $total_tickets_released;
1048
+            echo self::$nl.' . $total_tickets_released: '.$total_tickets_released;
1049 1049
         }
1050 1050
         // double check whether sold out events should remain sold out after releasing tickets
1051
-        if($sold_out_events !== array()){
1051
+        if ($sold_out_events !== array()) {
1052 1052
             foreach ($sold_out_events as $sold_out_event) {
1053 1053
                 /** @var EE_Event $sold_out_event */
1054 1054
                 $sold_out_event->perform_sold_out_status_check();
@@ -1075,7 +1075,7 @@  discard block
 block discarded – undo
1075 1075
     {
1076 1076
        /** @type WPDB $wpdb */
1077 1077
         global $wpdb;
1078
-        if (! absint($timestamp)) {
1078
+        if ( ! absint($timestamp)) {
1079 1079
             /** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */
1080 1080
             $session_lifespan = LoaderFactory::getLoader()->getShared(
1081 1081
                 'EventEspresso\core\domain\values\session\SessionLifespan'
@@ -1084,7 +1084,7 @@  discard block
 block discarded – undo
1084 1084
         }
1085 1085
          return $wpdb->query(
1086 1086
             $wpdb->prepare(
1087
-                'DELETE FROM ' . EEM_Line_Item::instance()->table() . '
1087
+                'DELETE FROM '.EEM_Line_Item::instance()->table().'
1088 1088
                 WHERE TXN_ID = 0 AND LIN_timestamp <= %s',
1089 1089
                 // use GMT time because that's what LIN_timestamps are in
1090 1090
                 date('Y-m-d H:i:s', $timestamp)
Please login to merge, or discard this patch.
core/services/payment_methods/gateways/GatewayDataFormatter.php 1 patch
Indentation   +116 added lines, -116 removed lines patch added patch discarded remove patch
@@ -17,122 +17,122 @@
 block discarded – undo
17 17
 class GatewayDataFormatter implements GatewayDataFormatterInterface
18 18
 {
19 19
 
20
-    /**
21
-     * Gets the text to use for a gateway's line item name when this is a partial payment
22
-     *
23
-     * @param \EEI_Payment $payment
24
-     * @return string
25
-     */
26
-    public function formatPartialPaymentLineItemName(\EEI_Payment $payment)
27
-    {
28
-        return apply_filters(
29
-            'EEG_Paypal_Pro__do_direct_payment__partial_amount_line_item_name',
30
-            $payment->get_first_event_name(),
31
-            $this,
32
-            $payment
33
-        );
34
-    }
35
-
36
-
37
-
38
-    /**
39
-     * Gets the text to use for a gateway's line item description when this is a partial payment
40
-     *
41
-     * @param \EEI_Payment $payment
42
-     * @return string
43
-     */
44
-    public function formatPartialPaymentLineItemDesc(\EEI_Payment $payment)
45
-    {
46
-        return apply_filters(
47
-            'FHEE__EE_Gateway___partial_payment_desc',
48
-            sprintf(
49
-                __("Payment of %s for %s", "event_espresso"),
50
-                $payment->get_pretty('PAY_amount', 'no_currency_code'),
51
-                $payment->get_first_event_name()
52
-            ),
53
-            $this,
54
-            $payment
55
-        );
56
-    }
57
-
58
-
59
-
60
-    /**
61
-     * Gets the name to use for a line item when sending line items to the gateway
62
-     *
63
-     * @param \EEI_Line_Item $line_item
64
-     * @param \EEI_Payment   $payment
65
-     * @return string
66
-     */
67
-    public function formatLineItemName(\EEI_Line_Item $line_item, \EEI_Payment $payment)
68
-    {
69
-        return apply_filters(
70
-            'FHEE__EE_gateway___line_item_name',
71
-            sprintf(
72
-                _x('%1$s for %2$s', 'Ticket for Event', 'event_espresso'),
73
-                $line_item->name(),
74
-                $line_item->ticket_event_name()
75
-            ),
76
-            $this,
77
-            $line_item,
78
-            $payment
79
-        );
80
-    }
81
-
82
-
83
-
84
-    /**
85
-     * Gets the description to use for a line item when sending line items to the gateway
86
-     *
87
-     * @param \EEI_Line_Item $line_item
88
-     * @param \EEI_Payment   $payment
89
-     * @return string
90
-     */
91
-    public function formatLineItemDesc(\EEI_Line_Item $line_item, \EEI_Payment $payment)
92
-    {
93
-        return apply_filters(
94
-            'FHEE__EE_Gateway___line_item_desc',
95
-            $line_item->desc(),
96
-            $this,
97
-            $line_item,
98
-            $payment
99
-        );
100
-    }
101
-
102
-
103
-
104
-    /**
105
-     * Gets the order description that should generally be sent to gateways
106
-     *
107
-     * @param \EEI_Payment $payment
108
-     * @return string
109
-     */
110
-    public function formatOrderDescription(\EEI_Payment $payment)
111
-    {
112
-        return apply_filters(
113
-            'FHEE__EE_Gateway___order_description',
114
-            sprintf(
115
-                __('Event Registrations from %1$s for %2$s', "event_espresso"),
116
-                wp_specialchars_decode(get_bloginfo(), ENT_QUOTES),
117
-                $payment->get_first_event_name()
118
-            ),
119
-            $this,
120
-            $payment
121
-        );
122
-    }
123
-
124
-
125
-
126
-    /**
127
-     * Formats the amount so it can generally be sent to gateways
128
-     *
129
-     * @param float $amount
130
-     * @return string
131
-     */
132
-    public function formatCurrency($amount)
133
-    {
134
-        return number_format($amount, 2, '.', '');
135
-    }
20
+	/**
21
+	 * Gets the text to use for a gateway's line item name when this is a partial payment
22
+	 *
23
+	 * @param \EEI_Payment $payment
24
+	 * @return string
25
+	 */
26
+	public function formatPartialPaymentLineItemName(\EEI_Payment $payment)
27
+	{
28
+		return apply_filters(
29
+			'EEG_Paypal_Pro__do_direct_payment__partial_amount_line_item_name',
30
+			$payment->get_first_event_name(),
31
+			$this,
32
+			$payment
33
+		);
34
+	}
35
+
36
+
37
+
38
+	/**
39
+	 * Gets the text to use for a gateway's line item description when this is a partial payment
40
+	 *
41
+	 * @param \EEI_Payment $payment
42
+	 * @return string
43
+	 */
44
+	public function formatPartialPaymentLineItemDesc(\EEI_Payment $payment)
45
+	{
46
+		return apply_filters(
47
+			'FHEE__EE_Gateway___partial_payment_desc',
48
+			sprintf(
49
+				__("Payment of %s for %s", "event_espresso"),
50
+				$payment->get_pretty('PAY_amount', 'no_currency_code'),
51
+				$payment->get_first_event_name()
52
+			),
53
+			$this,
54
+			$payment
55
+		);
56
+	}
57
+
58
+
59
+
60
+	/**
61
+	 * Gets the name to use for a line item when sending line items to the gateway
62
+	 *
63
+	 * @param \EEI_Line_Item $line_item
64
+	 * @param \EEI_Payment   $payment
65
+	 * @return string
66
+	 */
67
+	public function formatLineItemName(\EEI_Line_Item $line_item, \EEI_Payment $payment)
68
+	{
69
+		return apply_filters(
70
+			'FHEE__EE_gateway___line_item_name',
71
+			sprintf(
72
+				_x('%1$s for %2$s', 'Ticket for Event', 'event_espresso'),
73
+				$line_item->name(),
74
+				$line_item->ticket_event_name()
75
+			),
76
+			$this,
77
+			$line_item,
78
+			$payment
79
+		);
80
+	}
81
+
82
+
83
+
84
+	/**
85
+	 * Gets the description to use for a line item when sending line items to the gateway
86
+	 *
87
+	 * @param \EEI_Line_Item $line_item
88
+	 * @param \EEI_Payment   $payment
89
+	 * @return string
90
+	 */
91
+	public function formatLineItemDesc(\EEI_Line_Item $line_item, \EEI_Payment $payment)
92
+	{
93
+		return apply_filters(
94
+			'FHEE__EE_Gateway___line_item_desc',
95
+			$line_item->desc(),
96
+			$this,
97
+			$line_item,
98
+			$payment
99
+		);
100
+	}
101
+
102
+
103
+
104
+	/**
105
+	 * Gets the order description that should generally be sent to gateways
106
+	 *
107
+	 * @param \EEI_Payment $payment
108
+	 * @return string
109
+	 */
110
+	public function formatOrderDescription(\EEI_Payment $payment)
111
+	{
112
+		return apply_filters(
113
+			'FHEE__EE_Gateway___order_description',
114
+			sprintf(
115
+				__('Event Registrations from %1$s for %2$s', "event_espresso"),
116
+				wp_specialchars_decode(get_bloginfo(), ENT_QUOTES),
117
+				$payment->get_first_event_name()
118
+			),
119
+			$this,
120
+			$payment
121
+		);
122
+	}
123
+
124
+
125
+
126
+	/**
127
+	 * Formats the amount so it can generally be sent to gateways
128
+	 *
129
+	 * @param float $amount
130
+	 * @return string
131
+	 */
132
+	public function formatCurrency($amount)
133
+	{
134
+		return number_format($amount, 2, '.', '');
135
+	}
136 136
 }
137 137
 // End of file GatewayDataFormatter.php
138 138
 // Location: core\services\gateways/GatewayDataFormatter.php
139 139
\ No newline at end of file
Please login to merge, or discard this patch.