Completed
Pull Request — master (#881)
by
unknown
10:18
created
core/db_models/EEM_Event_Question_Group.model.php 3 patches
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -32,10 +32,10 @@
 block discarded – undo
32 32
         );
33 33
         // this model is generally available for reading
34 34
         $path_to_event = 'Event';
35
-        $this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Event_Related_Public($path_to_event);
36
-        $this->_cap_restriction_generators[ EEM_Base::caps_read_admin ] = new EE_Restriction_Generator_Event_Related_Protected($path_to_event);
37
-        $this->_cap_restriction_generators[ EEM_Base::caps_edit ] = new EE_Restriction_Generator_Event_Related_Protected($path_to_event);
38
-        $this->_cap_restriction_generators[ EEM_Base::caps_delete ] = new EE_Restriction_Generator_Event_Related_Protected($path_to_event, EEM_Base::caps_edit);
35
+        $this->_cap_restriction_generators[EEM_Base::caps_read] = new EE_Restriction_Generator_Event_Related_Public($path_to_event);
36
+        $this->_cap_restriction_generators[EEM_Base::caps_read_admin] = new EE_Restriction_Generator_Event_Related_Protected($path_to_event);
37
+        $this->_cap_restriction_generators[EEM_Base::caps_edit] = new EE_Restriction_Generator_Event_Related_Protected($path_to_event);
38
+        $this->_cap_restriction_generators[EEM_Base::caps_delete] = new EE_Restriction_Generator_Event_Related_Protected($path_to_event, EEM_Base::caps_edit);
39 39
         parent::__construct($timezone);
40 40
     }
41 41
 
Please login to merge, or discard this patch.
Indentation   +64 added lines, -64 removed lines patch added patch discarded remove patch
@@ -7,72 +7,72 @@
 block discarded – undo
7 7
  */
8 8
 class EEM_Event_Question_Group extends EEM_Base
9 9
 {
10
-    /**
11
-     * Name of the field indicating an event should use the question group for the primary attendee
12
-     */
13
-    const PRIMARY = 'EQG_primary';
10
+	/**
11
+	 * Name of the field indicating an event should use the question group for the primary attendee
12
+	 */
13
+	const PRIMARY = 'EQG_primary';
14 14
 
15
-    /**
16
-     * Name of hte field indicating an event should use the question group for additional attendees
17
-     */
18
-    const ADDITIONAL = 'EQG_additional';
15
+	/**
16
+	 * Name of hte field indicating an event should use the question group for additional attendees
17
+	 */
18
+	const ADDITIONAL = 'EQG_additional';
19 19
 
20
-    // private instance of the Event_Question_Group object
21
-    protected static $_instance = null;
20
+	// private instance of the Event_Question_Group object
21
+	protected static $_instance = null;
22 22
 
23
-    protected function __construct($timezone = null)
24
-    {
25
-        $this->singular_item = __('Event to Question Group Link', 'event_espresso');
26
-        $this->plural_item = __('Event to Question Group Links', 'event_espresso');
27
-        $this->_tables = array(
28
-            'Event_Question_Group'=>new EE_Primary_Table('esp_event_question_group', 'EQG_ID')
29
-        );
30
-        $this->_fields = array(
31
-            'Event_Question_Group'=>array(
32
-                'EQG_ID'=>new EE_Primary_Key_Int_Field('EQG_ID', __('Event to Question Group Link ID', 'event_espresso')),
33
-                'EVT_ID'=>new EE_Foreign_Key_Int_Field('EVT_ID', __('Event ID', 'event_espresso'), false, 0, 'Event'),
34
-                'QSG_ID'=>new EE_Foreign_Key_Int_Field('QSG_ID', __('Question Group Id', 'event_espresso'), false, 0, 'Question_Group'),
35
-                'EQG_primary'=>new EE_Boolean_Field('EQG_primary', __('Flag indicating question is only for primary attendees', 'event_espresso'), false, false),
36
-                'EQG_additional'=>new EE_Boolean_Field('EQG_additional', __('Flag indicating question is only for additional attendees', 'event_espresso'), false, false)
37
-            )
38
-        );
39
-        $this->_model_relations = array(
40
-            'Event'=>new EE_Belongs_To_Relation(),
41
-            'Question_Group'=>new EE_Belongs_To_Relation()
42
-        );
43
-        // this model is generally available for reading
44
-        $path_to_event = 'Event';
45
-        $this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Event_Related_Public($path_to_event);
46
-        $this->_cap_restriction_generators[ EEM_Base::caps_read_admin ] = new EE_Restriction_Generator_Event_Related_Protected($path_to_event);
47
-        $this->_cap_restriction_generators[ EEM_Base::caps_edit ] = new EE_Restriction_Generator_Event_Related_Protected($path_to_event);
48
-        $this->_cap_restriction_generators[ EEM_Base::caps_delete ] = new EE_Restriction_Generator_Event_Related_Protected($path_to_event, EEM_Base::caps_edit);
49
-        parent::__construct($timezone);
50
-    }
23
+	protected function __construct($timezone = null)
24
+	{
25
+		$this->singular_item = __('Event to Question Group Link', 'event_espresso');
26
+		$this->plural_item = __('Event to Question Group Links', 'event_espresso');
27
+		$this->_tables = array(
28
+			'Event_Question_Group'=>new EE_Primary_Table('esp_event_question_group', 'EQG_ID')
29
+		);
30
+		$this->_fields = array(
31
+			'Event_Question_Group'=>array(
32
+				'EQG_ID'=>new EE_Primary_Key_Int_Field('EQG_ID', __('Event to Question Group Link ID', 'event_espresso')),
33
+				'EVT_ID'=>new EE_Foreign_Key_Int_Field('EVT_ID', __('Event ID', 'event_espresso'), false, 0, 'Event'),
34
+				'QSG_ID'=>new EE_Foreign_Key_Int_Field('QSG_ID', __('Question Group Id', 'event_espresso'), false, 0, 'Question_Group'),
35
+				'EQG_primary'=>new EE_Boolean_Field('EQG_primary', __('Flag indicating question is only for primary attendees', 'event_espresso'), false, false),
36
+				'EQG_additional'=>new EE_Boolean_Field('EQG_additional', __('Flag indicating question is only for additional attendees', 'event_espresso'), false, false)
37
+			)
38
+		);
39
+		$this->_model_relations = array(
40
+			'Event'=>new EE_Belongs_To_Relation(),
41
+			'Question_Group'=>new EE_Belongs_To_Relation()
42
+		);
43
+		// this model is generally available for reading
44
+		$path_to_event = 'Event';
45
+		$this->_cap_restriction_generators[ EEM_Base::caps_read ] = new EE_Restriction_Generator_Event_Related_Public($path_to_event);
46
+		$this->_cap_restriction_generators[ EEM_Base::caps_read_admin ] = new EE_Restriction_Generator_Event_Related_Protected($path_to_event);
47
+		$this->_cap_restriction_generators[ EEM_Base::caps_edit ] = new EE_Restriction_Generator_Event_Related_Protected($path_to_event);
48
+		$this->_cap_restriction_generators[ EEM_Base::caps_delete ] = new EE_Restriction_Generator_Event_Related_Protected($path_to_event, EEM_Base::caps_edit);
49
+		parent::__construct($timezone);
50
+	}
51 51
 
52
-    /**
53
-     * Decides whether to use the 'EQG_primary' or newer 'EQG_additional' for use in queries, based on whether
54
-     * this is concerning primary attendees or additional attendees.
55
-     * If 1, true, or "primary" is passed in, returns EQG_primary. If 0, false, or "additional" is passed in, returns
56
-     * EQG_additional.
57
-     * @since $VID:$
58
-     * @param string|boolean|int $context
59
-     * @return string
60
-     */
61
-    public function fieldNameForContext($context)
62
-    {
63
-        // Basically do a strict switch statement.
64
-        switch (true) {
65
-            case $context === 'additional':
66
-            case $context === false:
67
-            case $context === 0:
68
-                $field_name = EEM_Event_Question_Group::ADDITIONAL;
69
-                break;
70
-            case $context === 'primary':
71
-            case $context === true:
72
-            case $context === 1:
73
-            default:
74
-                $field_name = EEM_Event_Question_Group::PRIMARY;
75
-        }
76
-        return apply_filters('FHEE__EEM_Event_Question_Group__fieldNameForContext', $field_name, $context);
77
-    }
52
+	/**
53
+	 * Decides whether to use the 'EQG_primary' or newer 'EQG_additional' for use in queries, based on whether
54
+	 * this is concerning primary attendees or additional attendees.
55
+	 * If 1, true, or "primary" is passed in, returns EQG_primary. If 0, false, or "additional" is passed in, returns
56
+	 * EQG_additional.
57
+	 * @since $VID:$
58
+	 * @param string|boolean|int $context
59
+	 * @return string
60
+	 */
61
+	public function fieldNameForContext($context)
62
+	{
63
+		// Basically do a strict switch statement.
64
+		switch (true) {
65
+			case $context === 'additional':
66
+			case $context === false:
67
+			case $context === 0:
68
+				$field_name = EEM_Event_Question_Group::ADDITIONAL;
69
+				break;
70
+			case $context === 'primary':
71
+			case $context === true:
72
+			case $context === 1:
73
+			default:
74
+				$field_name = EEM_Event_Question_Group::PRIMARY;
75
+		}
76
+		return apply_filters('FHEE__EEM_Event_Question_Group__fieldNameForContext', $field_name, $context);
77
+	}
78 78
 }
Please login to merge, or discard this patch.
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -55,7 +55,7 @@
 block discarded – undo
55 55
      * If 1, true, or "primary" is passed in, returns EQG_primary. If 0, false, or "additional" is passed in, returns
56 56
      * EQG_additional.
57 57
      * @since $VID:$
58
-     * @param string|boolean|int $context
58
+     * @param boolean $context
59 59
      * @return string
60 60
      */
61 61
     public function fieldNameForContext($context)
Please login to merge, or discard this patch.
caffeinated/admin/extend/events/Extend_Events_Admin_Page.core.php 2 patches
Indentation   +1253 added lines, -1253 removed lines patch added patch discarded remove patch
@@ -16,1257 +16,1257 @@
 block discarded – undo
16 16
 {
17 17
 
18 18
 
19
-    /**
20
-     * Extend_Events_Admin_Page constructor.
21
-     *
22
-     * @param bool $routing
23
-     */
24
-    public function __construct($routing = true)
25
-    {
26
-        parent::__construct($routing);
27
-        if (! defined('EVENTS_CAF_TEMPLATE_PATH')) {
28
-            define('EVENTS_CAF_TEMPLATE_PATH', EE_CORE_CAF_ADMIN_EXTEND . 'events/templates/');
29
-            define('EVENTS_CAF_ASSETS', EE_CORE_CAF_ADMIN_EXTEND . 'events/assets/');
30
-            define('EVENTS_CAF_ASSETS_URL', EE_CORE_CAF_ADMIN_EXTEND_URL . 'events/assets/');
31
-        }
32
-    }
33
-
34
-
35
-    /**
36
-     * Sets routes.
37
-     */
38
-    protected function _extend_page_config()
39
-    {
40
-        $this->_admin_base_path = EE_CORE_CAF_ADMIN_EXTEND . 'events';
41
-        // is there a evt_id in the request?
42
-        $evt_id = ! empty($this->_req_data['EVT_ID']) && ! is_array($this->_req_data['EVT_ID'])
43
-            ? $this->_req_data['EVT_ID']
44
-            : 0;
45
-        $evt_id = ! empty($this->_req_data['post']) ? $this->_req_data['post'] : $evt_id;
46
-        // tkt_id?
47
-        $tkt_id = ! empty($this->_req_data['TKT_ID']) && ! is_array($this->_req_data['TKT_ID'])
48
-            ? $this->_req_data['TKT_ID']
49
-            : 0;
50
-        $new_page_routes = array(
51
-            'duplicate_event'          => array(
52
-                'func'       => '_duplicate_event',
53
-                'capability' => 'ee_edit_event',
54
-                'obj_id'     => $evt_id,
55
-                'noheader'   => true,
56
-            ),
57
-            'ticket_list_table'        => array(
58
-                'func'       => '_tickets_overview_list_table',
59
-                'capability' => 'ee_read_default_tickets',
60
-            ),
61
-            'trash_ticket'             => array(
62
-                'func'       => '_trash_or_restore_ticket',
63
-                'capability' => 'ee_delete_default_ticket',
64
-                'obj_id'     => $tkt_id,
65
-                'noheader'   => true,
66
-                'args'       => array('trash' => true),
67
-            ),
68
-            'trash_tickets'            => array(
69
-                'func'       => '_trash_or_restore_ticket',
70
-                'capability' => 'ee_delete_default_tickets',
71
-                'noheader'   => true,
72
-                'args'       => array('trash' => true),
73
-            ),
74
-            'restore_ticket'           => array(
75
-                'func'       => '_trash_or_restore_ticket',
76
-                'capability' => 'ee_delete_default_ticket',
77
-                'obj_id'     => $tkt_id,
78
-                'noheader'   => true,
79
-            ),
80
-            'restore_tickets'          => array(
81
-                'func'       => '_trash_or_restore_ticket',
82
-                'capability' => 'ee_delete_default_tickets',
83
-                'noheader'   => true,
84
-            ),
85
-            'delete_ticket'            => array(
86
-                'func'       => '_delete_ticket',
87
-                'capability' => 'ee_delete_default_ticket',
88
-                'obj_id'     => $tkt_id,
89
-                'noheader'   => true,
90
-            ),
91
-            'delete_tickets'           => array(
92
-                'func'       => '_delete_ticket',
93
-                'capability' => 'ee_delete_default_tickets',
94
-                'noheader'   => true,
95
-            ),
96
-            'import_page'              => array(
97
-                'func'       => '_import_page',
98
-                'capability' => 'import',
99
-            ),
100
-            'import'                   => array(
101
-                'func'       => '_import_events',
102
-                'capability' => 'import',
103
-                'noheader'   => true,
104
-            ),
105
-            'import_events'            => array(
106
-                'func'       => '_import_events',
107
-                'capability' => 'import',
108
-                'noheader'   => true,
109
-            ),
110
-            'export_events'            => array(
111
-                'func'       => '_events_export',
112
-                'capability' => 'export',
113
-                'noheader'   => true,
114
-            ),
115
-            'export_categories'        => array(
116
-                'func'       => '_categories_export',
117
-                'capability' => 'export',
118
-                'noheader'   => true,
119
-            ),
120
-            'sample_export_file'       => array(
121
-                'func'       => '_sample_export_file',
122
-                'capability' => 'export',
123
-                'noheader'   => true,
124
-            ),
125
-            'update_template_settings' => array(
126
-                'func'       => '_update_template_settings',
127
-                'capability' => 'manage_options',
128
-                'noheader'   => true,
129
-            ),
130
-        );
131
-        $this->_page_routes = array_merge($this->_page_routes, $new_page_routes);
132
-        // partial route/config override
133
-        $this->_page_config['import_events']['metaboxes'] = $this->_default_espresso_metaboxes;
134
-        $this->_page_config['create_new']['metaboxes'][] = '_premium_event_editor_meta_boxes';
135
-        $this->_page_config['create_new']['qtips'][] = 'EE_Event_Editor_Tips';
136
-        $this->_page_config['edit']['qtips'][] = 'EE_Event_Editor_Tips';
137
-        $this->_page_config['edit']['metaboxes'][] = '_premium_event_editor_meta_boxes';
138
-        $this->_page_config['default']['list_table'] = 'Extend_Events_Admin_List_Table';
139
-        // add tickets tab but only if there are more than one default ticket!
140
-        $tkt_count = EEM_Ticket::instance()->count_deleted_and_undeleted(
141
-            array(array('TKT_is_default' => 1)),
142
-            'TKT_ID',
143
-            true
144
-        );
145
-        if ($tkt_count > 1) {
146
-            $new_page_config = array(
147
-                'ticket_list_table' => array(
148
-                    'nav'           => array(
149
-                        'label' => esc_html__('Default Tickets', 'event_espresso'),
150
-                        'order' => 60,
151
-                    ),
152
-                    'list_table'    => 'Tickets_List_Table',
153
-                    'require_nonce' => false,
154
-                ),
155
-            );
156
-        }
157
-        // template settings
158
-        $new_page_config['template_settings'] = array(
159
-            'nav'           => array(
160
-                'label' => esc_html__('Templates', 'event_espresso'),
161
-                'order' => 30,
162
-            ),
163
-            'metaboxes'     => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
164
-            'help_tabs'     => array(
165
-                'general_settings_templates_help_tab' => array(
166
-                    'title'    => esc_html__('Templates', 'event_espresso'),
167
-                    'filename' => 'general_settings_templates',
168
-                ),
169
-            ),
170
-            'help_tour'     => array('Templates_Help_Tour'),
171
-            'require_nonce' => false,
172
-        );
173
-        $this->_page_config = array_merge($this->_page_config, $new_page_config);
174
-        // add filters and actions
175
-        // modifying _views
176
-        add_filter(
177
-            'FHEE_event_datetime_metabox_add_additional_date_time_template',
178
-            array($this, 'add_additional_datetime_button'),
179
-            10,
180
-            2
181
-        );
182
-        add_filter(
183
-            'FHEE_event_datetime_metabox_clone_button_template',
184
-            array($this, 'add_datetime_clone_button'),
185
-            10,
186
-            2
187
-        );
188
-        add_filter(
189
-            'FHEE_event_datetime_metabox_timezones_template',
190
-            array($this, 'datetime_timezones_template'),
191
-            10,
192
-            2
193
-        );
194
-        // filters for event list table
195
-        add_filter('FHEE__Extend_Events_Admin_List_Table__filters', array($this, 'list_table_filters'), 10, 2);
196
-        add_filter(
197
-            'FHEE__Events_Admin_List_Table__column_actions__action_links',
198
-            array($this, 'extra_list_table_actions'),
199
-            10,
200
-            2
201
-        );
202
-        // legend item
203
-        add_filter('FHEE__Events_Admin_Page___event_legend_items__items', array($this, 'additional_legend_items'));
204
-        add_action('admin_init', array($this, 'admin_init'));
205
-    }
206
-
207
-
208
-    /**
209
-     * admin_init
210
-     */
211
-    public function admin_init()
212
-    {
213
-        EE_Registry::$i18n_js_strings = array_merge(
214
-            EE_Registry::$i18n_js_strings,
215
-            array(
216
-                'image_confirm'          => esc_html__(
217
-                    'Do you really want to delete this image? Please remember to update your event to complete the removal.',
218
-                    'event_espresso'
219
-                ),
220
-                'event_starts_on'        => esc_html__('Event Starts on', 'event_espresso'),
221
-                'event_ends_on'          => esc_html__('Event Ends on', 'event_espresso'),
222
-                'event_datetime_actions' => esc_html__('Actions', 'event_espresso'),
223
-                'event_clone_dt_msg'     => esc_html__('Clone this Event Date and Time', 'event_espresso'),
224
-                'remove_event_dt_msg'    => esc_html__('Remove this Event Time', 'event_espresso'),
225
-            )
226
-        );
227
-    }
228
-
229
-
230
-    /**
231
-     * Add per page screen options to the default ticket list table view.
232
-     */
233
-    protected function _add_screen_options_ticket_list_table()
234
-    {
235
-        $this->_per_page_screen_option();
236
-    }
237
-
238
-
239
-    /**
240
-     * @param string $return
241
-     * @param int    $id
242
-     * @param string $new_title
243
-     * @param string $new_slug
244
-     * @return string
245
-     */
246
-    public function extra_permalink_field_buttons($return, $id, $new_title, $new_slug)
247
-    {
248
-        $return = parent::extra_permalink_field_buttons($return, $id, $new_title, $new_slug);
249
-        // make sure this is only when editing
250
-        if (! empty($id)) {
251
-            $href = EE_Admin_Page::add_query_args_and_nonce(
252
-                array('action' => 'duplicate_event', 'EVT_ID' => $id),
253
-                $this->_admin_base_url
254
-            );
255
-            $title = esc_attr__('Duplicate Event', 'event_espresso');
256
-            $return .= '<a href="'
257
-                       . $href
258
-                       . '" title="'
259
-                       . $title
260
-                       . '" id="ee-duplicate-event-button" class="button button-small"  value="duplicate_event">'
261
-                       . $title
262
-                       . '</a>';
263
-        }
264
-        return $return;
265
-    }
266
-
267
-
268
-    /**
269
-     * Set the list table views for the default ticket list table view.
270
-     */
271
-    public function _set_list_table_views_ticket_list_table()
272
-    {
273
-        $this->_views = array(
274
-            'all'     => array(
275
-                'slug'        => 'all',
276
-                'label'       => esc_html__('All', 'event_espresso'),
277
-                'count'       => 0,
278
-                'bulk_action' => array(
279
-                    'trash_tickets' => esc_html__('Move to Trash', 'event_espresso'),
280
-                ),
281
-            ),
282
-            'trashed' => array(
283
-                'slug'        => 'trashed',
284
-                'label'       => esc_html__('Trash', 'event_espresso'),
285
-                'count'       => 0,
286
-                'bulk_action' => array(
287
-                    'restore_tickets' => esc_html__('Restore from Trash', 'event_espresso'),
288
-                    'delete_tickets'  => esc_html__('Delete Permanently', 'event_espresso'),
289
-                ),
290
-            ),
291
-        );
292
-    }
293
-
294
-
295
-    /**
296
-     * Enqueue scripts and styles for the event editor.
297
-     */
298
-    public function load_scripts_styles_edit()
299
-    {
300
-        wp_register_script(
301
-            'ee-event-editor-heartbeat',
302
-            EVENTS_CAF_ASSETS_URL . 'event-editor-heartbeat.js',
303
-            array('ee_admin_js', 'heartbeat'),
304
-            EVENT_ESPRESSO_VERSION,
305
-            true
306
-        );
307
-        wp_enqueue_script('ee-accounting');
308
-        // styles
309
-        wp_enqueue_style('espresso-ui-theme');
310
-        wp_enqueue_script('event_editor_js');
311
-        wp_enqueue_script('ee-event-editor-heartbeat');
312
-    }
313
-
314
-
315
-    /**
316
-     * Returns template for the additional datetime.
317
-     *
318
-     * @param $template
319
-     * @param $template_args
320
-     * @return mixed
321
-     * @throws DomainException
322
-     */
323
-    public function add_additional_datetime_button($template, $template_args)
324
-    {
325
-        return EEH_Template::display_template(
326
-            EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_add_additional_time.template.php',
327
-            $template_args,
328
-            true
329
-        );
330
-    }
331
-
332
-
333
-    /**
334
-     * Returns the template for cloning a datetime.
335
-     *
336
-     * @param $template
337
-     * @param $template_args
338
-     * @return mixed
339
-     * @throws DomainException
340
-     */
341
-    public function add_datetime_clone_button($template, $template_args)
342
-    {
343
-        return EEH_Template::display_template(
344
-            EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_metabox_clone_button.template.php',
345
-            $template_args,
346
-            true
347
-        );
348
-    }
349
-
350
-
351
-    /**
352
-     * Returns the template for datetime timezones.
353
-     *
354
-     * @param $template
355
-     * @param $template_args
356
-     * @return mixed
357
-     * @throws DomainException
358
-     */
359
-    public function datetime_timezones_template($template, $template_args)
360
-    {
361
-        return EEH_Template::display_template(
362
-            EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_timezones.template.php',
363
-            $template_args,
364
-            true
365
-        );
366
-    }
367
-
368
-
369
-    /**
370
-     * Sets the views for the default list table view.
371
-     */
372
-    protected function _set_list_table_views_default()
373
-    {
374
-        parent::_set_list_table_views_default();
375
-        $new_views = array(
376
-            'today' => array(
377
-                'slug'        => 'today',
378
-                'label'       => esc_html__('Today', 'event_espresso'),
379
-                'count'       => $this->total_events_today(),
380
-                'bulk_action' => array(
381
-                    'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
382
-                ),
383
-            ),
384
-            'month' => array(
385
-                'slug'        => 'month',
386
-                'label'       => esc_html__('This Month', 'event_espresso'),
387
-                'count'       => $this->total_events_this_month(),
388
-                'bulk_action' => array(
389
-                    'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
390
-                ),
391
-            ),
392
-        );
393
-        $this->_views = array_merge($this->_views, $new_views);
394
-    }
395
-
396
-
397
-    /**
398
-     * Returns the extra action links for the default list table view.
399
-     *
400
-     * @param array     $action_links
401
-     * @param \EE_Event $event
402
-     * @return array
403
-     * @throws EE_Error
404
-     */
405
-    public function extra_list_table_actions(array $action_links, \EE_Event $event)
406
-    {
407
-        if (EE_Registry::instance()->CAP->current_user_can(
408
-            'ee_read_registrations',
409
-            'espresso_registrations_reports',
410
-            $event->ID()
411
-        )
412
-        ) {
413
-            $reports_query_args = array(
414
-                'action' => 'reports',
415
-                'EVT_ID' => $event->ID(),
416
-            );
417
-            $reports_link = EE_Admin_Page::add_query_args_and_nonce($reports_query_args, REG_ADMIN_URL);
418
-            $action_links[] = '<a href="'
419
-                              . $reports_link
420
-                              . '" title="'
421
-                              . esc_attr__('View Report', 'event_espresso')
422
-                              . '"><div class="dashicons dashicons-chart-bar"></div></a>'
423
-                              . "\n\t";
424
-        }
425
-        if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
426
-            EE_Registry::instance()->load_helper('MSG_Template');
427
-            $action_links[] = EEH_MSG_Template::get_message_action_link(
428
-                'see_notifications_for',
429
-                null,
430
-                array('EVT_ID' => $event->ID())
431
-            );
432
-        }
433
-        return $action_links;
434
-    }
435
-
436
-
437
-    /**
438
-     * @param $items
439
-     * @return mixed
440
-     */
441
-    public function additional_legend_items($items)
442
-    {
443
-        if (EE_Registry::instance()->CAP->current_user_can(
444
-            'ee_read_registrations',
445
-            'espresso_registrations_reports'
446
-        )
447
-        ) {
448
-            $items['reports'] = array(
449
-                'class' => 'dashicons dashicons-chart-bar',
450
-                'desc'  => esc_html__('Event Reports', 'event_espresso'),
451
-            );
452
-        }
453
-        if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
454
-            $related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
455
-            if (isset($related_for_icon['css_class']) && isset($related_for_icon['label'])) {
456
-                $items['view_related_messages'] = array(
457
-                    'class' => $related_for_icon['css_class'],
458
-                    'desc'  => $related_for_icon['label'],
459
-                );
460
-            }
461
-        }
462
-        return $items;
463
-    }
464
-
465
-
466
-    /**
467
-     * This is the callback method for the duplicate event route
468
-     * Method looks for 'EVT_ID' in the request and retrieves that event and its details and duplicates them
469
-     * into a new event.  We add a hook so that any plugins that add extra event details can hook into this
470
-     * action.  Note that the dupe will have **DUPLICATE** as its title and slug.
471
-     * After duplication the redirect is to the new event edit page.
472
-     *
473
-     * @return void
474
-     * @access protected
475
-     * @throws EE_Error If EE_Event is not available with given ID
476
-     */
477
-    protected function _duplicate_event()
478
-    {
479
-        // first make sure the ID for the event is in the request.
480
-        //  If it isn't then we need to bail and redirect back to overview list table (cause how did we get here?)
481
-        if (! isset($this->_req_data['EVT_ID'])) {
482
-            EE_Error::add_error(
483
-                esc_html__(
484
-                    'In order to duplicate an event an Event ID is required.  None was given.',
485
-                    'event_espresso'
486
-                ),
487
-                __FILE__,
488
-                __FUNCTION__,
489
-                __LINE__
490
-            );
491
-            $this->_redirect_after_action(false, '', '', array(), true);
492
-            return;
493
-        }
494
-        // k we've got EVT_ID so let's use that to get the event we'll duplicate
495
-        $orig_event = EEM_Event::instance()->get_one_by_ID($this->_req_data['EVT_ID']);
496
-        if (! $orig_event instanceof EE_Event) {
497
-            throw new EE_Error(
498
-                sprintf(
499
-                    esc_html__('An EE_Event object could not be retrieved for the given ID (%s)', 'event_espresso'),
500
-                    $this->_req_data['EVT_ID']
501
-                )
502
-            );
503
-        }
504
-        // k now let's clone the $orig_event before getting relations
505
-        $new_event = clone $orig_event;
506
-        // original datetimes
507
-        $orig_datetimes = $orig_event->get_many_related('Datetime');
508
-        // other original relations
509
-        $orig_ven = $orig_event->get_many_related('Venue');
510
-        // reset the ID and modify other details to make it clear this is a dupe
511
-        $new_event->set('EVT_ID', 0);
512
-        $new_name = $new_event->name() . ' ' . esc_html__('**DUPLICATE**', 'event_espresso');
513
-        $new_event->set('EVT_name', $new_name);
514
-        $new_event->set(
515
-            'EVT_slug',
516
-            wp_unique_post_slug(
517
-                sanitize_title($orig_event->name()),
518
-                0,
519
-                'publish',
520
-                'espresso_events',
521
-                0
522
-            )
523
-        );
524
-        $new_event->set('status', 'draft');
525
-        // duplicate discussion settings
526
-        $new_event->set('comment_status', $orig_event->get('comment_status'));
527
-        $new_event->set('ping_status', $orig_event->get('ping_status'));
528
-        // save the new event
529
-        $new_event->save();
530
-        // venues
531
-        foreach ($orig_ven as $ven) {
532
-            $new_event->_add_relation_to($ven, 'Venue');
533
-        }
534
-        $new_event->save();
535
-        // now we need to get the question group relations and handle that
536
-        // first primary question groups
537
-        $orig_primary_qgs = $orig_event->get_many_related(
538
-            'Question_Group',
539
-            [['Event_Question_Group.EQG_primary' => true]]
540
-        );
541
-        if (! empty($orig_primary_qgs)) {
542
-            foreach ($orig_primary_qgs as $id => $obj) {
543
-                if ($obj instanceof EE_Question_Group) {
544
-                    $new_event->_add_relation_to($obj, 'Question_Group', ['EQG_primary' => true]);
545
-                }
546
-            }
547
-        }
548
-        // next additional attendee question groups
549
-        $orig_additional_qgs = $orig_event->get_many_related(
550
-            'Question_Group',
551
-            [['Event_Question_Group.EQG_additional' => true]]
552
-        );
553
-        if (! empty($orig_additional_qgs)) {
554
-            foreach ($orig_additional_qgs as $id => $obj) {
555
-                if ($obj instanceof EE_Question_Group) {
556
-                    $new_event->_add_relation_to($obj, 'Question_Group', ['EQG_additional' => true]);
557
-                }
558
-            }
559
-        }
560
-
561
-        $new_event->save();
562
-
563
-        // k now that we have the new event saved we can loop through the datetimes and start adding relations.
564
-        $cloned_tickets = array();
565
-        foreach ($orig_datetimes as $orig_dtt) {
566
-            if (! $orig_dtt instanceof EE_Datetime) {
567
-                continue;
568
-            }
569
-            $new_dtt = clone $orig_dtt;
570
-            $orig_tkts = $orig_dtt->tickets();
571
-            // save new dtt then add to event
572
-            $new_dtt->set('DTT_ID', 0);
573
-            $new_dtt->set('DTT_sold', 0);
574
-            $new_dtt->set_reserved(0);
575
-            $new_dtt->save();
576
-            $new_event->_add_relation_to($new_dtt, 'Datetime');
577
-            $new_event->save();
578
-            // now let's get the ticket relations setup.
579
-            foreach ((array) $orig_tkts as $orig_tkt) {
580
-                // it's possible a datetime will have no tickets so let's verify we HAVE a ticket first.
581
-                if (! $orig_tkt instanceof EE_Ticket) {
582
-                    continue;
583
-                }
584
-                // is this ticket archived?  If it is then let's skip
585
-                if ($orig_tkt->get('TKT_deleted')) {
586
-                    continue;
587
-                }
588
-                // does this original ticket already exist in the clone_tickets cache?
589
-                //  If so we'll just use the new ticket from it.
590
-                if (isset($cloned_tickets[ $orig_tkt->ID() ])) {
591
-                    $new_tkt = $cloned_tickets[ $orig_tkt->ID() ];
592
-                } else {
593
-                    $new_tkt = clone $orig_tkt;
594
-                    // get relations on the $orig_tkt that we need to setup.
595
-                    $orig_prices = $orig_tkt->prices();
596
-                    $new_tkt->set('TKT_ID', 0);
597
-                    $new_tkt->set('TKT_sold', 0);
598
-                    $new_tkt->set('TKT_reserved', 0);
599
-                    $new_tkt->save(); // make sure new ticket has ID.
600
-                    // price relations on new ticket need to be setup.
601
-                    foreach ($orig_prices as $orig_price) {
602
-                        $new_price = clone $orig_price;
603
-                        $new_price->set('PRC_ID', 0);
604
-                        $new_price->save();
605
-                        $new_tkt->_add_relation_to($new_price, 'Price');
606
-                        $new_tkt->save();
607
-                    }
608
-
609
-                    do_action(
610
-                        'AHEE__Extend_Events_Admin_Page___duplicate_event__duplicate_ticket__after',
611
-                        $orig_tkt,
612
-                        $new_tkt,
613
-                        $orig_prices,
614
-                        $orig_event,
615
-                        $orig_dtt,
616
-                        $new_dtt
617
-                    );
618
-                }
619
-                // k now we can add the new ticket as a relation to the new datetime
620
-                // and make sure its added to our cached $cloned_tickets array
621
-                // for use with later datetimes that have the same ticket.
622
-                $new_dtt->_add_relation_to($new_tkt, 'Ticket');
623
-                $new_dtt->save();
624
-                $cloned_tickets[ $orig_tkt->ID() ] = $new_tkt;
625
-            }
626
-        }
627
-        // clone taxonomy information
628
-        $taxonomies_to_clone_with = apply_filters(
629
-            'FHEE__Extend_Events_Admin_Page___duplicate_event__taxonomies_to_clone',
630
-            array('espresso_event_categories', 'espresso_event_type', 'post_tag')
631
-        );
632
-        // get terms for original event (notice)
633
-        $orig_terms = wp_get_object_terms($orig_event->ID(), $taxonomies_to_clone_with);
634
-        // loop through terms and add them to new event.
635
-        foreach ($orig_terms as $term) {
636
-            wp_set_object_terms($new_event->ID(), $term->term_id, $term->taxonomy, true);
637
-        }
638
-
639
-        // duplicate other core WP_Post items for this event.
640
-        // post thumbnail (feature image).
641
-        $feature_image_id = get_post_thumbnail_id($orig_event->ID());
642
-        if ($feature_image_id) {
643
-            update_post_meta($new_event->ID(), '_thumbnail_id', $feature_image_id);
644
-        }
645
-
646
-        // duplicate page_template setting
647
-        $page_template = get_post_meta($orig_event->ID(), '_wp_page_template', true);
648
-        if ($page_template) {
649
-            update_post_meta($new_event->ID(), '_wp_page_template', $page_template);
650
-        }
651
-
652
-        do_action('AHEE__Extend_Events_Admin_Page___duplicate_event__after', $new_event, $orig_event);
653
-        // now let's redirect to the edit page for this duplicated event if we have a new event id.
654
-        if ($new_event->ID()) {
655
-            $redirect_args = array(
656
-                'post'   => $new_event->ID(),
657
-                'action' => 'edit',
658
-            );
659
-            EE_Error::add_success(
660
-                esc_html__(
661
-                    'Event successfully duplicated.  Please review the details below and make any necessary edits',
662
-                    'event_espresso'
663
-                )
664
-            );
665
-        } else {
666
-            $redirect_args = array(
667
-                'action' => 'default',
668
-            );
669
-            EE_Error::add_error(
670
-                esc_html__('Not able to duplicate event.  Something went wrong.', 'event_espresso'),
671
-                __FILE__,
672
-                __FUNCTION__,
673
-                __LINE__
674
-            );
675
-        }
676
-        $this->_redirect_after_action(false, '', '', $redirect_args, true);
677
-    }
678
-
679
-
680
-    /**
681
-     * Generates output for the import page.
682
-     *
683
-     * @throws DomainException
684
-     */
685
-    protected function _import_page()
686
-    {
687
-        $title = esc_html__('Import', 'event_espresso');
688
-        $intro = esc_html__(
689
-            'If you have a previously exported Event Espresso 4 information in a Comma Separated Value (CSV) file format, you can upload the file here: ',
690
-            'event_espresso'
691
-        );
692
-        $form_url = EVENTS_ADMIN_URL;
693
-        $action = 'import_events';
694
-        $type = 'csv';
695
-        $this->_template_args['form'] = EE_Import::instance()->upload_form(
696
-            $title,
697
-            $intro,
698
-            $form_url,
699
-            $action,
700
-            $type
701
-        );
702
-        $this->_template_args['sample_file_link'] = EE_Admin_Page::add_query_args_and_nonce(
703
-            array('action' => 'sample_export_file'),
704
-            $this->_admin_base_url
705
-        );
706
-        $content = EEH_Template::display_template(
707
-            EVENTS_CAF_TEMPLATE_PATH . 'import_page.template.php',
708
-            $this->_template_args,
709
-            true
710
-        );
711
-        $this->_template_args['admin_page_content'] = $content;
712
-        $this->display_admin_page_with_sidebar();
713
-    }
714
-
715
-
716
-    /**
717
-     * _import_events
718
-     * This handles displaying the screen and running imports for importing events.
719
-     *
720
-     * @return void
721
-     */
722
-    protected function _import_events()
723
-    {
724
-        require_once(EE_CLASSES . 'EE_Import.class.php');
725
-        $success = EE_Import::instance()->import();
726
-        $this->_redirect_after_action($success, 'Import File', 'ran', array('action' => 'import_page'), true);
727
-    }
728
-
729
-
730
-    /**
731
-     * _events_export
732
-     * Will export all (or just the given event) to a Excel compatible file.
733
-     *
734
-     * @access protected
735
-     * @return void
736
-     */
737
-    protected function _events_export()
738
-    {
739
-        if (isset($this->_req_data['EVT_ID'])) {
740
-            $event_ids = $this->_req_data['EVT_ID'];
741
-        } elseif (isset($this->_req_data['EVT_IDs'])) {
742
-            $event_ids = $this->_req_data['EVT_IDs'];
743
-        } else {
744
-            $event_ids = null;
745
-        }
746
-        // todo: I don't like doing this but it'll do until we modify EE_Export Class.
747
-        $new_request_args = array(
748
-            'export' => 'report',
749
-            'action' => 'all_event_data',
750
-            'EVT_ID' => $event_ids,
751
-        );
752
-        $this->_req_data = array_merge($this->_req_data, $new_request_args);
753
-        if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
754
-            require_once(EE_CLASSES . 'EE_Export.class.php');
755
-            $EE_Export = EE_Export::instance($this->_req_data);
756
-            $EE_Export->export();
757
-        }
758
-    }
759
-
760
-
761
-    /**
762
-     * handle category exports()
763
-     *
764
-     * @return void
765
-     */
766
-    protected function _categories_export()
767
-    {
768
-        // todo: I don't like doing this but it'll do until we modify EE_Export Class.
769
-        $new_request_args = array(
770
-            'export'       => 'report',
771
-            'action'       => 'categories',
772
-            'category_ids' => $this->_req_data['EVT_CAT_ID'],
773
-        );
774
-        $this->_req_data = array_merge($this->_req_data, $new_request_args);
775
-        if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
776
-            require_once(EE_CLASSES . 'EE_Export.class.php');
777
-            $EE_Export = EE_Export::instance($this->_req_data);
778
-            $EE_Export->export();
779
-        }
780
-    }
781
-
782
-
783
-    /**
784
-     * Creates a sample CSV file for importing
785
-     */
786
-    protected function _sample_export_file()
787
-    {
788
-        // require_once(EE_CLASSES . 'EE_Export.class.php');
789
-        EE_Export::instance()->export_sample();
790
-    }
791
-
792
-
793
-    /*************        Template Settings        *************/
794
-    /**
795
-     * Generates template settings page output
796
-     *
797
-     * @throws DomainException
798
-     * @throws EE_Error
799
-     */
800
-    protected function _template_settings()
801
-    {
802
-        $this->_template_args['values'] = $this->_yes_no_values;
803
-        /**
804
-         * Note leaving this filter in for backward compatibility this was moved in 4.6.x
805
-         * from General_Settings_Admin_Page to here.
806
-         */
807
-        $this->_template_args = apply_filters(
808
-            'FHEE__General_Settings_Admin_Page__template_settings__template_args',
809
-            $this->_template_args
810
-        );
811
-        $this->_set_add_edit_form_tags('update_template_settings');
812
-        $this->_set_publish_post_box_vars(null, false, false, null, false);
813
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
814
-            EVENTS_CAF_TEMPLATE_PATH . 'template_settings.template.php',
815
-            $this->_template_args,
816
-            true
817
-        );
818
-        $this->display_admin_page_with_sidebar();
819
-    }
820
-
821
-
822
-    /**
823
-     * Handler for updating template settings.
824
-     *
825
-     * @throws InvalidInterfaceException
826
-     * @throws InvalidDataTypeException
827
-     * @throws InvalidArgumentException
828
-     */
829
-    protected function _update_template_settings()
830
-    {
831
-        /**
832
-         * Note leaving this filter in for backward compatibility this was moved in 4.6.x
833
-         * from General_Settings_Admin_Page to here.
834
-         */
835
-        EE_Registry::instance()->CFG->template_settings = apply_filters(
836
-            'FHEE__General_Settings_Admin_Page__update_template_settings__data',
837
-            EE_Registry::instance()->CFG->template_settings,
838
-            $this->_req_data
839
-        );
840
-        // update custom post type slugs and detect if we need to flush rewrite rules
841
-        $old_slug = EE_Registry::instance()->CFG->core->event_cpt_slug;
842
-        EE_Registry::instance()->CFG->core->event_cpt_slug = empty($this->_req_data['event_cpt_slug'])
843
-            ? EE_Registry::instance()->CFG->core->event_cpt_slug
844
-            : EEH_URL::slugify($this->_req_data['event_cpt_slug'], 'events');
845
-        $what = 'Template Settings';
846
-        $success = $this->_update_espresso_configuration(
847
-            $what,
848
-            EE_Registry::instance()->CFG->template_settings,
849
-            __FILE__,
850
-            __FUNCTION__,
851
-            __LINE__
852
-        );
853
-        if (EE_Registry::instance()->CFG->core->event_cpt_slug != $old_slug) {
854
-            /** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
855
-            $rewrite_rules = LoaderFactory::getLoader()->getShared(
856
-                'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
857
-            );
858
-            $rewrite_rules->flush();
859
-        }
860
-        $this->_redirect_after_action($success, $what, 'updated', array('action' => 'template_settings'));
861
-    }
862
-
863
-
864
-    /**
865
-     * _premium_event_editor_meta_boxes
866
-     * add all metaboxes related to the event_editor
867
-     *
868
-     * @access protected
869
-     * @return void
870
-     * @throws EE_Error
871
-     */
872
-    protected function _premium_event_editor_meta_boxes()
873
-    {
874
-        $this->verify_cpt_object();
875
-        add_meta_box(
876
-            'espresso_event_editor_event_options',
877
-            esc_html__('Event Registration Options', 'event_espresso'),
878
-            array($this, 'registration_options_meta_box'),
879
-            $this->page_slug,
880
-            'side',
881
-            'core'
882
-        );
883
-    }
884
-
885
-
886
-    /**
887
-     * override caf metabox
888
-     *
889
-     * @return void
890
-     * @throws DomainException
891
-     */
892
-    public function registration_options_meta_box()
893
-    {
894
-        $yes_no_values = array(
895
-            array('id' => true, 'text' => esc_html__('Yes', 'event_espresso')),
896
-            array('id' => false, 'text' => esc_html__('No', 'event_espresso')),
897
-        );
898
-        $default_reg_status_values = EEM_Registration::reg_status_array(
899
-            array(
900
-                EEM_Registration::status_id_cancelled,
901
-                EEM_Registration::status_id_declined,
902
-                EEM_Registration::status_id_incomplete,
903
-                EEM_Registration::status_id_wait_list,
904
-            ),
905
-            true
906
-        );
907
-        $template_args['active_status'] = $this->_cpt_model_obj->pretty_active_status(false);
908
-        $template_args['_event'] = $this->_cpt_model_obj;
909
-        $template_args['additional_limit'] = $this->_cpt_model_obj->additional_limit();
910
-        $template_args['default_registration_status'] = EEH_Form_Fields::select_input(
911
-            'default_reg_status',
912
-            $default_reg_status_values,
913
-            $this->_cpt_model_obj->default_registration_status()
914
-        );
915
-        $template_args['display_description'] = EEH_Form_Fields::select_input(
916
-            'display_desc',
917
-            $yes_no_values,
918
-            $this->_cpt_model_obj->display_description()
919
-        );
920
-        $template_args['display_ticket_selector'] = EEH_Form_Fields::select_input(
921
-            'display_ticket_selector',
922
-            $yes_no_values,
923
-            $this->_cpt_model_obj->display_ticket_selector(),
924
-            '',
925
-            '',
926
-            false
927
-        );
928
-        $template_args['EVT_default_registration_status'] = EEH_Form_Fields::select_input(
929
-            'EVT_default_registration_status',
930
-            $default_reg_status_values,
931
-            $this->_cpt_model_obj->default_registration_status()
932
-        );
933
-        $template_args['additional_registration_options'] = apply_filters(
934
-            'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options',
935
-            '',
936
-            $template_args,
937
-            $yes_no_values,
938
-            $default_reg_status_values
939
-        );
940
-        EEH_Template::display_template(
941
-            EVENTS_CAF_TEMPLATE_PATH . 'event_registration_options.template.php',
942
-            $template_args
943
-        );
944
-    }
945
-
946
-
947
-
948
-    /**
949
-     * wp_list_table_mods for caf
950
-     * ============================
951
-     */
952
-    /**
953
-     * hook into list table filters and provide filters for caffeinated list table
954
-     *
955
-     * @param  array $old_filters    any existing filters present
956
-     * @param  array $list_table_obj the list table object
957
-     * @return array                  new filters
958
-     */
959
-    public function list_table_filters($old_filters, $list_table_obj)
960
-    {
961
-        $filters = array();
962
-        // first month/year filters
963
-        $filters[] = $this->espresso_event_months_dropdown();
964
-        $status = isset($this->_req_data['status']) ? $this->_req_data['status'] : null;
965
-        // active status dropdown
966
-        if ($status !== 'draft') {
967
-            $filters[] = $this->active_status_dropdown(
968
-                isset($this->_req_data['active_status']) ? $this->_req_data['active_status'] : ''
969
-            );
970
-        }
971
-        // category filter
972
-        $filters[] = $this->category_dropdown();
973
-        return array_merge($old_filters, $filters);
974
-    }
975
-
976
-
977
-    /**
978
-     * espresso_event_months_dropdown
979
-     *
980
-     * @access public
981
-     * @return string                dropdown listing month/year selections for events.
982
-     */
983
-    public function espresso_event_months_dropdown()
984
-    {
985
-        // what we need to do is get all PRIMARY datetimes for all events to filter on.
986
-        // Note we need to include any other filters that are set!
987
-        $status = isset($this->_req_data['status']) ? $this->_req_data['status'] : null;
988
-        // categories?
989
-        $category = isset($this->_req_data['EVT_CAT']) && $this->_req_data['EVT_CAT'] > 0
990
-            ? $this->_req_data['EVT_CAT']
991
-            : null;
992
-        // active status?
993
-        $active_status = isset($this->_req_data['active_status']) ? $this->_req_data['active_status'] : null;
994
-        $cur_date = isset($this->_req_data['month_range']) ? $this->_req_data['month_range'] : '';
995
-        return EEH_Form_Fields::generate_event_months_dropdown($cur_date, $status, $category, $active_status);
996
-    }
997
-
998
-
999
-    /**
1000
-     * returns a list of "active" statuses on the event
1001
-     *
1002
-     * @param  string $current_value whatever the current active status is
1003
-     * @return string
1004
-     */
1005
-    public function active_status_dropdown($current_value = '')
1006
-    {
1007
-        $select_name = 'active_status';
1008
-        $values = array(
1009
-            'none'     => esc_html__('Show Active/Inactive', 'event_espresso'),
1010
-            'active'   => esc_html__('Active', 'event_espresso'),
1011
-            'upcoming' => esc_html__('Upcoming', 'event_espresso'),
1012
-            'expired'  => esc_html__('Expired', 'event_espresso'),
1013
-            'inactive' => esc_html__('Inactive', 'event_espresso'),
1014
-        );
1015
-        $id = 'id="espresso-active-status-dropdown-filter"';
1016
-        $class = 'wide';
1017
-        return EEH_Form_Fields::select_input($select_name, $values, $current_value, $id, $class);
1018
-    }
1019
-
1020
-
1021
-    /**
1022
-     * output a dropdown of the categories for the category filter on the event admin list table
1023
-     *
1024
-     * @access  public
1025
-     * @return string html
1026
-     */
1027
-    public function category_dropdown()
1028
-    {
1029
-        $cur_cat = isset($this->_req_data['EVT_CAT']) ? $this->_req_data['EVT_CAT'] : -1;
1030
-        return EEH_Form_Fields::generate_event_category_dropdown($cur_cat);
1031
-    }
1032
-
1033
-
1034
-    /**
1035
-     * get total number of events today
1036
-     *
1037
-     * @access public
1038
-     * @return int
1039
-     * @throws EE_Error
1040
-     */
1041
-    public function total_events_today()
1042
-    {
1043
-        $start = EEM_Datetime::instance()->convert_datetime_for_query(
1044
-            'DTT_EVT_start',
1045
-            date('Y-m-d') . ' 00:00:00',
1046
-            'Y-m-d H:i:s',
1047
-            'UTC'
1048
-        );
1049
-        $end = EEM_Datetime::instance()->convert_datetime_for_query(
1050
-            'DTT_EVT_start',
1051
-            date('Y-m-d') . ' 23:59:59',
1052
-            'Y-m-d H:i:s',
1053
-            'UTC'
1054
-        );
1055
-        $where = array(
1056
-            'Datetime.DTT_EVT_start' => array('BETWEEN', array($start, $end)),
1057
-        );
1058
-        $count = EEM_Event::instance()->count(array($where, 'caps' => 'read_admin'), 'EVT_ID', true);
1059
-        return $count;
1060
-    }
1061
-
1062
-
1063
-    /**
1064
-     * get total number of events this month
1065
-     *
1066
-     * @access public
1067
-     * @return int
1068
-     * @throws EE_Error
1069
-     */
1070
-    public function total_events_this_month()
1071
-    {
1072
-        // Dates
1073
-        $this_year_r = date('Y');
1074
-        $this_month_r = date('m');
1075
-        $days_this_month = date('t');
1076
-        $start = EEM_Datetime::instance()->convert_datetime_for_query(
1077
-            'DTT_EVT_start',
1078
-            $this_year_r . '-' . $this_month_r . '-01 00:00:00',
1079
-            'Y-m-d H:i:s',
1080
-            'UTC'
1081
-        );
1082
-        $end = EEM_Datetime::instance()->convert_datetime_for_query(
1083
-            'DTT_EVT_start',
1084
-            $this_year_r . '-' . $this_month_r . '-' . $days_this_month . ' 23:59:59',
1085
-            'Y-m-d H:i:s',
1086
-            'UTC'
1087
-        );
1088
-        $where = array(
1089
-            'Datetime.DTT_EVT_start' => array('BETWEEN', array($start, $end)),
1090
-        );
1091
-        $count = EEM_Event::instance()->count(array($where, 'caps' => 'read_admin'), 'EVT_ID', true);
1092
-        return $count;
1093
-    }
1094
-
1095
-
1096
-    /** DEFAULT TICKETS STUFF **/
1097
-
1098
-    /**
1099
-     * Output default tickets list table view.
1100
-     */
1101
-    public function _tickets_overview_list_table()
1102
-    {
1103
-        $this->_search_btn_label = esc_html__('Tickets', 'event_espresso');
1104
-        $this->display_admin_list_table_page_with_no_sidebar();
1105
-    }
1106
-
1107
-
1108
-    /**
1109
-     * @param int  $per_page
1110
-     * @param bool $count
1111
-     * @param bool $trashed
1112
-     * @return \EE_Soft_Delete_Base_Class[]|int
1113
-     */
1114
-    public function get_default_tickets($per_page = 10, $count = false, $trashed = false)
1115
-    {
1116
-        $orderby = empty($this->_req_data['orderby']) ? 'TKT_name' : $this->_req_data['orderby'];
1117
-        $order = empty($this->_req_data['order']) ? 'ASC' : $this->_req_data['order'];
1118
-        switch ($orderby) {
1119
-            case 'TKT_name':
1120
-                $orderby = array('TKT_name' => $order);
1121
-                break;
1122
-            case 'TKT_price':
1123
-                $orderby = array('TKT_price' => $order);
1124
-                break;
1125
-            case 'TKT_uses':
1126
-                $orderby = array('TKT_uses' => $order);
1127
-                break;
1128
-            case 'TKT_min':
1129
-                $orderby = array('TKT_min' => $order);
1130
-                break;
1131
-            case 'TKT_max':
1132
-                $orderby = array('TKT_max' => $order);
1133
-                break;
1134
-            case 'TKT_qty':
1135
-                $orderby = array('TKT_qty' => $order);
1136
-                break;
1137
-        }
1138
-        $current_page = isset($this->_req_data['paged']) && ! empty($this->_req_data['paged'])
1139
-            ? $this->_req_data['paged']
1140
-            : 1;
1141
-        $per_page = isset($this->_req_data['perpage']) && ! empty($this->_req_data['perpage'])
1142
-            ? $this->_req_data['perpage']
1143
-            : $per_page;
1144
-        $_where = array(
1145
-            'TKT_is_default' => 1,
1146
-            'TKT_deleted'    => $trashed,
1147
-        );
1148
-        $offset = ($current_page - 1) * $per_page;
1149
-        $limit = array($offset, $per_page);
1150
-        if (isset($this->_req_data['s'])) {
1151
-            $sstr = '%' . $this->_req_data['s'] . '%';
1152
-            $_where['OR'] = array(
1153
-                'TKT_name'        => array('LIKE', $sstr),
1154
-                'TKT_description' => array('LIKE', $sstr),
1155
-            );
1156
-        }
1157
-        $query_params = array(
1158
-            $_where,
1159
-            'order_by' => $orderby,
1160
-            'limit'    => $limit,
1161
-            'group_by' => 'TKT_ID',
1162
-        );
1163
-        if ($count) {
1164
-            return EEM_Ticket::instance()->count_deleted_and_undeleted(array($_where));
1165
-        } else {
1166
-            return EEM_Ticket::instance()->get_all_deleted_and_undeleted($query_params);
1167
-        }
1168
-    }
1169
-
1170
-
1171
-    /**
1172
-     * @param bool $trash
1173
-     * @throws EE_Error
1174
-     */
1175
-    protected function _trash_or_restore_ticket($trash = false)
1176
-    {
1177
-        $success = 1;
1178
-        $TKT = EEM_Ticket::instance();
1179
-        // checkboxes?
1180
-        if (! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
1181
-            // if array has more than one element then success message should be plural
1182
-            $success = count($this->_req_data['checkbox']) > 1 ? 2 : 1;
1183
-            // cycle thru the boxes
1184
-            while (list($TKT_ID, $value) = each($this->_req_data['checkbox'])) {
1185
-                if ($trash) {
1186
-                    if (! $TKT->delete_by_ID($TKT_ID)) {
1187
-                        $success = 0;
1188
-                    }
1189
-                } else {
1190
-                    if (! $TKT->restore_by_ID($TKT_ID)) {
1191
-                        $success = 0;
1192
-                    }
1193
-                }
1194
-            }
1195
-        } else {
1196
-            // grab single id and trash
1197
-            $TKT_ID = absint($this->_req_data['TKT_ID']);
1198
-            if ($trash) {
1199
-                if (! $TKT->delete_by_ID($TKT_ID)) {
1200
-                    $success = 0;
1201
-                }
1202
-            } else {
1203
-                if (! $TKT->restore_by_ID($TKT_ID)) {
1204
-                    $success = 0;
1205
-                }
1206
-            }
1207
-        }
1208
-        $action_desc = $trash ? 'moved to the trash' : 'restored';
1209
-        $query_args = array(
1210
-            'action' => 'ticket_list_table',
1211
-            'status' => $trash ? '' : 'trashed',
1212
-        );
1213
-        $this->_redirect_after_action($success, 'Tickets', $action_desc, $query_args);
1214
-    }
1215
-
1216
-
1217
-    /**
1218
-     * Handles trashing default ticket.
1219
-     */
1220
-    protected function _delete_ticket()
1221
-    {
1222
-        $success = 1;
1223
-        // checkboxes?
1224
-        if (! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
1225
-            // if array has more than one element then success message should be plural
1226
-            $success = count($this->_req_data['checkbox']) > 1 ? 2 : 1;
1227
-            // cycle thru the boxes
1228
-            while (list($TKT_ID, $value) = each($this->_req_data['checkbox'])) {
1229
-                // delete
1230
-                if (! $this->_delete_the_ticket($TKT_ID)) {
1231
-                    $success = 0;
1232
-                }
1233
-            }
1234
-        } else {
1235
-            // grab single id and trash
1236
-            $TKT_ID = absint($this->_req_data['TKT_ID']);
1237
-            if (! $this->_delete_the_ticket($TKT_ID)) {
1238
-                $success = 0;
1239
-            }
1240
-        }
1241
-        $action_desc = 'deleted';
1242
-        $query_args = array(
1243
-            'action' => 'ticket_list_table',
1244
-            'status' => 'trashed',
1245
-        );
1246
-        // fail safe.  If the default ticket count === 1 then we need to redirect to event overview.
1247
-        if (EEM_Ticket::instance()->count_deleted_and_undeleted(
1248
-            array(array('TKT_is_default' => 1)),
1249
-            'TKT_ID',
1250
-            true
1251
-        )
1252
-        ) {
1253
-            $query_args = array();
1254
-        }
1255
-        $this->_redirect_after_action($success, 'Tickets', $action_desc, $query_args);
1256
-    }
1257
-
1258
-
1259
-    /**
1260
-     * @param int $TKT_ID
1261
-     * @return bool|int
1262
-     * @throws EE_Error
1263
-     */
1264
-    protected function _delete_the_ticket($TKT_ID)
1265
-    {
1266
-        $tkt = EEM_Ticket::instance()->get_one_by_ID($TKT_ID);
1267
-        $tkt->_remove_relations('Datetime');
1268
-        // delete all related prices first
1269
-        $tkt->delete_related_permanently('Price');
1270
-        return $tkt->delete_permanently();
1271
-    }
19
+	/**
20
+	 * Extend_Events_Admin_Page constructor.
21
+	 *
22
+	 * @param bool $routing
23
+	 */
24
+	public function __construct($routing = true)
25
+	{
26
+		parent::__construct($routing);
27
+		if (! defined('EVENTS_CAF_TEMPLATE_PATH')) {
28
+			define('EVENTS_CAF_TEMPLATE_PATH', EE_CORE_CAF_ADMIN_EXTEND . 'events/templates/');
29
+			define('EVENTS_CAF_ASSETS', EE_CORE_CAF_ADMIN_EXTEND . 'events/assets/');
30
+			define('EVENTS_CAF_ASSETS_URL', EE_CORE_CAF_ADMIN_EXTEND_URL . 'events/assets/');
31
+		}
32
+	}
33
+
34
+
35
+	/**
36
+	 * Sets routes.
37
+	 */
38
+	protected function _extend_page_config()
39
+	{
40
+		$this->_admin_base_path = EE_CORE_CAF_ADMIN_EXTEND . 'events';
41
+		// is there a evt_id in the request?
42
+		$evt_id = ! empty($this->_req_data['EVT_ID']) && ! is_array($this->_req_data['EVT_ID'])
43
+			? $this->_req_data['EVT_ID']
44
+			: 0;
45
+		$evt_id = ! empty($this->_req_data['post']) ? $this->_req_data['post'] : $evt_id;
46
+		// tkt_id?
47
+		$tkt_id = ! empty($this->_req_data['TKT_ID']) && ! is_array($this->_req_data['TKT_ID'])
48
+			? $this->_req_data['TKT_ID']
49
+			: 0;
50
+		$new_page_routes = array(
51
+			'duplicate_event'          => array(
52
+				'func'       => '_duplicate_event',
53
+				'capability' => 'ee_edit_event',
54
+				'obj_id'     => $evt_id,
55
+				'noheader'   => true,
56
+			),
57
+			'ticket_list_table'        => array(
58
+				'func'       => '_tickets_overview_list_table',
59
+				'capability' => 'ee_read_default_tickets',
60
+			),
61
+			'trash_ticket'             => array(
62
+				'func'       => '_trash_or_restore_ticket',
63
+				'capability' => 'ee_delete_default_ticket',
64
+				'obj_id'     => $tkt_id,
65
+				'noheader'   => true,
66
+				'args'       => array('trash' => true),
67
+			),
68
+			'trash_tickets'            => array(
69
+				'func'       => '_trash_or_restore_ticket',
70
+				'capability' => 'ee_delete_default_tickets',
71
+				'noheader'   => true,
72
+				'args'       => array('trash' => true),
73
+			),
74
+			'restore_ticket'           => array(
75
+				'func'       => '_trash_or_restore_ticket',
76
+				'capability' => 'ee_delete_default_ticket',
77
+				'obj_id'     => $tkt_id,
78
+				'noheader'   => true,
79
+			),
80
+			'restore_tickets'          => array(
81
+				'func'       => '_trash_or_restore_ticket',
82
+				'capability' => 'ee_delete_default_tickets',
83
+				'noheader'   => true,
84
+			),
85
+			'delete_ticket'            => array(
86
+				'func'       => '_delete_ticket',
87
+				'capability' => 'ee_delete_default_ticket',
88
+				'obj_id'     => $tkt_id,
89
+				'noheader'   => true,
90
+			),
91
+			'delete_tickets'           => array(
92
+				'func'       => '_delete_ticket',
93
+				'capability' => 'ee_delete_default_tickets',
94
+				'noheader'   => true,
95
+			),
96
+			'import_page'              => array(
97
+				'func'       => '_import_page',
98
+				'capability' => 'import',
99
+			),
100
+			'import'                   => array(
101
+				'func'       => '_import_events',
102
+				'capability' => 'import',
103
+				'noheader'   => true,
104
+			),
105
+			'import_events'            => array(
106
+				'func'       => '_import_events',
107
+				'capability' => 'import',
108
+				'noheader'   => true,
109
+			),
110
+			'export_events'            => array(
111
+				'func'       => '_events_export',
112
+				'capability' => 'export',
113
+				'noheader'   => true,
114
+			),
115
+			'export_categories'        => array(
116
+				'func'       => '_categories_export',
117
+				'capability' => 'export',
118
+				'noheader'   => true,
119
+			),
120
+			'sample_export_file'       => array(
121
+				'func'       => '_sample_export_file',
122
+				'capability' => 'export',
123
+				'noheader'   => true,
124
+			),
125
+			'update_template_settings' => array(
126
+				'func'       => '_update_template_settings',
127
+				'capability' => 'manage_options',
128
+				'noheader'   => true,
129
+			),
130
+		);
131
+		$this->_page_routes = array_merge($this->_page_routes, $new_page_routes);
132
+		// partial route/config override
133
+		$this->_page_config['import_events']['metaboxes'] = $this->_default_espresso_metaboxes;
134
+		$this->_page_config['create_new']['metaboxes'][] = '_premium_event_editor_meta_boxes';
135
+		$this->_page_config['create_new']['qtips'][] = 'EE_Event_Editor_Tips';
136
+		$this->_page_config['edit']['qtips'][] = 'EE_Event_Editor_Tips';
137
+		$this->_page_config['edit']['metaboxes'][] = '_premium_event_editor_meta_boxes';
138
+		$this->_page_config['default']['list_table'] = 'Extend_Events_Admin_List_Table';
139
+		// add tickets tab but only if there are more than one default ticket!
140
+		$tkt_count = EEM_Ticket::instance()->count_deleted_and_undeleted(
141
+			array(array('TKT_is_default' => 1)),
142
+			'TKT_ID',
143
+			true
144
+		);
145
+		if ($tkt_count > 1) {
146
+			$new_page_config = array(
147
+				'ticket_list_table' => array(
148
+					'nav'           => array(
149
+						'label' => esc_html__('Default Tickets', 'event_espresso'),
150
+						'order' => 60,
151
+					),
152
+					'list_table'    => 'Tickets_List_Table',
153
+					'require_nonce' => false,
154
+				),
155
+			);
156
+		}
157
+		// template settings
158
+		$new_page_config['template_settings'] = array(
159
+			'nav'           => array(
160
+				'label' => esc_html__('Templates', 'event_espresso'),
161
+				'order' => 30,
162
+			),
163
+			'metaboxes'     => array_merge($this->_default_espresso_metaboxes, array('_publish_post_box')),
164
+			'help_tabs'     => array(
165
+				'general_settings_templates_help_tab' => array(
166
+					'title'    => esc_html__('Templates', 'event_espresso'),
167
+					'filename' => 'general_settings_templates',
168
+				),
169
+			),
170
+			'help_tour'     => array('Templates_Help_Tour'),
171
+			'require_nonce' => false,
172
+		);
173
+		$this->_page_config = array_merge($this->_page_config, $new_page_config);
174
+		// add filters and actions
175
+		// modifying _views
176
+		add_filter(
177
+			'FHEE_event_datetime_metabox_add_additional_date_time_template',
178
+			array($this, 'add_additional_datetime_button'),
179
+			10,
180
+			2
181
+		);
182
+		add_filter(
183
+			'FHEE_event_datetime_metabox_clone_button_template',
184
+			array($this, 'add_datetime_clone_button'),
185
+			10,
186
+			2
187
+		);
188
+		add_filter(
189
+			'FHEE_event_datetime_metabox_timezones_template',
190
+			array($this, 'datetime_timezones_template'),
191
+			10,
192
+			2
193
+		);
194
+		// filters for event list table
195
+		add_filter('FHEE__Extend_Events_Admin_List_Table__filters', array($this, 'list_table_filters'), 10, 2);
196
+		add_filter(
197
+			'FHEE__Events_Admin_List_Table__column_actions__action_links',
198
+			array($this, 'extra_list_table_actions'),
199
+			10,
200
+			2
201
+		);
202
+		// legend item
203
+		add_filter('FHEE__Events_Admin_Page___event_legend_items__items', array($this, 'additional_legend_items'));
204
+		add_action('admin_init', array($this, 'admin_init'));
205
+	}
206
+
207
+
208
+	/**
209
+	 * admin_init
210
+	 */
211
+	public function admin_init()
212
+	{
213
+		EE_Registry::$i18n_js_strings = array_merge(
214
+			EE_Registry::$i18n_js_strings,
215
+			array(
216
+				'image_confirm'          => esc_html__(
217
+					'Do you really want to delete this image? Please remember to update your event to complete the removal.',
218
+					'event_espresso'
219
+				),
220
+				'event_starts_on'        => esc_html__('Event Starts on', 'event_espresso'),
221
+				'event_ends_on'          => esc_html__('Event Ends on', 'event_espresso'),
222
+				'event_datetime_actions' => esc_html__('Actions', 'event_espresso'),
223
+				'event_clone_dt_msg'     => esc_html__('Clone this Event Date and Time', 'event_espresso'),
224
+				'remove_event_dt_msg'    => esc_html__('Remove this Event Time', 'event_espresso'),
225
+			)
226
+		);
227
+	}
228
+
229
+
230
+	/**
231
+	 * Add per page screen options to the default ticket list table view.
232
+	 */
233
+	protected function _add_screen_options_ticket_list_table()
234
+	{
235
+		$this->_per_page_screen_option();
236
+	}
237
+
238
+
239
+	/**
240
+	 * @param string $return
241
+	 * @param int    $id
242
+	 * @param string $new_title
243
+	 * @param string $new_slug
244
+	 * @return string
245
+	 */
246
+	public function extra_permalink_field_buttons($return, $id, $new_title, $new_slug)
247
+	{
248
+		$return = parent::extra_permalink_field_buttons($return, $id, $new_title, $new_slug);
249
+		// make sure this is only when editing
250
+		if (! empty($id)) {
251
+			$href = EE_Admin_Page::add_query_args_and_nonce(
252
+				array('action' => 'duplicate_event', 'EVT_ID' => $id),
253
+				$this->_admin_base_url
254
+			);
255
+			$title = esc_attr__('Duplicate Event', 'event_espresso');
256
+			$return .= '<a href="'
257
+					   . $href
258
+					   . '" title="'
259
+					   . $title
260
+					   . '" id="ee-duplicate-event-button" class="button button-small"  value="duplicate_event">'
261
+					   . $title
262
+					   . '</a>';
263
+		}
264
+		return $return;
265
+	}
266
+
267
+
268
+	/**
269
+	 * Set the list table views for the default ticket list table view.
270
+	 */
271
+	public function _set_list_table_views_ticket_list_table()
272
+	{
273
+		$this->_views = array(
274
+			'all'     => array(
275
+				'slug'        => 'all',
276
+				'label'       => esc_html__('All', 'event_espresso'),
277
+				'count'       => 0,
278
+				'bulk_action' => array(
279
+					'trash_tickets' => esc_html__('Move to Trash', 'event_espresso'),
280
+				),
281
+			),
282
+			'trashed' => array(
283
+				'slug'        => 'trashed',
284
+				'label'       => esc_html__('Trash', 'event_espresso'),
285
+				'count'       => 0,
286
+				'bulk_action' => array(
287
+					'restore_tickets' => esc_html__('Restore from Trash', 'event_espresso'),
288
+					'delete_tickets'  => esc_html__('Delete Permanently', 'event_espresso'),
289
+				),
290
+			),
291
+		);
292
+	}
293
+
294
+
295
+	/**
296
+	 * Enqueue scripts and styles for the event editor.
297
+	 */
298
+	public function load_scripts_styles_edit()
299
+	{
300
+		wp_register_script(
301
+			'ee-event-editor-heartbeat',
302
+			EVENTS_CAF_ASSETS_URL . 'event-editor-heartbeat.js',
303
+			array('ee_admin_js', 'heartbeat'),
304
+			EVENT_ESPRESSO_VERSION,
305
+			true
306
+		);
307
+		wp_enqueue_script('ee-accounting');
308
+		// styles
309
+		wp_enqueue_style('espresso-ui-theme');
310
+		wp_enqueue_script('event_editor_js');
311
+		wp_enqueue_script('ee-event-editor-heartbeat');
312
+	}
313
+
314
+
315
+	/**
316
+	 * Returns template for the additional datetime.
317
+	 *
318
+	 * @param $template
319
+	 * @param $template_args
320
+	 * @return mixed
321
+	 * @throws DomainException
322
+	 */
323
+	public function add_additional_datetime_button($template, $template_args)
324
+	{
325
+		return EEH_Template::display_template(
326
+			EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_add_additional_time.template.php',
327
+			$template_args,
328
+			true
329
+		);
330
+	}
331
+
332
+
333
+	/**
334
+	 * Returns the template for cloning a datetime.
335
+	 *
336
+	 * @param $template
337
+	 * @param $template_args
338
+	 * @return mixed
339
+	 * @throws DomainException
340
+	 */
341
+	public function add_datetime_clone_button($template, $template_args)
342
+	{
343
+		return EEH_Template::display_template(
344
+			EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_metabox_clone_button.template.php',
345
+			$template_args,
346
+			true
347
+		);
348
+	}
349
+
350
+
351
+	/**
352
+	 * Returns the template for datetime timezones.
353
+	 *
354
+	 * @param $template
355
+	 * @param $template_args
356
+	 * @return mixed
357
+	 * @throws DomainException
358
+	 */
359
+	public function datetime_timezones_template($template, $template_args)
360
+	{
361
+		return EEH_Template::display_template(
362
+			EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_timezones.template.php',
363
+			$template_args,
364
+			true
365
+		);
366
+	}
367
+
368
+
369
+	/**
370
+	 * Sets the views for the default list table view.
371
+	 */
372
+	protected function _set_list_table_views_default()
373
+	{
374
+		parent::_set_list_table_views_default();
375
+		$new_views = array(
376
+			'today' => array(
377
+				'slug'        => 'today',
378
+				'label'       => esc_html__('Today', 'event_espresso'),
379
+				'count'       => $this->total_events_today(),
380
+				'bulk_action' => array(
381
+					'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
382
+				),
383
+			),
384
+			'month' => array(
385
+				'slug'        => 'month',
386
+				'label'       => esc_html__('This Month', 'event_espresso'),
387
+				'count'       => $this->total_events_this_month(),
388
+				'bulk_action' => array(
389
+					'trash_events' => esc_html__('Move to Trash', 'event_espresso'),
390
+				),
391
+			),
392
+		);
393
+		$this->_views = array_merge($this->_views, $new_views);
394
+	}
395
+
396
+
397
+	/**
398
+	 * Returns the extra action links for the default list table view.
399
+	 *
400
+	 * @param array     $action_links
401
+	 * @param \EE_Event $event
402
+	 * @return array
403
+	 * @throws EE_Error
404
+	 */
405
+	public function extra_list_table_actions(array $action_links, \EE_Event $event)
406
+	{
407
+		if (EE_Registry::instance()->CAP->current_user_can(
408
+			'ee_read_registrations',
409
+			'espresso_registrations_reports',
410
+			$event->ID()
411
+		)
412
+		) {
413
+			$reports_query_args = array(
414
+				'action' => 'reports',
415
+				'EVT_ID' => $event->ID(),
416
+			);
417
+			$reports_link = EE_Admin_Page::add_query_args_and_nonce($reports_query_args, REG_ADMIN_URL);
418
+			$action_links[] = '<a href="'
419
+							  . $reports_link
420
+							  . '" title="'
421
+							  . esc_attr__('View Report', 'event_espresso')
422
+							  . '"><div class="dashicons dashicons-chart-bar"></div></a>'
423
+							  . "\n\t";
424
+		}
425
+		if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
426
+			EE_Registry::instance()->load_helper('MSG_Template');
427
+			$action_links[] = EEH_MSG_Template::get_message_action_link(
428
+				'see_notifications_for',
429
+				null,
430
+				array('EVT_ID' => $event->ID())
431
+			);
432
+		}
433
+		return $action_links;
434
+	}
435
+
436
+
437
+	/**
438
+	 * @param $items
439
+	 * @return mixed
440
+	 */
441
+	public function additional_legend_items($items)
442
+	{
443
+		if (EE_Registry::instance()->CAP->current_user_can(
444
+			'ee_read_registrations',
445
+			'espresso_registrations_reports'
446
+		)
447
+		) {
448
+			$items['reports'] = array(
449
+				'class' => 'dashicons dashicons-chart-bar',
450
+				'desc'  => esc_html__('Event Reports', 'event_espresso'),
451
+			);
452
+		}
453
+		if (EE_Registry::instance()->CAP->current_user_can('ee_read_global_messages', 'view_filtered_messages')) {
454
+			$related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
455
+			if (isset($related_for_icon['css_class']) && isset($related_for_icon['label'])) {
456
+				$items['view_related_messages'] = array(
457
+					'class' => $related_for_icon['css_class'],
458
+					'desc'  => $related_for_icon['label'],
459
+				);
460
+			}
461
+		}
462
+		return $items;
463
+	}
464
+
465
+
466
+	/**
467
+	 * This is the callback method for the duplicate event route
468
+	 * Method looks for 'EVT_ID' in the request and retrieves that event and its details and duplicates them
469
+	 * into a new event.  We add a hook so that any plugins that add extra event details can hook into this
470
+	 * action.  Note that the dupe will have **DUPLICATE** as its title and slug.
471
+	 * After duplication the redirect is to the new event edit page.
472
+	 *
473
+	 * @return void
474
+	 * @access protected
475
+	 * @throws EE_Error If EE_Event is not available with given ID
476
+	 */
477
+	protected function _duplicate_event()
478
+	{
479
+		// first make sure the ID for the event is in the request.
480
+		//  If it isn't then we need to bail and redirect back to overview list table (cause how did we get here?)
481
+		if (! isset($this->_req_data['EVT_ID'])) {
482
+			EE_Error::add_error(
483
+				esc_html__(
484
+					'In order to duplicate an event an Event ID is required.  None was given.',
485
+					'event_espresso'
486
+				),
487
+				__FILE__,
488
+				__FUNCTION__,
489
+				__LINE__
490
+			);
491
+			$this->_redirect_after_action(false, '', '', array(), true);
492
+			return;
493
+		}
494
+		// k we've got EVT_ID so let's use that to get the event we'll duplicate
495
+		$orig_event = EEM_Event::instance()->get_one_by_ID($this->_req_data['EVT_ID']);
496
+		if (! $orig_event instanceof EE_Event) {
497
+			throw new EE_Error(
498
+				sprintf(
499
+					esc_html__('An EE_Event object could not be retrieved for the given ID (%s)', 'event_espresso'),
500
+					$this->_req_data['EVT_ID']
501
+				)
502
+			);
503
+		}
504
+		// k now let's clone the $orig_event before getting relations
505
+		$new_event = clone $orig_event;
506
+		// original datetimes
507
+		$orig_datetimes = $orig_event->get_many_related('Datetime');
508
+		// other original relations
509
+		$orig_ven = $orig_event->get_many_related('Venue');
510
+		// reset the ID and modify other details to make it clear this is a dupe
511
+		$new_event->set('EVT_ID', 0);
512
+		$new_name = $new_event->name() . ' ' . esc_html__('**DUPLICATE**', 'event_espresso');
513
+		$new_event->set('EVT_name', $new_name);
514
+		$new_event->set(
515
+			'EVT_slug',
516
+			wp_unique_post_slug(
517
+				sanitize_title($orig_event->name()),
518
+				0,
519
+				'publish',
520
+				'espresso_events',
521
+				0
522
+			)
523
+		);
524
+		$new_event->set('status', 'draft');
525
+		// duplicate discussion settings
526
+		$new_event->set('comment_status', $orig_event->get('comment_status'));
527
+		$new_event->set('ping_status', $orig_event->get('ping_status'));
528
+		// save the new event
529
+		$new_event->save();
530
+		// venues
531
+		foreach ($orig_ven as $ven) {
532
+			$new_event->_add_relation_to($ven, 'Venue');
533
+		}
534
+		$new_event->save();
535
+		// now we need to get the question group relations and handle that
536
+		// first primary question groups
537
+		$orig_primary_qgs = $orig_event->get_many_related(
538
+			'Question_Group',
539
+			[['Event_Question_Group.EQG_primary' => true]]
540
+		);
541
+		if (! empty($orig_primary_qgs)) {
542
+			foreach ($orig_primary_qgs as $id => $obj) {
543
+				if ($obj instanceof EE_Question_Group) {
544
+					$new_event->_add_relation_to($obj, 'Question_Group', ['EQG_primary' => true]);
545
+				}
546
+			}
547
+		}
548
+		// next additional attendee question groups
549
+		$orig_additional_qgs = $orig_event->get_many_related(
550
+			'Question_Group',
551
+			[['Event_Question_Group.EQG_additional' => true]]
552
+		);
553
+		if (! empty($orig_additional_qgs)) {
554
+			foreach ($orig_additional_qgs as $id => $obj) {
555
+				if ($obj instanceof EE_Question_Group) {
556
+					$new_event->_add_relation_to($obj, 'Question_Group', ['EQG_additional' => true]);
557
+				}
558
+			}
559
+		}
560
+
561
+		$new_event->save();
562
+
563
+		// k now that we have the new event saved we can loop through the datetimes and start adding relations.
564
+		$cloned_tickets = array();
565
+		foreach ($orig_datetimes as $orig_dtt) {
566
+			if (! $orig_dtt instanceof EE_Datetime) {
567
+				continue;
568
+			}
569
+			$new_dtt = clone $orig_dtt;
570
+			$orig_tkts = $orig_dtt->tickets();
571
+			// save new dtt then add to event
572
+			$new_dtt->set('DTT_ID', 0);
573
+			$new_dtt->set('DTT_sold', 0);
574
+			$new_dtt->set_reserved(0);
575
+			$new_dtt->save();
576
+			$new_event->_add_relation_to($new_dtt, 'Datetime');
577
+			$new_event->save();
578
+			// now let's get the ticket relations setup.
579
+			foreach ((array) $orig_tkts as $orig_tkt) {
580
+				// it's possible a datetime will have no tickets so let's verify we HAVE a ticket first.
581
+				if (! $orig_tkt instanceof EE_Ticket) {
582
+					continue;
583
+				}
584
+				// is this ticket archived?  If it is then let's skip
585
+				if ($orig_tkt->get('TKT_deleted')) {
586
+					continue;
587
+				}
588
+				// does this original ticket already exist in the clone_tickets cache?
589
+				//  If so we'll just use the new ticket from it.
590
+				if (isset($cloned_tickets[ $orig_tkt->ID() ])) {
591
+					$new_tkt = $cloned_tickets[ $orig_tkt->ID() ];
592
+				} else {
593
+					$new_tkt = clone $orig_tkt;
594
+					// get relations on the $orig_tkt that we need to setup.
595
+					$orig_prices = $orig_tkt->prices();
596
+					$new_tkt->set('TKT_ID', 0);
597
+					$new_tkt->set('TKT_sold', 0);
598
+					$new_tkt->set('TKT_reserved', 0);
599
+					$new_tkt->save(); // make sure new ticket has ID.
600
+					// price relations on new ticket need to be setup.
601
+					foreach ($orig_prices as $orig_price) {
602
+						$new_price = clone $orig_price;
603
+						$new_price->set('PRC_ID', 0);
604
+						$new_price->save();
605
+						$new_tkt->_add_relation_to($new_price, 'Price');
606
+						$new_tkt->save();
607
+					}
608
+
609
+					do_action(
610
+						'AHEE__Extend_Events_Admin_Page___duplicate_event__duplicate_ticket__after',
611
+						$orig_tkt,
612
+						$new_tkt,
613
+						$orig_prices,
614
+						$orig_event,
615
+						$orig_dtt,
616
+						$new_dtt
617
+					);
618
+				}
619
+				// k now we can add the new ticket as a relation to the new datetime
620
+				// and make sure its added to our cached $cloned_tickets array
621
+				// for use with later datetimes that have the same ticket.
622
+				$new_dtt->_add_relation_to($new_tkt, 'Ticket');
623
+				$new_dtt->save();
624
+				$cloned_tickets[ $orig_tkt->ID() ] = $new_tkt;
625
+			}
626
+		}
627
+		// clone taxonomy information
628
+		$taxonomies_to_clone_with = apply_filters(
629
+			'FHEE__Extend_Events_Admin_Page___duplicate_event__taxonomies_to_clone',
630
+			array('espresso_event_categories', 'espresso_event_type', 'post_tag')
631
+		);
632
+		// get terms for original event (notice)
633
+		$orig_terms = wp_get_object_terms($orig_event->ID(), $taxonomies_to_clone_with);
634
+		// loop through terms and add them to new event.
635
+		foreach ($orig_terms as $term) {
636
+			wp_set_object_terms($new_event->ID(), $term->term_id, $term->taxonomy, true);
637
+		}
638
+
639
+		// duplicate other core WP_Post items for this event.
640
+		// post thumbnail (feature image).
641
+		$feature_image_id = get_post_thumbnail_id($orig_event->ID());
642
+		if ($feature_image_id) {
643
+			update_post_meta($new_event->ID(), '_thumbnail_id', $feature_image_id);
644
+		}
645
+
646
+		// duplicate page_template setting
647
+		$page_template = get_post_meta($orig_event->ID(), '_wp_page_template', true);
648
+		if ($page_template) {
649
+			update_post_meta($new_event->ID(), '_wp_page_template', $page_template);
650
+		}
651
+
652
+		do_action('AHEE__Extend_Events_Admin_Page___duplicate_event__after', $new_event, $orig_event);
653
+		// now let's redirect to the edit page for this duplicated event if we have a new event id.
654
+		if ($new_event->ID()) {
655
+			$redirect_args = array(
656
+				'post'   => $new_event->ID(),
657
+				'action' => 'edit',
658
+			);
659
+			EE_Error::add_success(
660
+				esc_html__(
661
+					'Event successfully duplicated.  Please review the details below and make any necessary edits',
662
+					'event_espresso'
663
+				)
664
+			);
665
+		} else {
666
+			$redirect_args = array(
667
+				'action' => 'default',
668
+			);
669
+			EE_Error::add_error(
670
+				esc_html__('Not able to duplicate event.  Something went wrong.', 'event_espresso'),
671
+				__FILE__,
672
+				__FUNCTION__,
673
+				__LINE__
674
+			);
675
+		}
676
+		$this->_redirect_after_action(false, '', '', $redirect_args, true);
677
+	}
678
+
679
+
680
+	/**
681
+	 * Generates output for the import page.
682
+	 *
683
+	 * @throws DomainException
684
+	 */
685
+	protected function _import_page()
686
+	{
687
+		$title = esc_html__('Import', 'event_espresso');
688
+		$intro = esc_html__(
689
+			'If you have a previously exported Event Espresso 4 information in a Comma Separated Value (CSV) file format, you can upload the file here: ',
690
+			'event_espresso'
691
+		);
692
+		$form_url = EVENTS_ADMIN_URL;
693
+		$action = 'import_events';
694
+		$type = 'csv';
695
+		$this->_template_args['form'] = EE_Import::instance()->upload_form(
696
+			$title,
697
+			$intro,
698
+			$form_url,
699
+			$action,
700
+			$type
701
+		);
702
+		$this->_template_args['sample_file_link'] = EE_Admin_Page::add_query_args_and_nonce(
703
+			array('action' => 'sample_export_file'),
704
+			$this->_admin_base_url
705
+		);
706
+		$content = EEH_Template::display_template(
707
+			EVENTS_CAF_TEMPLATE_PATH . 'import_page.template.php',
708
+			$this->_template_args,
709
+			true
710
+		);
711
+		$this->_template_args['admin_page_content'] = $content;
712
+		$this->display_admin_page_with_sidebar();
713
+	}
714
+
715
+
716
+	/**
717
+	 * _import_events
718
+	 * This handles displaying the screen and running imports for importing events.
719
+	 *
720
+	 * @return void
721
+	 */
722
+	protected function _import_events()
723
+	{
724
+		require_once(EE_CLASSES . 'EE_Import.class.php');
725
+		$success = EE_Import::instance()->import();
726
+		$this->_redirect_after_action($success, 'Import File', 'ran', array('action' => 'import_page'), true);
727
+	}
728
+
729
+
730
+	/**
731
+	 * _events_export
732
+	 * Will export all (or just the given event) to a Excel compatible file.
733
+	 *
734
+	 * @access protected
735
+	 * @return void
736
+	 */
737
+	protected function _events_export()
738
+	{
739
+		if (isset($this->_req_data['EVT_ID'])) {
740
+			$event_ids = $this->_req_data['EVT_ID'];
741
+		} elseif (isset($this->_req_data['EVT_IDs'])) {
742
+			$event_ids = $this->_req_data['EVT_IDs'];
743
+		} else {
744
+			$event_ids = null;
745
+		}
746
+		// todo: I don't like doing this but it'll do until we modify EE_Export Class.
747
+		$new_request_args = array(
748
+			'export' => 'report',
749
+			'action' => 'all_event_data',
750
+			'EVT_ID' => $event_ids,
751
+		);
752
+		$this->_req_data = array_merge($this->_req_data, $new_request_args);
753
+		if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
754
+			require_once(EE_CLASSES . 'EE_Export.class.php');
755
+			$EE_Export = EE_Export::instance($this->_req_data);
756
+			$EE_Export->export();
757
+		}
758
+	}
759
+
760
+
761
+	/**
762
+	 * handle category exports()
763
+	 *
764
+	 * @return void
765
+	 */
766
+	protected function _categories_export()
767
+	{
768
+		// todo: I don't like doing this but it'll do until we modify EE_Export Class.
769
+		$new_request_args = array(
770
+			'export'       => 'report',
771
+			'action'       => 'categories',
772
+			'category_ids' => $this->_req_data['EVT_CAT_ID'],
773
+		);
774
+		$this->_req_data = array_merge($this->_req_data, $new_request_args);
775
+		if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
776
+			require_once(EE_CLASSES . 'EE_Export.class.php');
777
+			$EE_Export = EE_Export::instance($this->_req_data);
778
+			$EE_Export->export();
779
+		}
780
+	}
781
+
782
+
783
+	/**
784
+	 * Creates a sample CSV file for importing
785
+	 */
786
+	protected function _sample_export_file()
787
+	{
788
+		// require_once(EE_CLASSES . 'EE_Export.class.php');
789
+		EE_Export::instance()->export_sample();
790
+	}
791
+
792
+
793
+	/*************        Template Settings        *************/
794
+	/**
795
+	 * Generates template settings page output
796
+	 *
797
+	 * @throws DomainException
798
+	 * @throws EE_Error
799
+	 */
800
+	protected function _template_settings()
801
+	{
802
+		$this->_template_args['values'] = $this->_yes_no_values;
803
+		/**
804
+		 * Note leaving this filter in for backward compatibility this was moved in 4.6.x
805
+		 * from General_Settings_Admin_Page to here.
806
+		 */
807
+		$this->_template_args = apply_filters(
808
+			'FHEE__General_Settings_Admin_Page__template_settings__template_args',
809
+			$this->_template_args
810
+		);
811
+		$this->_set_add_edit_form_tags('update_template_settings');
812
+		$this->_set_publish_post_box_vars(null, false, false, null, false);
813
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
814
+			EVENTS_CAF_TEMPLATE_PATH . 'template_settings.template.php',
815
+			$this->_template_args,
816
+			true
817
+		);
818
+		$this->display_admin_page_with_sidebar();
819
+	}
820
+
821
+
822
+	/**
823
+	 * Handler for updating template settings.
824
+	 *
825
+	 * @throws InvalidInterfaceException
826
+	 * @throws InvalidDataTypeException
827
+	 * @throws InvalidArgumentException
828
+	 */
829
+	protected function _update_template_settings()
830
+	{
831
+		/**
832
+		 * Note leaving this filter in for backward compatibility this was moved in 4.6.x
833
+		 * from General_Settings_Admin_Page to here.
834
+		 */
835
+		EE_Registry::instance()->CFG->template_settings = apply_filters(
836
+			'FHEE__General_Settings_Admin_Page__update_template_settings__data',
837
+			EE_Registry::instance()->CFG->template_settings,
838
+			$this->_req_data
839
+		);
840
+		// update custom post type slugs and detect if we need to flush rewrite rules
841
+		$old_slug = EE_Registry::instance()->CFG->core->event_cpt_slug;
842
+		EE_Registry::instance()->CFG->core->event_cpt_slug = empty($this->_req_data['event_cpt_slug'])
843
+			? EE_Registry::instance()->CFG->core->event_cpt_slug
844
+			: EEH_URL::slugify($this->_req_data['event_cpt_slug'], 'events');
845
+		$what = 'Template Settings';
846
+		$success = $this->_update_espresso_configuration(
847
+			$what,
848
+			EE_Registry::instance()->CFG->template_settings,
849
+			__FILE__,
850
+			__FUNCTION__,
851
+			__LINE__
852
+		);
853
+		if (EE_Registry::instance()->CFG->core->event_cpt_slug != $old_slug) {
854
+			/** @var EventEspresso\core\domain\services\custom_post_types\RewriteRules $rewrite_rules */
855
+			$rewrite_rules = LoaderFactory::getLoader()->getShared(
856
+				'EventEspresso\core\domain\services\custom_post_types\RewriteRules'
857
+			);
858
+			$rewrite_rules->flush();
859
+		}
860
+		$this->_redirect_after_action($success, $what, 'updated', array('action' => 'template_settings'));
861
+	}
862
+
863
+
864
+	/**
865
+	 * _premium_event_editor_meta_boxes
866
+	 * add all metaboxes related to the event_editor
867
+	 *
868
+	 * @access protected
869
+	 * @return void
870
+	 * @throws EE_Error
871
+	 */
872
+	protected function _premium_event_editor_meta_boxes()
873
+	{
874
+		$this->verify_cpt_object();
875
+		add_meta_box(
876
+			'espresso_event_editor_event_options',
877
+			esc_html__('Event Registration Options', 'event_espresso'),
878
+			array($this, 'registration_options_meta_box'),
879
+			$this->page_slug,
880
+			'side',
881
+			'core'
882
+		);
883
+	}
884
+
885
+
886
+	/**
887
+	 * override caf metabox
888
+	 *
889
+	 * @return void
890
+	 * @throws DomainException
891
+	 */
892
+	public function registration_options_meta_box()
893
+	{
894
+		$yes_no_values = array(
895
+			array('id' => true, 'text' => esc_html__('Yes', 'event_espresso')),
896
+			array('id' => false, 'text' => esc_html__('No', 'event_espresso')),
897
+		);
898
+		$default_reg_status_values = EEM_Registration::reg_status_array(
899
+			array(
900
+				EEM_Registration::status_id_cancelled,
901
+				EEM_Registration::status_id_declined,
902
+				EEM_Registration::status_id_incomplete,
903
+				EEM_Registration::status_id_wait_list,
904
+			),
905
+			true
906
+		);
907
+		$template_args['active_status'] = $this->_cpt_model_obj->pretty_active_status(false);
908
+		$template_args['_event'] = $this->_cpt_model_obj;
909
+		$template_args['additional_limit'] = $this->_cpt_model_obj->additional_limit();
910
+		$template_args['default_registration_status'] = EEH_Form_Fields::select_input(
911
+			'default_reg_status',
912
+			$default_reg_status_values,
913
+			$this->_cpt_model_obj->default_registration_status()
914
+		);
915
+		$template_args['display_description'] = EEH_Form_Fields::select_input(
916
+			'display_desc',
917
+			$yes_no_values,
918
+			$this->_cpt_model_obj->display_description()
919
+		);
920
+		$template_args['display_ticket_selector'] = EEH_Form_Fields::select_input(
921
+			'display_ticket_selector',
922
+			$yes_no_values,
923
+			$this->_cpt_model_obj->display_ticket_selector(),
924
+			'',
925
+			'',
926
+			false
927
+		);
928
+		$template_args['EVT_default_registration_status'] = EEH_Form_Fields::select_input(
929
+			'EVT_default_registration_status',
930
+			$default_reg_status_values,
931
+			$this->_cpt_model_obj->default_registration_status()
932
+		);
933
+		$template_args['additional_registration_options'] = apply_filters(
934
+			'FHEE__Events_Admin_Page__registration_options_meta_box__additional_registration_options',
935
+			'',
936
+			$template_args,
937
+			$yes_no_values,
938
+			$default_reg_status_values
939
+		);
940
+		EEH_Template::display_template(
941
+			EVENTS_CAF_TEMPLATE_PATH . 'event_registration_options.template.php',
942
+			$template_args
943
+		);
944
+	}
945
+
946
+
947
+
948
+	/**
949
+	 * wp_list_table_mods for caf
950
+	 * ============================
951
+	 */
952
+	/**
953
+	 * hook into list table filters and provide filters for caffeinated list table
954
+	 *
955
+	 * @param  array $old_filters    any existing filters present
956
+	 * @param  array $list_table_obj the list table object
957
+	 * @return array                  new filters
958
+	 */
959
+	public function list_table_filters($old_filters, $list_table_obj)
960
+	{
961
+		$filters = array();
962
+		// first month/year filters
963
+		$filters[] = $this->espresso_event_months_dropdown();
964
+		$status = isset($this->_req_data['status']) ? $this->_req_data['status'] : null;
965
+		// active status dropdown
966
+		if ($status !== 'draft') {
967
+			$filters[] = $this->active_status_dropdown(
968
+				isset($this->_req_data['active_status']) ? $this->_req_data['active_status'] : ''
969
+			);
970
+		}
971
+		// category filter
972
+		$filters[] = $this->category_dropdown();
973
+		return array_merge($old_filters, $filters);
974
+	}
975
+
976
+
977
+	/**
978
+	 * espresso_event_months_dropdown
979
+	 *
980
+	 * @access public
981
+	 * @return string                dropdown listing month/year selections for events.
982
+	 */
983
+	public function espresso_event_months_dropdown()
984
+	{
985
+		// what we need to do is get all PRIMARY datetimes for all events to filter on.
986
+		// Note we need to include any other filters that are set!
987
+		$status = isset($this->_req_data['status']) ? $this->_req_data['status'] : null;
988
+		// categories?
989
+		$category = isset($this->_req_data['EVT_CAT']) && $this->_req_data['EVT_CAT'] > 0
990
+			? $this->_req_data['EVT_CAT']
991
+			: null;
992
+		// active status?
993
+		$active_status = isset($this->_req_data['active_status']) ? $this->_req_data['active_status'] : null;
994
+		$cur_date = isset($this->_req_data['month_range']) ? $this->_req_data['month_range'] : '';
995
+		return EEH_Form_Fields::generate_event_months_dropdown($cur_date, $status, $category, $active_status);
996
+	}
997
+
998
+
999
+	/**
1000
+	 * returns a list of "active" statuses on the event
1001
+	 *
1002
+	 * @param  string $current_value whatever the current active status is
1003
+	 * @return string
1004
+	 */
1005
+	public function active_status_dropdown($current_value = '')
1006
+	{
1007
+		$select_name = 'active_status';
1008
+		$values = array(
1009
+			'none'     => esc_html__('Show Active/Inactive', 'event_espresso'),
1010
+			'active'   => esc_html__('Active', 'event_espresso'),
1011
+			'upcoming' => esc_html__('Upcoming', 'event_espresso'),
1012
+			'expired'  => esc_html__('Expired', 'event_espresso'),
1013
+			'inactive' => esc_html__('Inactive', 'event_espresso'),
1014
+		);
1015
+		$id = 'id="espresso-active-status-dropdown-filter"';
1016
+		$class = 'wide';
1017
+		return EEH_Form_Fields::select_input($select_name, $values, $current_value, $id, $class);
1018
+	}
1019
+
1020
+
1021
+	/**
1022
+	 * output a dropdown of the categories for the category filter on the event admin list table
1023
+	 *
1024
+	 * @access  public
1025
+	 * @return string html
1026
+	 */
1027
+	public function category_dropdown()
1028
+	{
1029
+		$cur_cat = isset($this->_req_data['EVT_CAT']) ? $this->_req_data['EVT_CAT'] : -1;
1030
+		return EEH_Form_Fields::generate_event_category_dropdown($cur_cat);
1031
+	}
1032
+
1033
+
1034
+	/**
1035
+	 * get total number of events today
1036
+	 *
1037
+	 * @access public
1038
+	 * @return int
1039
+	 * @throws EE_Error
1040
+	 */
1041
+	public function total_events_today()
1042
+	{
1043
+		$start = EEM_Datetime::instance()->convert_datetime_for_query(
1044
+			'DTT_EVT_start',
1045
+			date('Y-m-d') . ' 00:00:00',
1046
+			'Y-m-d H:i:s',
1047
+			'UTC'
1048
+		);
1049
+		$end = EEM_Datetime::instance()->convert_datetime_for_query(
1050
+			'DTT_EVT_start',
1051
+			date('Y-m-d') . ' 23:59:59',
1052
+			'Y-m-d H:i:s',
1053
+			'UTC'
1054
+		);
1055
+		$where = array(
1056
+			'Datetime.DTT_EVT_start' => array('BETWEEN', array($start, $end)),
1057
+		);
1058
+		$count = EEM_Event::instance()->count(array($where, 'caps' => 'read_admin'), 'EVT_ID', true);
1059
+		return $count;
1060
+	}
1061
+
1062
+
1063
+	/**
1064
+	 * get total number of events this month
1065
+	 *
1066
+	 * @access public
1067
+	 * @return int
1068
+	 * @throws EE_Error
1069
+	 */
1070
+	public function total_events_this_month()
1071
+	{
1072
+		// Dates
1073
+		$this_year_r = date('Y');
1074
+		$this_month_r = date('m');
1075
+		$days_this_month = date('t');
1076
+		$start = EEM_Datetime::instance()->convert_datetime_for_query(
1077
+			'DTT_EVT_start',
1078
+			$this_year_r . '-' . $this_month_r . '-01 00:00:00',
1079
+			'Y-m-d H:i:s',
1080
+			'UTC'
1081
+		);
1082
+		$end = EEM_Datetime::instance()->convert_datetime_for_query(
1083
+			'DTT_EVT_start',
1084
+			$this_year_r . '-' . $this_month_r . '-' . $days_this_month . ' 23:59:59',
1085
+			'Y-m-d H:i:s',
1086
+			'UTC'
1087
+		);
1088
+		$where = array(
1089
+			'Datetime.DTT_EVT_start' => array('BETWEEN', array($start, $end)),
1090
+		);
1091
+		$count = EEM_Event::instance()->count(array($where, 'caps' => 'read_admin'), 'EVT_ID', true);
1092
+		return $count;
1093
+	}
1094
+
1095
+
1096
+	/** DEFAULT TICKETS STUFF **/
1097
+
1098
+	/**
1099
+	 * Output default tickets list table view.
1100
+	 */
1101
+	public function _tickets_overview_list_table()
1102
+	{
1103
+		$this->_search_btn_label = esc_html__('Tickets', 'event_espresso');
1104
+		$this->display_admin_list_table_page_with_no_sidebar();
1105
+	}
1106
+
1107
+
1108
+	/**
1109
+	 * @param int  $per_page
1110
+	 * @param bool $count
1111
+	 * @param bool $trashed
1112
+	 * @return \EE_Soft_Delete_Base_Class[]|int
1113
+	 */
1114
+	public function get_default_tickets($per_page = 10, $count = false, $trashed = false)
1115
+	{
1116
+		$orderby = empty($this->_req_data['orderby']) ? 'TKT_name' : $this->_req_data['orderby'];
1117
+		$order = empty($this->_req_data['order']) ? 'ASC' : $this->_req_data['order'];
1118
+		switch ($orderby) {
1119
+			case 'TKT_name':
1120
+				$orderby = array('TKT_name' => $order);
1121
+				break;
1122
+			case 'TKT_price':
1123
+				$orderby = array('TKT_price' => $order);
1124
+				break;
1125
+			case 'TKT_uses':
1126
+				$orderby = array('TKT_uses' => $order);
1127
+				break;
1128
+			case 'TKT_min':
1129
+				$orderby = array('TKT_min' => $order);
1130
+				break;
1131
+			case 'TKT_max':
1132
+				$orderby = array('TKT_max' => $order);
1133
+				break;
1134
+			case 'TKT_qty':
1135
+				$orderby = array('TKT_qty' => $order);
1136
+				break;
1137
+		}
1138
+		$current_page = isset($this->_req_data['paged']) && ! empty($this->_req_data['paged'])
1139
+			? $this->_req_data['paged']
1140
+			: 1;
1141
+		$per_page = isset($this->_req_data['perpage']) && ! empty($this->_req_data['perpage'])
1142
+			? $this->_req_data['perpage']
1143
+			: $per_page;
1144
+		$_where = array(
1145
+			'TKT_is_default' => 1,
1146
+			'TKT_deleted'    => $trashed,
1147
+		);
1148
+		$offset = ($current_page - 1) * $per_page;
1149
+		$limit = array($offset, $per_page);
1150
+		if (isset($this->_req_data['s'])) {
1151
+			$sstr = '%' . $this->_req_data['s'] . '%';
1152
+			$_where['OR'] = array(
1153
+				'TKT_name'        => array('LIKE', $sstr),
1154
+				'TKT_description' => array('LIKE', $sstr),
1155
+			);
1156
+		}
1157
+		$query_params = array(
1158
+			$_where,
1159
+			'order_by' => $orderby,
1160
+			'limit'    => $limit,
1161
+			'group_by' => 'TKT_ID',
1162
+		);
1163
+		if ($count) {
1164
+			return EEM_Ticket::instance()->count_deleted_and_undeleted(array($_where));
1165
+		} else {
1166
+			return EEM_Ticket::instance()->get_all_deleted_and_undeleted($query_params);
1167
+		}
1168
+	}
1169
+
1170
+
1171
+	/**
1172
+	 * @param bool $trash
1173
+	 * @throws EE_Error
1174
+	 */
1175
+	protected function _trash_or_restore_ticket($trash = false)
1176
+	{
1177
+		$success = 1;
1178
+		$TKT = EEM_Ticket::instance();
1179
+		// checkboxes?
1180
+		if (! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
1181
+			// if array has more than one element then success message should be plural
1182
+			$success = count($this->_req_data['checkbox']) > 1 ? 2 : 1;
1183
+			// cycle thru the boxes
1184
+			while (list($TKT_ID, $value) = each($this->_req_data['checkbox'])) {
1185
+				if ($trash) {
1186
+					if (! $TKT->delete_by_ID($TKT_ID)) {
1187
+						$success = 0;
1188
+					}
1189
+				} else {
1190
+					if (! $TKT->restore_by_ID($TKT_ID)) {
1191
+						$success = 0;
1192
+					}
1193
+				}
1194
+			}
1195
+		} else {
1196
+			// grab single id and trash
1197
+			$TKT_ID = absint($this->_req_data['TKT_ID']);
1198
+			if ($trash) {
1199
+				if (! $TKT->delete_by_ID($TKT_ID)) {
1200
+					$success = 0;
1201
+				}
1202
+			} else {
1203
+				if (! $TKT->restore_by_ID($TKT_ID)) {
1204
+					$success = 0;
1205
+				}
1206
+			}
1207
+		}
1208
+		$action_desc = $trash ? 'moved to the trash' : 'restored';
1209
+		$query_args = array(
1210
+			'action' => 'ticket_list_table',
1211
+			'status' => $trash ? '' : 'trashed',
1212
+		);
1213
+		$this->_redirect_after_action($success, 'Tickets', $action_desc, $query_args);
1214
+	}
1215
+
1216
+
1217
+	/**
1218
+	 * Handles trashing default ticket.
1219
+	 */
1220
+	protected function _delete_ticket()
1221
+	{
1222
+		$success = 1;
1223
+		// checkboxes?
1224
+		if (! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
1225
+			// if array has more than one element then success message should be plural
1226
+			$success = count($this->_req_data['checkbox']) > 1 ? 2 : 1;
1227
+			// cycle thru the boxes
1228
+			while (list($TKT_ID, $value) = each($this->_req_data['checkbox'])) {
1229
+				// delete
1230
+				if (! $this->_delete_the_ticket($TKT_ID)) {
1231
+					$success = 0;
1232
+				}
1233
+			}
1234
+		} else {
1235
+			// grab single id and trash
1236
+			$TKT_ID = absint($this->_req_data['TKT_ID']);
1237
+			if (! $this->_delete_the_ticket($TKT_ID)) {
1238
+				$success = 0;
1239
+			}
1240
+		}
1241
+		$action_desc = 'deleted';
1242
+		$query_args = array(
1243
+			'action' => 'ticket_list_table',
1244
+			'status' => 'trashed',
1245
+		);
1246
+		// fail safe.  If the default ticket count === 1 then we need to redirect to event overview.
1247
+		if (EEM_Ticket::instance()->count_deleted_and_undeleted(
1248
+			array(array('TKT_is_default' => 1)),
1249
+			'TKT_ID',
1250
+			true
1251
+		)
1252
+		) {
1253
+			$query_args = array();
1254
+		}
1255
+		$this->_redirect_after_action($success, 'Tickets', $action_desc, $query_args);
1256
+	}
1257
+
1258
+
1259
+	/**
1260
+	 * @param int $TKT_ID
1261
+	 * @return bool|int
1262
+	 * @throws EE_Error
1263
+	 */
1264
+	protected function _delete_the_ticket($TKT_ID)
1265
+	{
1266
+		$tkt = EEM_Ticket::instance()->get_one_by_ID($TKT_ID);
1267
+		$tkt->_remove_relations('Datetime');
1268
+		// delete all related prices first
1269
+		$tkt->delete_related_permanently('Price');
1270
+		return $tkt->delete_permanently();
1271
+	}
1272 1272
 }
Please login to merge, or discard this patch.
Spacing   +41 added lines, -41 removed lines patch added patch discarded remove patch
@@ -24,10 +24,10 @@  discard block
 block discarded – undo
24 24
     public function __construct($routing = true)
25 25
     {
26 26
         parent::__construct($routing);
27
-        if (! defined('EVENTS_CAF_TEMPLATE_PATH')) {
28
-            define('EVENTS_CAF_TEMPLATE_PATH', EE_CORE_CAF_ADMIN_EXTEND . 'events/templates/');
29
-            define('EVENTS_CAF_ASSETS', EE_CORE_CAF_ADMIN_EXTEND . 'events/assets/');
30
-            define('EVENTS_CAF_ASSETS_URL', EE_CORE_CAF_ADMIN_EXTEND_URL . 'events/assets/');
27
+        if ( ! defined('EVENTS_CAF_TEMPLATE_PATH')) {
28
+            define('EVENTS_CAF_TEMPLATE_PATH', EE_CORE_CAF_ADMIN_EXTEND.'events/templates/');
29
+            define('EVENTS_CAF_ASSETS', EE_CORE_CAF_ADMIN_EXTEND.'events/assets/');
30
+            define('EVENTS_CAF_ASSETS_URL', EE_CORE_CAF_ADMIN_EXTEND_URL.'events/assets/');
31 31
         }
32 32
     }
33 33
 
@@ -37,7 +37,7 @@  discard block
 block discarded – undo
37 37
      */
38 38
     protected function _extend_page_config()
39 39
     {
40
-        $this->_admin_base_path = EE_CORE_CAF_ADMIN_EXTEND . 'events';
40
+        $this->_admin_base_path = EE_CORE_CAF_ADMIN_EXTEND.'events';
41 41
         // is there a evt_id in the request?
42 42
         $evt_id = ! empty($this->_req_data['EVT_ID']) && ! is_array($this->_req_data['EVT_ID'])
43 43
             ? $this->_req_data['EVT_ID']
@@ -247,7 +247,7 @@  discard block
 block discarded – undo
247 247
     {
248 248
         $return = parent::extra_permalink_field_buttons($return, $id, $new_title, $new_slug);
249 249
         // make sure this is only when editing
250
-        if (! empty($id)) {
250
+        if ( ! empty($id)) {
251 251
             $href = EE_Admin_Page::add_query_args_and_nonce(
252 252
                 array('action' => 'duplicate_event', 'EVT_ID' => $id),
253 253
                 $this->_admin_base_url
@@ -299,7 +299,7 @@  discard block
 block discarded – undo
299 299
     {
300 300
         wp_register_script(
301 301
             'ee-event-editor-heartbeat',
302
-            EVENTS_CAF_ASSETS_URL . 'event-editor-heartbeat.js',
302
+            EVENTS_CAF_ASSETS_URL.'event-editor-heartbeat.js',
303 303
             array('ee_admin_js', 'heartbeat'),
304 304
             EVENT_ESPRESSO_VERSION,
305 305
             true
@@ -323,7 +323,7 @@  discard block
 block discarded – undo
323 323
     public function add_additional_datetime_button($template, $template_args)
324 324
     {
325 325
         return EEH_Template::display_template(
326
-            EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_add_additional_time.template.php',
326
+            EVENTS_CAF_TEMPLATE_PATH.'event_datetime_add_additional_time.template.php',
327 327
             $template_args,
328 328
             true
329 329
         );
@@ -341,7 +341,7 @@  discard block
 block discarded – undo
341 341
     public function add_datetime_clone_button($template, $template_args)
342 342
     {
343 343
         return EEH_Template::display_template(
344
-            EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_metabox_clone_button.template.php',
344
+            EVENTS_CAF_TEMPLATE_PATH.'event_datetime_metabox_clone_button.template.php',
345 345
             $template_args,
346 346
             true
347 347
         );
@@ -359,7 +359,7 @@  discard block
 block discarded – undo
359 359
     public function datetime_timezones_template($template, $template_args)
360 360
     {
361 361
         return EEH_Template::display_template(
362
-            EVENTS_CAF_TEMPLATE_PATH . 'event_datetime_timezones.template.php',
362
+            EVENTS_CAF_TEMPLATE_PATH.'event_datetime_timezones.template.php',
363 363
             $template_args,
364 364
             true
365 365
         );
@@ -478,7 +478,7 @@  discard block
 block discarded – undo
478 478
     {
479 479
         // first make sure the ID for the event is in the request.
480 480
         //  If it isn't then we need to bail and redirect back to overview list table (cause how did we get here?)
481
-        if (! isset($this->_req_data['EVT_ID'])) {
481
+        if ( ! isset($this->_req_data['EVT_ID'])) {
482 482
             EE_Error::add_error(
483 483
                 esc_html__(
484 484
                     'In order to duplicate an event an Event ID is required.  None was given.',
@@ -493,7 +493,7 @@  discard block
 block discarded – undo
493 493
         }
494 494
         // k we've got EVT_ID so let's use that to get the event we'll duplicate
495 495
         $orig_event = EEM_Event::instance()->get_one_by_ID($this->_req_data['EVT_ID']);
496
-        if (! $orig_event instanceof EE_Event) {
496
+        if ( ! $orig_event instanceof EE_Event) {
497 497
             throw new EE_Error(
498 498
                 sprintf(
499 499
                     esc_html__('An EE_Event object could not be retrieved for the given ID (%s)', 'event_espresso'),
@@ -509,7 +509,7 @@  discard block
 block discarded – undo
509 509
         $orig_ven = $orig_event->get_many_related('Venue');
510 510
         // reset the ID and modify other details to make it clear this is a dupe
511 511
         $new_event->set('EVT_ID', 0);
512
-        $new_name = $new_event->name() . ' ' . esc_html__('**DUPLICATE**', 'event_espresso');
512
+        $new_name = $new_event->name().' '.esc_html__('**DUPLICATE**', 'event_espresso');
513 513
         $new_event->set('EVT_name', $new_name);
514 514
         $new_event->set(
515 515
             'EVT_slug',
@@ -538,7 +538,7 @@  discard block
 block discarded – undo
538 538
             'Question_Group',
539 539
             [['Event_Question_Group.EQG_primary' => true]]
540 540
         );
541
-        if (! empty($orig_primary_qgs)) {
541
+        if ( ! empty($orig_primary_qgs)) {
542 542
             foreach ($orig_primary_qgs as $id => $obj) {
543 543
                 if ($obj instanceof EE_Question_Group) {
544 544
                     $new_event->_add_relation_to($obj, 'Question_Group', ['EQG_primary' => true]);
@@ -550,7 +550,7 @@  discard block
 block discarded – undo
550 550
             'Question_Group',
551 551
             [['Event_Question_Group.EQG_additional' => true]]
552 552
         );
553
-        if (! empty($orig_additional_qgs)) {
553
+        if ( ! empty($orig_additional_qgs)) {
554 554
             foreach ($orig_additional_qgs as $id => $obj) {
555 555
                 if ($obj instanceof EE_Question_Group) {
556 556
                     $new_event->_add_relation_to($obj, 'Question_Group', ['EQG_additional' => true]);
@@ -563,7 +563,7 @@  discard block
 block discarded – undo
563 563
         // k now that we have the new event saved we can loop through the datetimes and start adding relations.
564 564
         $cloned_tickets = array();
565 565
         foreach ($orig_datetimes as $orig_dtt) {
566
-            if (! $orig_dtt instanceof EE_Datetime) {
566
+            if ( ! $orig_dtt instanceof EE_Datetime) {
567 567
                 continue;
568 568
             }
569 569
             $new_dtt = clone $orig_dtt;
@@ -578,7 +578,7 @@  discard block
 block discarded – undo
578 578
             // now let's get the ticket relations setup.
579 579
             foreach ((array) $orig_tkts as $orig_tkt) {
580 580
                 // it's possible a datetime will have no tickets so let's verify we HAVE a ticket first.
581
-                if (! $orig_tkt instanceof EE_Ticket) {
581
+                if ( ! $orig_tkt instanceof EE_Ticket) {
582 582
                     continue;
583 583
                 }
584 584
                 // is this ticket archived?  If it is then let's skip
@@ -587,8 +587,8 @@  discard block
 block discarded – undo
587 587
                 }
588 588
                 // does this original ticket already exist in the clone_tickets cache?
589 589
                 //  If so we'll just use the new ticket from it.
590
-                if (isset($cloned_tickets[ $orig_tkt->ID() ])) {
591
-                    $new_tkt = $cloned_tickets[ $orig_tkt->ID() ];
590
+                if (isset($cloned_tickets[$orig_tkt->ID()])) {
591
+                    $new_tkt = $cloned_tickets[$orig_tkt->ID()];
592 592
                 } else {
593 593
                     $new_tkt = clone $orig_tkt;
594 594
                     // get relations on the $orig_tkt that we need to setup.
@@ -621,7 +621,7 @@  discard block
 block discarded – undo
621 621
                 // for use with later datetimes that have the same ticket.
622 622
                 $new_dtt->_add_relation_to($new_tkt, 'Ticket');
623 623
                 $new_dtt->save();
624
-                $cloned_tickets[ $orig_tkt->ID() ] = $new_tkt;
624
+                $cloned_tickets[$orig_tkt->ID()] = $new_tkt;
625 625
             }
626 626
         }
627 627
         // clone taxonomy information
@@ -704,7 +704,7 @@  discard block
 block discarded – undo
704 704
             $this->_admin_base_url
705 705
         );
706 706
         $content = EEH_Template::display_template(
707
-            EVENTS_CAF_TEMPLATE_PATH . 'import_page.template.php',
707
+            EVENTS_CAF_TEMPLATE_PATH.'import_page.template.php',
708 708
             $this->_template_args,
709 709
             true
710 710
         );
@@ -721,7 +721,7 @@  discard block
 block discarded – undo
721 721
      */
722 722
     protected function _import_events()
723 723
     {
724
-        require_once(EE_CLASSES . 'EE_Import.class.php');
724
+        require_once(EE_CLASSES.'EE_Import.class.php');
725 725
         $success = EE_Import::instance()->import();
726 726
         $this->_redirect_after_action($success, 'Import File', 'ran', array('action' => 'import_page'), true);
727 727
     }
@@ -750,8 +750,8 @@  discard block
 block discarded – undo
750 750
             'EVT_ID' => $event_ids,
751 751
         );
752 752
         $this->_req_data = array_merge($this->_req_data, $new_request_args);
753
-        if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
754
-            require_once(EE_CLASSES . 'EE_Export.class.php');
753
+        if (is_readable(EE_CLASSES.'EE_Export.class.php')) {
754
+            require_once(EE_CLASSES.'EE_Export.class.php');
755 755
             $EE_Export = EE_Export::instance($this->_req_data);
756 756
             $EE_Export->export();
757 757
         }
@@ -772,8 +772,8 @@  discard block
 block discarded – undo
772 772
             'category_ids' => $this->_req_data['EVT_CAT_ID'],
773 773
         );
774 774
         $this->_req_data = array_merge($this->_req_data, $new_request_args);
775
-        if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
776
-            require_once(EE_CLASSES . 'EE_Export.class.php');
775
+        if (is_readable(EE_CLASSES.'EE_Export.class.php')) {
776
+            require_once(EE_CLASSES.'EE_Export.class.php');
777 777
             $EE_Export = EE_Export::instance($this->_req_data);
778 778
             $EE_Export->export();
779 779
         }
@@ -811,7 +811,7 @@  discard block
 block discarded – undo
811 811
         $this->_set_add_edit_form_tags('update_template_settings');
812 812
         $this->_set_publish_post_box_vars(null, false, false, null, false);
813 813
         $this->_template_args['admin_page_content'] = EEH_Template::display_template(
814
-            EVENTS_CAF_TEMPLATE_PATH . 'template_settings.template.php',
814
+            EVENTS_CAF_TEMPLATE_PATH.'template_settings.template.php',
815 815
             $this->_template_args,
816 816
             true
817 817
         );
@@ -938,7 +938,7 @@  discard block
 block discarded – undo
938 938
             $default_reg_status_values
939 939
         );
940 940
         EEH_Template::display_template(
941
-            EVENTS_CAF_TEMPLATE_PATH . 'event_registration_options.template.php',
941
+            EVENTS_CAF_TEMPLATE_PATH.'event_registration_options.template.php',
942 942
             $template_args
943 943
         );
944 944
     }
@@ -1042,13 +1042,13 @@  discard block
 block discarded – undo
1042 1042
     {
1043 1043
         $start = EEM_Datetime::instance()->convert_datetime_for_query(
1044 1044
             'DTT_EVT_start',
1045
-            date('Y-m-d') . ' 00:00:00',
1045
+            date('Y-m-d').' 00:00:00',
1046 1046
             'Y-m-d H:i:s',
1047 1047
             'UTC'
1048 1048
         );
1049 1049
         $end = EEM_Datetime::instance()->convert_datetime_for_query(
1050 1050
             'DTT_EVT_start',
1051
-            date('Y-m-d') . ' 23:59:59',
1051
+            date('Y-m-d').' 23:59:59',
1052 1052
             'Y-m-d H:i:s',
1053 1053
             'UTC'
1054 1054
         );
@@ -1075,13 +1075,13 @@  discard block
 block discarded – undo
1075 1075
         $days_this_month = date('t');
1076 1076
         $start = EEM_Datetime::instance()->convert_datetime_for_query(
1077 1077
             'DTT_EVT_start',
1078
-            $this_year_r . '-' . $this_month_r . '-01 00:00:00',
1078
+            $this_year_r.'-'.$this_month_r.'-01 00:00:00',
1079 1079
             'Y-m-d H:i:s',
1080 1080
             'UTC'
1081 1081
         );
1082 1082
         $end = EEM_Datetime::instance()->convert_datetime_for_query(
1083 1083
             'DTT_EVT_start',
1084
-            $this_year_r . '-' . $this_month_r . '-' . $days_this_month . ' 23:59:59',
1084
+            $this_year_r.'-'.$this_month_r.'-'.$days_this_month.' 23:59:59',
1085 1085
             'Y-m-d H:i:s',
1086 1086
             'UTC'
1087 1087
         );
@@ -1148,7 +1148,7 @@  discard block
 block discarded – undo
1148 1148
         $offset = ($current_page - 1) * $per_page;
1149 1149
         $limit = array($offset, $per_page);
1150 1150
         if (isset($this->_req_data['s'])) {
1151
-            $sstr = '%' . $this->_req_data['s'] . '%';
1151
+            $sstr = '%'.$this->_req_data['s'].'%';
1152 1152
             $_where['OR'] = array(
1153 1153
                 'TKT_name'        => array('LIKE', $sstr),
1154 1154
                 'TKT_description' => array('LIKE', $sstr),
@@ -1177,17 +1177,17 @@  discard block
 block discarded – undo
1177 1177
         $success = 1;
1178 1178
         $TKT = EEM_Ticket::instance();
1179 1179
         // checkboxes?
1180
-        if (! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
1180
+        if ( ! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
1181 1181
             // if array has more than one element then success message should be plural
1182 1182
             $success = count($this->_req_data['checkbox']) > 1 ? 2 : 1;
1183 1183
             // cycle thru the boxes
1184 1184
             while (list($TKT_ID, $value) = each($this->_req_data['checkbox'])) {
1185 1185
                 if ($trash) {
1186
-                    if (! $TKT->delete_by_ID($TKT_ID)) {
1186
+                    if ( ! $TKT->delete_by_ID($TKT_ID)) {
1187 1187
                         $success = 0;
1188 1188
                     }
1189 1189
                 } else {
1190
-                    if (! $TKT->restore_by_ID($TKT_ID)) {
1190
+                    if ( ! $TKT->restore_by_ID($TKT_ID)) {
1191 1191
                         $success = 0;
1192 1192
                     }
1193 1193
                 }
@@ -1196,11 +1196,11 @@  discard block
 block discarded – undo
1196 1196
             // grab single id and trash
1197 1197
             $TKT_ID = absint($this->_req_data['TKT_ID']);
1198 1198
             if ($trash) {
1199
-                if (! $TKT->delete_by_ID($TKT_ID)) {
1199
+                if ( ! $TKT->delete_by_ID($TKT_ID)) {
1200 1200
                     $success = 0;
1201 1201
                 }
1202 1202
             } else {
1203
-                if (! $TKT->restore_by_ID($TKT_ID)) {
1203
+                if ( ! $TKT->restore_by_ID($TKT_ID)) {
1204 1204
                     $success = 0;
1205 1205
                 }
1206 1206
             }
@@ -1221,20 +1221,20 @@  discard block
 block discarded – undo
1221 1221
     {
1222 1222
         $success = 1;
1223 1223
         // checkboxes?
1224
-        if (! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
1224
+        if ( ! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
1225 1225
             // if array has more than one element then success message should be plural
1226 1226
             $success = count($this->_req_data['checkbox']) > 1 ? 2 : 1;
1227 1227
             // cycle thru the boxes
1228 1228
             while (list($TKT_ID, $value) = each($this->_req_data['checkbox'])) {
1229 1229
                 // delete
1230
-                if (! $this->_delete_the_ticket($TKT_ID)) {
1230
+                if ( ! $this->_delete_the_ticket($TKT_ID)) {
1231 1231
                     $success = 0;
1232 1232
                 }
1233 1233
             }
1234 1234
         } else {
1235 1235
             // grab single id and trash
1236 1236
             $TKT_ID = absint($this->_req_data['TKT_ID']);
1237
-            if (! $this->_delete_the_ticket($TKT_ID)) {
1237
+            if ( ! $this->_delete_the_ticket($TKT_ID)) {
1238 1238
                 $success = 0;
1239 1239
             }
1240 1240
         }
Please login to merge, or discard this patch.
registration_form/espresso_events_Registration_Form_Hooks_Extend.class.php 2 patches
Indentation   +189 added lines, -189 removed lines patch added patch discarded remove patch
@@ -16,208 +16,208 @@
 block discarded – undo
16 16
 class espresso_events_Registration_Form_Hooks_Extend extends espresso_events_Registration_Form_Hooks
17 17
 {
18 18
 
19
-    /**
20
-     * extending the properties set in espresso_events_Registration_From_Hooks
21
-     *
22
-     * @access protected
23
-     * @return void
24
-     */
25
-    protected function _extend_properties()
26
-    {
27
-        $this->_metaboxes = array_merge(
28
-            $this->_metaboxes,
29
-            array(
30
-                1 => array(
31
-                    'page_route' => array('create_new', 'edit'),
32
-                    'func'       => 'additional_questions',
33
-                    'label'      => esc_html__('Questions for Additional Registrants', 'event_espresso'),
34
-                    'priority'   => 'default',
35
-                    'context'    => 'side',
36
-                ),
37
-            )
38
-        );
39
-        $this->_scripts_styles = array(
40
-            'registers' => array(
41
-                'extended-event-editor' => array(
42
-                    'url'     => EE_CORE_CAF_ADMIN_EXTEND_URL
43
-                                 . 'registration_form/assets/event-editor-question-groups.js',
44
-                    'depends' => array('jquery'),
45
-                ),
46
-            ),
47
-            'enqueues'  => array(
48
-                'extended-event-editor' => array('edit', 'create_new'),
49
-            ),
50
-        );
51
-    }
52
-
53
-
54
-    /**
55
-     * @param Callable[] $callbacks
56
-     * @return array
57
-     */
58
-    public function modify_callbacks($callbacks)
59
-    {
60
-        $callbacks = parent::modify_callbacks($callbacks);
61
-        $callbacks[] = array($this, 'additional_question_group_update');
62
-        return $callbacks;
63
-    }
64
-
65
-
66
-    /**
67
-     * Call back hooked into revision restores.
68
-     *
69
-     * @param $post_id
70
-     * @param $revision_id
71
-     * @return EE_Base_Class|void
72
-     * @throws EE_Error
73
-     * @throws InvalidArgumentException
74
-     * @throws InvalidDataTypeException
75
-     * @throws InvalidInterfaceException
76
-     * @throws ReflectionException
77
-     */
78
-    public function restore_revision($post_id, $revision_id)
79
-    {
80
-        $post_evt = parent::restore_revision($post_id, $revision_id);
81
-
82
-        // restore revision for additional questions
83
-        $post_evt->restore_revision(
84
-            $revision_id,
85
-            ['Question_Group'],
86
-            [
87
-                'Question_Group' => ['Event_Question_Group.EQG_additional' => true],
88
-            ]
89
-        );
90
-    }
91
-
92
-
93
-    /**
94
-     * @param $post_id
95
-     * @param $post
96
-     * @throws EE_Error
97
-     * @throws InvalidArgumentException
98
-     * @throws InvalidDataTypeException
99
-     * @throws InvalidInterfaceException
100
-     */
101
-    public function additional_questions($post_id, $post)
102
-    {
103
-        $this->_event = $this->_adminpage_obj->get_event_object();
104
-        $event_id = $this->_event->ID();
105
-        ?>
19
+	/**
20
+	 * extending the properties set in espresso_events_Registration_From_Hooks
21
+	 *
22
+	 * @access protected
23
+	 * @return void
24
+	 */
25
+	protected function _extend_properties()
26
+	{
27
+		$this->_metaboxes = array_merge(
28
+			$this->_metaboxes,
29
+			array(
30
+				1 => array(
31
+					'page_route' => array('create_new', 'edit'),
32
+					'func'       => 'additional_questions',
33
+					'label'      => esc_html__('Questions for Additional Registrants', 'event_espresso'),
34
+					'priority'   => 'default',
35
+					'context'    => 'side',
36
+				),
37
+			)
38
+		);
39
+		$this->_scripts_styles = array(
40
+			'registers' => array(
41
+				'extended-event-editor' => array(
42
+					'url'     => EE_CORE_CAF_ADMIN_EXTEND_URL
43
+								 . 'registration_form/assets/event-editor-question-groups.js',
44
+					'depends' => array('jquery'),
45
+				),
46
+			),
47
+			'enqueues'  => array(
48
+				'extended-event-editor' => array('edit', 'create_new'),
49
+			),
50
+		);
51
+	}
52
+
53
+
54
+	/**
55
+	 * @param Callable[] $callbacks
56
+	 * @return array
57
+	 */
58
+	public function modify_callbacks($callbacks)
59
+	{
60
+		$callbacks = parent::modify_callbacks($callbacks);
61
+		$callbacks[] = array($this, 'additional_question_group_update');
62
+		return $callbacks;
63
+	}
64
+
65
+
66
+	/**
67
+	 * Call back hooked into revision restores.
68
+	 *
69
+	 * @param $post_id
70
+	 * @param $revision_id
71
+	 * @return EE_Base_Class|void
72
+	 * @throws EE_Error
73
+	 * @throws InvalidArgumentException
74
+	 * @throws InvalidDataTypeException
75
+	 * @throws InvalidInterfaceException
76
+	 * @throws ReflectionException
77
+	 */
78
+	public function restore_revision($post_id, $revision_id)
79
+	{
80
+		$post_evt = parent::restore_revision($post_id, $revision_id);
81
+
82
+		// restore revision for additional questions
83
+		$post_evt->restore_revision(
84
+			$revision_id,
85
+			['Question_Group'],
86
+			[
87
+				'Question_Group' => ['Event_Question_Group.EQG_additional' => true],
88
+			]
89
+		);
90
+	}
91
+
92
+
93
+	/**
94
+	 * @param $post_id
95
+	 * @param $post
96
+	 * @throws EE_Error
97
+	 * @throws InvalidArgumentException
98
+	 * @throws InvalidDataTypeException
99
+	 * @throws InvalidInterfaceException
100
+	 */
101
+	public function additional_questions($post_id, $post)
102
+	{
103
+		$this->_event = $this->_adminpage_obj->get_event_object();
104
+		$event_id = $this->_event->ID();
105
+		?>
106 106
         <div class="inside">
107 107
             <p><strong>
108 108
                     <?php _e('Question Groups', 'event_espresso'); ?>
109 109
                 </strong><br/>
110 110
                 <?php
111
-                printf(
112
-                    esc_html__(
113
-                        'Add a pre-populated %1$sgroup of questions%2$s to your event.',
114
-                        'event_espresso'
115
-                    ),
116
-                    '<a href="admin.php?page=espresso_registration_form" target="_blank">',
117
-                    '</a>'
118
-                );
119
-                ?>
111
+				printf(
112
+					esc_html__(
113
+						'Add a pre-populated %1$sgroup of questions%2$s to your event.',
114
+						'event_espresso'
115
+					),
116
+					'<a href="admin.php?page=espresso_registration_form" target="_blank">',
117
+					'</a>'
118
+				);
119
+				?>
120 120
             </p>
121 121
             <?php
122 122
 
123
-            $qsg_where['QSG_deleted'] = false;
124
-            $query_params = apply_filters(
125
-                'FHEE__espresso_events_Registration_Form_Hooks_Extend__additional_questions__question_group_query_parameters',
126
-                array($qsg_where, 'order_by' => array('QSG_order' => 'ASC'))
127
-            );
128
-            $QSGs = EEM_Question_Group::instance()->get_all($query_params);
129
-            $EQGs = ! empty($event_id)
130
-                ? $this->_event->get_many_related(
131
-                    'Question_Group',
132
-                    [['Event_Question_Group.EQG_additional' => true]]
133
-                )
134
-                : [];
135
-            $EQGids = array_keys($EQGs);
136
-
137
-            if (! empty($QSGs)) {
138
-                $html = count($QSGs) > 10 ? '<div style="height:250px;overflow:auto;">' : '';
139
-                foreach ($QSGs as $QSG) {
140
-                    $checked = in_array($QSG->ID(), $EQGids, true) ? ' checked="checked" ' : '';
141
-                    $edit_link = EE_Admin_Page::add_query_args_and_nonce(
142
-                        array(
143
-                            'action' => 'edit_question_group',
144
-                            'QSG_ID' => $QSG->ID(),
145
-                        ),
146
-                        EE_FORMS_ADMIN_URL
147
-                    );
148
-
149
-                    $html .= '
123
+			$qsg_where['QSG_deleted'] = false;
124
+			$query_params = apply_filters(
125
+				'FHEE__espresso_events_Registration_Form_Hooks_Extend__additional_questions__question_group_query_parameters',
126
+				array($qsg_where, 'order_by' => array('QSG_order' => 'ASC'))
127
+			);
128
+			$QSGs = EEM_Question_Group::instance()->get_all($query_params);
129
+			$EQGs = ! empty($event_id)
130
+				? $this->_event->get_many_related(
131
+					'Question_Group',
132
+					[['Event_Question_Group.EQG_additional' => true]]
133
+				)
134
+				: [];
135
+			$EQGids = array_keys($EQGs);
136
+
137
+			if (! empty($QSGs)) {
138
+				$html = count($QSGs) > 10 ? '<div style="height:250px;overflow:auto;">' : '';
139
+				foreach ($QSGs as $QSG) {
140
+					$checked = in_array($QSG->ID(), $EQGids, true) ? ' checked="checked" ' : '';
141
+					$edit_link = EE_Admin_Page::add_query_args_and_nonce(
142
+						array(
143
+							'action' => 'edit_question_group',
144
+							'QSG_ID' => $QSG->ID(),
145
+						),
146
+						EE_FORMS_ADMIN_URL
147
+					);
148
+
149
+					$html .= '
150 150
 					<p id="event-question-group-' . $QSG->ID() . '">
151 151
 						<input value="' . $QSG->ID() . '"'
152
-                             . ' type="checkbox" name="add_attendee_question_groups[' . $QSG->ID() . ']"' . $checked . ' />
152
+							 . ' type="checkbox" name="add_attendee_question_groups[' . $QSG->ID() . ']"' . $checked . ' />
153 153
 						<a href="' . $edit_link . '" title="'
154
-                             . sprintf(
155
-                                 esc_attr__('Edit %s Group', 'event_espresso'),
156
-                                 $QSG->get('QSG_name')
157
-                             )
158
-                             . '" target="_blank">' . $QSG->get('QSG_name') . '</a>
154
+							 . sprintf(
155
+								 esc_attr__('Edit %s Group', 'event_espresso'),
156
+								 $QSG->get('QSG_name')
157
+							 )
158
+							 . '" target="_blank">' . $QSG->get('QSG_name') . '</a>
159 159
 					</p>';
160
-                    if ($QSG->ID() === 2) {
161
-                        $html .= '
160
+					if ($QSG->ID() === 2) {
161
+						$html .= '
162 162
 					<p id="question-group-requirements-notice-pg" class="important-notice small-text" style="display: none;">'
163
-                                 . esc_html__(
164
-                                     'The Personal Information question group is required whenever the Address Information question group is activated.',
165
-                                     'event_espresso'
166
-                                 )
167
-                                 . '</p>';
168
-                    }
169
-                }
170
-                $html .= count($QSGs) > 10 ? '</div>' : '';
171
-
172
-                echo $html;
173
-            } else {
174
-                esc_html_e(
175
-                    'There seems to be a problem with your questions. Please contact [email protected]',
176
-                    'event_espresso'
177
-                );
178
-            }
179
-            do_action('AHEE__espresso_events_Registration_Form_Hooks__additional_questions__after_content');
180
-            ?>
163
+								 . esc_html__(
164
+									 'The Personal Information question group is required whenever the Address Information question group is activated.',
165
+									 'event_espresso'
166
+								 )
167
+								 . '</p>';
168
+					}
169
+				}
170
+				$html .= count($QSGs) > 10 ? '</div>' : '';
171
+
172
+				echo $html;
173
+			} else {
174
+				esc_html_e(
175
+					'There seems to be a problem with your questions. Please contact [email protected]',
176
+					'event_espresso'
177
+				);
178
+			}
179
+			do_action('AHEE__espresso_events_Registration_Form_Hooks__additional_questions__after_content');
180
+			?>
181 181
         </div>
182 182
         <?php
183
-    }
184
-
185
-
186
-    public function additional_question_group_update($evtobj, $data)
187
-    {
188
-        $question_groups = ! empty($data['add_attendee_question_groups'])
189
-            ? (array) $data['add_attendee_question_groups']
190
-            : [];
191
-        $added_qgs = array_keys($question_groups);
192
-        $success = [];
193
-
194
-        // let's get all current question groups associated with this event.
195
-        $current_qgs = $evtobj->get_many_related(
196
-            'Question_Group',
197
-            [['Event_Question_Group.EQG_additional' => true]]
198
-        );
199
-        $current_qgs = array_keys($current_qgs); // we just want the ids
200
-
201
-        // now let's get the groups selected in the editor and update (IF we have data)
202
-        if (! empty($question_groups)) {
203
-            foreach ($question_groups as $qgid) {
204
-                // add to event
205
-                if ($qgid) {
206
-                    $qg = $evtobj->add_question_group($qgid, false);
207
-                }
208
-                $success[] = ! empty($qg) ? 1 : 0;
209
-            }
210
-        }
211
-
212
-        // wait a minute... are there question groups missing in the saved groups that ARE with the current event?
213
-        $removed_qgs = array_diff($current_qgs, $added_qgs);
214
-
215
-        foreach ($removed_qgs as $qgid) {
216
-            $qg = $evtobj->remove_question_group($qgid, false);
217
-            $success[] = ! empty($qg) ? 1 : 0;
218
-        }
219
-
220
-
221
-        return in_array(0, $success, true) ? false : true;
222
-    }
183
+	}
184
+
185
+
186
+	public function additional_question_group_update($evtobj, $data)
187
+	{
188
+		$question_groups = ! empty($data['add_attendee_question_groups'])
189
+			? (array) $data['add_attendee_question_groups']
190
+			: [];
191
+		$added_qgs = array_keys($question_groups);
192
+		$success = [];
193
+
194
+		// let's get all current question groups associated with this event.
195
+		$current_qgs = $evtobj->get_many_related(
196
+			'Question_Group',
197
+			[['Event_Question_Group.EQG_additional' => true]]
198
+		);
199
+		$current_qgs = array_keys($current_qgs); // we just want the ids
200
+
201
+		// now let's get the groups selected in the editor and update (IF we have data)
202
+		if (! empty($question_groups)) {
203
+			foreach ($question_groups as $qgid) {
204
+				// add to event
205
+				if ($qgid) {
206
+					$qg = $evtobj->add_question_group($qgid, false);
207
+				}
208
+				$success[] = ! empty($qg) ? 1 : 0;
209
+			}
210
+		}
211
+
212
+		// wait a minute... are there question groups missing in the saved groups that ARE with the current event?
213
+		$removed_qgs = array_diff($current_qgs, $added_qgs);
214
+
215
+		foreach ($removed_qgs as $qgid) {
216
+			$qg = $evtobj->remove_question_group($qgid, false);
217
+			$success[] = ! empty($qg) ? 1 : 0;
218
+		}
219
+
220
+
221
+		return in_array(0, $success, true) ? false : true;
222
+	}
223 223
 }
Please login to merge, or discard this patch.
Spacing   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -134,7 +134,7 @@  discard block
 block discarded – undo
134 134
                 : [];
135 135
             $EQGids = array_keys($EQGs);
136 136
 
137
-            if (! empty($QSGs)) {
137
+            if ( ! empty($QSGs)) {
138 138
                 $html = count($QSGs) > 10 ? '<div style="height:250px;overflow:auto;">' : '';
139 139
                 foreach ($QSGs as $QSG) {
140 140
                     $checked = in_array($QSG->ID(), $EQGids, true) ? ' checked="checked" ' : '';
@@ -147,15 +147,15 @@  discard block
 block discarded – undo
147 147
                     );
148 148
 
149 149
                     $html .= '
150
-					<p id="event-question-group-' . $QSG->ID() . '">
151
-						<input value="' . $QSG->ID() . '"'
152
-                             . ' type="checkbox" name="add_attendee_question_groups[' . $QSG->ID() . ']"' . $checked . ' />
153
-						<a href="' . $edit_link . '" title="'
150
+					<p id="event-question-group-' . $QSG->ID().'">
151
+						<input value="' . $QSG->ID().'"'
152
+                             . ' type="checkbox" name="add_attendee_question_groups['.$QSG->ID().']"'.$checked.' />
153
+						<a href="' . $edit_link.'" title="'
154 154
                              . sprintf(
155 155
                                  esc_attr__('Edit %s Group', 'event_espresso'),
156 156
                                  $QSG->get('QSG_name')
157 157
                              )
158
-                             . '" target="_blank">' . $QSG->get('QSG_name') . '</a>
158
+                             . '" target="_blank">'.$QSG->get('QSG_name').'</a>
159 159
 					</p>';
160 160
                     if ($QSG->ID() === 2) {
161 161
                         $html .= '
@@ -199,7 +199,7 @@  discard block
 block discarded – undo
199 199
         $current_qgs = array_keys($current_qgs); // we just want the ids
200 200
 
201 201
         // now let's get the groups selected in the editor and update (IF we have data)
202
-        if (! empty($question_groups)) {
202
+        if ( ! empty($question_groups)) {
203 203
             foreach ($question_groups as $qgid) {
204 204
                 // add to event
205 205
                 if ($qgid) {
Please login to merge, or discard this patch.
core/db_classes/EE_Event.class.php 2 patches
Indentation   +1382 added lines, -1382 removed lines patch added patch discarded remove patch
@@ -15,1386 +15,1386 @@
 block discarded – undo
15 15
 class EE_Event extends EE_CPT_Base implements EEI_Line_Item_Object, EEI_Admin_Links, EEI_Has_Icon, EEI_Event
16 16
 {
17 17
 
18
-    /**
19
-     * cached value for the the logical active status for the event
20
-     *
21
-     * @see get_active_status()
22
-     * @var string
23
-     */
24
-    protected $_active_status = '';
25
-
26
-    /**
27
-     * This is just used for caching the Primary Datetime for the Event on initial retrieval
28
-     *
29
-     * @var EE_Datetime
30
-     */
31
-    protected $_Primary_Datetime;
32
-
33
-    /**
34
-     * @var EventSpacesCalculator $available_spaces_calculator
35
-     */
36
-    protected $available_spaces_calculator;
37
-
38
-
39
-    /**
40
-     * @param array  $props_n_values          incoming values
41
-     * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
42
-     *                                        used.)
43
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
44
-     *                                        date_format and the second value is the time format
45
-     * @return EE_Event
46
-     * @throws EE_Error
47
-     */
48
-    public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
49
-    {
50
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
51
-        return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
52
-    }
53
-
54
-
55
-    /**
56
-     * @param array  $props_n_values  incoming values from the database
57
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
58
-     *                                the website will be used.
59
-     * @return EE_Event
60
-     * @throws EE_Error
61
-     */
62
-    public static function new_instance_from_db($props_n_values = array(), $timezone = null)
63
-    {
64
-        return new self($props_n_values, true, $timezone);
65
-    }
66
-
67
-
68
-    /**
69
-     * @return EventSpacesCalculator
70
-     * @throws \EE_Error
71
-     */
72
-    public function getAvailableSpacesCalculator()
73
-    {
74
-        if (! $this->available_spaces_calculator instanceof EventSpacesCalculator) {
75
-            $this->available_spaces_calculator = new EventSpacesCalculator($this);
76
-        }
77
-        return $this->available_spaces_calculator;
78
-    }
79
-
80
-
81
-    /**
82
-     * Overrides parent set() method so that all calls to set( 'status', $status ) can be routed to internal methods
83
-     *
84
-     * @param string $field_name
85
-     * @param mixed  $field_value
86
-     * @param bool   $use_default
87
-     * @throws EE_Error
88
-     */
89
-    public function set($field_name, $field_value, $use_default = false)
90
-    {
91
-        switch ($field_name) {
92
-            case 'status':
93
-                $this->set_status($field_value, $use_default);
94
-                break;
95
-            default:
96
-                parent::set($field_name, $field_value, $use_default);
97
-        }
98
-    }
99
-
100
-
101
-    /**
102
-     *    set_status
103
-     * Checks if event status is being changed to SOLD OUT
104
-     * and updates event meta data with previous event status
105
-     * so that we can revert things if/when the event is no longer sold out
106
-     *
107
-     * @access public
108
-     * @param string $new_status
109
-     * @param bool   $use_default
110
-     * @return void
111
-     * @throws EE_Error
112
-     */
113
-    public function set_status($new_status = null, $use_default = false)
114
-    {
115
-        // if nothing is set, and we aren't explicitly wanting to reset the status, then just leave
116
-        if (empty($new_status) && ! $use_default) {
117
-            return;
118
-        }
119
-        // get current Event status
120
-        $old_status = $this->status();
121
-        // if status has changed
122
-        if ($old_status !== $new_status) {
123
-            // TO sold_out
124
-            if ($new_status === EEM_Event::sold_out) {
125
-                // save the previous event status so that we can revert if the event is no longer sold out
126
-                $this->add_post_meta('_previous_event_status', $old_status);
127
-                do_action('AHEE__EE_Event__set_status__to_sold_out', $this, $old_status, $new_status);
128
-                // OR FROM  sold_out
129
-            } elseif ($old_status === EEM_Event::sold_out) {
130
-                $this->delete_post_meta('_previous_event_status');
131
-                do_action('AHEE__EE_Event__set_status__from_sold_out', $this, $old_status, $new_status);
132
-            }
133
-            // clear out the active status so that it gets reset the next time it is requested
134
-            $this->_active_status = null;
135
-            // update status
136
-            parent::set('status', $new_status, $use_default);
137
-            do_action('AHEE__EE_Event__set_status__after_update', $this);
138
-            return;
139
-        }
140
-        // even though the old value matches the new value, it's still good to
141
-        // allow the parent set method to have a say
142
-        parent::set('status', $new_status, $use_default);
143
-    }
144
-
145
-
146
-    /**
147
-     * Gets all the datetimes for this event
148
-     *
149
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
150
-     * @return EE_Base_Class[]|EE_Datetime[]
151
-     * @throws EE_Error
152
-     */
153
-    public function datetimes($query_params = array())
154
-    {
155
-        return $this->get_many_related('Datetime', $query_params);
156
-    }
157
-
158
-
159
-    /**
160
-     * Gets all the datetimes for this event, ordered by DTT_EVT_start in ascending order
161
-     *
162
-     * @return EE_Base_Class[]|EE_Datetime[]
163
-     * @throws EE_Error
164
-     */
165
-    public function datetimes_in_chronological_order()
166
-    {
167
-        return $this->get_many_related('Datetime', array('order_by' => array('DTT_EVT_start' => 'ASC')));
168
-    }
169
-
170
-
171
-    /**
172
-     * Gets all the datetimes for this event, ordered by the DTT_order on the datetime.
173
-     * @darren, we should probably UNSET timezone on the EEM_Datetime model
174
-     * after running our query, so that this timezone isn't set for EVERY query
175
-     * on EEM_Datetime for the rest of the request, no?
176
-     *
177
-     * @param boolean $show_expired whether or not to include expired events
178
-     * @param boolean $show_deleted whether or not to include deleted events
179
-     * @param null    $limit
180
-     * @return EE_Datetime[]
181
-     * @throws EE_Error
182
-     */
183
-    public function datetimes_ordered($show_expired = true, $show_deleted = false, $limit = null)
184
-    {
185
-        return EEM_Datetime::instance($this->_timezone)->get_datetimes_for_event_ordered_by_DTT_order(
186
-            $this->ID(),
187
-            $show_expired,
188
-            $show_deleted,
189
-            $limit
190
-        );
191
-    }
192
-
193
-
194
-    /**
195
-     * Returns one related datetime. Mostly only used by some legacy code.
196
-     *
197
-     * @return EE_Base_Class|EE_Datetime
198
-     * @throws EE_Error
199
-     */
200
-    public function first_datetime()
201
-    {
202
-        return $this->get_first_related('Datetime');
203
-    }
204
-
205
-
206
-    /**
207
-     * Returns the 'primary' datetime for the event
208
-     *
209
-     * @param bool $try_to_exclude_expired
210
-     * @param bool $try_to_exclude_deleted
211
-     * @return EE_Datetime
212
-     * @throws EE_Error
213
-     */
214
-    public function primary_datetime($try_to_exclude_expired = true, $try_to_exclude_deleted = true)
215
-    {
216
-        if (! empty($this->_Primary_Datetime)) {
217
-            return $this->_Primary_Datetime;
218
-        }
219
-        $this->_Primary_Datetime = EEM_Datetime::instance($this->_timezone)->get_primary_datetime_for_event(
220
-            $this->ID(),
221
-            $try_to_exclude_expired,
222
-            $try_to_exclude_deleted
223
-        );
224
-        return $this->_Primary_Datetime;
225
-    }
226
-
227
-
228
-    /**
229
-     * Gets all the tickets available for purchase of this event
230
-     *
231
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
232
-     * @return EE_Base_Class[]|EE_Ticket[]
233
-     * @throws EE_Error
234
-     */
235
-    public function tickets($query_params = array())
236
-    {
237
-        // first get all datetimes
238
-        $datetimes = $this->datetimes_ordered();
239
-        if (! $datetimes) {
240
-            return array();
241
-        }
242
-        $datetime_ids = array();
243
-        foreach ($datetimes as $datetime) {
244
-            $datetime_ids[] = $datetime->ID();
245
-        }
246
-        $where_params = array('Datetime.DTT_ID' => array('IN', $datetime_ids));
247
-        // if incoming $query_params has where conditions let's merge but not override existing.
248
-        if (is_array($query_params) && isset($query_params[0])) {
249
-            $where_params = array_merge($query_params[0], $where_params);
250
-            unset($query_params[0]);
251
-        }
252
-        // now add $where_params to $query_params
253
-        $query_params[0] = $where_params;
254
-        return EEM_Ticket::instance()->get_all($query_params);
255
-    }
256
-
257
-
258
-    /**
259
-     * get all unexpired untrashed tickets
260
-     *
261
-     * @return EE_Ticket[]
262
-     * @throws EE_Error
263
-     */
264
-    public function active_tickets()
265
-    {
266
-        return $this->tickets(
267
-            array(
268
-                array(
269
-                    'TKT_end_date' => array('>=', EEM_Ticket::instance()->current_time_for_query('TKT_end_date')),
270
-                    'TKT_deleted'  => false,
271
-                ),
272
-            )
273
-        );
274
-    }
275
-
276
-
277
-    /**
278
-     * @return bool
279
-     * @throws EE_Error
280
-     */
281
-    public function additional_limit()
282
-    {
283
-        return $this->get('EVT_additional_limit');
284
-    }
285
-
286
-
287
-    /**
288
-     * @return bool
289
-     * @throws EE_Error
290
-     */
291
-    public function allow_overflow()
292
-    {
293
-        return $this->get('EVT_allow_overflow');
294
-    }
295
-
296
-
297
-    /**
298
-     * @return bool
299
-     * @throws EE_Error
300
-     */
301
-    public function created()
302
-    {
303
-        return $this->get('EVT_created');
304
-    }
305
-
306
-
307
-    /**
308
-     * @return bool
309
-     * @throws EE_Error
310
-     */
311
-    public function description()
312
-    {
313
-        return $this->get('EVT_desc');
314
-    }
315
-
316
-
317
-    /**
318
-     * Runs do_shortcode and wpautop on the description
319
-     *
320
-     * @return string of html
321
-     * @throws EE_Error
322
-     */
323
-    public function description_filtered()
324
-    {
325
-        return $this->get_pretty('EVT_desc');
326
-    }
327
-
328
-
329
-    /**
330
-     * @return bool
331
-     * @throws EE_Error
332
-     */
333
-    public function display_description()
334
-    {
335
-        return $this->get('EVT_display_desc');
336
-    }
337
-
338
-
339
-    /**
340
-     * @return bool
341
-     * @throws EE_Error
342
-     */
343
-    public function display_ticket_selector()
344
-    {
345
-        return (bool) $this->get('EVT_display_ticket_selector');
346
-    }
347
-
348
-
349
-    /**
350
-     * @return bool
351
-     * @throws EE_Error
352
-     */
353
-    public function external_url()
354
-    {
355
-        return $this->get('EVT_external_URL');
356
-    }
357
-
358
-
359
-    /**
360
-     * @return bool
361
-     * @throws EE_Error
362
-     */
363
-    public function member_only()
364
-    {
365
-        return $this->get('EVT_member_only');
366
-    }
367
-
368
-
369
-    /**
370
-     * @return bool
371
-     * @throws EE_Error
372
-     */
373
-    public function phone()
374
-    {
375
-        return $this->get('EVT_phone');
376
-    }
377
-
378
-
379
-    /**
380
-     * @return bool
381
-     * @throws EE_Error
382
-     */
383
-    public function modified()
384
-    {
385
-        return $this->get('EVT_modified');
386
-    }
387
-
388
-
389
-    /**
390
-     * @return bool
391
-     * @throws EE_Error
392
-     */
393
-    public function name()
394
-    {
395
-        return $this->get('EVT_name');
396
-    }
397
-
398
-
399
-    /**
400
-     * @return bool
401
-     * @throws EE_Error
402
-     */
403
-    public function order()
404
-    {
405
-        return $this->get('EVT_order');
406
-    }
407
-
408
-
409
-    /**
410
-     * @return bool|string
411
-     * @throws EE_Error
412
-     */
413
-    public function default_registration_status()
414
-    {
415
-        $event_default_registration_status = $this->get('EVT_default_registration_status');
416
-        return ! empty($event_default_registration_status)
417
-            ? $event_default_registration_status
418
-            : EE_Registry::instance()->CFG->registration->default_STS_ID;
419
-    }
420
-
421
-
422
-    /**
423
-     * @param int  $num_words
424
-     * @param null $more
425
-     * @param bool $not_full_desc
426
-     * @return bool|string
427
-     * @throws EE_Error
428
-     */
429
-    public function short_description($num_words = 55, $more = null, $not_full_desc = false)
430
-    {
431
-        $short_desc = $this->get('EVT_short_desc');
432
-        if (! empty($short_desc) || $not_full_desc) {
433
-            return $short_desc;
434
-        }
435
-        $full_desc = $this->get('EVT_desc');
436
-        return wp_trim_words($full_desc, $num_words, $more);
437
-    }
438
-
439
-
440
-    /**
441
-     * @return bool
442
-     * @throws EE_Error
443
-     */
444
-    public function slug()
445
-    {
446
-        return $this->get('EVT_slug');
447
-    }
448
-
449
-
450
-    /**
451
-     * @return bool
452
-     * @throws EE_Error
453
-     */
454
-    public function timezone_string()
455
-    {
456
-        return $this->get('EVT_timezone_string');
457
-    }
458
-
459
-
460
-    /**
461
-     * @return bool
462
-     * @throws EE_Error
463
-     */
464
-    public function visible_on()
465
-    {
466
-        return $this->get('EVT_visible_on');
467
-    }
468
-
469
-
470
-    /**
471
-     * @return int
472
-     * @throws EE_Error
473
-     */
474
-    public function wp_user()
475
-    {
476
-        return $this->get('EVT_wp_user');
477
-    }
478
-
479
-
480
-    /**
481
-     * @return bool
482
-     * @throws EE_Error
483
-     */
484
-    public function donations()
485
-    {
486
-        return $this->get('EVT_donations');
487
-    }
488
-
489
-
490
-    /**
491
-     * @param $limit
492
-     * @throws EE_Error
493
-     */
494
-    public function set_additional_limit($limit)
495
-    {
496
-        $this->set('EVT_additional_limit', $limit);
497
-    }
498
-
499
-
500
-    /**
501
-     * @param $created
502
-     * @throws EE_Error
503
-     */
504
-    public function set_created($created)
505
-    {
506
-        $this->set('EVT_created', $created);
507
-    }
508
-
509
-
510
-    /**
511
-     * @param $desc
512
-     * @throws EE_Error
513
-     */
514
-    public function set_description($desc)
515
-    {
516
-        $this->set('EVT_desc', $desc);
517
-    }
518
-
519
-
520
-    /**
521
-     * @param $display_desc
522
-     * @throws EE_Error
523
-     */
524
-    public function set_display_description($display_desc)
525
-    {
526
-        $this->set('EVT_display_desc', $display_desc);
527
-    }
528
-
529
-
530
-    /**
531
-     * @param $display_ticket_selector
532
-     * @throws EE_Error
533
-     */
534
-    public function set_display_ticket_selector($display_ticket_selector)
535
-    {
536
-        $this->set('EVT_display_ticket_selector', $display_ticket_selector);
537
-    }
538
-
539
-
540
-    /**
541
-     * @param $external_url
542
-     * @throws EE_Error
543
-     */
544
-    public function set_external_url($external_url)
545
-    {
546
-        $this->set('EVT_external_URL', $external_url);
547
-    }
548
-
549
-
550
-    /**
551
-     * @param $member_only
552
-     * @throws EE_Error
553
-     */
554
-    public function set_member_only($member_only)
555
-    {
556
-        $this->set('EVT_member_only', $member_only);
557
-    }
558
-
559
-
560
-    /**
561
-     * @param $event_phone
562
-     * @throws EE_Error
563
-     */
564
-    public function set_event_phone($event_phone)
565
-    {
566
-        $this->set('EVT_phone', $event_phone);
567
-    }
568
-
569
-
570
-    /**
571
-     * @param $modified
572
-     * @throws EE_Error
573
-     */
574
-    public function set_modified($modified)
575
-    {
576
-        $this->set('EVT_modified', $modified);
577
-    }
578
-
579
-
580
-    /**
581
-     * @param $name
582
-     * @throws EE_Error
583
-     */
584
-    public function set_name($name)
585
-    {
586
-        $this->set('EVT_name', $name);
587
-    }
588
-
589
-
590
-    /**
591
-     * @param $order
592
-     * @throws EE_Error
593
-     */
594
-    public function set_order($order)
595
-    {
596
-        $this->set('EVT_order', $order);
597
-    }
598
-
599
-
600
-    /**
601
-     * @param $short_desc
602
-     * @throws EE_Error
603
-     */
604
-    public function set_short_description($short_desc)
605
-    {
606
-        $this->set('EVT_short_desc', $short_desc);
607
-    }
608
-
609
-
610
-    /**
611
-     * @param $slug
612
-     * @throws EE_Error
613
-     */
614
-    public function set_slug($slug)
615
-    {
616
-        $this->set('EVT_slug', $slug);
617
-    }
618
-
619
-
620
-    /**
621
-     * @param $timezone_string
622
-     * @throws EE_Error
623
-     */
624
-    public function set_timezone_string($timezone_string)
625
-    {
626
-        $this->set('EVT_timezone_string', $timezone_string);
627
-    }
628
-
629
-
630
-    /**
631
-     * @param $visible_on
632
-     * @throws EE_Error
633
-     */
634
-    public function set_visible_on($visible_on)
635
-    {
636
-        $this->set('EVT_visible_on', $visible_on);
637
-    }
638
-
639
-
640
-    /**
641
-     * @param $wp_user
642
-     * @throws EE_Error
643
-     */
644
-    public function set_wp_user($wp_user)
645
-    {
646
-        $this->set('EVT_wp_user', $wp_user);
647
-    }
648
-
649
-
650
-    /**
651
-     * @param $default_registration_status
652
-     * @throws EE_Error
653
-     */
654
-    public function set_default_registration_status($default_registration_status)
655
-    {
656
-        $this->set('EVT_default_registration_status', $default_registration_status);
657
-    }
658
-
659
-
660
-    /**
661
-     * @param $donations
662
-     * @throws EE_Error
663
-     */
664
-    public function set_donations($donations)
665
-    {
666
-        $this->set('EVT_donations', $donations);
667
-    }
668
-
669
-
670
-    /**
671
-     * Adds a venue to this event
672
-     *
673
-     * @param EE_Venue /int $venue_id_or_obj
674
-     * @return EE_Base_Class|EE_Venue
675
-     * @throws EE_Error
676
-     */
677
-    public function add_venue($venue_id_or_obj)
678
-    {
679
-        return $this->_add_relation_to($venue_id_or_obj, 'Venue');
680
-    }
681
-
682
-
683
-    /**
684
-     * Removes a venue from the event
685
-     *
686
-     * @param EE_Venue /int $venue_id_or_obj
687
-     * @return EE_Base_Class|EE_Venue
688
-     * @throws EE_Error
689
-     */
690
-    public function remove_venue($venue_id_or_obj)
691
-    {
692
-        return $this->_remove_relation_to($venue_id_or_obj, 'Venue');
693
-    }
694
-
695
-
696
-    /**
697
-     * Gets all the venues related ot the event. May provide additional $query_params if desired
698
-     *
699
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
700
-     * @return EE_Base_Class[]|EE_Venue[]
701
-     * @throws EE_Error
702
-     */
703
-    public function venues($query_params = array())
704
-    {
705
-        return $this->get_many_related('Venue', $query_params);
706
-    }
707
-
708
-
709
-    /**
710
-     * check if event id is present and if event is published
711
-     *
712
-     * @access public
713
-     * @return boolean true yes, false no
714
-     * @throws EE_Error
715
-     */
716
-    private function _has_ID_and_is_published()
717
-    {
718
-        // first check if event id is present and not NULL,
719
-        // then check if this event is published (or any of the equivalent "published" statuses)
720
-        return
721
-            $this->ID() && $this->ID() !== null
722
-            && (
723
-                $this->status() === 'publish'
724
-                || $this->status() === EEM_Event::sold_out
725
-                || $this->status() === EEM_Event::postponed
726
-                || $this->status() === EEM_Event::cancelled
727
-            );
728
-    }
729
-
730
-
731
-    /**
732
-     * This simply compares the internal dates with NOW and determines if the event is upcoming or not.
733
-     *
734
-     * @access public
735
-     * @return boolean true yes, false no
736
-     * @throws EE_Error
737
-     */
738
-    public function is_upcoming()
739
-    {
740
-        // check if event id is present and if this event is published
741
-        if ($this->is_inactive()) {
742
-            return false;
743
-        }
744
-        // set initial value
745
-        $upcoming = false;
746
-        // next let's get all datetimes and loop through them
747
-        $datetimes = $this->datetimes_in_chronological_order();
748
-        foreach ($datetimes as $datetime) {
749
-            if ($datetime instanceof EE_Datetime) {
750
-                // if this dtt is expired then we continue cause one of the other datetimes might be upcoming.
751
-                if ($datetime->is_expired()) {
752
-                    continue;
753
-                }
754
-                // if this dtt is active then we return false.
755
-                if ($datetime->is_active()) {
756
-                    return false;
757
-                }
758
-                // otherwise let's check upcoming status
759
-                $upcoming = $datetime->is_upcoming();
760
-            }
761
-        }
762
-        return $upcoming;
763
-    }
764
-
765
-
766
-    /**
767
-     * @return bool
768
-     * @throws EE_Error
769
-     */
770
-    public function is_active()
771
-    {
772
-        // check if event id is present and if this event is published
773
-        if ($this->is_inactive()) {
774
-            return false;
775
-        }
776
-        // set initial value
777
-        $active = false;
778
-        // next let's get all datetimes and loop through them
779
-        $datetimes = $this->datetimes_in_chronological_order();
780
-        foreach ($datetimes as $datetime) {
781
-            if ($datetime instanceof EE_Datetime) {
782
-                // if this dtt is expired then we continue cause one of the other datetimes might be active.
783
-                if ($datetime->is_expired()) {
784
-                    continue;
785
-                }
786
-                // if this dtt is upcoming then we return false.
787
-                if ($datetime->is_upcoming()) {
788
-                    return false;
789
-                }
790
-                // otherwise let's check active status
791
-                $active = $datetime->is_active();
792
-            }
793
-        }
794
-        return $active;
795
-    }
796
-
797
-
798
-    /**
799
-     * @return bool
800
-     * @throws EE_Error
801
-     */
802
-    public function is_expired()
803
-    {
804
-        // check if event id is present and if this event is published
805
-        if ($this->is_inactive()) {
806
-            return false;
807
-        }
808
-        // set initial value
809
-        $expired = false;
810
-        // first let's get all datetimes and loop through them
811
-        $datetimes = $this->datetimes_in_chronological_order();
812
-        foreach ($datetimes as $datetime) {
813
-            if ($datetime instanceof EE_Datetime) {
814
-                // if this dtt is upcoming or active then we return false.
815
-                if ($datetime->is_upcoming() || $datetime->is_active()) {
816
-                    return false;
817
-                }
818
-                // otherwise let's check active status
819
-                $expired = $datetime->is_expired();
820
-            }
821
-        }
822
-        return $expired;
823
-    }
824
-
825
-
826
-    /**
827
-     * @return bool
828
-     * @throws EE_Error
829
-     */
830
-    public function is_inactive()
831
-    {
832
-        // check if event id is present and if this event is published
833
-        if ($this->_has_ID_and_is_published()) {
834
-            return false;
835
-        }
836
-        return true;
837
-    }
838
-
839
-
840
-    /**
841
-     * calculate spaces remaining based on "saleable" tickets
842
-     *
843
-     * @param array $tickets
844
-     * @param bool  $filtered
845
-     * @return int|float
846
-     * @throws EE_Error
847
-     * @throws DomainException
848
-     * @throws UnexpectedEntityException
849
-     */
850
-    public function spaces_remaining($tickets = array(), $filtered = true)
851
-    {
852
-        $this->getAvailableSpacesCalculator()->setActiveTickets($tickets);
853
-        $spaces_remaining = $this->getAvailableSpacesCalculator()->spacesRemaining();
854
-        return $filtered
855
-            ? apply_filters(
856
-                'FHEE_EE_Event__spaces_remaining',
857
-                $spaces_remaining,
858
-                $this,
859
-                $tickets
860
-            )
861
-            : $spaces_remaining;
862
-    }
863
-
864
-
865
-    /**
866
-     *    perform_sold_out_status_check
867
-     *    checks all of this events's datetime  reg_limit - sold values to determine if ANY datetimes have spaces
868
-     *    available... if NOT, then the event status will get toggled to 'sold_out'
869
-     *
870
-     * @return bool    return the ACTUAL sold out state.
871
-     * @throws EE_Error
872
-     * @throws DomainException
873
-     * @throws UnexpectedEntityException
874
-     */
875
-    public function perform_sold_out_status_check()
876
-    {
877
-        // get all unexpired untrashed tickets
878
-        $tickets = $this->tickets(
879
-            array(
880
-                array('TKT_deleted' => false),
881
-                'order_by' => array('TKT_qty' => 'ASC'),
882
-            )
883
-        );
884
-        $all_expired = true;
885
-        foreach ($tickets as $ticket) {
886
-            if (! $ticket->is_expired()) {
887
-                $all_expired = false;
888
-                break;
889
-            }
890
-        }
891
-        // if all the tickets are just expired, then don't update the event status to sold out
892
-        if ($all_expired) {
893
-            return true;
894
-        }
895
-        $spaces_remaining = $this->spaces_remaining($tickets);
896
-        if ($spaces_remaining < 1) {
897
-            $this->set_status(EEM_Event::sold_out);
898
-            $this->save();
899
-            $sold_out = true;
900
-        } else {
901
-            $sold_out = false;
902
-            // was event previously marked as sold out ?
903
-            if ($this->status() === EEM_Event::sold_out) {
904
-                // revert status to previous value, if it was set
905
-                $previous_event_status = $this->get_post_meta('_previous_event_status', true);
906
-                if ($previous_event_status) {
907
-                    $this->set_status($previous_event_status);
908
-                    $this->save();
909
-                }
910
-            }
911
-        }
912
-        do_action('AHEE__EE_Event__perform_sold_out_status_check__end', $this, $sold_out, $spaces_remaining, $tickets);
913
-        return $sold_out;
914
-    }
915
-
916
-
917
-    /**
918
-     * This returns the total remaining spaces for sale on this event.
919
-     *
920
-     * @uses EE_Event::total_available_spaces()
921
-     * @return float|int
922
-     * @throws EE_Error
923
-     * @throws DomainException
924
-     * @throws UnexpectedEntityException
925
-     */
926
-    public function spaces_remaining_for_sale()
927
-    {
928
-        return $this->total_available_spaces(true);
929
-    }
930
-
931
-
932
-    /**
933
-     * This returns the total spaces available for an event
934
-     * while considering all the qtys on the tickets and the reg limits
935
-     * on the datetimes attached to this event.
936
-     *
937
-     * @param   bool $consider_sold Whether to consider any tickets that have already sold in our calculation.
938
-     *                              If this is false, then we return the most tickets that could ever be sold
939
-     *                              for this event with the datetime and tickets setup on the event under optimal
940
-     *                              selling conditions.  Otherwise we return a live calculation of spaces available
941
-     *                              based on tickets sold.  Depending on setup and stage of sales, this
942
-     *                              may appear to equal remaining tickets.  However, the more tickets are
943
-     *                              sold out, the more accurate the "live" total is.
944
-     * @return float|int
945
-     * @throws EE_Error
946
-     * @throws DomainException
947
-     * @throws UnexpectedEntityException
948
-     */
949
-    public function total_available_spaces($consider_sold = false)
950
-    {
951
-        $spaces_available = $consider_sold
952
-            ? $this->getAvailableSpacesCalculator()->spacesRemaining()
953
-            : $this->getAvailableSpacesCalculator()->totalSpacesAvailable();
954
-        return apply_filters(
955
-            'FHEE_EE_Event__total_available_spaces__spaces_available',
956
-            $spaces_available,
957
-            $this,
958
-            $this->getAvailableSpacesCalculator()->getDatetimes(),
959
-            $this->getAvailableSpacesCalculator()->getActiveTickets()
960
-        );
961
-    }
962
-
963
-
964
-    /**
965
-     * Checks if the event is set to sold out
966
-     *
967
-     * @param  bool $actual whether or not to perform calculations to not only figure the
968
-     *                      actual status but also to flip the status if necessary to sold
969
-     *                      out If false, we just check the existing status of the event
970
-     * @return boolean
971
-     * @throws EE_Error
972
-     */
973
-    public function is_sold_out($actual = false)
974
-    {
975
-        if (! $actual) {
976
-            return $this->status() === EEM_Event::sold_out;
977
-        }
978
-        return $this->perform_sold_out_status_check();
979
-    }
980
-
981
-
982
-    /**
983
-     * Checks if the event is marked as postponed
984
-     *
985
-     * @return boolean
986
-     */
987
-    public function is_postponed()
988
-    {
989
-        return $this->status() === EEM_Event::postponed;
990
-    }
991
-
992
-
993
-    /**
994
-     * Checks if the event is marked as cancelled
995
-     *
996
-     * @return boolean
997
-     */
998
-    public function is_cancelled()
999
-    {
1000
-        return $this->status() === EEM_Event::cancelled;
1001
-    }
1002
-
1003
-
1004
-    /**
1005
-     * Get the logical active status in a hierarchical order for all the datetimes.  Note
1006
-     * Basically, we order the datetimes by EVT_start_date.  Then first test on whether the event is published.  If its
1007
-     * NOT published then we test for whether its expired or not.  IF it IS published then we test first on whether an
1008
-     * event has any active dates.  If no active dates then we check for any upcoming dates.  If no upcoming dates then
1009
-     * the event is considered expired.
1010
-     * NOTE: this method does NOT calculate whether the datetimes are sold out when event is published.  Sold Out is a
1011
-     * status set on the EVENT when it is not published and thus is done
1012
-     *
1013
-     * @param bool $reset
1014
-     * @return bool | string - based on EE_Datetime active constants or FALSE if error.
1015
-     * @throws EE_Error
1016
-     */
1017
-    public function get_active_status($reset = false)
1018
-    {
1019
-        // if the active status has already been set, then just use that value (unless we are resetting it)
1020
-        if (! empty($this->_active_status) && ! $reset) {
1021
-            return $this->_active_status;
1022
-        }
1023
-        // first check if event id is present on this object
1024
-        if (! $this->ID()) {
1025
-            return false;
1026
-        }
1027
-        $where_params_for_event = array(array('EVT_ID' => $this->ID()));
1028
-        // if event is published:
1029
-        if ($this->status() === 'publish') {
1030
-            // active?
1031
-            if (EEM_Datetime::instance()->get_datetime_count_for_status(
1032
-                EE_Datetime::active,
1033
-                $where_params_for_event
1034
-            ) > 0) {
1035
-                $this->_active_status = EE_Datetime::active;
1036
-            } else {
1037
-                // upcoming?
1038
-                if (EEM_Datetime::instance()->get_datetime_count_for_status(
1039
-                    EE_Datetime::upcoming,
1040
-                    $where_params_for_event
1041
-                ) > 0) {
1042
-                    $this->_active_status = EE_Datetime::upcoming;
1043
-                } else {
1044
-                    // expired?
1045
-                    if (EEM_Datetime::instance()->get_datetime_count_for_status(
1046
-                        EE_Datetime::expired,
1047
-                        $where_params_for_event
1048
-                    ) > 0
1049
-                    ) {
1050
-                        $this->_active_status = EE_Datetime::expired;
1051
-                    } else {
1052
-                        // it would be odd if things make it this far because it basically means there are no datetime's
1053
-                        // attached to the event.  So in this case it will just be considered inactive.
1054
-                        $this->_active_status = EE_Datetime::inactive;
1055
-                    }
1056
-                }
1057
-            }
1058
-        } else {
1059
-            // the event is not published, so let's just set it's active status according to its' post status
1060
-            switch ($this->status()) {
1061
-                case EEM_Event::sold_out:
1062
-                    $this->_active_status = EE_Datetime::sold_out;
1063
-                    break;
1064
-                case EEM_Event::cancelled:
1065
-                    $this->_active_status = EE_Datetime::cancelled;
1066
-                    break;
1067
-                case EEM_Event::postponed:
1068
-                    $this->_active_status = EE_Datetime::postponed;
1069
-                    break;
1070
-                default:
1071
-                    $this->_active_status = EE_Datetime::inactive;
1072
-            }
1073
-        }
1074
-        return $this->_active_status;
1075
-    }
1076
-
1077
-
1078
-    /**
1079
-     *    pretty_active_status
1080
-     *
1081
-     * @access public
1082
-     * @param boolean $echo whether to return (FALSE), or echo out the result (TRUE)
1083
-     * @return mixed void|string
1084
-     * @throws EE_Error
1085
-     */
1086
-    public function pretty_active_status($echo = true)
1087
-    {
1088
-        $active_status = $this->get_active_status();
1089
-        $status = '<span class="ee-status event-active-status-'
1090
-                  . $active_status
1091
-                  . '">'
1092
-                  . EEH_Template::pretty_status($active_status, false, 'sentence')
1093
-                  . '</span>';
1094
-        if ($echo) {
1095
-            echo $status;
1096
-            return '';
1097
-        }
1098
-        return $status;
1099
-    }
1100
-
1101
-
1102
-    /**
1103
-     * @return bool|int
1104
-     * @throws EE_Error
1105
-     */
1106
-    public function get_number_of_tickets_sold()
1107
-    {
1108
-        $tkt_sold = 0;
1109
-        if (! $this->ID()) {
1110
-            return 0;
1111
-        }
1112
-        $datetimes = $this->datetimes();
1113
-        foreach ($datetimes as $datetime) {
1114
-            if ($datetime instanceof EE_Datetime) {
1115
-                $tkt_sold += $datetime->sold();
1116
-            }
1117
-        }
1118
-        return $tkt_sold;
1119
-    }
1120
-
1121
-
1122
-    /**
1123
-     * This just returns a count of all the registrations for this event
1124
-     *
1125
-     * @access  public
1126
-     * @return int
1127
-     * @throws EE_Error
1128
-     */
1129
-    public function get_count_of_all_registrations()
1130
-    {
1131
-        return EEM_Event::instance()->count_related($this, 'Registration');
1132
-    }
1133
-
1134
-
1135
-    /**
1136
-     * This returns the ticket with the earliest start time that is
1137
-     * available for this event (across all datetimes attached to the event)
1138
-     *
1139
-     * @return EE_Base_Class|EE_Ticket|null
1140
-     * @throws EE_Error
1141
-     */
1142
-    public function get_ticket_with_earliest_start_time()
1143
-    {
1144
-        $where['Datetime.EVT_ID'] = $this->ID();
1145
-        $query_params = array($where, 'order_by' => array('TKT_start_date' => 'ASC'));
1146
-        return EE_Registry::instance()->load_model('Ticket')->get_one($query_params);
1147
-    }
1148
-
1149
-
1150
-    /**
1151
-     * This returns the ticket with the latest end time that is available
1152
-     * for this event (across all datetimes attached to the event)
1153
-     *
1154
-     * @return EE_Base_Class|EE_Ticket|null
1155
-     * @throws EE_Error
1156
-     */
1157
-    public function get_ticket_with_latest_end_time()
1158
-    {
1159
-        $where['Datetime.EVT_ID'] = $this->ID();
1160
-        $query_params = array($where, 'order_by' => array('TKT_end_date' => 'DESC'));
1161
-        return EE_Registry::instance()->load_model('Ticket')->get_one($query_params);
1162
-    }
1163
-
1164
-
1165
-    /**
1166
-     * This returns the number of different ticket types currently on sale for this event.
1167
-     *
1168
-     * @return int
1169
-     * @throws EE_Error
1170
-     */
1171
-    public function countTicketsOnSale()
1172
-    {
1173
-        $where = array(
1174
-            'Datetime.EVT_ID' => $this->ID(),
1175
-            'TKT_start_date'  => array('<', time()),
1176
-            'TKT_end_date'    => array('>', time()),
1177
-        );
1178
-        return EEM_Ticket::instance()->count(array($where));
1179
-    }
1180
-
1181
-
1182
-    /**
1183
-     * This returns whether there are any tickets on sale for this event.
1184
-     *
1185
-     * @return bool true = YES tickets on sale.
1186
-     * @throws EE_Error
1187
-     */
1188
-    public function tickets_on_sale()
1189
-    {
1190
-        return $this->countTicketsOnSale() > 0;
1191
-    }
1192
-
1193
-
1194
-    /**
1195
-     * Gets the URL for viewing this event on the front-end. Overrides parent
1196
-     * to check for an external URL first
1197
-     *
1198
-     * @return string
1199
-     * @throws EE_Error
1200
-     */
1201
-    public function get_permalink()
1202
-    {
1203
-        if ($this->external_url()) {
1204
-            return $this->external_url();
1205
-        }
1206
-        return parent::get_permalink();
1207
-    }
1208
-
1209
-
1210
-    /**
1211
-     * Gets the first term for 'espresso_event_categories' we can find
1212
-     *
1213
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1214
-     * @return EE_Base_Class|EE_Term|null
1215
-     * @throws EE_Error
1216
-     */
1217
-    public function first_event_category($query_params = array())
1218
-    {
1219
-        $query_params[0]['Term_Taxonomy.taxonomy'] = 'espresso_event_categories';
1220
-        $query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $this->ID();
1221
-        return EEM_Term::instance()->get_one($query_params);
1222
-    }
1223
-
1224
-
1225
-    /**
1226
-     * Gets all terms for 'espresso_event_categories' we can find
1227
-     *
1228
-     * @param array $query_params
1229
-     * @return EE_Base_Class[]|EE_Term[]
1230
-     * @throws EE_Error
1231
-     */
1232
-    public function get_all_event_categories($query_params = array())
1233
-    {
1234
-        $query_params[0]['Term_Taxonomy.taxonomy'] = 'espresso_event_categories';
1235
-        $query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $this->ID();
1236
-        return EEM_Term::instance()->get_all($query_params);
1237
-    }
1238
-
1239
-
1240
-    /**
1241
-     * Adds a question group to this event
1242
-     *
1243
-     * @param EE_Question_Group|int $question_group_id_or_obj
1244
-     * @param bool $for_primary if true, the question group will be added for the primary
1245
-     *                                           registrant, if false will be added for others. default: false
1246
-     * @return EE_Base_Class|EE_Question_Group
1247
-     * @throws EE_Error
1248
-     * @throws InvalidArgumentException
1249
-     * @throws InvalidDataTypeException
1250
-     * @throws InvalidInterfaceException
1251
-     * @throws ReflectionException
1252
-     */
1253
-    public function add_question_group($question_group_id_or_obj, $for_primary = false)
1254
-    {
1255
-        // If the row already exists, it will be updated. If it doesn't, it will be inserted.
1256
-        // That's in EE_HABTM_Relation::add_relation_to().
1257
-        return $this->_add_relation_to(
1258
-            $question_group_id_or_obj,
1259
-            'Question_Group',
1260
-            [
1261
-                EEM_Event_Question_Group::instance()->fieldNameForContext($for_primary) => true
1262
-            ]
1263
-        );
1264
-    }
1265
-
1266
-
1267
-    /**
1268
-     * Removes a question group from the event
1269
-     *
1270
-     * @param EE_Question_Group|int $question_group_id_or_obj
1271
-     * @param bool $for_primary if true, the question group will be removed from the primary
1272
-     *                                           registrant, if false will be removed from others. default: false
1273
-     * @return EE_Base_Class|EE_Question_Group
1274
-     * @throws EE_Error
1275
-     * @throws InvalidArgumentException
1276
-     * @throws ReflectionException
1277
-     * @throws InvalidDataTypeException
1278
-     * @throws InvalidInterfaceException
1279
-     */
1280
-    public function remove_question_group($question_group_id_or_obj, $for_primary = false)
1281
-    {
1282
-        // If the question group is used for the other type (primary or additional)
1283
-        // then just update it. If not, delete it outright.
1284
-        $existing_relation = $this->get_first_related(
1285
-            'Event_Question_Group',
1286
-            [
1287
-                [
1288
-                    'QSG_ID' => EEM_Question_Group::instance()->ensure_is_ID($question_group_id_or_obj)
1289
-                ]
1290
-            ]
1291
-        );
1292
-        $field_to_update = EEM_Event_Question_Group::instance()->fieldNameForContext($for_primary);
1293
-        $other_field = EEM_Event_Question_Group::instance()->fieldNameForContext(! $for_primary);
1294
-        if ($existing_relation->get($other_field) === false) {
1295
-            // Delete it. It's now no longer for primary or additional question groups.
1296
-            return $this->_remove_relation_to($question_group_id_or_obj, 'Question_Group');
1297
-        }
1298
-        // Just update it. They'll still use this question group for the other category
1299
-        $existing_relation->save(
1300
-            [
1301
-                $field_to_update => false
1302
-            ]
1303
-        );
1304
-    }
1305
-
1306
-
1307
-    /**
1308
-     * Gets all the question groups, ordering them by QSG_order ascending
1309
-     *
1310
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1311
-     * @return EE_Base_Class[]|EE_Question_Group[]
1312
-     * @throws EE_Error
1313
-     */
1314
-    public function question_groups($query_params = array())
1315
-    {
1316
-        $query_params = ! empty($query_params) ? $query_params : array('order_by' => array('QSG_order' => 'ASC'));
1317
-        return $this->get_many_related('Question_Group', $query_params);
1318
-    }
1319
-
1320
-
1321
-    /**
1322
-     * Implementation for EEI_Has_Icon interface method.
1323
-     *
1324
-     * @see EEI_Visual_Representation for comments
1325
-     * @return string
1326
-     */
1327
-    public function get_icon()
1328
-    {
1329
-        return '<span class="dashicons dashicons-flag"></span>';
1330
-    }
1331
-
1332
-
1333
-    /**
1334
-     * Implementation for EEI_Admin_Links interface method.
1335
-     *
1336
-     * @see EEI_Admin_Links for comments
1337
-     * @return string
1338
-     * @throws EE_Error
1339
-     */
1340
-    public function get_admin_details_link()
1341
-    {
1342
-        return $this->get_admin_edit_link();
1343
-    }
1344
-
1345
-
1346
-    /**
1347
-     * Implementation for EEI_Admin_Links interface method.
1348
-     *
1349
-     * @see EEI_Admin_Links for comments
1350
-     * @return string
1351
-     * @throws EE_Error
1352
-     */
1353
-    public function get_admin_edit_link()
1354
-    {
1355
-        return EEH_URL::add_query_args_and_nonce(
1356
-            array(
1357
-                'page'   => 'espresso_events',
1358
-                'action' => 'edit',
1359
-                'post'   => $this->ID(),
1360
-            ),
1361
-            admin_url('admin.php')
1362
-        );
1363
-    }
1364
-
1365
-
1366
-    /**
1367
-     * Implementation for EEI_Admin_Links interface method.
1368
-     *
1369
-     * @see EEI_Admin_Links for comments
1370
-     * @return string
1371
-     */
1372
-    public function get_admin_settings_link()
1373
-    {
1374
-        return EEH_URL::add_query_args_and_nonce(
1375
-            array(
1376
-                'page'   => 'espresso_events',
1377
-                'action' => 'default_event_settings',
1378
-            ),
1379
-            admin_url('admin.php')
1380
-        );
1381
-    }
1382
-
1383
-
1384
-    /**
1385
-     * Implementation for EEI_Admin_Links interface method.
1386
-     *
1387
-     * @see EEI_Admin_Links for comments
1388
-     * @return string
1389
-     */
1390
-    public function get_admin_overview_link()
1391
-    {
1392
-        return EEH_URL::add_query_args_and_nonce(
1393
-            array(
1394
-                'page'   => 'espresso_events',
1395
-                'action' => 'default',
1396
-            ),
1397
-            admin_url('admin.php')
1398
-        );
1399
-    }
18
+	/**
19
+	 * cached value for the the logical active status for the event
20
+	 *
21
+	 * @see get_active_status()
22
+	 * @var string
23
+	 */
24
+	protected $_active_status = '';
25
+
26
+	/**
27
+	 * This is just used for caching the Primary Datetime for the Event on initial retrieval
28
+	 *
29
+	 * @var EE_Datetime
30
+	 */
31
+	protected $_Primary_Datetime;
32
+
33
+	/**
34
+	 * @var EventSpacesCalculator $available_spaces_calculator
35
+	 */
36
+	protected $available_spaces_calculator;
37
+
38
+
39
+	/**
40
+	 * @param array  $props_n_values          incoming values
41
+	 * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
42
+	 *                                        used.)
43
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
44
+	 *                                        date_format and the second value is the time format
45
+	 * @return EE_Event
46
+	 * @throws EE_Error
47
+	 */
48
+	public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
49
+	{
50
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
51
+		return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
52
+	}
53
+
54
+
55
+	/**
56
+	 * @param array  $props_n_values  incoming values from the database
57
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
58
+	 *                                the website will be used.
59
+	 * @return EE_Event
60
+	 * @throws EE_Error
61
+	 */
62
+	public static function new_instance_from_db($props_n_values = array(), $timezone = null)
63
+	{
64
+		return new self($props_n_values, true, $timezone);
65
+	}
66
+
67
+
68
+	/**
69
+	 * @return EventSpacesCalculator
70
+	 * @throws \EE_Error
71
+	 */
72
+	public function getAvailableSpacesCalculator()
73
+	{
74
+		if (! $this->available_spaces_calculator instanceof EventSpacesCalculator) {
75
+			$this->available_spaces_calculator = new EventSpacesCalculator($this);
76
+		}
77
+		return $this->available_spaces_calculator;
78
+	}
79
+
80
+
81
+	/**
82
+	 * Overrides parent set() method so that all calls to set( 'status', $status ) can be routed to internal methods
83
+	 *
84
+	 * @param string $field_name
85
+	 * @param mixed  $field_value
86
+	 * @param bool   $use_default
87
+	 * @throws EE_Error
88
+	 */
89
+	public function set($field_name, $field_value, $use_default = false)
90
+	{
91
+		switch ($field_name) {
92
+			case 'status':
93
+				$this->set_status($field_value, $use_default);
94
+				break;
95
+			default:
96
+				parent::set($field_name, $field_value, $use_default);
97
+		}
98
+	}
99
+
100
+
101
+	/**
102
+	 *    set_status
103
+	 * Checks if event status is being changed to SOLD OUT
104
+	 * and updates event meta data with previous event status
105
+	 * so that we can revert things if/when the event is no longer sold out
106
+	 *
107
+	 * @access public
108
+	 * @param string $new_status
109
+	 * @param bool   $use_default
110
+	 * @return void
111
+	 * @throws EE_Error
112
+	 */
113
+	public function set_status($new_status = null, $use_default = false)
114
+	{
115
+		// if nothing is set, and we aren't explicitly wanting to reset the status, then just leave
116
+		if (empty($new_status) && ! $use_default) {
117
+			return;
118
+		}
119
+		// get current Event status
120
+		$old_status = $this->status();
121
+		// if status has changed
122
+		if ($old_status !== $new_status) {
123
+			// TO sold_out
124
+			if ($new_status === EEM_Event::sold_out) {
125
+				// save the previous event status so that we can revert if the event is no longer sold out
126
+				$this->add_post_meta('_previous_event_status', $old_status);
127
+				do_action('AHEE__EE_Event__set_status__to_sold_out', $this, $old_status, $new_status);
128
+				// OR FROM  sold_out
129
+			} elseif ($old_status === EEM_Event::sold_out) {
130
+				$this->delete_post_meta('_previous_event_status');
131
+				do_action('AHEE__EE_Event__set_status__from_sold_out', $this, $old_status, $new_status);
132
+			}
133
+			// clear out the active status so that it gets reset the next time it is requested
134
+			$this->_active_status = null;
135
+			// update status
136
+			parent::set('status', $new_status, $use_default);
137
+			do_action('AHEE__EE_Event__set_status__after_update', $this);
138
+			return;
139
+		}
140
+		// even though the old value matches the new value, it's still good to
141
+		// allow the parent set method to have a say
142
+		parent::set('status', $new_status, $use_default);
143
+	}
144
+
145
+
146
+	/**
147
+	 * Gets all the datetimes for this event
148
+	 *
149
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
150
+	 * @return EE_Base_Class[]|EE_Datetime[]
151
+	 * @throws EE_Error
152
+	 */
153
+	public function datetimes($query_params = array())
154
+	{
155
+		return $this->get_many_related('Datetime', $query_params);
156
+	}
157
+
158
+
159
+	/**
160
+	 * Gets all the datetimes for this event, ordered by DTT_EVT_start in ascending order
161
+	 *
162
+	 * @return EE_Base_Class[]|EE_Datetime[]
163
+	 * @throws EE_Error
164
+	 */
165
+	public function datetimes_in_chronological_order()
166
+	{
167
+		return $this->get_many_related('Datetime', array('order_by' => array('DTT_EVT_start' => 'ASC')));
168
+	}
169
+
170
+
171
+	/**
172
+	 * Gets all the datetimes for this event, ordered by the DTT_order on the datetime.
173
+	 * @darren, we should probably UNSET timezone on the EEM_Datetime model
174
+	 * after running our query, so that this timezone isn't set for EVERY query
175
+	 * on EEM_Datetime for the rest of the request, no?
176
+	 *
177
+	 * @param boolean $show_expired whether or not to include expired events
178
+	 * @param boolean $show_deleted whether or not to include deleted events
179
+	 * @param null    $limit
180
+	 * @return EE_Datetime[]
181
+	 * @throws EE_Error
182
+	 */
183
+	public function datetimes_ordered($show_expired = true, $show_deleted = false, $limit = null)
184
+	{
185
+		return EEM_Datetime::instance($this->_timezone)->get_datetimes_for_event_ordered_by_DTT_order(
186
+			$this->ID(),
187
+			$show_expired,
188
+			$show_deleted,
189
+			$limit
190
+		);
191
+	}
192
+
193
+
194
+	/**
195
+	 * Returns one related datetime. Mostly only used by some legacy code.
196
+	 *
197
+	 * @return EE_Base_Class|EE_Datetime
198
+	 * @throws EE_Error
199
+	 */
200
+	public function first_datetime()
201
+	{
202
+		return $this->get_first_related('Datetime');
203
+	}
204
+
205
+
206
+	/**
207
+	 * Returns the 'primary' datetime for the event
208
+	 *
209
+	 * @param bool $try_to_exclude_expired
210
+	 * @param bool $try_to_exclude_deleted
211
+	 * @return EE_Datetime
212
+	 * @throws EE_Error
213
+	 */
214
+	public function primary_datetime($try_to_exclude_expired = true, $try_to_exclude_deleted = true)
215
+	{
216
+		if (! empty($this->_Primary_Datetime)) {
217
+			return $this->_Primary_Datetime;
218
+		}
219
+		$this->_Primary_Datetime = EEM_Datetime::instance($this->_timezone)->get_primary_datetime_for_event(
220
+			$this->ID(),
221
+			$try_to_exclude_expired,
222
+			$try_to_exclude_deleted
223
+		);
224
+		return $this->_Primary_Datetime;
225
+	}
226
+
227
+
228
+	/**
229
+	 * Gets all the tickets available for purchase of this event
230
+	 *
231
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
232
+	 * @return EE_Base_Class[]|EE_Ticket[]
233
+	 * @throws EE_Error
234
+	 */
235
+	public function tickets($query_params = array())
236
+	{
237
+		// first get all datetimes
238
+		$datetimes = $this->datetimes_ordered();
239
+		if (! $datetimes) {
240
+			return array();
241
+		}
242
+		$datetime_ids = array();
243
+		foreach ($datetimes as $datetime) {
244
+			$datetime_ids[] = $datetime->ID();
245
+		}
246
+		$where_params = array('Datetime.DTT_ID' => array('IN', $datetime_ids));
247
+		// if incoming $query_params has where conditions let's merge but not override existing.
248
+		if (is_array($query_params) && isset($query_params[0])) {
249
+			$where_params = array_merge($query_params[0], $where_params);
250
+			unset($query_params[0]);
251
+		}
252
+		// now add $where_params to $query_params
253
+		$query_params[0] = $where_params;
254
+		return EEM_Ticket::instance()->get_all($query_params);
255
+	}
256
+
257
+
258
+	/**
259
+	 * get all unexpired untrashed tickets
260
+	 *
261
+	 * @return EE_Ticket[]
262
+	 * @throws EE_Error
263
+	 */
264
+	public function active_tickets()
265
+	{
266
+		return $this->tickets(
267
+			array(
268
+				array(
269
+					'TKT_end_date' => array('>=', EEM_Ticket::instance()->current_time_for_query('TKT_end_date')),
270
+					'TKT_deleted'  => false,
271
+				),
272
+			)
273
+		);
274
+	}
275
+
276
+
277
+	/**
278
+	 * @return bool
279
+	 * @throws EE_Error
280
+	 */
281
+	public function additional_limit()
282
+	{
283
+		return $this->get('EVT_additional_limit');
284
+	}
285
+
286
+
287
+	/**
288
+	 * @return bool
289
+	 * @throws EE_Error
290
+	 */
291
+	public function allow_overflow()
292
+	{
293
+		return $this->get('EVT_allow_overflow');
294
+	}
295
+
296
+
297
+	/**
298
+	 * @return bool
299
+	 * @throws EE_Error
300
+	 */
301
+	public function created()
302
+	{
303
+		return $this->get('EVT_created');
304
+	}
305
+
306
+
307
+	/**
308
+	 * @return bool
309
+	 * @throws EE_Error
310
+	 */
311
+	public function description()
312
+	{
313
+		return $this->get('EVT_desc');
314
+	}
315
+
316
+
317
+	/**
318
+	 * Runs do_shortcode and wpautop on the description
319
+	 *
320
+	 * @return string of html
321
+	 * @throws EE_Error
322
+	 */
323
+	public function description_filtered()
324
+	{
325
+		return $this->get_pretty('EVT_desc');
326
+	}
327
+
328
+
329
+	/**
330
+	 * @return bool
331
+	 * @throws EE_Error
332
+	 */
333
+	public function display_description()
334
+	{
335
+		return $this->get('EVT_display_desc');
336
+	}
337
+
338
+
339
+	/**
340
+	 * @return bool
341
+	 * @throws EE_Error
342
+	 */
343
+	public function display_ticket_selector()
344
+	{
345
+		return (bool) $this->get('EVT_display_ticket_selector');
346
+	}
347
+
348
+
349
+	/**
350
+	 * @return bool
351
+	 * @throws EE_Error
352
+	 */
353
+	public function external_url()
354
+	{
355
+		return $this->get('EVT_external_URL');
356
+	}
357
+
358
+
359
+	/**
360
+	 * @return bool
361
+	 * @throws EE_Error
362
+	 */
363
+	public function member_only()
364
+	{
365
+		return $this->get('EVT_member_only');
366
+	}
367
+
368
+
369
+	/**
370
+	 * @return bool
371
+	 * @throws EE_Error
372
+	 */
373
+	public function phone()
374
+	{
375
+		return $this->get('EVT_phone');
376
+	}
377
+
378
+
379
+	/**
380
+	 * @return bool
381
+	 * @throws EE_Error
382
+	 */
383
+	public function modified()
384
+	{
385
+		return $this->get('EVT_modified');
386
+	}
387
+
388
+
389
+	/**
390
+	 * @return bool
391
+	 * @throws EE_Error
392
+	 */
393
+	public function name()
394
+	{
395
+		return $this->get('EVT_name');
396
+	}
397
+
398
+
399
+	/**
400
+	 * @return bool
401
+	 * @throws EE_Error
402
+	 */
403
+	public function order()
404
+	{
405
+		return $this->get('EVT_order');
406
+	}
407
+
408
+
409
+	/**
410
+	 * @return bool|string
411
+	 * @throws EE_Error
412
+	 */
413
+	public function default_registration_status()
414
+	{
415
+		$event_default_registration_status = $this->get('EVT_default_registration_status');
416
+		return ! empty($event_default_registration_status)
417
+			? $event_default_registration_status
418
+			: EE_Registry::instance()->CFG->registration->default_STS_ID;
419
+	}
420
+
421
+
422
+	/**
423
+	 * @param int  $num_words
424
+	 * @param null $more
425
+	 * @param bool $not_full_desc
426
+	 * @return bool|string
427
+	 * @throws EE_Error
428
+	 */
429
+	public function short_description($num_words = 55, $more = null, $not_full_desc = false)
430
+	{
431
+		$short_desc = $this->get('EVT_short_desc');
432
+		if (! empty($short_desc) || $not_full_desc) {
433
+			return $short_desc;
434
+		}
435
+		$full_desc = $this->get('EVT_desc');
436
+		return wp_trim_words($full_desc, $num_words, $more);
437
+	}
438
+
439
+
440
+	/**
441
+	 * @return bool
442
+	 * @throws EE_Error
443
+	 */
444
+	public function slug()
445
+	{
446
+		return $this->get('EVT_slug');
447
+	}
448
+
449
+
450
+	/**
451
+	 * @return bool
452
+	 * @throws EE_Error
453
+	 */
454
+	public function timezone_string()
455
+	{
456
+		return $this->get('EVT_timezone_string');
457
+	}
458
+
459
+
460
+	/**
461
+	 * @return bool
462
+	 * @throws EE_Error
463
+	 */
464
+	public function visible_on()
465
+	{
466
+		return $this->get('EVT_visible_on');
467
+	}
468
+
469
+
470
+	/**
471
+	 * @return int
472
+	 * @throws EE_Error
473
+	 */
474
+	public function wp_user()
475
+	{
476
+		return $this->get('EVT_wp_user');
477
+	}
478
+
479
+
480
+	/**
481
+	 * @return bool
482
+	 * @throws EE_Error
483
+	 */
484
+	public function donations()
485
+	{
486
+		return $this->get('EVT_donations');
487
+	}
488
+
489
+
490
+	/**
491
+	 * @param $limit
492
+	 * @throws EE_Error
493
+	 */
494
+	public function set_additional_limit($limit)
495
+	{
496
+		$this->set('EVT_additional_limit', $limit);
497
+	}
498
+
499
+
500
+	/**
501
+	 * @param $created
502
+	 * @throws EE_Error
503
+	 */
504
+	public function set_created($created)
505
+	{
506
+		$this->set('EVT_created', $created);
507
+	}
508
+
509
+
510
+	/**
511
+	 * @param $desc
512
+	 * @throws EE_Error
513
+	 */
514
+	public function set_description($desc)
515
+	{
516
+		$this->set('EVT_desc', $desc);
517
+	}
518
+
519
+
520
+	/**
521
+	 * @param $display_desc
522
+	 * @throws EE_Error
523
+	 */
524
+	public function set_display_description($display_desc)
525
+	{
526
+		$this->set('EVT_display_desc', $display_desc);
527
+	}
528
+
529
+
530
+	/**
531
+	 * @param $display_ticket_selector
532
+	 * @throws EE_Error
533
+	 */
534
+	public function set_display_ticket_selector($display_ticket_selector)
535
+	{
536
+		$this->set('EVT_display_ticket_selector', $display_ticket_selector);
537
+	}
538
+
539
+
540
+	/**
541
+	 * @param $external_url
542
+	 * @throws EE_Error
543
+	 */
544
+	public function set_external_url($external_url)
545
+	{
546
+		$this->set('EVT_external_URL', $external_url);
547
+	}
548
+
549
+
550
+	/**
551
+	 * @param $member_only
552
+	 * @throws EE_Error
553
+	 */
554
+	public function set_member_only($member_only)
555
+	{
556
+		$this->set('EVT_member_only', $member_only);
557
+	}
558
+
559
+
560
+	/**
561
+	 * @param $event_phone
562
+	 * @throws EE_Error
563
+	 */
564
+	public function set_event_phone($event_phone)
565
+	{
566
+		$this->set('EVT_phone', $event_phone);
567
+	}
568
+
569
+
570
+	/**
571
+	 * @param $modified
572
+	 * @throws EE_Error
573
+	 */
574
+	public function set_modified($modified)
575
+	{
576
+		$this->set('EVT_modified', $modified);
577
+	}
578
+
579
+
580
+	/**
581
+	 * @param $name
582
+	 * @throws EE_Error
583
+	 */
584
+	public function set_name($name)
585
+	{
586
+		$this->set('EVT_name', $name);
587
+	}
588
+
589
+
590
+	/**
591
+	 * @param $order
592
+	 * @throws EE_Error
593
+	 */
594
+	public function set_order($order)
595
+	{
596
+		$this->set('EVT_order', $order);
597
+	}
598
+
599
+
600
+	/**
601
+	 * @param $short_desc
602
+	 * @throws EE_Error
603
+	 */
604
+	public function set_short_description($short_desc)
605
+	{
606
+		$this->set('EVT_short_desc', $short_desc);
607
+	}
608
+
609
+
610
+	/**
611
+	 * @param $slug
612
+	 * @throws EE_Error
613
+	 */
614
+	public function set_slug($slug)
615
+	{
616
+		$this->set('EVT_slug', $slug);
617
+	}
618
+
619
+
620
+	/**
621
+	 * @param $timezone_string
622
+	 * @throws EE_Error
623
+	 */
624
+	public function set_timezone_string($timezone_string)
625
+	{
626
+		$this->set('EVT_timezone_string', $timezone_string);
627
+	}
628
+
629
+
630
+	/**
631
+	 * @param $visible_on
632
+	 * @throws EE_Error
633
+	 */
634
+	public function set_visible_on($visible_on)
635
+	{
636
+		$this->set('EVT_visible_on', $visible_on);
637
+	}
638
+
639
+
640
+	/**
641
+	 * @param $wp_user
642
+	 * @throws EE_Error
643
+	 */
644
+	public function set_wp_user($wp_user)
645
+	{
646
+		$this->set('EVT_wp_user', $wp_user);
647
+	}
648
+
649
+
650
+	/**
651
+	 * @param $default_registration_status
652
+	 * @throws EE_Error
653
+	 */
654
+	public function set_default_registration_status($default_registration_status)
655
+	{
656
+		$this->set('EVT_default_registration_status', $default_registration_status);
657
+	}
658
+
659
+
660
+	/**
661
+	 * @param $donations
662
+	 * @throws EE_Error
663
+	 */
664
+	public function set_donations($donations)
665
+	{
666
+		$this->set('EVT_donations', $donations);
667
+	}
668
+
669
+
670
+	/**
671
+	 * Adds a venue to this event
672
+	 *
673
+	 * @param EE_Venue /int $venue_id_or_obj
674
+	 * @return EE_Base_Class|EE_Venue
675
+	 * @throws EE_Error
676
+	 */
677
+	public function add_venue($venue_id_or_obj)
678
+	{
679
+		return $this->_add_relation_to($venue_id_or_obj, 'Venue');
680
+	}
681
+
682
+
683
+	/**
684
+	 * Removes a venue from the event
685
+	 *
686
+	 * @param EE_Venue /int $venue_id_or_obj
687
+	 * @return EE_Base_Class|EE_Venue
688
+	 * @throws EE_Error
689
+	 */
690
+	public function remove_venue($venue_id_or_obj)
691
+	{
692
+		return $this->_remove_relation_to($venue_id_or_obj, 'Venue');
693
+	}
694
+
695
+
696
+	/**
697
+	 * Gets all the venues related ot the event. May provide additional $query_params if desired
698
+	 *
699
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
700
+	 * @return EE_Base_Class[]|EE_Venue[]
701
+	 * @throws EE_Error
702
+	 */
703
+	public function venues($query_params = array())
704
+	{
705
+		return $this->get_many_related('Venue', $query_params);
706
+	}
707
+
708
+
709
+	/**
710
+	 * check if event id is present and if event is published
711
+	 *
712
+	 * @access public
713
+	 * @return boolean true yes, false no
714
+	 * @throws EE_Error
715
+	 */
716
+	private function _has_ID_and_is_published()
717
+	{
718
+		// first check if event id is present and not NULL,
719
+		// then check if this event is published (or any of the equivalent "published" statuses)
720
+		return
721
+			$this->ID() && $this->ID() !== null
722
+			&& (
723
+				$this->status() === 'publish'
724
+				|| $this->status() === EEM_Event::sold_out
725
+				|| $this->status() === EEM_Event::postponed
726
+				|| $this->status() === EEM_Event::cancelled
727
+			);
728
+	}
729
+
730
+
731
+	/**
732
+	 * This simply compares the internal dates with NOW and determines if the event is upcoming or not.
733
+	 *
734
+	 * @access public
735
+	 * @return boolean true yes, false no
736
+	 * @throws EE_Error
737
+	 */
738
+	public function is_upcoming()
739
+	{
740
+		// check if event id is present and if this event is published
741
+		if ($this->is_inactive()) {
742
+			return false;
743
+		}
744
+		// set initial value
745
+		$upcoming = false;
746
+		// next let's get all datetimes and loop through them
747
+		$datetimes = $this->datetimes_in_chronological_order();
748
+		foreach ($datetimes as $datetime) {
749
+			if ($datetime instanceof EE_Datetime) {
750
+				// if this dtt is expired then we continue cause one of the other datetimes might be upcoming.
751
+				if ($datetime->is_expired()) {
752
+					continue;
753
+				}
754
+				// if this dtt is active then we return false.
755
+				if ($datetime->is_active()) {
756
+					return false;
757
+				}
758
+				// otherwise let's check upcoming status
759
+				$upcoming = $datetime->is_upcoming();
760
+			}
761
+		}
762
+		return $upcoming;
763
+	}
764
+
765
+
766
+	/**
767
+	 * @return bool
768
+	 * @throws EE_Error
769
+	 */
770
+	public function is_active()
771
+	{
772
+		// check if event id is present and if this event is published
773
+		if ($this->is_inactive()) {
774
+			return false;
775
+		}
776
+		// set initial value
777
+		$active = false;
778
+		// next let's get all datetimes and loop through them
779
+		$datetimes = $this->datetimes_in_chronological_order();
780
+		foreach ($datetimes as $datetime) {
781
+			if ($datetime instanceof EE_Datetime) {
782
+				// if this dtt is expired then we continue cause one of the other datetimes might be active.
783
+				if ($datetime->is_expired()) {
784
+					continue;
785
+				}
786
+				// if this dtt is upcoming then we return false.
787
+				if ($datetime->is_upcoming()) {
788
+					return false;
789
+				}
790
+				// otherwise let's check active status
791
+				$active = $datetime->is_active();
792
+			}
793
+		}
794
+		return $active;
795
+	}
796
+
797
+
798
+	/**
799
+	 * @return bool
800
+	 * @throws EE_Error
801
+	 */
802
+	public function is_expired()
803
+	{
804
+		// check if event id is present and if this event is published
805
+		if ($this->is_inactive()) {
806
+			return false;
807
+		}
808
+		// set initial value
809
+		$expired = false;
810
+		// first let's get all datetimes and loop through them
811
+		$datetimes = $this->datetimes_in_chronological_order();
812
+		foreach ($datetimes as $datetime) {
813
+			if ($datetime instanceof EE_Datetime) {
814
+				// if this dtt is upcoming or active then we return false.
815
+				if ($datetime->is_upcoming() || $datetime->is_active()) {
816
+					return false;
817
+				}
818
+				// otherwise let's check active status
819
+				$expired = $datetime->is_expired();
820
+			}
821
+		}
822
+		return $expired;
823
+	}
824
+
825
+
826
+	/**
827
+	 * @return bool
828
+	 * @throws EE_Error
829
+	 */
830
+	public function is_inactive()
831
+	{
832
+		// check if event id is present and if this event is published
833
+		if ($this->_has_ID_and_is_published()) {
834
+			return false;
835
+		}
836
+		return true;
837
+	}
838
+
839
+
840
+	/**
841
+	 * calculate spaces remaining based on "saleable" tickets
842
+	 *
843
+	 * @param array $tickets
844
+	 * @param bool  $filtered
845
+	 * @return int|float
846
+	 * @throws EE_Error
847
+	 * @throws DomainException
848
+	 * @throws UnexpectedEntityException
849
+	 */
850
+	public function spaces_remaining($tickets = array(), $filtered = true)
851
+	{
852
+		$this->getAvailableSpacesCalculator()->setActiveTickets($tickets);
853
+		$spaces_remaining = $this->getAvailableSpacesCalculator()->spacesRemaining();
854
+		return $filtered
855
+			? apply_filters(
856
+				'FHEE_EE_Event__spaces_remaining',
857
+				$spaces_remaining,
858
+				$this,
859
+				$tickets
860
+			)
861
+			: $spaces_remaining;
862
+	}
863
+
864
+
865
+	/**
866
+	 *    perform_sold_out_status_check
867
+	 *    checks all of this events's datetime  reg_limit - sold values to determine if ANY datetimes have spaces
868
+	 *    available... if NOT, then the event status will get toggled to 'sold_out'
869
+	 *
870
+	 * @return bool    return the ACTUAL sold out state.
871
+	 * @throws EE_Error
872
+	 * @throws DomainException
873
+	 * @throws UnexpectedEntityException
874
+	 */
875
+	public function perform_sold_out_status_check()
876
+	{
877
+		// get all unexpired untrashed tickets
878
+		$tickets = $this->tickets(
879
+			array(
880
+				array('TKT_deleted' => false),
881
+				'order_by' => array('TKT_qty' => 'ASC'),
882
+			)
883
+		);
884
+		$all_expired = true;
885
+		foreach ($tickets as $ticket) {
886
+			if (! $ticket->is_expired()) {
887
+				$all_expired = false;
888
+				break;
889
+			}
890
+		}
891
+		// if all the tickets are just expired, then don't update the event status to sold out
892
+		if ($all_expired) {
893
+			return true;
894
+		}
895
+		$spaces_remaining = $this->spaces_remaining($tickets);
896
+		if ($spaces_remaining < 1) {
897
+			$this->set_status(EEM_Event::sold_out);
898
+			$this->save();
899
+			$sold_out = true;
900
+		} else {
901
+			$sold_out = false;
902
+			// was event previously marked as sold out ?
903
+			if ($this->status() === EEM_Event::sold_out) {
904
+				// revert status to previous value, if it was set
905
+				$previous_event_status = $this->get_post_meta('_previous_event_status', true);
906
+				if ($previous_event_status) {
907
+					$this->set_status($previous_event_status);
908
+					$this->save();
909
+				}
910
+			}
911
+		}
912
+		do_action('AHEE__EE_Event__perform_sold_out_status_check__end', $this, $sold_out, $spaces_remaining, $tickets);
913
+		return $sold_out;
914
+	}
915
+
916
+
917
+	/**
918
+	 * This returns the total remaining spaces for sale on this event.
919
+	 *
920
+	 * @uses EE_Event::total_available_spaces()
921
+	 * @return float|int
922
+	 * @throws EE_Error
923
+	 * @throws DomainException
924
+	 * @throws UnexpectedEntityException
925
+	 */
926
+	public function spaces_remaining_for_sale()
927
+	{
928
+		return $this->total_available_spaces(true);
929
+	}
930
+
931
+
932
+	/**
933
+	 * This returns the total spaces available for an event
934
+	 * while considering all the qtys on the tickets and the reg limits
935
+	 * on the datetimes attached to this event.
936
+	 *
937
+	 * @param   bool $consider_sold Whether to consider any tickets that have already sold in our calculation.
938
+	 *                              If this is false, then we return the most tickets that could ever be sold
939
+	 *                              for this event with the datetime and tickets setup on the event under optimal
940
+	 *                              selling conditions.  Otherwise we return a live calculation of spaces available
941
+	 *                              based on tickets sold.  Depending on setup and stage of sales, this
942
+	 *                              may appear to equal remaining tickets.  However, the more tickets are
943
+	 *                              sold out, the more accurate the "live" total is.
944
+	 * @return float|int
945
+	 * @throws EE_Error
946
+	 * @throws DomainException
947
+	 * @throws UnexpectedEntityException
948
+	 */
949
+	public function total_available_spaces($consider_sold = false)
950
+	{
951
+		$spaces_available = $consider_sold
952
+			? $this->getAvailableSpacesCalculator()->spacesRemaining()
953
+			: $this->getAvailableSpacesCalculator()->totalSpacesAvailable();
954
+		return apply_filters(
955
+			'FHEE_EE_Event__total_available_spaces__spaces_available',
956
+			$spaces_available,
957
+			$this,
958
+			$this->getAvailableSpacesCalculator()->getDatetimes(),
959
+			$this->getAvailableSpacesCalculator()->getActiveTickets()
960
+		);
961
+	}
962
+
963
+
964
+	/**
965
+	 * Checks if the event is set to sold out
966
+	 *
967
+	 * @param  bool $actual whether or not to perform calculations to not only figure the
968
+	 *                      actual status but also to flip the status if necessary to sold
969
+	 *                      out If false, we just check the existing status of the event
970
+	 * @return boolean
971
+	 * @throws EE_Error
972
+	 */
973
+	public function is_sold_out($actual = false)
974
+	{
975
+		if (! $actual) {
976
+			return $this->status() === EEM_Event::sold_out;
977
+		}
978
+		return $this->perform_sold_out_status_check();
979
+	}
980
+
981
+
982
+	/**
983
+	 * Checks if the event is marked as postponed
984
+	 *
985
+	 * @return boolean
986
+	 */
987
+	public function is_postponed()
988
+	{
989
+		return $this->status() === EEM_Event::postponed;
990
+	}
991
+
992
+
993
+	/**
994
+	 * Checks if the event is marked as cancelled
995
+	 *
996
+	 * @return boolean
997
+	 */
998
+	public function is_cancelled()
999
+	{
1000
+		return $this->status() === EEM_Event::cancelled;
1001
+	}
1002
+
1003
+
1004
+	/**
1005
+	 * Get the logical active status in a hierarchical order for all the datetimes.  Note
1006
+	 * Basically, we order the datetimes by EVT_start_date.  Then first test on whether the event is published.  If its
1007
+	 * NOT published then we test for whether its expired or not.  IF it IS published then we test first on whether an
1008
+	 * event has any active dates.  If no active dates then we check for any upcoming dates.  If no upcoming dates then
1009
+	 * the event is considered expired.
1010
+	 * NOTE: this method does NOT calculate whether the datetimes are sold out when event is published.  Sold Out is a
1011
+	 * status set on the EVENT when it is not published and thus is done
1012
+	 *
1013
+	 * @param bool $reset
1014
+	 * @return bool | string - based on EE_Datetime active constants or FALSE if error.
1015
+	 * @throws EE_Error
1016
+	 */
1017
+	public function get_active_status($reset = false)
1018
+	{
1019
+		// if the active status has already been set, then just use that value (unless we are resetting it)
1020
+		if (! empty($this->_active_status) && ! $reset) {
1021
+			return $this->_active_status;
1022
+		}
1023
+		// first check if event id is present on this object
1024
+		if (! $this->ID()) {
1025
+			return false;
1026
+		}
1027
+		$where_params_for_event = array(array('EVT_ID' => $this->ID()));
1028
+		// if event is published:
1029
+		if ($this->status() === 'publish') {
1030
+			// active?
1031
+			if (EEM_Datetime::instance()->get_datetime_count_for_status(
1032
+				EE_Datetime::active,
1033
+				$where_params_for_event
1034
+			) > 0) {
1035
+				$this->_active_status = EE_Datetime::active;
1036
+			} else {
1037
+				// upcoming?
1038
+				if (EEM_Datetime::instance()->get_datetime_count_for_status(
1039
+					EE_Datetime::upcoming,
1040
+					$where_params_for_event
1041
+				) > 0) {
1042
+					$this->_active_status = EE_Datetime::upcoming;
1043
+				} else {
1044
+					// expired?
1045
+					if (EEM_Datetime::instance()->get_datetime_count_for_status(
1046
+						EE_Datetime::expired,
1047
+						$where_params_for_event
1048
+					) > 0
1049
+					) {
1050
+						$this->_active_status = EE_Datetime::expired;
1051
+					} else {
1052
+						// it would be odd if things make it this far because it basically means there are no datetime's
1053
+						// attached to the event.  So in this case it will just be considered inactive.
1054
+						$this->_active_status = EE_Datetime::inactive;
1055
+					}
1056
+				}
1057
+			}
1058
+		} else {
1059
+			// the event is not published, so let's just set it's active status according to its' post status
1060
+			switch ($this->status()) {
1061
+				case EEM_Event::sold_out:
1062
+					$this->_active_status = EE_Datetime::sold_out;
1063
+					break;
1064
+				case EEM_Event::cancelled:
1065
+					$this->_active_status = EE_Datetime::cancelled;
1066
+					break;
1067
+				case EEM_Event::postponed:
1068
+					$this->_active_status = EE_Datetime::postponed;
1069
+					break;
1070
+				default:
1071
+					$this->_active_status = EE_Datetime::inactive;
1072
+			}
1073
+		}
1074
+		return $this->_active_status;
1075
+	}
1076
+
1077
+
1078
+	/**
1079
+	 *    pretty_active_status
1080
+	 *
1081
+	 * @access public
1082
+	 * @param boolean $echo whether to return (FALSE), or echo out the result (TRUE)
1083
+	 * @return mixed void|string
1084
+	 * @throws EE_Error
1085
+	 */
1086
+	public function pretty_active_status($echo = true)
1087
+	{
1088
+		$active_status = $this->get_active_status();
1089
+		$status = '<span class="ee-status event-active-status-'
1090
+				  . $active_status
1091
+				  . '">'
1092
+				  . EEH_Template::pretty_status($active_status, false, 'sentence')
1093
+				  . '</span>';
1094
+		if ($echo) {
1095
+			echo $status;
1096
+			return '';
1097
+		}
1098
+		return $status;
1099
+	}
1100
+
1101
+
1102
+	/**
1103
+	 * @return bool|int
1104
+	 * @throws EE_Error
1105
+	 */
1106
+	public function get_number_of_tickets_sold()
1107
+	{
1108
+		$tkt_sold = 0;
1109
+		if (! $this->ID()) {
1110
+			return 0;
1111
+		}
1112
+		$datetimes = $this->datetimes();
1113
+		foreach ($datetimes as $datetime) {
1114
+			if ($datetime instanceof EE_Datetime) {
1115
+				$tkt_sold += $datetime->sold();
1116
+			}
1117
+		}
1118
+		return $tkt_sold;
1119
+	}
1120
+
1121
+
1122
+	/**
1123
+	 * This just returns a count of all the registrations for this event
1124
+	 *
1125
+	 * @access  public
1126
+	 * @return int
1127
+	 * @throws EE_Error
1128
+	 */
1129
+	public function get_count_of_all_registrations()
1130
+	{
1131
+		return EEM_Event::instance()->count_related($this, 'Registration');
1132
+	}
1133
+
1134
+
1135
+	/**
1136
+	 * This returns the ticket with the earliest start time that is
1137
+	 * available for this event (across all datetimes attached to the event)
1138
+	 *
1139
+	 * @return EE_Base_Class|EE_Ticket|null
1140
+	 * @throws EE_Error
1141
+	 */
1142
+	public function get_ticket_with_earliest_start_time()
1143
+	{
1144
+		$where['Datetime.EVT_ID'] = $this->ID();
1145
+		$query_params = array($where, 'order_by' => array('TKT_start_date' => 'ASC'));
1146
+		return EE_Registry::instance()->load_model('Ticket')->get_one($query_params);
1147
+	}
1148
+
1149
+
1150
+	/**
1151
+	 * This returns the ticket with the latest end time that is available
1152
+	 * for this event (across all datetimes attached to the event)
1153
+	 *
1154
+	 * @return EE_Base_Class|EE_Ticket|null
1155
+	 * @throws EE_Error
1156
+	 */
1157
+	public function get_ticket_with_latest_end_time()
1158
+	{
1159
+		$where['Datetime.EVT_ID'] = $this->ID();
1160
+		$query_params = array($where, 'order_by' => array('TKT_end_date' => 'DESC'));
1161
+		return EE_Registry::instance()->load_model('Ticket')->get_one($query_params);
1162
+	}
1163
+
1164
+
1165
+	/**
1166
+	 * This returns the number of different ticket types currently on sale for this event.
1167
+	 *
1168
+	 * @return int
1169
+	 * @throws EE_Error
1170
+	 */
1171
+	public function countTicketsOnSale()
1172
+	{
1173
+		$where = array(
1174
+			'Datetime.EVT_ID' => $this->ID(),
1175
+			'TKT_start_date'  => array('<', time()),
1176
+			'TKT_end_date'    => array('>', time()),
1177
+		);
1178
+		return EEM_Ticket::instance()->count(array($where));
1179
+	}
1180
+
1181
+
1182
+	/**
1183
+	 * This returns whether there are any tickets on sale for this event.
1184
+	 *
1185
+	 * @return bool true = YES tickets on sale.
1186
+	 * @throws EE_Error
1187
+	 */
1188
+	public function tickets_on_sale()
1189
+	{
1190
+		return $this->countTicketsOnSale() > 0;
1191
+	}
1192
+
1193
+
1194
+	/**
1195
+	 * Gets the URL for viewing this event on the front-end. Overrides parent
1196
+	 * to check for an external URL first
1197
+	 *
1198
+	 * @return string
1199
+	 * @throws EE_Error
1200
+	 */
1201
+	public function get_permalink()
1202
+	{
1203
+		if ($this->external_url()) {
1204
+			return $this->external_url();
1205
+		}
1206
+		return parent::get_permalink();
1207
+	}
1208
+
1209
+
1210
+	/**
1211
+	 * Gets the first term for 'espresso_event_categories' we can find
1212
+	 *
1213
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1214
+	 * @return EE_Base_Class|EE_Term|null
1215
+	 * @throws EE_Error
1216
+	 */
1217
+	public function first_event_category($query_params = array())
1218
+	{
1219
+		$query_params[0]['Term_Taxonomy.taxonomy'] = 'espresso_event_categories';
1220
+		$query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $this->ID();
1221
+		return EEM_Term::instance()->get_one($query_params);
1222
+	}
1223
+
1224
+
1225
+	/**
1226
+	 * Gets all terms for 'espresso_event_categories' we can find
1227
+	 *
1228
+	 * @param array $query_params
1229
+	 * @return EE_Base_Class[]|EE_Term[]
1230
+	 * @throws EE_Error
1231
+	 */
1232
+	public function get_all_event_categories($query_params = array())
1233
+	{
1234
+		$query_params[0]['Term_Taxonomy.taxonomy'] = 'espresso_event_categories';
1235
+		$query_params[0]['Term_Taxonomy.Event.EVT_ID'] = $this->ID();
1236
+		return EEM_Term::instance()->get_all($query_params);
1237
+	}
1238
+
1239
+
1240
+	/**
1241
+	 * Adds a question group to this event
1242
+	 *
1243
+	 * @param EE_Question_Group|int $question_group_id_or_obj
1244
+	 * @param bool $for_primary if true, the question group will be added for the primary
1245
+	 *                                           registrant, if false will be added for others. default: false
1246
+	 * @return EE_Base_Class|EE_Question_Group
1247
+	 * @throws EE_Error
1248
+	 * @throws InvalidArgumentException
1249
+	 * @throws InvalidDataTypeException
1250
+	 * @throws InvalidInterfaceException
1251
+	 * @throws ReflectionException
1252
+	 */
1253
+	public function add_question_group($question_group_id_or_obj, $for_primary = false)
1254
+	{
1255
+		// If the row already exists, it will be updated. If it doesn't, it will be inserted.
1256
+		// That's in EE_HABTM_Relation::add_relation_to().
1257
+		return $this->_add_relation_to(
1258
+			$question_group_id_or_obj,
1259
+			'Question_Group',
1260
+			[
1261
+				EEM_Event_Question_Group::instance()->fieldNameForContext($for_primary) => true
1262
+			]
1263
+		);
1264
+	}
1265
+
1266
+
1267
+	/**
1268
+	 * Removes a question group from the event
1269
+	 *
1270
+	 * @param EE_Question_Group|int $question_group_id_or_obj
1271
+	 * @param bool $for_primary if true, the question group will be removed from the primary
1272
+	 *                                           registrant, if false will be removed from others. default: false
1273
+	 * @return EE_Base_Class|EE_Question_Group
1274
+	 * @throws EE_Error
1275
+	 * @throws InvalidArgumentException
1276
+	 * @throws ReflectionException
1277
+	 * @throws InvalidDataTypeException
1278
+	 * @throws InvalidInterfaceException
1279
+	 */
1280
+	public function remove_question_group($question_group_id_or_obj, $for_primary = false)
1281
+	{
1282
+		// If the question group is used for the other type (primary or additional)
1283
+		// then just update it. If not, delete it outright.
1284
+		$existing_relation = $this->get_first_related(
1285
+			'Event_Question_Group',
1286
+			[
1287
+				[
1288
+					'QSG_ID' => EEM_Question_Group::instance()->ensure_is_ID($question_group_id_or_obj)
1289
+				]
1290
+			]
1291
+		);
1292
+		$field_to_update = EEM_Event_Question_Group::instance()->fieldNameForContext($for_primary);
1293
+		$other_field = EEM_Event_Question_Group::instance()->fieldNameForContext(! $for_primary);
1294
+		if ($existing_relation->get($other_field) === false) {
1295
+			// Delete it. It's now no longer for primary or additional question groups.
1296
+			return $this->_remove_relation_to($question_group_id_or_obj, 'Question_Group');
1297
+		}
1298
+		// Just update it. They'll still use this question group for the other category
1299
+		$existing_relation->save(
1300
+			[
1301
+				$field_to_update => false
1302
+			]
1303
+		);
1304
+	}
1305
+
1306
+
1307
+	/**
1308
+	 * Gets all the question groups, ordering them by QSG_order ascending
1309
+	 *
1310
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1311
+	 * @return EE_Base_Class[]|EE_Question_Group[]
1312
+	 * @throws EE_Error
1313
+	 */
1314
+	public function question_groups($query_params = array())
1315
+	{
1316
+		$query_params = ! empty($query_params) ? $query_params : array('order_by' => array('QSG_order' => 'ASC'));
1317
+		return $this->get_many_related('Question_Group', $query_params);
1318
+	}
1319
+
1320
+
1321
+	/**
1322
+	 * Implementation for EEI_Has_Icon interface method.
1323
+	 *
1324
+	 * @see EEI_Visual_Representation for comments
1325
+	 * @return string
1326
+	 */
1327
+	public function get_icon()
1328
+	{
1329
+		return '<span class="dashicons dashicons-flag"></span>';
1330
+	}
1331
+
1332
+
1333
+	/**
1334
+	 * Implementation for EEI_Admin_Links interface method.
1335
+	 *
1336
+	 * @see EEI_Admin_Links for comments
1337
+	 * @return string
1338
+	 * @throws EE_Error
1339
+	 */
1340
+	public function get_admin_details_link()
1341
+	{
1342
+		return $this->get_admin_edit_link();
1343
+	}
1344
+
1345
+
1346
+	/**
1347
+	 * Implementation for EEI_Admin_Links interface method.
1348
+	 *
1349
+	 * @see EEI_Admin_Links for comments
1350
+	 * @return string
1351
+	 * @throws EE_Error
1352
+	 */
1353
+	public function get_admin_edit_link()
1354
+	{
1355
+		return EEH_URL::add_query_args_and_nonce(
1356
+			array(
1357
+				'page'   => 'espresso_events',
1358
+				'action' => 'edit',
1359
+				'post'   => $this->ID(),
1360
+			),
1361
+			admin_url('admin.php')
1362
+		);
1363
+	}
1364
+
1365
+
1366
+	/**
1367
+	 * Implementation for EEI_Admin_Links interface method.
1368
+	 *
1369
+	 * @see EEI_Admin_Links for comments
1370
+	 * @return string
1371
+	 */
1372
+	public function get_admin_settings_link()
1373
+	{
1374
+		return EEH_URL::add_query_args_and_nonce(
1375
+			array(
1376
+				'page'   => 'espresso_events',
1377
+				'action' => 'default_event_settings',
1378
+			),
1379
+			admin_url('admin.php')
1380
+		);
1381
+	}
1382
+
1383
+
1384
+	/**
1385
+	 * Implementation for EEI_Admin_Links interface method.
1386
+	 *
1387
+	 * @see EEI_Admin_Links for comments
1388
+	 * @return string
1389
+	 */
1390
+	public function get_admin_overview_link()
1391
+	{
1392
+		return EEH_URL::add_query_args_and_nonce(
1393
+			array(
1394
+				'page'   => 'espresso_events',
1395
+				'action' => 'default',
1396
+			),
1397
+			admin_url('admin.php')
1398
+		);
1399
+	}
1400 1400
 }
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -71,7 +71,7 @@  discard block
 block discarded – undo
71 71
      */
72 72
     public function getAvailableSpacesCalculator()
73 73
     {
74
-        if (! $this->available_spaces_calculator instanceof EventSpacesCalculator) {
74
+        if ( ! $this->available_spaces_calculator instanceof EventSpacesCalculator) {
75 75
             $this->available_spaces_calculator = new EventSpacesCalculator($this);
76 76
         }
77 77
         return $this->available_spaces_calculator;
@@ -213,7 +213,7 @@  discard block
 block discarded – undo
213 213
      */
214 214
     public function primary_datetime($try_to_exclude_expired = true, $try_to_exclude_deleted = true)
215 215
     {
216
-        if (! empty($this->_Primary_Datetime)) {
216
+        if ( ! empty($this->_Primary_Datetime)) {
217 217
             return $this->_Primary_Datetime;
218 218
         }
219 219
         $this->_Primary_Datetime = EEM_Datetime::instance($this->_timezone)->get_primary_datetime_for_event(
@@ -236,7 +236,7 @@  discard block
 block discarded – undo
236 236
     {
237 237
         // first get all datetimes
238 238
         $datetimes = $this->datetimes_ordered();
239
-        if (! $datetimes) {
239
+        if ( ! $datetimes) {
240 240
             return array();
241 241
         }
242 242
         $datetime_ids = array();
@@ -429,7 +429,7 @@  discard block
 block discarded – undo
429 429
     public function short_description($num_words = 55, $more = null, $not_full_desc = false)
430 430
     {
431 431
         $short_desc = $this->get('EVT_short_desc');
432
-        if (! empty($short_desc) || $not_full_desc) {
432
+        if ( ! empty($short_desc) || $not_full_desc) {
433 433
             return $short_desc;
434 434
         }
435 435
         $full_desc = $this->get('EVT_desc');
@@ -883,7 +883,7 @@  discard block
 block discarded – undo
883 883
         );
884 884
         $all_expired = true;
885 885
         foreach ($tickets as $ticket) {
886
-            if (! $ticket->is_expired()) {
886
+            if ( ! $ticket->is_expired()) {
887 887
                 $all_expired = false;
888 888
                 break;
889 889
             }
@@ -972,7 +972,7 @@  discard block
 block discarded – undo
972 972
      */
973 973
     public function is_sold_out($actual = false)
974 974
     {
975
-        if (! $actual) {
975
+        if ( ! $actual) {
976 976
             return $this->status() === EEM_Event::sold_out;
977 977
         }
978 978
         return $this->perform_sold_out_status_check();
@@ -1017,11 +1017,11 @@  discard block
 block discarded – undo
1017 1017
     public function get_active_status($reset = false)
1018 1018
     {
1019 1019
         // if the active status has already been set, then just use that value (unless we are resetting it)
1020
-        if (! empty($this->_active_status) && ! $reset) {
1020
+        if ( ! empty($this->_active_status) && ! $reset) {
1021 1021
             return $this->_active_status;
1022 1022
         }
1023 1023
         // first check if event id is present on this object
1024
-        if (! $this->ID()) {
1024
+        if ( ! $this->ID()) {
1025 1025
             return false;
1026 1026
         }
1027 1027
         $where_params_for_event = array(array('EVT_ID' => $this->ID()));
@@ -1106,7 +1106,7 @@  discard block
 block discarded – undo
1106 1106
     public function get_number_of_tickets_sold()
1107 1107
     {
1108 1108
         $tkt_sold = 0;
1109
-        if (! $this->ID()) {
1109
+        if ( ! $this->ID()) {
1110 1110
             return 0;
1111 1111
         }
1112 1112
         $datetimes = $this->datetimes();
@@ -1290,7 +1290,7 @@  discard block
 block discarded – undo
1290 1290
             ]
1291 1291
         );
1292 1292
         $field_to_update = EEM_Event_Question_Group::instance()->fieldNameForContext($for_primary);
1293
-        $other_field = EEM_Event_Question_Group::instance()->fieldNameForContext(! $for_primary);
1293
+        $other_field = EEM_Event_Question_Group::instance()->fieldNameForContext( ! $for_primary);
1294 1294
         if ($existing_relation->get($other_field) === false) {
1295 1295
             // Delete it. It's now no longer for primary or additional question groups.
1296 1296
             return $this->_remove_relation_to($question_group_id_or_obj, 'Question_Group');
Please login to merge, or discard this patch.
attendee_information/EE_SPCO_Reg_Step_Attendee_Information.class.php 1 patch
Indentation   +1422 added lines, -1422 removed lines patch added patch discarded remove patch
@@ -18,1429 +18,1429 @@
 block discarded – undo
18 18
 class EE_SPCO_Reg_Step_Attendee_Information extends EE_SPCO_Reg_Step
19 19
 {
20 20
 
21
-    /**
22
-     * @type bool $_print_copy_info
23
-     */
24
-    private $_print_copy_info = false;
25
-
26
-    /**
27
-     * @type array $_attendee_data
28
-     */
29
-    private $_attendee_data = array();
30
-
31
-    /**
32
-     * @type array $_required_questions
33
-     */
34
-    private $_required_questions = array();
35
-
36
-    /**
37
-     * @type array $_registration_answers
38
-     */
39
-    private $_registration_answers = array();
40
-
41
-
42
-    /**
43
-     *    class constructor
44
-     *
45
-     * @access    public
46
-     * @param    EE_Checkout $checkout
47
-     */
48
-    public function __construct(EE_Checkout $checkout)
49
-    {
50
-        $this->_slug = 'attendee_information';
51
-        $this->_name = esc_html__('Attendee Information', 'event_espresso');
52
-        $this->_template = SPCO_REG_STEPS_PATH . $this->_slug . DS . 'attendee_info_main.template.php';
53
-        $this->checkout = $checkout;
54
-        $this->_reset_success_message();
55
-        $this->set_instructions(
56
-            esc_html__('Please answer the following registration questions before proceeding.', 'event_espresso')
57
-        );
58
-    }
59
-
60
-
61
-    public function translate_js_strings()
62
-    {
63
-        EE_Registry::$i18n_js_strings['required_field'] = esc_html__(
64
-            ' is a required question.',
65
-            'event_espresso'
66
-        );
67
-        EE_Registry::$i18n_js_strings['required_multi_field'] = esc_html__(
68
-            ' is a required question. Please enter a value for at least one of the options.',
69
-            'event_espresso'
70
-        );
71
-        EE_Registry::$i18n_js_strings['answer_required_questions'] = esc_html__(
72
-            'Please answer all required questions correctly before proceeding.',
73
-            'event_espresso'
74
-        );
75
-        EE_Registry::$i18n_js_strings['attendee_info_copied'] = sprintf(
76
-            esc_html_x(
77
-                'The attendee information was successfully copied.%sPlease ensure the rest of the registration form is completed before proceeding.',
78
-                'The attendee information was successfully copied.(line break)Please ensure the rest of the registration form is completed before proceeding.',
79
-                'event_espresso'
80
-            ),
81
-            '<br/>'
82
-        );
83
-        EE_Registry::$i18n_js_strings['attendee_info_copy_error'] = esc_html__(
84
-            'An unknown error occurred on the server while attempting to copy the attendee information. Please refresh the page and try again.',
85
-            'event_espresso'
86
-        );
87
-        EE_Registry::$i18n_js_strings['enter_valid_email'] = esc_html__(
88
-            'You must enter a valid email address.',
89
-            'event_espresso'
90
-        );
91
-        EE_Registry::$i18n_js_strings['valid_email_and_questions'] = esc_html__(
92
-            'You must enter a valid email address and answer all other required questions before you can proceed.',
93
-            'event_espresso'
94
-        );
95
-    }
96
-
97
-
98
-    public function enqueue_styles_and_scripts()
99
-    {
100
-    }
101
-
102
-
103
-    /**
104
-     * @return boolean
105
-     */
106
-    public function initialize_reg_step()
107
-    {
108
-        return true;
109
-    }
110
-
111
-
112
-    /**
113
-     * @return EE_Form_Section_Proper
114
-     * @throws DomainException
115
-     * @throws EE_Error
116
-     * @throws InvalidArgumentException
117
-     * @throws ReflectionException
118
-     * @throws EntityNotFoundException
119
-     * @throws InvalidDataTypeException
120
-     * @throws InvalidInterfaceException
121
-     */
122
-    public function generate_reg_form()
123
-    {
124
-        $this->_print_copy_info = false;
125
-        $primary_registrant = null;
126
-        // autoload Line_Item_Display classes
127
-        EEH_Autoloader::register_line_item_display_autoloaders();
128
-        $Line_Item_Display = new EE_Line_Item_Display();
129
-        // calculate taxes
130
-        $Line_Item_Display->display_line_item(
131
-            $this->checkout->cart->get_grand_total(),
132
-            array('set_tax_rate' => true)
133
-        );
134
-        /** @var $subsections EE_Form_Section_Proper[] */
135
-        $extra_inputs_section = $this->reg_step_hidden_inputs();
136
-        $subsections = array(
137
-            'default_hidden_inputs' => $extra_inputs_section,
138
-        );
139
-
140
-        /**
141
-         * @var $reg_config EE_Registration_Config
142
-         */
143
-        $reg_config = LoaderFactory::getLoader()->getShared('EE_Registration_Config');
144
-        // if this isn't a revisit, and they have the privacy consent box enalbed, add it
145
-        if (! $this->checkout->revisit && $reg_config->isConsentCheckboxEnabled()) {
146
-            $extra_inputs_section->add_subsections(
147
-                array(
148
-                    'consent_box' => new EE_Form_Section_Proper(
149
-                        array(
150
-                            'layout_strategy' =>
151
-                                new EE_Template_Layout(
152
-                                    array(
153
-                                        'input_template_file' => SPCO_REG_STEPS_PATH . $this->_slug . DS . 'privacy_consent.template.php',
154
-                                    )
155
-                                ),
156
-                            'subsections'     => array(
157
-                                'consent' => new EE_Checkbox_Multi_Input(
158
-                                    array(
159
-                                        'consent' => $reg_config->getConsentCheckboxLabelText(),
160
-                                    ),
161
-                                    array(
162
-                                        'required'                          => true,
163
-                                        'required_validation_error_message' => esc_html__(
164
-                                            'You must consent to these terms in order to register.',
165
-                                            'event_espresso'
166
-                                        ),
167
-                                        'html_label_text'                   => '',
168
-                                    )
169
-                                ),
170
-                            ),
171
-                        )
172
-                    ),
173
-                ),
174
-                null,
175
-                false
176
-            );
177
-        }
178
-        $template_args = array(
179
-            'revisit'       => $this->checkout->revisit,
180
-            'registrations' => array(),
181
-            'ticket_count'  => array(),
182
-        );
183
-        // grab the saved registrations from the transaction
184
-        $registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
185
-        if ($registrations) {
186
-            foreach ($registrations as $registration) {
187
-                // can this registration be processed during this visit ?
188
-                if ($registration instanceof EE_Registration
189
-                    && $this->checkout->visit_allows_processing_of_this_registration($registration)
190
-                ) {
191
-                    $subsections[ $registration->reg_url_link() ] = $this->_registrations_reg_form($registration);
192
-                    if (! $this->checkout->admin_request) {
193
-                        $template_args['registrations'][ $registration->reg_url_link() ] = $registration;
194
-                        $template_args['ticket_count'][ $registration->ticket()->ID() ] = isset(
195
-                            $template_args['ticket_count'][ $registration->ticket()->ID() ]
196
-                        )
197
-                            ? $template_args['ticket_count'][ $registration->ticket()->ID() ] + 1
198
-                            : 1;
199
-                        $ticket_line_item = EEH_Line_Item::get_line_items_by_object_type_and_IDs(
200
-                            $this->checkout->cart->get_grand_total(),
201
-                            'Ticket',
202
-                            array($registration->ticket()->ID())
203
-                        );
204
-                        $ticket_line_item = is_array($ticket_line_item)
205
-                            ? reset($ticket_line_item)
206
-                            : $ticket_line_item;
207
-                        $template_args['ticket_line_item'][ $registration->ticket()->ID() ] =
208
-                            $Line_Item_Display->display_line_item($ticket_line_item);
209
-                    }
210
-                    if ($registration->is_primary_registrant()) {
211
-                        $primary_registrant = $registration->reg_url_link();
212
-                    }
213
-                }
214
-            }
215
-            // print_copy_info ?
216
-            if ($primary_registrant && ! $this->checkout->admin_request && count($registrations) > 1) {
217
-                // TODO: add admin option for toggling copy attendee info,
218
-                // then use that value to change $this->_print_copy_info
219
-                $copy_options['spco_copy_attendee_chk'] = $this->_print_copy_info
220
-                    ? $this->_copy_attendee_info_form()
221
-                    : $this->_auto_copy_attendee_info();
222
-                // generate hidden input
223
-                if (isset($subsections[ $primary_registrant ])
224
-                    && $subsections[ $primary_registrant ] instanceof EE_Form_Section_Proper
225
-                ) {
226
-                    $subsections[ $primary_registrant ]->add_subsections(
227
-                        $copy_options,
228
-                        'primary_registrant',
229
-                        false
230
-                    );
231
-                }
232
-            }
233
-        }
234
-        return new EE_Form_Section_Proper(
235
-            array(
236
-                'name'            => $this->reg_form_name(),
237
-                'html_id'         => $this->reg_form_name(),
238
-                'subsections'     => $subsections,
239
-                'layout_strategy' => $this->checkout->admin_request
240
-                    ?
241
-                    new EE_Div_Per_Section_Layout()
242
-                    :
243
-                    new EE_Template_Layout(
244
-                        array(
245
-                            'layout_template_file' => $this->_template, // layout_template
246
-                            'template_args'        => $template_args,
247
-                        )
248
-                    ),
249
-            )
250
-        );
251
-    }
252
-
253
-
254
-    /**
255
-     * @param EE_Registration $registration
256
-     * @return EE_Form_Section_Base
257
-     * @throws EE_Error
258
-     * @throws InvalidArgumentException
259
-     * @throws EntityNotFoundException
260
-     * @throws InvalidDataTypeException
261
-     * @throws InvalidInterfaceException
262
-     * @throws ReflectionException
263
-     */
264
-    private function _registrations_reg_form(EE_Registration $registration)
265
-    {
266
-        static $attendee_nmbr = 1;
267
-        $form_args = array();
268
-        // verify that registration has valid event
269
-        if ($registration->event() instanceof EE_Event) {
270
-            $field_name = 'Event_Question_Group.'
271
-                . EEM_Event_Question_Group::instance()->fieldNameForContext(
272
-                    $registration->is_primary_registrant()
273
-                );
274
-            $question_groups = $registration->event()->question_groups(
275
-                apply_filters(
276
-                    // @codingStandardsIgnoreStart
277
-                    'FHEE__EE_SPCO_Reg_Step_Attendee_Information___registrations_reg_form__question_groups_query_parameters',
278
-                    // @codingStandardsIgnoreEnd
279
-                    [
280
-                        [
281
-                            'Event.EVT_ID'                     => $registration->event()->ID(),
282
-                            $field_name => true,
283
-                        ],
284
-                        'order_by' => ['QSG_order' => 'ASC'],
285
-                    ],
286
-                    $registration,
287
-                    $this
288
-                )
289
-            );
290
-            if ($question_groups) {
291
-                // array of params to pass to parent constructor
292
-                $form_args = array(
293
-                    'html_id'         => 'ee-registration-' . $registration->reg_url_link(),
294
-                    'html_class'      => 'ee-reg-form-attendee-dv',
295
-                    'html_style'      => $this->checkout->admin_request
296
-                        ? 'padding:0em 2em 1em; margin:3em 0 0; border:1px solid #ddd;'
297
-                        : '',
298
-                    'subsections'     => array(),
299
-                    'layout_strategy' => new EE_Fieldset_Section_Layout(
300
-                        array(
301
-                            'legend_class' => 'spco-attendee-lgnd smaller-text lt-grey-text',
302
-                            'legend_text'  => sprintf(
303
-                                esc_html_x(
304
-                                    'Attendee %d',
305
-                                    'Attendee 123',
306
-                                    'event_espresso'
307
-                                ),
308
-                                $attendee_nmbr
309
-                            ),
310
-                        )
311
-                    ),
312
-                );
313
-                foreach ($question_groups as $question_group) {
314
-                    if ($question_group instanceof EE_Question_Group) {
315
-                        $form_args['subsections'][ $question_group->identifier() ] = $this->_question_group_reg_form(
316
-                            $registration,
317
-                            $question_group
318
-                        );
319
-                    }
320
-                }
321
-                // add hidden input
322
-                $form_args['subsections']['additional_attendee_reg_info'] = $this->_additional_attendee_reg_info_input(
323
-                    $registration
324
-                );
325
-                // if we have question groups for additional attendees, then display the copy options
326
-                $this->_print_copy_info = $attendee_nmbr > 1 ? true : $this->_print_copy_info;
327
-                if ($registration->is_primary_registrant()) {
328
-                    // generate hidden input
329
-                    $form_args['subsections']['primary_registrant'] = $this->_additional_primary_registrant_inputs(
330
-                        $registration
331
-                    );
332
-                }
333
-            }
334
-        }
335
-        $attendee_nmbr++;
336
-        return ! empty($form_args)
337
-            ? new EE_Form_Section_Proper($form_args)
338
-            : new EE_Form_Section_HTML();
339
-    }
340
-
341
-
342
-    /**
343
-     * @param EE_Registration $registration
344
-     * @param bool            $additional_attendee_reg_info
345
-     * @return EE_Form_Input_Base
346
-     * @throws EE_Error
347
-     */
348
-    private function _additional_attendee_reg_info_input(
349
-        EE_Registration $registration,
350
-        $additional_attendee_reg_info = true
351
-    ) {
352
-        // generate hidden input
353
-        return new EE_Hidden_Input(
354
-            array(
355
-                'html_id' => 'additional-attendee-reg-info-' . $registration->reg_url_link(),
356
-                'default' => $additional_attendee_reg_info,
357
-            )
358
-        );
359
-    }
360
-
361
-
362
-    /**
363
-     * @param EE_Registration   $registration
364
-     * @param EE_Question_Group $question_group
365
-     * @return EE_Form_Section_Proper
366
-     * @throws EE_Error
367
-     * @throws InvalidArgumentException
368
-     * @throws InvalidDataTypeException
369
-     * @throws InvalidInterfaceException
370
-     * @throws ReflectionException
371
-     */
372
-    private function _question_group_reg_form(EE_Registration $registration, EE_Question_Group $question_group)
373
-    {
374
-        // array of params to pass to parent constructor
375
-        $form_args = array(
376
-            'html_id'         => 'ee-reg-form-qstn-grp-' . $question_group->identifier() . '-' . $registration->ID(),
377
-            'html_class'      => $this->checkout->admin_request
378
-                ? 'form-table ee-reg-form-qstn-grp-dv'
379
-                : 'ee-reg-form-qstn-grp-dv',
380
-            'html_label_id'   => 'ee-reg-form-qstn-grp-' . $question_group->identifier() . '-'
381
-                                 . $registration->ID() . '-lbl',
382
-            'subsections'     => array(
383
-                'reg_form_qstn_grp_hdr' => $this->_question_group_header($question_group),
384
-            ),
385
-            'layout_strategy' => $this->checkout->admin_request
386
-                ? new EE_Admin_Two_Column_Layout()
387
-                : new EE_Div_Per_Section_Layout(),
388
-        );
389
-        // where params
390
-        $query_params = array('QST_deleted' => 0);
391
-        // don't load admin only questions on the frontend
392
-        if (! $this->checkout->admin_request) {
393
-            $query_params['QST_admin_only'] = array('!=', true);
394
-        }
395
-        $questions = $question_group->get_many_related(
396
-            'Question',
397
-            apply_filters(
398
-                'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__related_questions_query_params',
399
-                array(
400
-                    $query_params,
401
-                    'order_by' => array(
402
-                        'Question_Group_Question.QGQ_order' => 'ASC',
403
-                    ),
404
-                ),
405
-                $question_group,
406
-                $registration,
407
-                $this
408
-            )
409
-        );
410
-        // filter for additional content before questions
411
-        $form_args['subsections']['reg_form_questions_before'] = new EE_Form_Section_HTML(
412
-            apply_filters(
413
-                'FHEE__EEH_Form_Fields__generate_question_groups_html__before_question_group_questions',
414
-                '',
415
-                $registration,
416
-                $question_group,
417
-                $this
418
-            )
419
-        );
420
-        // loop thru questions
421
-        foreach ($questions as $question) {
422
-            if ($question instanceof EE_Question) {
423
-                $identifier = $question->is_system_question()
424
-                    ? $question->system_ID()
425
-                    : $question->ID();
426
-                $form_args['subsections'][ $identifier ] = $this->reg_form_question($registration, $question);
427
-            }
428
-        }
429
-        $form_args['subsections'] = apply_filters(
430
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information__question_group_reg_form__subsections_array',
431
-            $form_args['subsections'],
432
-            $registration,
433
-            $question_group,
434
-            $this
435
-        );
436
-        // filter for additional content after questions
437
-        $form_args['subsections']['reg_form_questions_after'] = new EE_Form_Section_HTML(
438
-            apply_filters(
439
-                'FHEE__EEH_Form_Fields__generate_question_groups_html__after_question_group_questions',
440
-                '',
441
-                $registration,
442
-                $question_group,
443
-                $this
444
-            )
445
-        );
446
-        // d($form_args);
447
-        $question_group_reg_form = new EE_Form_Section_Proper($form_args);
448
-        return apply_filters(
449
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__question_group_reg_form',
450
-            $question_group_reg_form,
451
-            $registration,
452
-            $question_group,
453
-            $this
454
-        );
455
-    }
456
-
457
-
458
-    /**
459
-     * @param EE_Question_Group $question_group
460
-     * @return    EE_Form_Section_HTML
461
-     */
462
-    private function _question_group_header(EE_Question_Group $question_group)
463
-    {
464
-        $html = '';
465
-        // group_name
466
-        if ($question_group->show_group_name() && $question_group->name() !== '') {
467
-            if ($this->checkout->admin_request) {
468
-                $html .= EEH_HTML::br();
469
-                $html .= EEH_HTML::h3(
470
-                    $question_group->name(),
471
-                    '',
472
-                    'ee-reg-form-qstn-grp-title title',
473
-                    'font-size: 1.3em; padding-left:0;'
474
-                );
475
-            } else {
476
-                $html .= EEH_HTML::h4(
477
-                    $question_group->name(),
478
-                    '',
479
-                    'ee-reg-form-qstn-grp-title section-title'
480
-                );
481
-            }
482
-        }
483
-        // group_desc
484
-        if ($question_group->show_group_desc() && $question_group->desc() !== '') {
485
-            $html .= EEH_HTML::p(
486
-                $question_group->desc(),
487
-                '',
488
-                $this->checkout->admin_request
489
-                    ? 'ee-reg-form-qstn-grp-desc-pg'
490
-                    : 'ee-reg-form-qstn-grp-desc-pg small-text lt-grey-text'
491
-            );
492
-        }
493
-        return new EE_Form_Section_HTML($html);
494
-    }
495
-
496
-
497
-    /**
498
-     * @return    EE_Form_Section_Proper
499
-     * @throws EE_Error
500
-     * @throws InvalidArgumentException
501
-     * @throws ReflectionException
502
-     * @throws InvalidDataTypeException
503
-     * @throws InvalidInterfaceException
504
-     */
505
-    private function _copy_attendee_info_form()
506
-    {
507
-        // array of params to pass to parent constructor
508
-        return new EE_Form_Section_Proper(
509
-            array(
510
-                'subsections'     => $this->_copy_attendee_info_inputs(),
511
-                'layout_strategy' => new EE_Template_Layout(
512
-                    array(
513
-                        'layout_template_file'     => SPCO_REG_STEPS_PATH
514
-                                                      . $this->_slug
515
-                                                      . DS
516
-                                                      . 'copy_attendee_info.template.php',
517
-                        'begin_template_file'      => null,
518
-                        'input_template_file'      => null,
519
-                        'subsection_template_file' => null,
520
-                        'end_template_file'        => null,
521
-                    )
522
-                ),
523
-            )
524
-        );
525
-    }
526
-
527
-
528
-    /**
529
-     * @return EE_Form_Section_HTML
530
-     * @throws DomainException
531
-     * @throws InvalidArgumentException
532
-     * @throws InvalidDataTypeException
533
-     * @throws InvalidInterfaceException
534
-     */
535
-    private function _auto_copy_attendee_info()
536
-    {
537
-        return new EE_Form_Section_HTML(
538
-            EEH_Template::locate_template(
539
-                SPCO_REG_STEPS_PATH . $this->_slug . DS . '_auto_copy_attendee_info.template.php',
540
-                apply_filters(
541
-                    'FHEE__EE_SPCO_Reg_Step_Attendee_Information__auto_copy_attendee_info__template_args',
542
-                    array()
543
-                ),
544
-                true,
545
-                true
546
-            )
547
-        );
548
-    }
549
-
550
-
551
-    /**
552
-     * @return array
553
-     * @throws EE_Error
554
-     * @throws InvalidArgumentException
555
-     * @throws ReflectionException
556
-     * @throws InvalidDataTypeException
557
-     * @throws InvalidInterfaceException
558
-     */
559
-    private function _copy_attendee_info_inputs()
560
-    {
561
-        $copy_attendee_info_inputs = array();
562
-        $prev_ticket = null;
563
-        // grab the saved registrations from the transaction
564
-        $registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
565
-        foreach ($registrations as $registration) {
566
-            // for all  attendees other than the primary attendee
567
-            if ($registration instanceof EE_Registration && ! $registration->is_primary_registrant()) {
568
-                // if this is a new ticket OR if this is the very first additional attendee after the primary attendee
569
-                if ($registration->ticket()->ID() !== $prev_ticket) {
570
-                    $item_name = $registration->ticket()->name();
571
-                    $item_name .= $registration->ticket()->description() !== ''
572
-                        ? ' - ' . $registration->ticket()->description()
573
-                        : '';
574
-                    $copy_attendee_info_inputs[ 'spco_copy_attendee_chk[ticket-' . $registration->ticket()->ID(
575
-                    ) . ']' ] =
576
-                        new EE_Form_Section_HTML(
577
-                            '<h6 class="spco-copy-attendee-event-hdr">' . $item_name . '</h6>'
578
-                        );
579
-                    $prev_ticket = $registration->ticket()->ID();
580
-                }
581
-
582
-                $copy_attendee_info_inputs[ 'spco_copy_attendee_chk[' . $registration->ID() . ']' ] =
583
-                    new EE_Checkbox_Multi_Input(
584
-                        array(
585
-                            $registration->ID() => sprintf(
586
-                                esc_html_x('Attendee #%s', 'Attendee #123', 'event_espresso'),
587
-                                $registration->count()
588
-                            ),
589
-                        ),
590
-                        array(
591
-                            'html_id'                 => 'spco-copy-attendee-chk-' . $registration->reg_url_link(),
592
-                            'html_class'              => 'spco-copy-attendee-chk ee-do-not-validate',
593
-                            'display_html_label_text' => false,
594
-                        )
595
-                    );
596
-            }
597
-        }
598
-        return $copy_attendee_info_inputs;
599
-    }
600
-
601
-
602
-    /**
603
-     * @param EE_Registration $registration
604
-     * @return    EE_Form_Input_Base
605
-     * @throws EE_Error
606
-     */
607
-    private function _additional_primary_registrant_inputs(EE_Registration $registration)
608
-    {
609
-        // generate hidden input
610
-        return new EE_Hidden_Input(
611
-            array(
612
-                'html_id' => 'primary_registrant',
613
-                'default' => $registration->reg_url_link(),
614
-            )
615
-        );
616
-    }
617
-
618
-
619
-    /**
620
-     * @param EE_Registration $registration
621
-     * @param EE_Question     $question
622
-     * @return EE_Form_Input_Base
623
-     * @throws EE_Error
624
-     * @throws InvalidArgumentException
625
-     * @throws InvalidDataTypeException
626
-     * @throws InvalidInterfaceException
627
-     * @throws ReflectionException
628
-     */
629
-    public function reg_form_question(EE_Registration $registration, EE_Question $question)
630
-    {
631
-
632
-        // if this question was for an attendee detail, then check for that answer
633
-        $answer_value = EEM_Answer::instance()->get_attendee_property_answer_value(
634
-            $registration,
635
-            $question->system_ID()
636
-        );
637
-        $answer = $answer_value === null
638
-            ? EEM_Answer::instance()->get_one(
639
-                array(array('QST_ID' => $question->ID(), 'REG_ID' => $registration->ID()))
640
-            )
641
-            : null;
642
-        // if NOT returning to edit an existing registration
643
-        // OR if this question is for an attendee property
644
-        // OR we still don't have an EE_Answer object
645
-        if ($answer_value || ! $answer instanceof EE_Answer || ! $registration->reg_url_link()) {
646
-            // create an EE_Answer object for storing everything in
647
-            $answer = EE_Answer::new_instance(
648
-                array(
649
-                    'QST_ID' => $question->ID(),
650
-                    'REG_ID' => $registration->ID(),
651
-                )
652
-            );
653
-        }
654
-        // verify instance
655
-        if ($answer instanceof EE_Answer) {
656
-            if (! empty($answer_value)) {
657
-                $answer->set('ANS_value', $answer_value);
658
-            }
659
-            $answer->cache('Question', $question);
660
-            // remember system ID had a bug where sometimes it could be null
661
-            $answer_cache_id = $question->is_system_question()
662
-                ? $question->system_ID() . '-' . $registration->reg_url_link()
663
-                : $question->ID() . '-' . $registration->reg_url_link();
664
-            $registration->cache('Answer', $answer, $answer_cache_id);
665
-        }
666
-        return $this->_generate_question_input($registration, $question, $answer);
667
-    }
668
-
669
-
670
-    /**
671
-     * @param EE_Registration $registration
672
-     * @param EE_Question     $question
673
-     * @param                 $answer
674
-     * @return EE_Form_Input_Base
675
-     * @throws EE_Error
676
-     * @throws InvalidArgumentException
677
-     * @throws ReflectionException
678
-     * @throws InvalidDataTypeException
679
-     * @throws InvalidInterfaceException
680
-     */
681
-    private function _generate_question_input(EE_Registration $registration, EE_Question $question, $answer)
682
-    {
683
-        $identifier = $question->is_system_question()
684
-            ? $question->system_ID()
685
-            : $question->ID();
686
-        $this->_required_questions[ $identifier ] = $question->required() ? true : false;
687
-        add_filter(
688
-            'FHEE__EE_Question__generate_form_input__country_options',
689
-            array($this, 'use_cached_countries_for_form_input'),
690
-            10,
691
-            4
692
-        );
693
-        add_filter(
694
-            'FHEE__EE_Question__generate_form_input__state_options',
695
-            array($this, 'use_cached_states_for_form_input'),
696
-            10,
697
-            4
698
-        );
699
-        $input_constructor_args = array(
700
-            'html_name'        => 'ee_reg_qstn[' . $registration->ID() . '][' . $identifier . ']',
701
-            'html_id'          => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
702
-            'html_class'       => 'ee-reg-qstn ee-reg-qstn-' . $identifier,
703
-            'html_label_id'    => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
704
-            'html_label_class' => 'ee-reg-qstn',
705
-        );
706
-        $input_constructor_args['html_label_id'] .= '-lbl';
707
-        if ($answer instanceof EE_Answer && $answer->ID()) {
708
-            $input_constructor_args['html_name'] .= '[' . $answer->ID() . ']';
709
-            $input_constructor_args['html_id'] .= '-' . $answer->ID();
710
-            $input_constructor_args['html_label_id'] .= '-' . $answer->ID();
711
-        }
712
-        $form_input = $question->generate_form_input(
713
-            $registration,
714
-            $answer,
715
-            $input_constructor_args
716
-        );
717
-        remove_filter(
718
-            'FHEE__EE_Question__generate_form_input__country_options',
719
-            array($this, 'use_cached_countries_for_form_input')
720
-        );
721
-        remove_filter(
722
-            'FHEE__EE_Question__generate_form_input__state_options',
723
-            array($this, 'use_cached_states_for_form_input')
724
-        );
725
-        return $form_input;
726
-    }
727
-
728
-
729
-    /**
730
-     * Gets the list of countries for the form input
731
-     *
732
-     * @param array|null      $countries_list
733
-     * @param EE_Question     $question
734
-     * @param EE_Registration $registration
735
-     * @param EE_Answer       $answer
736
-     * @return array 2d keys are country IDs, values are their names
737
-     * @throws EE_Error
738
-     * @throws InvalidArgumentException
739
-     * @throws InvalidDataTypeException
740
-     * @throws InvalidInterfaceException
741
-     * @throws ReflectionException
742
-     */
743
-    public function use_cached_countries_for_form_input(
744
-        $countries_list,
745
-        EE_Question $question = null,
746
-        EE_Registration $registration = null,
747
-        EE_Answer $answer = null
748
-    ) {
749
-        $country_options = array('' => '');
750
-        // get possibly cached list of countries
751
-        $countries = $this->checkout->action === 'process_reg_step'
752
-            ? EEM_Country::instance()->get_all_countries()
753
-            : EEM_Country::instance()->get_all_active_countries();
754
-        if (! empty($countries)) {
755
-            foreach ($countries as $country) {
756
-                if ($country instanceof EE_Country) {
757
-                    $country_options[ $country->ID() ] = $country->name();
758
-                }
759
-            }
760
-        }
761
-        if ($question instanceof EE_Question && $registration instanceof EE_Registration) {
762
-            $answer = EEM_Answer::instance()->get_one(
763
-                array(array('QST_ID' => $question->ID(), 'REG_ID' => $registration->ID()))
764
-            );
765
-        } else {
766
-            $answer = EE_Answer::new_instance();
767
-        }
768
-        $country_options = apply_filters(
769
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__country_options',
770
-            $country_options,
771
-            $this,
772
-            $registration,
773
-            $question,
774
-            $answer
775
-        );
776
-        return $country_options;
777
-    }
778
-
779
-
780
-    /**
781
-     * Gets the list of states for the form input
782
-     *
783
-     * @param array|null      $states_list
784
-     * @param EE_Question     $question
785
-     * @param EE_Registration $registration
786
-     * @param EE_Answer       $answer
787
-     * @return array 2d keys are state IDs, values are their names
788
-     * @throws EE_Error
789
-     * @throws InvalidArgumentException
790
-     * @throws InvalidDataTypeException
791
-     * @throws InvalidInterfaceException
792
-     * @throws ReflectionException
793
-     */
794
-    public function use_cached_states_for_form_input(
795
-        $states_list,
796
-        EE_Question $question = null,
797
-        EE_Registration $registration = null,
798
-        EE_Answer $answer = null
799
-    ) {
800
-        $state_options = array('' => array('' => ''));
801
-        $states = $this->checkout->action === 'process_reg_step'
802
-            ? EEM_State::instance()->get_all_states()
803
-            : EEM_State::instance()->get_all_active_states();
804
-        if (! empty($states)) {
805
-            foreach ($states as $state) {
806
-                if ($state instanceof EE_State) {
807
-                    $state_options[ $state->country()->name() ][ $state->ID() ] = $state->name();
808
-                }
809
-            }
810
-        }
811
-        $state_options = apply_filters(
812
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__state_options',
813
-            $state_options,
814
-            $this,
815
-            $registration,
816
-            $question,
817
-            $answer
818
-        );
819
-        return $state_options;
820
-    }
821
-
822
-
823
-    /********************************************************************************************************/
824
-    /****************************************  PROCESS REG STEP  ****************************************/
825
-    /********************************************************************************************************/
826
-
827
-
828
-    /**
829
-     * @return bool
830
-     * @throws EE_Error
831
-     * @throws InvalidArgumentException
832
-     * @throws ReflectionException
833
-     * @throws RuntimeException
834
-     * @throws InvalidDataTypeException
835
-     * @throws InvalidInterfaceException
836
-     */
837
-    public function process_reg_step()
838
-    {
839
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
840
-        // grab validated data from form
841
-        $valid_data = $this->checkout->current_step->valid_data();
842
-        // EEH_Debug_Tools::printr( $_REQUEST, '$_REQUEST', __FILE__, __LINE__ );
843
-        // EEH_Debug_Tools::printr( $valid_data, '$valid_data', __FILE__, __LINE__ );
844
-        // if we don't have any $valid_data then something went TERRIBLY WRONG !!!
845
-        if (empty($valid_data)) {
846
-            EE_Error::add_error(
847
-                esc_html__('No valid question responses were received.', 'event_espresso'),
848
-                __FILE__,
849
-                __FUNCTION__,
850
-                __LINE__
851
-            );
852
-            return false;
853
-        }
854
-        if (! $this->checkout->transaction instanceof EE_Transaction || ! $this->checkout->continue_reg) {
855
-            EE_Error::add_error(
856
-                esc_html__(
857
-                    'A valid transaction could not be initiated for processing your registrations.',
858
-                    'event_espresso'
859
-                ),
860
-                __FILE__,
861
-                __FUNCTION__,
862
-                __LINE__
863
-            );
864
-            return false;
865
-        }
866
-        // get cached registrations
867
-        $registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
868
-        // verify we got the goods
869
-        if (empty($registrations)) {
870
-            // combine the old translated string with a new one, in order to not break translations
871
-            $error_message = esc_html__(
872
-                'Your form data could not be applied to any valid registrations.',
873
-                'event_espresso'
874
-            )
875
-            . sprintf(
876
-                esc_html_x(
877
-                    '%3$sThis can sometimes happen if too much time has been taken to complete the registration process.%3$sPlease return to the %1$sEvent List%2$s and reselect your tickets. If the problem continues, please contact the site administrator.',
878
-                    '(line break)This can sometimes happen if too much time has been taken to complete the registration process.(line break)Please return to the (link)Event List(end link) and reselect your tickets. If the problem continues, please contact the site administrator.',
879
-                    'event_espresso'
880
-                ),
881
-                '<a href="' . get_post_type_archive_link('espresso_events') . '" >',
882
-                '</a>',
883
-                '<br />'
884
-            );
885
-            EE_Error::add_error(
886
-                $error_message,
887
-                __FILE__,
888
-                __FUNCTION__,
889
-                __LINE__
890
-            );
891
-            return false;
892
-        }
893
-        // extract attendee info from form data and save to model objects
894
-        $registrations_processed = $this->_process_registrations($registrations, $valid_data);
895
-        // if first pass thru SPCO,
896
-        // then let's check processed registrations against the total number of tickets in the cart
897
-        if ($registrations_processed === false) {
898
-            // but return immediately if the previous step exited early due to errors
899
-            return false;
900
-        }
901
-        if (! $this->checkout->revisit && $registrations_processed !== $this->checkout->total_ticket_count) {
902
-            // generate a correctly translated string for all possible singular/plural combinations
903
-            if ($this->checkout->total_ticket_count === 1 && $registrations_processed !== 1) {
904
-                $error_msg = sprintf(
905
-                    esc_html_x(
906
-                        'There was %1$d ticket in the Event Queue, but %2$ds registrations were processed',
907
-                        'There was 1 ticket in the Event Queue, but 2 registrations were processed',
908
-                        'event_espresso'
909
-                    ),
910
-                    $this->checkout->total_ticket_count,
911
-                    $registrations_processed
912
-                );
913
-            } elseif ($this->checkout->total_ticket_count !== 1 && $registrations_processed === 1) {
914
-                $error_msg = sprintf(
915
-                    esc_html_x(
916
-                        'There was a total of %1$d tickets in the Event Queue, but only %2$ds registration was processed',
917
-                        'There was a total of 2 tickets in the Event Queue, but only 1 registration was processed',
918
-                        'event_espresso'
919
-                    ),
920
-                    $this->checkout->total_ticket_count,
921
-                    $registrations_processed
922
-                );
923
-            } else {
924
-                $error_msg = sprintf(
925
-                    esc_html__(
926
-                        'There was a total of 2 tickets in the Event Queue, but 2 registrations were processed',
927
-                        'event_espresso'
928
-                    ),
929
-                    $this->checkout->total_ticket_count,
930
-                    $registrations_processed
931
-                );
932
-            }
933
-            EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
934
-            return false;
935
-        }
936
-        // mark this reg step as completed
937
-        $this->set_completed();
938
-        $this->_set_success_message(
939
-            esc_html__('The Attendee Information Step has been successfully completed.', 'event_espresso')
940
-        );
941
-        // do action in case a plugin wants to do something with the data submitted in step 1.
942
-        // passes EE_Single_Page_Checkout, and it's posted data
943
-        do_action('AHEE__EE_Single_Page_Checkout__process_attendee_information__end', $this, $valid_data);
944
-        return true;
945
-    }
946
-
947
-
948
-    /**
949
-     *    _process_registrations
950
-     *
951
-     * @param EE_Registration[] $registrations
952
-     * @param array[][]         $valid_data
953
-     * @return bool|int
954
-     * @throws EntityNotFoundException
955
-     * @throws EE_Error
956
-     * @throws InvalidArgumentException
957
-     * @throws ReflectionException
958
-     * @throws RuntimeException
959
-     * @throws InvalidDataTypeException
960
-     * @throws InvalidInterfaceException
961
-     */
962
-    private function _process_registrations($registrations = array(), $valid_data = array())
963
-    {
964
-        // load resources and set some defaults
965
-        EE_Registry::instance()->load_model('Attendee');
966
-        // holder for primary registrant attendee object
967
-        $this->checkout->primary_attendee_obj = null;
968
-        // array for tracking reg form data for the primary registrant
969
-        $primary_registrant = array(
970
-            'line_item_id' => null,
971
-        );
972
-        $copy_primary = false;
973
-        // reg form sections that do not contain inputs
974
-        $non_input_form_sections = array(
975
-            'primary_registrant',
976
-            'additional_attendee_reg_info',
977
-            'spco_copy_attendee_chk',
978
-        );
979
-        // attendee counter
980
-        $att_nmbr = 0;
981
-        // grab the saved registrations from the transaction
982
-        foreach ($registrations as $registration) {
983
-            // verify EE_Registration object
984
-            if (! $registration instanceof EE_Registration) {
985
-                EE_Error::add_error(
986
-                    esc_html__(
987
-                        'An invalid Registration object was discovered when attempting to process your registration information.',
988
-                        'event_espresso'
989
-                    ),
990
-                    __FILE__,
991
-                    __FUNCTION__,
992
-                    __LINE__
993
-                );
994
-                return false;
995
-            }
996
-            /** @var string $reg_url_link */
997
-            $reg_url_link = $registration->reg_url_link();
998
-            // reg_url_link exists ?
999
-            if (! empty($reg_url_link)) {
1000
-                // should this registration be processed during this visit ?
1001
-                if ($this->checkout->visit_allows_processing_of_this_registration($registration)) {
1002
-                    // if NOT revisiting, then let's save the registration now,
1003
-                    // so that we have a REG_ID to use when generating other objects
1004
-                    if (! $this->checkout->revisit) {
1005
-                        $registration->save();
1006
-                    }
1007
-                    /**
1008
-                     * This allows plugins to trigger a fail on processing of a
1009
-                     * registration for any conditions they may have for it to pass.
1010
-                     *
1011
-                     * @var bool   if true is returned by the plugin then the
1012
-                     *            registration processing is halted.
1013
-                     */
1014
-                    if (apply_filters(
1015
-                        'FHEE__EE_SPCO_Reg_Step_Attendee_Information___process_registrations__pre_registration_process',
1016
-                        false,
1017
-                        $att_nmbr,
1018
-                        $registration,
1019
-                        $registrations,
1020
-                        $valid_data,
1021
-                        $this
1022
-                    )) {
1023
-                        return false;
1024
-                    }
1025
-
1026
-                    // Houston, we have a registration!
1027
-                    $att_nmbr++;
1028
-                    $this->_attendee_data[ $reg_url_link ] = array();
1029
-                    // grab any existing related answer objects
1030
-                    $this->_registration_answers = $registration->answers();
1031
-                    // unset( $valid_data[ $reg_url_link ]['additional_attendee_reg_info'] );
1032
-                    if (isset($valid_data[ $reg_url_link ])) {
1033
-                        // do we need to copy basic info from primary attendee ?
1034
-                        $copy_primary = isset($valid_data[ $reg_url_link ]['additional_attendee_reg_info'])
1035
-                                        && absint($valid_data[ $reg_url_link ]['additional_attendee_reg_info']) === 0;
1036
-                        // filter form input data for this registration
1037
-                        $valid_data[ $reg_url_link ] = (array) apply_filters(
1038
-                            'FHEE__EE_Single_Page_Checkout__process_attendee_information__valid_data_line_item',
1039
-                            $valid_data[ $reg_url_link ]
1040
-                        );
1041
-                        if (isset($valid_data['primary_attendee'])) {
1042
-                            $primary_registrant['line_item_id'] = ! empty($valid_data['primary_attendee'])
1043
-                                ? $valid_data['primary_attendee']
1044
-                                : false;
1045
-                            unset($valid_data['primary_attendee']);
1046
-                        }
1047
-                        // now loop through our array of valid post data && process attendee reg forms
1048
-                        foreach ($valid_data[ $reg_url_link ] as $form_section => $form_inputs) {
1049
-                            if (! in_array($form_section, $non_input_form_sections, true)) {
1050
-                                foreach ($form_inputs as $form_input => $input_value) {
1051
-                                    // \EEH_Debug_Tools::printr( $input_value, $form_input, __FILE__, __LINE__ );
1052
-                                    // check for critical inputs
1053
-                                    if (! $this->_verify_critical_attendee_details_are_set_and_validate_email(
1054
-                                        $form_input,
1055
-                                        $input_value
1056
-                                    )
1057
-                                    ) {
1058
-                                        return false;
1059
-                                    }
1060
-                                    // store a bit of data about the primary attendee
1061
-                                    if ($att_nmbr === 1
1062
-                                        && ! empty($input_value)
1063
-                                        && $reg_url_link === $primary_registrant['line_item_id']
1064
-                                    ) {
1065
-                                        $primary_registrant[ $form_input ] = $input_value;
1066
-                                    } elseif ($copy_primary
1067
-                                              && $input_value === null
1068
-                                              && isset($primary_registrant[ $form_input ])
1069
-                                    ) {
1070
-                                        $input_value = $primary_registrant[ $form_input ];
1071
-                                    }
1072
-                                    // now attempt to save the input data
1073
-                                    if (! $this->_save_registration_form_input(
1074
-                                        $registration,
1075
-                                        $form_input,
1076
-                                        $input_value
1077
-                                    )
1078
-                                    ) {
1079
-                                        EE_Error::add_error(
1080
-                                            sprintf(
1081
-                                                esc_html_x(
1082
-                                                    'Unable to save registration form data for the form input: "%1$s" with the submitted value: "%2$s"',
1083
-                                                    'Unable to save registration form data for the form input: "form input name" with the submitted value: "form input value"',
1084
-                                                    'event_espresso'
1085
-                                                ),
1086
-                                                $form_input,
1087
-                                                $input_value
1088
-                                            ),
1089
-                                            __FILE__,
1090
-                                            __FUNCTION__,
1091
-                                            __LINE__
1092
-                                        );
1093
-                                        return false;
1094
-                                    }
1095
-                                }
1096
-                            }
1097
-                        }  // end of foreach ( $valid_data[ $reg_url_link ] as $form_section => $form_inputs )
1098
-                    }
1099
-                    // EEH_Debug_Tools::printr( $this->_attendee_data, '$this->_attendee_data', __FILE__, __LINE__ );
1100
-                    // this registration does not require additional attendee information ?
1101
-                    if ($copy_primary
1102
-                        && $att_nmbr > 1
1103
-                        && $this->checkout->primary_attendee_obj instanceof EE_Attendee
1104
-                    ) {
1105
-                        // just copy the primary registrant
1106
-                        $attendee = $this->checkout->primary_attendee_obj;
1107
-                    } else {
1108
-                        // ensure critical details are set for additional attendees
1109
-                        $this->_attendee_data[ $reg_url_link ] = $att_nmbr > 1
1110
-                            ? $this->_copy_critical_attendee_details_from_primary_registrant(
1111
-                                $this->_attendee_data[ $reg_url_link ]
1112
-                            )
1113
-                            : $this->_attendee_data[ $reg_url_link ];
1114
-                        // execute create attendee command (which may return an existing attendee)
1115
-                        $attendee = EE_Registry::instance()->BUS->execute(
1116
-                            new CreateAttendeeCommand(
1117
-                                $this->_attendee_data[ $reg_url_link ],
1118
-                                $registration
1119
-                            )
1120
-                        );
1121
-                        // who's #1 ?
1122
-                        if ($att_nmbr === 1) {
1123
-                            $this->checkout->primary_attendee_obj = $attendee;
1124
-                        }
1125
-                    }
1126
-                    // EEH_Debug_Tools::printr( $attendee, '$attendee', __FILE__, __LINE__ );
1127
-                    // add relation to registration, set attendee ID, and cache attendee
1128
-                    $this->_associate_attendee_with_registration($registration, $attendee);
1129
-                    // \EEH_Debug_Tools::printr( $registration, '$registration', __FILE__, __LINE__ );
1130
-                    if (! $registration->attendee() instanceof EE_Attendee) {
1131
-                        EE_Error::add_error(
1132
-                            sprintf(
1133
-                                esc_html_x(
1134
-                                    'Registration %s has an invalid or missing Attendee object.',
1135
-                                    'Registration 123-456-789 has an invalid or missing Attendee object.',
1136
-                                    'event_espresso'
1137
-                                ),
1138
-                                $reg_url_link
1139
-                            ),
1140
-                            __FILE__,
1141
-                            __FUNCTION__,
1142
-                            __LINE__
1143
-                        );
1144
-                        return false;
1145
-                    }
1146
-                    /** @type EE_Registration_Processor $registration_processor */
1147
-                    $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
1148
-                    // at this point, we should have enough details about the registrant to consider the registration
1149
-                    // NOT incomplete
1150
-                    $registration_processor->toggle_incomplete_registration_status_to_default(
1151
-                        $registration,
1152
-                        false,
1153
-                        new Context(
1154
-                            'spco_reg_step_attendee_information_process_registrations',
1155
-                            esc_html__(
1156
-                                'Finished populating registration with details from the registration form after submitting the Attendee Information Reg Step.',
1157
-                                'event_espresso'
1158
-                            )
1159
-                        )
1160
-                    );
1161
-                    // we can also consider the TXN to not have been failed, so temporarily upgrade it's status to
1162
-                    // abandoned
1163
-                    $this->checkout->transaction->toggle_failed_transaction_status();
1164
-                    // if we've gotten this far, then let's save what we have
1165
-                    $registration->save();
1166
-                    // add relation between TXN and registration
1167
-                    $this->_associate_registration_with_transaction($registration);
1168
-                }
1169
-            } else {
1170
-                EE_Error::add_error(
1171
-                    esc_html__(
1172
-                        'An invalid or missing line item ID was encountered while attempting to process the registration form.',
1173
-                        'event_espresso'
1174
-                    ),
1175
-                    __FILE__,
1176
-                    __FUNCTION__,
1177
-                    __LINE__
1178
-                );
1179
-                // remove malformed data
1180
-                unset($valid_data[ $reg_url_link ]);
1181
-                return false;
1182
-            }
1183
-        } // end of foreach ( $this->checkout->transaction->registrations()  as $registration )
1184
-        return $att_nmbr;
1185
-    }
1186
-
1187
-
1188
-    /**
1189
-     *    _save_registration_form_input
1190
-     *
1191
-     * @param EE_Registration $registration
1192
-     * @param string          $form_input
1193
-     * @param string          $input_value
1194
-     * @return bool
1195
-     * @throws EE_Error
1196
-     * @throws InvalidArgumentException
1197
-     * @throws InvalidDataTypeException
1198
-     * @throws InvalidInterfaceException
1199
-     * @throws ReflectionException
1200
-     */
1201
-    private function _save_registration_form_input(
1202
-        EE_Registration $registration,
1203
-        $form_input = '',
1204
-        $input_value = ''
1205
-    ) {
1206
-        // \EEH_Debug_Tools::printr( __FUNCTION__, __CLASS__, __FILE__, __LINE__, 2 );
1207
-        // \EEH_Debug_Tools::printr( $form_input, '$form_input', __FILE__, __LINE__ );
1208
-        // \EEH_Debug_Tools::printr( $input_value, '$input_value', __FILE__, __LINE__ );
1209
-        // allow for plugins to hook in and do their own processing of the form input.
1210
-        // For plugins to bypass normal processing here, they just need to return a boolean value.
1211
-        if (apply_filters(
1212
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information___save_registration_form_input',
1213
-            false,
1214
-            $registration,
1215
-            $form_input,
1216
-            $input_value,
1217
-            $this
1218
-        )) {
1219
-            return true;
1220
-        }
1221
-        /*
21
+	/**
22
+	 * @type bool $_print_copy_info
23
+	 */
24
+	private $_print_copy_info = false;
25
+
26
+	/**
27
+	 * @type array $_attendee_data
28
+	 */
29
+	private $_attendee_data = array();
30
+
31
+	/**
32
+	 * @type array $_required_questions
33
+	 */
34
+	private $_required_questions = array();
35
+
36
+	/**
37
+	 * @type array $_registration_answers
38
+	 */
39
+	private $_registration_answers = array();
40
+
41
+
42
+	/**
43
+	 *    class constructor
44
+	 *
45
+	 * @access    public
46
+	 * @param    EE_Checkout $checkout
47
+	 */
48
+	public function __construct(EE_Checkout $checkout)
49
+	{
50
+		$this->_slug = 'attendee_information';
51
+		$this->_name = esc_html__('Attendee Information', 'event_espresso');
52
+		$this->_template = SPCO_REG_STEPS_PATH . $this->_slug . DS . 'attendee_info_main.template.php';
53
+		$this->checkout = $checkout;
54
+		$this->_reset_success_message();
55
+		$this->set_instructions(
56
+			esc_html__('Please answer the following registration questions before proceeding.', 'event_espresso')
57
+		);
58
+	}
59
+
60
+
61
+	public function translate_js_strings()
62
+	{
63
+		EE_Registry::$i18n_js_strings['required_field'] = esc_html__(
64
+			' is a required question.',
65
+			'event_espresso'
66
+		);
67
+		EE_Registry::$i18n_js_strings['required_multi_field'] = esc_html__(
68
+			' is a required question. Please enter a value for at least one of the options.',
69
+			'event_espresso'
70
+		);
71
+		EE_Registry::$i18n_js_strings['answer_required_questions'] = esc_html__(
72
+			'Please answer all required questions correctly before proceeding.',
73
+			'event_espresso'
74
+		);
75
+		EE_Registry::$i18n_js_strings['attendee_info_copied'] = sprintf(
76
+			esc_html_x(
77
+				'The attendee information was successfully copied.%sPlease ensure the rest of the registration form is completed before proceeding.',
78
+				'The attendee information was successfully copied.(line break)Please ensure the rest of the registration form is completed before proceeding.',
79
+				'event_espresso'
80
+			),
81
+			'<br/>'
82
+		);
83
+		EE_Registry::$i18n_js_strings['attendee_info_copy_error'] = esc_html__(
84
+			'An unknown error occurred on the server while attempting to copy the attendee information. Please refresh the page and try again.',
85
+			'event_espresso'
86
+		);
87
+		EE_Registry::$i18n_js_strings['enter_valid_email'] = esc_html__(
88
+			'You must enter a valid email address.',
89
+			'event_espresso'
90
+		);
91
+		EE_Registry::$i18n_js_strings['valid_email_and_questions'] = esc_html__(
92
+			'You must enter a valid email address and answer all other required questions before you can proceed.',
93
+			'event_espresso'
94
+		);
95
+	}
96
+
97
+
98
+	public function enqueue_styles_and_scripts()
99
+	{
100
+	}
101
+
102
+
103
+	/**
104
+	 * @return boolean
105
+	 */
106
+	public function initialize_reg_step()
107
+	{
108
+		return true;
109
+	}
110
+
111
+
112
+	/**
113
+	 * @return EE_Form_Section_Proper
114
+	 * @throws DomainException
115
+	 * @throws EE_Error
116
+	 * @throws InvalidArgumentException
117
+	 * @throws ReflectionException
118
+	 * @throws EntityNotFoundException
119
+	 * @throws InvalidDataTypeException
120
+	 * @throws InvalidInterfaceException
121
+	 */
122
+	public function generate_reg_form()
123
+	{
124
+		$this->_print_copy_info = false;
125
+		$primary_registrant = null;
126
+		// autoload Line_Item_Display classes
127
+		EEH_Autoloader::register_line_item_display_autoloaders();
128
+		$Line_Item_Display = new EE_Line_Item_Display();
129
+		// calculate taxes
130
+		$Line_Item_Display->display_line_item(
131
+			$this->checkout->cart->get_grand_total(),
132
+			array('set_tax_rate' => true)
133
+		);
134
+		/** @var $subsections EE_Form_Section_Proper[] */
135
+		$extra_inputs_section = $this->reg_step_hidden_inputs();
136
+		$subsections = array(
137
+			'default_hidden_inputs' => $extra_inputs_section,
138
+		);
139
+
140
+		/**
141
+		 * @var $reg_config EE_Registration_Config
142
+		 */
143
+		$reg_config = LoaderFactory::getLoader()->getShared('EE_Registration_Config');
144
+		// if this isn't a revisit, and they have the privacy consent box enalbed, add it
145
+		if (! $this->checkout->revisit && $reg_config->isConsentCheckboxEnabled()) {
146
+			$extra_inputs_section->add_subsections(
147
+				array(
148
+					'consent_box' => new EE_Form_Section_Proper(
149
+						array(
150
+							'layout_strategy' =>
151
+								new EE_Template_Layout(
152
+									array(
153
+										'input_template_file' => SPCO_REG_STEPS_PATH . $this->_slug . DS . 'privacy_consent.template.php',
154
+									)
155
+								),
156
+							'subsections'     => array(
157
+								'consent' => new EE_Checkbox_Multi_Input(
158
+									array(
159
+										'consent' => $reg_config->getConsentCheckboxLabelText(),
160
+									),
161
+									array(
162
+										'required'                          => true,
163
+										'required_validation_error_message' => esc_html__(
164
+											'You must consent to these terms in order to register.',
165
+											'event_espresso'
166
+										),
167
+										'html_label_text'                   => '',
168
+									)
169
+								),
170
+							),
171
+						)
172
+					),
173
+				),
174
+				null,
175
+				false
176
+			);
177
+		}
178
+		$template_args = array(
179
+			'revisit'       => $this->checkout->revisit,
180
+			'registrations' => array(),
181
+			'ticket_count'  => array(),
182
+		);
183
+		// grab the saved registrations from the transaction
184
+		$registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
185
+		if ($registrations) {
186
+			foreach ($registrations as $registration) {
187
+				// can this registration be processed during this visit ?
188
+				if ($registration instanceof EE_Registration
189
+					&& $this->checkout->visit_allows_processing_of_this_registration($registration)
190
+				) {
191
+					$subsections[ $registration->reg_url_link() ] = $this->_registrations_reg_form($registration);
192
+					if (! $this->checkout->admin_request) {
193
+						$template_args['registrations'][ $registration->reg_url_link() ] = $registration;
194
+						$template_args['ticket_count'][ $registration->ticket()->ID() ] = isset(
195
+							$template_args['ticket_count'][ $registration->ticket()->ID() ]
196
+						)
197
+							? $template_args['ticket_count'][ $registration->ticket()->ID() ] + 1
198
+							: 1;
199
+						$ticket_line_item = EEH_Line_Item::get_line_items_by_object_type_and_IDs(
200
+							$this->checkout->cart->get_grand_total(),
201
+							'Ticket',
202
+							array($registration->ticket()->ID())
203
+						);
204
+						$ticket_line_item = is_array($ticket_line_item)
205
+							? reset($ticket_line_item)
206
+							: $ticket_line_item;
207
+						$template_args['ticket_line_item'][ $registration->ticket()->ID() ] =
208
+							$Line_Item_Display->display_line_item($ticket_line_item);
209
+					}
210
+					if ($registration->is_primary_registrant()) {
211
+						$primary_registrant = $registration->reg_url_link();
212
+					}
213
+				}
214
+			}
215
+			// print_copy_info ?
216
+			if ($primary_registrant && ! $this->checkout->admin_request && count($registrations) > 1) {
217
+				// TODO: add admin option for toggling copy attendee info,
218
+				// then use that value to change $this->_print_copy_info
219
+				$copy_options['spco_copy_attendee_chk'] = $this->_print_copy_info
220
+					? $this->_copy_attendee_info_form()
221
+					: $this->_auto_copy_attendee_info();
222
+				// generate hidden input
223
+				if (isset($subsections[ $primary_registrant ])
224
+					&& $subsections[ $primary_registrant ] instanceof EE_Form_Section_Proper
225
+				) {
226
+					$subsections[ $primary_registrant ]->add_subsections(
227
+						$copy_options,
228
+						'primary_registrant',
229
+						false
230
+					);
231
+				}
232
+			}
233
+		}
234
+		return new EE_Form_Section_Proper(
235
+			array(
236
+				'name'            => $this->reg_form_name(),
237
+				'html_id'         => $this->reg_form_name(),
238
+				'subsections'     => $subsections,
239
+				'layout_strategy' => $this->checkout->admin_request
240
+					?
241
+					new EE_Div_Per_Section_Layout()
242
+					:
243
+					new EE_Template_Layout(
244
+						array(
245
+							'layout_template_file' => $this->_template, // layout_template
246
+							'template_args'        => $template_args,
247
+						)
248
+					),
249
+			)
250
+		);
251
+	}
252
+
253
+
254
+	/**
255
+	 * @param EE_Registration $registration
256
+	 * @return EE_Form_Section_Base
257
+	 * @throws EE_Error
258
+	 * @throws InvalidArgumentException
259
+	 * @throws EntityNotFoundException
260
+	 * @throws InvalidDataTypeException
261
+	 * @throws InvalidInterfaceException
262
+	 * @throws ReflectionException
263
+	 */
264
+	private function _registrations_reg_form(EE_Registration $registration)
265
+	{
266
+		static $attendee_nmbr = 1;
267
+		$form_args = array();
268
+		// verify that registration has valid event
269
+		if ($registration->event() instanceof EE_Event) {
270
+			$field_name = 'Event_Question_Group.'
271
+				. EEM_Event_Question_Group::instance()->fieldNameForContext(
272
+					$registration->is_primary_registrant()
273
+				);
274
+			$question_groups = $registration->event()->question_groups(
275
+				apply_filters(
276
+					// @codingStandardsIgnoreStart
277
+					'FHEE__EE_SPCO_Reg_Step_Attendee_Information___registrations_reg_form__question_groups_query_parameters',
278
+					// @codingStandardsIgnoreEnd
279
+					[
280
+						[
281
+							'Event.EVT_ID'                     => $registration->event()->ID(),
282
+							$field_name => true,
283
+						],
284
+						'order_by' => ['QSG_order' => 'ASC'],
285
+					],
286
+					$registration,
287
+					$this
288
+				)
289
+			);
290
+			if ($question_groups) {
291
+				// array of params to pass to parent constructor
292
+				$form_args = array(
293
+					'html_id'         => 'ee-registration-' . $registration->reg_url_link(),
294
+					'html_class'      => 'ee-reg-form-attendee-dv',
295
+					'html_style'      => $this->checkout->admin_request
296
+						? 'padding:0em 2em 1em; margin:3em 0 0; border:1px solid #ddd;'
297
+						: '',
298
+					'subsections'     => array(),
299
+					'layout_strategy' => new EE_Fieldset_Section_Layout(
300
+						array(
301
+							'legend_class' => 'spco-attendee-lgnd smaller-text lt-grey-text',
302
+							'legend_text'  => sprintf(
303
+								esc_html_x(
304
+									'Attendee %d',
305
+									'Attendee 123',
306
+									'event_espresso'
307
+								),
308
+								$attendee_nmbr
309
+							),
310
+						)
311
+					),
312
+				);
313
+				foreach ($question_groups as $question_group) {
314
+					if ($question_group instanceof EE_Question_Group) {
315
+						$form_args['subsections'][ $question_group->identifier() ] = $this->_question_group_reg_form(
316
+							$registration,
317
+							$question_group
318
+						);
319
+					}
320
+				}
321
+				// add hidden input
322
+				$form_args['subsections']['additional_attendee_reg_info'] = $this->_additional_attendee_reg_info_input(
323
+					$registration
324
+				);
325
+				// if we have question groups for additional attendees, then display the copy options
326
+				$this->_print_copy_info = $attendee_nmbr > 1 ? true : $this->_print_copy_info;
327
+				if ($registration->is_primary_registrant()) {
328
+					// generate hidden input
329
+					$form_args['subsections']['primary_registrant'] = $this->_additional_primary_registrant_inputs(
330
+						$registration
331
+					);
332
+				}
333
+			}
334
+		}
335
+		$attendee_nmbr++;
336
+		return ! empty($form_args)
337
+			? new EE_Form_Section_Proper($form_args)
338
+			: new EE_Form_Section_HTML();
339
+	}
340
+
341
+
342
+	/**
343
+	 * @param EE_Registration $registration
344
+	 * @param bool            $additional_attendee_reg_info
345
+	 * @return EE_Form_Input_Base
346
+	 * @throws EE_Error
347
+	 */
348
+	private function _additional_attendee_reg_info_input(
349
+		EE_Registration $registration,
350
+		$additional_attendee_reg_info = true
351
+	) {
352
+		// generate hidden input
353
+		return new EE_Hidden_Input(
354
+			array(
355
+				'html_id' => 'additional-attendee-reg-info-' . $registration->reg_url_link(),
356
+				'default' => $additional_attendee_reg_info,
357
+			)
358
+		);
359
+	}
360
+
361
+
362
+	/**
363
+	 * @param EE_Registration   $registration
364
+	 * @param EE_Question_Group $question_group
365
+	 * @return EE_Form_Section_Proper
366
+	 * @throws EE_Error
367
+	 * @throws InvalidArgumentException
368
+	 * @throws InvalidDataTypeException
369
+	 * @throws InvalidInterfaceException
370
+	 * @throws ReflectionException
371
+	 */
372
+	private function _question_group_reg_form(EE_Registration $registration, EE_Question_Group $question_group)
373
+	{
374
+		// array of params to pass to parent constructor
375
+		$form_args = array(
376
+			'html_id'         => 'ee-reg-form-qstn-grp-' . $question_group->identifier() . '-' . $registration->ID(),
377
+			'html_class'      => $this->checkout->admin_request
378
+				? 'form-table ee-reg-form-qstn-grp-dv'
379
+				: 'ee-reg-form-qstn-grp-dv',
380
+			'html_label_id'   => 'ee-reg-form-qstn-grp-' . $question_group->identifier() . '-'
381
+								 . $registration->ID() . '-lbl',
382
+			'subsections'     => array(
383
+				'reg_form_qstn_grp_hdr' => $this->_question_group_header($question_group),
384
+			),
385
+			'layout_strategy' => $this->checkout->admin_request
386
+				? new EE_Admin_Two_Column_Layout()
387
+				: new EE_Div_Per_Section_Layout(),
388
+		);
389
+		// where params
390
+		$query_params = array('QST_deleted' => 0);
391
+		// don't load admin only questions on the frontend
392
+		if (! $this->checkout->admin_request) {
393
+			$query_params['QST_admin_only'] = array('!=', true);
394
+		}
395
+		$questions = $question_group->get_many_related(
396
+			'Question',
397
+			apply_filters(
398
+				'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__related_questions_query_params',
399
+				array(
400
+					$query_params,
401
+					'order_by' => array(
402
+						'Question_Group_Question.QGQ_order' => 'ASC',
403
+					),
404
+				),
405
+				$question_group,
406
+				$registration,
407
+				$this
408
+			)
409
+		);
410
+		// filter for additional content before questions
411
+		$form_args['subsections']['reg_form_questions_before'] = new EE_Form_Section_HTML(
412
+			apply_filters(
413
+				'FHEE__EEH_Form_Fields__generate_question_groups_html__before_question_group_questions',
414
+				'',
415
+				$registration,
416
+				$question_group,
417
+				$this
418
+			)
419
+		);
420
+		// loop thru questions
421
+		foreach ($questions as $question) {
422
+			if ($question instanceof EE_Question) {
423
+				$identifier = $question->is_system_question()
424
+					? $question->system_ID()
425
+					: $question->ID();
426
+				$form_args['subsections'][ $identifier ] = $this->reg_form_question($registration, $question);
427
+			}
428
+		}
429
+		$form_args['subsections'] = apply_filters(
430
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information__question_group_reg_form__subsections_array',
431
+			$form_args['subsections'],
432
+			$registration,
433
+			$question_group,
434
+			$this
435
+		);
436
+		// filter for additional content after questions
437
+		$form_args['subsections']['reg_form_questions_after'] = new EE_Form_Section_HTML(
438
+			apply_filters(
439
+				'FHEE__EEH_Form_Fields__generate_question_groups_html__after_question_group_questions',
440
+				'',
441
+				$registration,
442
+				$question_group,
443
+				$this
444
+			)
445
+		);
446
+		// d($form_args);
447
+		$question_group_reg_form = new EE_Form_Section_Proper($form_args);
448
+		return apply_filters(
449
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___question_group_reg_form__question_group_reg_form',
450
+			$question_group_reg_form,
451
+			$registration,
452
+			$question_group,
453
+			$this
454
+		);
455
+	}
456
+
457
+
458
+	/**
459
+	 * @param EE_Question_Group $question_group
460
+	 * @return    EE_Form_Section_HTML
461
+	 */
462
+	private function _question_group_header(EE_Question_Group $question_group)
463
+	{
464
+		$html = '';
465
+		// group_name
466
+		if ($question_group->show_group_name() && $question_group->name() !== '') {
467
+			if ($this->checkout->admin_request) {
468
+				$html .= EEH_HTML::br();
469
+				$html .= EEH_HTML::h3(
470
+					$question_group->name(),
471
+					'',
472
+					'ee-reg-form-qstn-grp-title title',
473
+					'font-size: 1.3em; padding-left:0;'
474
+				);
475
+			} else {
476
+				$html .= EEH_HTML::h4(
477
+					$question_group->name(),
478
+					'',
479
+					'ee-reg-form-qstn-grp-title section-title'
480
+				);
481
+			}
482
+		}
483
+		// group_desc
484
+		if ($question_group->show_group_desc() && $question_group->desc() !== '') {
485
+			$html .= EEH_HTML::p(
486
+				$question_group->desc(),
487
+				'',
488
+				$this->checkout->admin_request
489
+					? 'ee-reg-form-qstn-grp-desc-pg'
490
+					: 'ee-reg-form-qstn-grp-desc-pg small-text lt-grey-text'
491
+			);
492
+		}
493
+		return new EE_Form_Section_HTML($html);
494
+	}
495
+
496
+
497
+	/**
498
+	 * @return    EE_Form_Section_Proper
499
+	 * @throws EE_Error
500
+	 * @throws InvalidArgumentException
501
+	 * @throws ReflectionException
502
+	 * @throws InvalidDataTypeException
503
+	 * @throws InvalidInterfaceException
504
+	 */
505
+	private function _copy_attendee_info_form()
506
+	{
507
+		// array of params to pass to parent constructor
508
+		return new EE_Form_Section_Proper(
509
+			array(
510
+				'subsections'     => $this->_copy_attendee_info_inputs(),
511
+				'layout_strategy' => new EE_Template_Layout(
512
+					array(
513
+						'layout_template_file'     => SPCO_REG_STEPS_PATH
514
+													  . $this->_slug
515
+													  . DS
516
+													  . 'copy_attendee_info.template.php',
517
+						'begin_template_file'      => null,
518
+						'input_template_file'      => null,
519
+						'subsection_template_file' => null,
520
+						'end_template_file'        => null,
521
+					)
522
+				),
523
+			)
524
+		);
525
+	}
526
+
527
+
528
+	/**
529
+	 * @return EE_Form_Section_HTML
530
+	 * @throws DomainException
531
+	 * @throws InvalidArgumentException
532
+	 * @throws InvalidDataTypeException
533
+	 * @throws InvalidInterfaceException
534
+	 */
535
+	private function _auto_copy_attendee_info()
536
+	{
537
+		return new EE_Form_Section_HTML(
538
+			EEH_Template::locate_template(
539
+				SPCO_REG_STEPS_PATH . $this->_slug . DS . '_auto_copy_attendee_info.template.php',
540
+				apply_filters(
541
+					'FHEE__EE_SPCO_Reg_Step_Attendee_Information__auto_copy_attendee_info__template_args',
542
+					array()
543
+				),
544
+				true,
545
+				true
546
+			)
547
+		);
548
+	}
549
+
550
+
551
+	/**
552
+	 * @return array
553
+	 * @throws EE_Error
554
+	 * @throws InvalidArgumentException
555
+	 * @throws ReflectionException
556
+	 * @throws InvalidDataTypeException
557
+	 * @throws InvalidInterfaceException
558
+	 */
559
+	private function _copy_attendee_info_inputs()
560
+	{
561
+		$copy_attendee_info_inputs = array();
562
+		$prev_ticket = null;
563
+		// grab the saved registrations from the transaction
564
+		$registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
565
+		foreach ($registrations as $registration) {
566
+			// for all  attendees other than the primary attendee
567
+			if ($registration instanceof EE_Registration && ! $registration->is_primary_registrant()) {
568
+				// if this is a new ticket OR if this is the very first additional attendee after the primary attendee
569
+				if ($registration->ticket()->ID() !== $prev_ticket) {
570
+					$item_name = $registration->ticket()->name();
571
+					$item_name .= $registration->ticket()->description() !== ''
572
+						? ' - ' . $registration->ticket()->description()
573
+						: '';
574
+					$copy_attendee_info_inputs[ 'spco_copy_attendee_chk[ticket-' . $registration->ticket()->ID(
575
+					) . ']' ] =
576
+						new EE_Form_Section_HTML(
577
+							'<h6 class="spco-copy-attendee-event-hdr">' . $item_name . '</h6>'
578
+						);
579
+					$prev_ticket = $registration->ticket()->ID();
580
+				}
581
+
582
+				$copy_attendee_info_inputs[ 'spco_copy_attendee_chk[' . $registration->ID() . ']' ] =
583
+					new EE_Checkbox_Multi_Input(
584
+						array(
585
+							$registration->ID() => sprintf(
586
+								esc_html_x('Attendee #%s', 'Attendee #123', 'event_espresso'),
587
+								$registration->count()
588
+							),
589
+						),
590
+						array(
591
+							'html_id'                 => 'spco-copy-attendee-chk-' . $registration->reg_url_link(),
592
+							'html_class'              => 'spco-copy-attendee-chk ee-do-not-validate',
593
+							'display_html_label_text' => false,
594
+						)
595
+					);
596
+			}
597
+		}
598
+		return $copy_attendee_info_inputs;
599
+	}
600
+
601
+
602
+	/**
603
+	 * @param EE_Registration $registration
604
+	 * @return    EE_Form_Input_Base
605
+	 * @throws EE_Error
606
+	 */
607
+	private function _additional_primary_registrant_inputs(EE_Registration $registration)
608
+	{
609
+		// generate hidden input
610
+		return new EE_Hidden_Input(
611
+			array(
612
+				'html_id' => 'primary_registrant',
613
+				'default' => $registration->reg_url_link(),
614
+			)
615
+		);
616
+	}
617
+
618
+
619
+	/**
620
+	 * @param EE_Registration $registration
621
+	 * @param EE_Question     $question
622
+	 * @return EE_Form_Input_Base
623
+	 * @throws EE_Error
624
+	 * @throws InvalidArgumentException
625
+	 * @throws InvalidDataTypeException
626
+	 * @throws InvalidInterfaceException
627
+	 * @throws ReflectionException
628
+	 */
629
+	public function reg_form_question(EE_Registration $registration, EE_Question $question)
630
+	{
631
+
632
+		// if this question was for an attendee detail, then check for that answer
633
+		$answer_value = EEM_Answer::instance()->get_attendee_property_answer_value(
634
+			$registration,
635
+			$question->system_ID()
636
+		);
637
+		$answer = $answer_value === null
638
+			? EEM_Answer::instance()->get_one(
639
+				array(array('QST_ID' => $question->ID(), 'REG_ID' => $registration->ID()))
640
+			)
641
+			: null;
642
+		// if NOT returning to edit an existing registration
643
+		// OR if this question is for an attendee property
644
+		// OR we still don't have an EE_Answer object
645
+		if ($answer_value || ! $answer instanceof EE_Answer || ! $registration->reg_url_link()) {
646
+			// create an EE_Answer object for storing everything in
647
+			$answer = EE_Answer::new_instance(
648
+				array(
649
+					'QST_ID' => $question->ID(),
650
+					'REG_ID' => $registration->ID(),
651
+				)
652
+			);
653
+		}
654
+		// verify instance
655
+		if ($answer instanceof EE_Answer) {
656
+			if (! empty($answer_value)) {
657
+				$answer->set('ANS_value', $answer_value);
658
+			}
659
+			$answer->cache('Question', $question);
660
+			// remember system ID had a bug where sometimes it could be null
661
+			$answer_cache_id = $question->is_system_question()
662
+				? $question->system_ID() . '-' . $registration->reg_url_link()
663
+				: $question->ID() . '-' . $registration->reg_url_link();
664
+			$registration->cache('Answer', $answer, $answer_cache_id);
665
+		}
666
+		return $this->_generate_question_input($registration, $question, $answer);
667
+	}
668
+
669
+
670
+	/**
671
+	 * @param EE_Registration $registration
672
+	 * @param EE_Question     $question
673
+	 * @param                 $answer
674
+	 * @return EE_Form_Input_Base
675
+	 * @throws EE_Error
676
+	 * @throws InvalidArgumentException
677
+	 * @throws ReflectionException
678
+	 * @throws InvalidDataTypeException
679
+	 * @throws InvalidInterfaceException
680
+	 */
681
+	private function _generate_question_input(EE_Registration $registration, EE_Question $question, $answer)
682
+	{
683
+		$identifier = $question->is_system_question()
684
+			? $question->system_ID()
685
+			: $question->ID();
686
+		$this->_required_questions[ $identifier ] = $question->required() ? true : false;
687
+		add_filter(
688
+			'FHEE__EE_Question__generate_form_input__country_options',
689
+			array($this, 'use_cached_countries_for_form_input'),
690
+			10,
691
+			4
692
+		);
693
+		add_filter(
694
+			'FHEE__EE_Question__generate_form_input__state_options',
695
+			array($this, 'use_cached_states_for_form_input'),
696
+			10,
697
+			4
698
+		);
699
+		$input_constructor_args = array(
700
+			'html_name'        => 'ee_reg_qstn[' . $registration->ID() . '][' . $identifier . ']',
701
+			'html_id'          => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
702
+			'html_class'       => 'ee-reg-qstn ee-reg-qstn-' . $identifier,
703
+			'html_label_id'    => 'ee_reg_qstn-' . $registration->ID() . '-' . $identifier,
704
+			'html_label_class' => 'ee-reg-qstn',
705
+		);
706
+		$input_constructor_args['html_label_id'] .= '-lbl';
707
+		if ($answer instanceof EE_Answer && $answer->ID()) {
708
+			$input_constructor_args['html_name'] .= '[' . $answer->ID() . ']';
709
+			$input_constructor_args['html_id'] .= '-' . $answer->ID();
710
+			$input_constructor_args['html_label_id'] .= '-' . $answer->ID();
711
+		}
712
+		$form_input = $question->generate_form_input(
713
+			$registration,
714
+			$answer,
715
+			$input_constructor_args
716
+		);
717
+		remove_filter(
718
+			'FHEE__EE_Question__generate_form_input__country_options',
719
+			array($this, 'use_cached_countries_for_form_input')
720
+		);
721
+		remove_filter(
722
+			'FHEE__EE_Question__generate_form_input__state_options',
723
+			array($this, 'use_cached_states_for_form_input')
724
+		);
725
+		return $form_input;
726
+	}
727
+
728
+
729
+	/**
730
+	 * Gets the list of countries for the form input
731
+	 *
732
+	 * @param array|null      $countries_list
733
+	 * @param EE_Question     $question
734
+	 * @param EE_Registration $registration
735
+	 * @param EE_Answer       $answer
736
+	 * @return array 2d keys are country IDs, values are their names
737
+	 * @throws EE_Error
738
+	 * @throws InvalidArgumentException
739
+	 * @throws InvalidDataTypeException
740
+	 * @throws InvalidInterfaceException
741
+	 * @throws ReflectionException
742
+	 */
743
+	public function use_cached_countries_for_form_input(
744
+		$countries_list,
745
+		EE_Question $question = null,
746
+		EE_Registration $registration = null,
747
+		EE_Answer $answer = null
748
+	) {
749
+		$country_options = array('' => '');
750
+		// get possibly cached list of countries
751
+		$countries = $this->checkout->action === 'process_reg_step'
752
+			? EEM_Country::instance()->get_all_countries()
753
+			: EEM_Country::instance()->get_all_active_countries();
754
+		if (! empty($countries)) {
755
+			foreach ($countries as $country) {
756
+				if ($country instanceof EE_Country) {
757
+					$country_options[ $country->ID() ] = $country->name();
758
+				}
759
+			}
760
+		}
761
+		if ($question instanceof EE_Question && $registration instanceof EE_Registration) {
762
+			$answer = EEM_Answer::instance()->get_one(
763
+				array(array('QST_ID' => $question->ID(), 'REG_ID' => $registration->ID()))
764
+			);
765
+		} else {
766
+			$answer = EE_Answer::new_instance();
767
+		}
768
+		$country_options = apply_filters(
769
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__country_options',
770
+			$country_options,
771
+			$this,
772
+			$registration,
773
+			$question,
774
+			$answer
775
+		);
776
+		return $country_options;
777
+	}
778
+
779
+
780
+	/**
781
+	 * Gets the list of states for the form input
782
+	 *
783
+	 * @param array|null      $states_list
784
+	 * @param EE_Question     $question
785
+	 * @param EE_Registration $registration
786
+	 * @param EE_Answer       $answer
787
+	 * @return array 2d keys are state IDs, values are their names
788
+	 * @throws EE_Error
789
+	 * @throws InvalidArgumentException
790
+	 * @throws InvalidDataTypeException
791
+	 * @throws InvalidInterfaceException
792
+	 * @throws ReflectionException
793
+	 */
794
+	public function use_cached_states_for_form_input(
795
+		$states_list,
796
+		EE_Question $question = null,
797
+		EE_Registration $registration = null,
798
+		EE_Answer $answer = null
799
+	) {
800
+		$state_options = array('' => array('' => ''));
801
+		$states = $this->checkout->action === 'process_reg_step'
802
+			? EEM_State::instance()->get_all_states()
803
+			: EEM_State::instance()->get_all_active_states();
804
+		if (! empty($states)) {
805
+			foreach ($states as $state) {
806
+				if ($state instanceof EE_State) {
807
+					$state_options[ $state->country()->name() ][ $state->ID() ] = $state->name();
808
+				}
809
+			}
810
+		}
811
+		$state_options = apply_filters(
812
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___generate_question_input__state_options',
813
+			$state_options,
814
+			$this,
815
+			$registration,
816
+			$question,
817
+			$answer
818
+		);
819
+		return $state_options;
820
+	}
821
+
822
+
823
+	/********************************************************************************************************/
824
+	/****************************************  PROCESS REG STEP  ****************************************/
825
+	/********************************************************************************************************/
826
+
827
+
828
+	/**
829
+	 * @return bool
830
+	 * @throws EE_Error
831
+	 * @throws InvalidArgumentException
832
+	 * @throws ReflectionException
833
+	 * @throws RuntimeException
834
+	 * @throws InvalidDataTypeException
835
+	 * @throws InvalidInterfaceException
836
+	 */
837
+	public function process_reg_step()
838
+	{
839
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
840
+		// grab validated data from form
841
+		$valid_data = $this->checkout->current_step->valid_data();
842
+		// EEH_Debug_Tools::printr( $_REQUEST, '$_REQUEST', __FILE__, __LINE__ );
843
+		// EEH_Debug_Tools::printr( $valid_data, '$valid_data', __FILE__, __LINE__ );
844
+		// if we don't have any $valid_data then something went TERRIBLY WRONG !!!
845
+		if (empty($valid_data)) {
846
+			EE_Error::add_error(
847
+				esc_html__('No valid question responses were received.', 'event_espresso'),
848
+				__FILE__,
849
+				__FUNCTION__,
850
+				__LINE__
851
+			);
852
+			return false;
853
+		}
854
+		if (! $this->checkout->transaction instanceof EE_Transaction || ! $this->checkout->continue_reg) {
855
+			EE_Error::add_error(
856
+				esc_html__(
857
+					'A valid transaction could not be initiated for processing your registrations.',
858
+					'event_espresso'
859
+				),
860
+				__FILE__,
861
+				__FUNCTION__,
862
+				__LINE__
863
+			);
864
+			return false;
865
+		}
866
+		// get cached registrations
867
+		$registrations = $this->checkout->transaction->registrations($this->checkout->reg_cache_where_params);
868
+		// verify we got the goods
869
+		if (empty($registrations)) {
870
+			// combine the old translated string with a new one, in order to not break translations
871
+			$error_message = esc_html__(
872
+				'Your form data could not be applied to any valid registrations.',
873
+				'event_espresso'
874
+			)
875
+			. sprintf(
876
+				esc_html_x(
877
+					'%3$sThis can sometimes happen if too much time has been taken to complete the registration process.%3$sPlease return to the %1$sEvent List%2$s and reselect your tickets. If the problem continues, please contact the site administrator.',
878
+					'(line break)This can sometimes happen if too much time has been taken to complete the registration process.(line break)Please return to the (link)Event List(end link) and reselect your tickets. If the problem continues, please contact the site administrator.',
879
+					'event_espresso'
880
+				),
881
+				'<a href="' . get_post_type_archive_link('espresso_events') . '" >',
882
+				'</a>',
883
+				'<br />'
884
+			);
885
+			EE_Error::add_error(
886
+				$error_message,
887
+				__FILE__,
888
+				__FUNCTION__,
889
+				__LINE__
890
+			);
891
+			return false;
892
+		}
893
+		// extract attendee info from form data and save to model objects
894
+		$registrations_processed = $this->_process_registrations($registrations, $valid_data);
895
+		// if first pass thru SPCO,
896
+		// then let's check processed registrations against the total number of tickets in the cart
897
+		if ($registrations_processed === false) {
898
+			// but return immediately if the previous step exited early due to errors
899
+			return false;
900
+		}
901
+		if (! $this->checkout->revisit && $registrations_processed !== $this->checkout->total_ticket_count) {
902
+			// generate a correctly translated string for all possible singular/plural combinations
903
+			if ($this->checkout->total_ticket_count === 1 && $registrations_processed !== 1) {
904
+				$error_msg = sprintf(
905
+					esc_html_x(
906
+						'There was %1$d ticket in the Event Queue, but %2$ds registrations were processed',
907
+						'There was 1 ticket in the Event Queue, but 2 registrations were processed',
908
+						'event_espresso'
909
+					),
910
+					$this->checkout->total_ticket_count,
911
+					$registrations_processed
912
+				);
913
+			} elseif ($this->checkout->total_ticket_count !== 1 && $registrations_processed === 1) {
914
+				$error_msg = sprintf(
915
+					esc_html_x(
916
+						'There was a total of %1$d tickets in the Event Queue, but only %2$ds registration was processed',
917
+						'There was a total of 2 tickets in the Event Queue, but only 1 registration was processed',
918
+						'event_espresso'
919
+					),
920
+					$this->checkout->total_ticket_count,
921
+					$registrations_processed
922
+				);
923
+			} else {
924
+				$error_msg = sprintf(
925
+					esc_html__(
926
+						'There was a total of 2 tickets in the Event Queue, but 2 registrations were processed',
927
+						'event_espresso'
928
+					),
929
+					$this->checkout->total_ticket_count,
930
+					$registrations_processed
931
+				);
932
+			}
933
+			EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
934
+			return false;
935
+		}
936
+		// mark this reg step as completed
937
+		$this->set_completed();
938
+		$this->_set_success_message(
939
+			esc_html__('The Attendee Information Step has been successfully completed.', 'event_espresso')
940
+		);
941
+		// do action in case a plugin wants to do something with the data submitted in step 1.
942
+		// passes EE_Single_Page_Checkout, and it's posted data
943
+		do_action('AHEE__EE_Single_Page_Checkout__process_attendee_information__end', $this, $valid_data);
944
+		return true;
945
+	}
946
+
947
+
948
+	/**
949
+	 *    _process_registrations
950
+	 *
951
+	 * @param EE_Registration[] $registrations
952
+	 * @param array[][]         $valid_data
953
+	 * @return bool|int
954
+	 * @throws EntityNotFoundException
955
+	 * @throws EE_Error
956
+	 * @throws InvalidArgumentException
957
+	 * @throws ReflectionException
958
+	 * @throws RuntimeException
959
+	 * @throws InvalidDataTypeException
960
+	 * @throws InvalidInterfaceException
961
+	 */
962
+	private function _process_registrations($registrations = array(), $valid_data = array())
963
+	{
964
+		// load resources and set some defaults
965
+		EE_Registry::instance()->load_model('Attendee');
966
+		// holder for primary registrant attendee object
967
+		$this->checkout->primary_attendee_obj = null;
968
+		// array for tracking reg form data for the primary registrant
969
+		$primary_registrant = array(
970
+			'line_item_id' => null,
971
+		);
972
+		$copy_primary = false;
973
+		// reg form sections that do not contain inputs
974
+		$non_input_form_sections = array(
975
+			'primary_registrant',
976
+			'additional_attendee_reg_info',
977
+			'spco_copy_attendee_chk',
978
+		);
979
+		// attendee counter
980
+		$att_nmbr = 0;
981
+		// grab the saved registrations from the transaction
982
+		foreach ($registrations as $registration) {
983
+			// verify EE_Registration object
984
+			if (! $registration instanceof EE_Registration) {
985
+				EE_Error::add_error(
986
+					esc_html__(
987
+						'An invalid Registration object was discovered when attempting to process your registration information.',
988
+						'event_espresso'
989
+					),
990
+					__FILE__,
991
+					__FUNCTION__,
992
+					__LINE__
993
+				);
994
+				return false;
995
+			}
996
+			/** @var string $reg_url_link */
997
+			$reg_url_link = $registration->reg_url_link();
998
+			// reg_url_link exists ?
999
+			if (! empty($reg_url_link)) {
1000
+				// should this registration be processed during this visit ?
1001
+				if ($this->checkout->visit_allows_processing_of_this_registration($registration)) {
1002
+					// if NOT revisiting, then let's save the registration now,
1003
+					// so that we have a REG_ID to use when generating other objects
1004
+					if (! $this->checkout->revisit) {
1005
+						$registration->save();
1006
+					}
1007
+					/**
1008
+					 * This allows plugins to trigger a fail on processing of a
1009
+					 * registration for any conditions they may have for it to pass.
1010
+					 *
1011
+					 * @var bool   if true is returned by the plugin then the
1012
+					 *            registration processing is halted.
1013
+					 */
1014
+					if (apply_filters(
1015
+						'FHEE__EE_SPCO_Reg_Step_Attendee_Information___process_registrations__pre_registration_process',
1016
+						false,
1017
+						$att_nmbr,
1018
+						$registration,
1019
+						$registrations,
1020
+						$valid_data,
1021
+						$this
1022
+					)) {
1023
+						return false;
1024
+					}
1025
+
1026
+					// Houston, we have a registration!
1027
+					$att_nmbr++;
1028
+					$this->_attendee_data[ $reg_url_link ] = array();
1029
+					// grab any existing related answer objects
1030
+					$this->_registration_answers = $registration->answers();
1031
+					// unset( $valid_data[ $reg_url_link ]['additional_attendee_reg_info'] );
1032
+					if (isset($valid_data[ $reg_url_link ])) {
1033
+						// do we need to copy basic info from primary attendee ?
1034
+						$copy_primary = isset($valid_data[ $reg_url_link ]['additional_attendee_reg_info'])
1035
+										&& absint($valid_data[ $reg_url_link ]['additional_attendee_reg_info']) === 0;
1036
+						// filter form input data for this registration
1037
+						$valid_data[ $reg_url_link ] = (array) apply_filters(
1038
+							'FHEE__EE_Single_Page_Checkout__process_attendee_information__valid_data_line_item',
1039
+							$valid_data[ $reg_url_link ]
1040
+						);
1041
+						if (isset($valid_data['primary_attendee'])) {
1042
+							$primary_registrant['line_item_id'] = ! empty($valid_data['primary_attendee'])
1043
+								? $valid_data['primary_attendee']
1044
+								: false;
1045
+							unset($valid_data['primary_attendee']);
1046
+						}
1047
+						// now loop through our array of valid post data && process attendee reg forms
1048
+						foreach ($valid_data[ $reg_url_link ] as $form_section => $form_inputs) {
1049
+							if (! in_array($form_section, $non_input_form_sections, true)) {
1050
+								foreach ($form_inputs as $form_input => $input_value) {
1051
+									// \EEH_Debug_Tools::printr( $input_value, $form_input, __FILE__, __LINE__ );
1052
+									// check for critical inputs
1053
+									if (! $this->_verify_critical_attendee_details_are_set_and_validate_email(
1054
+										$form_input,
1055
+										$input_value
1056
+									)
1057
+									) {
1058
+										return false;
1059
+									}
1060
+									// store a bit of data about the primary attendee
1061
+									if ($att_nmbr === 1
1062
+										&& ! empty($input_value)
1063
+										&& $reg_url_link === $primary_registrant['line_item_id']
1064
+									) {
1065
+										$primary_registrant[ $form_input ] = $input_value;
1066
+									} elseif ($copy_primary
1067
+											  && $input_value === null
1068
+											  && isset($primary_registrant[ $form_input ])
1069
+									) {
1070
+										$input_value = $primary_registrant[ $form_input ];
1071
+									}
1072
+									// now attempt to save the input data
1073
+									if (! $this->_save_registration_form_input(
1074
+										$registration,
1075
+										$form_input,
1076
+										$input_value
1077
+									)
1078
+									) {
1079
+										EE_Error::add_error(
1080
+											sprintf(
1081
+												esc_html_x(
1082
+													'Unable to save registration form data for the form input: "%1$s" with the submitted value: "%2$s"',
1083
+													'Unable to save registration form data for the form input: "form input name" with the submitted value: "form input value"',
1084
+													'event_espresso'
1085
+												),
1086
+												$form_input,
1087
+												$input_value
1088
+											),
1089
+											__FILE__,
1090
+											__FUNCTION__,
1091
+											__LINE__
1092
+										);
1093
+										return false;
1094
+									}
1095
+								}
1096
+							}
1097
+						}  // end of foreach ( $valid_data[ $reg_url_link ] as $form_section => $form_inputs )
1098
+					}
1099
+					// EEH_Debug_Tools::printr( $this->_attendee_data, '$this->_attendee_data', __FILE__, __LINE__ );
1100
+					// this registration does not require additional attendee information ?
1101
+					if ($copy_primary
1102
+						&& $att_nmbr > 1
1103
+						&& $this->checkout->primary_attendee_obj instanceof EE_Attendee
1104
+					) {
1105
+						// just copy the primary registrant
1106
+						$attendee = $this->checkout->primary_attendee_obj;
1107
+					} else {
1108
+						// ensure critical details are set for additional attendees
1109
+						$this->_attendee_data[ $reg_url_link ] = $att_nmbr > 1
1110
+							? $this->_copy_critical_attendee_details_from_primary_registrant(
1111
+								$this->_attendee_data[ $reg_url_link ]
1112
+							)
1113
+							: $this->_attendee_data[ $reg_url_link ];
1114
+						// execute create attendee command (which may return an existing attendee)
1115
+						$attendee = EE_Registry::instance()->BUS->execute(
1116
+							new CreateAttendeeCommand(
1117
+								$this->_attendee_data[ $reg_url_link ],
1118
+								$registration
1119
+							)
1120
+						);
1121
+						// who's #1 ?
1122
+						if ($att_nmbr === 1) {
1123
+							$this->checkout->primary_attendee_obj = $attendee;
1124
+						}
1125
+					}
1126
+					// EEH_Debug_Tools::printr( $attendee, '$attendee', __FILE__, __LINE__ );
1127
+					// add relation to registration, set attendee ID, and cache attendee
1128
+					$this->_associate_attendee_with_registration($registration, $attendee);
1129
+					// \EEH_Debug_Tools::printr( $registration, '$registration', __FILE__, __LINE__ );
1130
+					if (! $registration->attendee() instanceof EE_Attendee) {
1131
+						EE_Error::add_error(
1132
+							sprintf(
1133
+								esc_html_x(
1134
+									'Registration %s has an invalid or missing Attendee object.',
1135
+									'Registration 123-456-789 has an invalid or missing Attendee object.',
1136
+									'event_espresso'
1137
+								),
1138
+								$reg_url_link
1139
+							),
1140
+							__FILE__,
1141
+							__FUNCTION__,
1142
+							__LINE__
1143
+						);
1144
+						return false;
1145
+					}
1146
+					/** @type EE_Registration_Processor $registration_processor */
1147
+					$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
1148
+					// at this point, we should have enough details about the registrant to consider the registration
1149
+					// NOT incomplete
1150
+					$registration_processor->toggle_incomplete_registration_status_to_default(
1151
+						$registration,
1152
+						false,
1153
+						new Context(
1154
+							'spco_reg_step_attendee_information_process_registrations',
1155
+							esc_html__(
1156
+								'Finished populating registration with details from the registration form after submitting the Attendee Information Reg Step.',
1157
+								'event_espresso'
1158
+							)
1159
+						)
1160
+					);
1161
+					// we can also consider the TXN to not have been failed, so temporarily upgrade it's status to
1162
+					// abandoned
1163
+					$this->checkout->transaction->toggle_failed_transaction_status();
1164
+					// if we've gotten this far, then let's save what we have
1165
+					$registration->save();
1166
+					// add relation between TXN and registration
1167
+					$this->_associate_registration_with_transaction($registration);
1168
+				}
1169
+			} else {
1170
+				EE_Error::add_error(
1171
+					esc_html__(
1172
+						'An invalid or missing line item ID was encountered while attempting to process the registration form.',
1173
+						'event_espresso'
1174
+					),
1175
+					__FILE__,
1176
+					__FUNCTION__,
1177
+					__LINE__
1178
+				);
1179
+				// remove malformed data
1180
+				unset($valid_data[ $reg_url_link ]);
1181
+				return false;
1182
+			}
1183
+		} // end of foreach ( $this->checkout->transaction->registrations()  as $registration )
1184
+		return $att_nmbr;
1185
+	}
1186
+
1187
+
1188
+	/**
1189
+	 *    _save_registration_form_input
1190
+	 *
1191
+	 * @param EE_Registration $registration
1192
+	 * @param string          $form_input
1193
+	 * @param string          $input_value
1194
+	 * @return bool
1195
+	 * @throws EE_Error
1196
+	 * @throws InvalidArgumentException
1197
+	 * @throws InvalidDataTypeException
1198
+	 * @throws InvalidInterfaceException
1199
+	 * @throws ReflectionException
1200
+	 */
1201
+	private function _save_registration_form_input(
1202
+		EE_Registration $registration,
1203
+		$form_input = '',
1204
+		$input_value = ''
1205
+	) {
1206
+		// \EEH_Debug_Tools::printr( __FUNCTION__, __CLASS__, __FILE__, __LINE__, 2 );
1207
+		// \EEH_Debug_Tools::printr( $form_input, '$form_input', __FILE__, __LINE__ );
1208
+		// \EEH_Debug_Tools::printr( $input_value, '$input_value', __FILE__, __LINE__ );
1209
+		// allow for plugins to hook in and do their own processing of the form input.
1210
+		// For plugins to bypass normal processing here, they just need to return a boolean value.
1211
+		if (apply_filters(
1212
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information___save_registration_form_input',
1213
+			false,
1214
+			$registration,
1215
+			$form_input,
1216
+			$input_value,
1217
+			$this
1218
+		)) {
1219
+			return true;
1220
+		}
1221
+		/*
1222 1222
          * $answer_cache_id is the key used to find the EE_Answer we want
1223 1223
          * @see https://events.codebasehq.com/projects/event-espresso/tickets/10477
1224 1224
          */
1225
-        $answer_cache_id = $this->checkout->reg_url_link
1226
-            ? $form_input . '-' . $registration->reg_url_link()
1227
-            : $form_input;
1228
-        $answer_is_obj = isset($this->_registration_answers[ $answer_cache_id ])
1229
-                         && $this->_registration_answers[ $answer_cache_id ] instanceof EE_Answer;
1230
-        // rename form_inputs if they are EE_Attendee properties
1231
-        switch ((string) $form_input) {
1232
-            case 'state':
1233
-            case 'STA_ID':
1234
-                $attendee_property = true;
1235
-                $form_input = 'STA_ID';
1236
-                break;
1237
-
1238
-            case 'country':
1239
-            case 'CNT_ISO':
1240
-                $attendee_property = true;
1241
-                $form_input = 'CNT_ISO';
1242
-                break;
1243
-
1244
-            default:
1245
-                $ATT_input = 'ATT_' . $form_input;
1246
-                // EEH_Debug_Tools::printr( $ATT_input, '$ATT_input', __FILE__, __LINE__ );
1247
-                $attendee_property = EEM_Attendee::instance()->has_field($ATT_input) ? true : false;
1248
-                $form_input = $attendee_property ? 'ATT_' . $form_input : $form_input;
1249
-        }
1250
-        // EEH_Debug_Tools::printr( $answer_cache_id, '$answer_cache_id', __FILE__, __LINE__ );
1251
-        // EEH_Debug_Tools::printr( $attendee_property, '$attendee_property', __FILE__, __LINE__ );
1252
-        // EEH_Debug_Tools::printr( $answer_is_obj, '$answer_is_obj', __FILE__, __LINE__ );
1253
-        // if this form input has a corresponding attendee property
1254
-        if ($attendee_property) {
1255
-            $this->_attendee_data[ $registration->reg_url_link() ][ $form_input ] = $input_value;
1256
-            if ($answer_is_obj) {
1257
-                // and delete the corresponding answer since we won't be storing this data in that object
1258
-                $registration->_remove_relation_to($this->_registration_answers[ $answer_cache_id ], 'Answer');
1259
-                $this->_registration_answers[ $answer_cache_id ]->delete_permanently();
1260
-            }
1261
-            return true;
1262
-        }
1263
-        if ($answer_is_obj) {
1264
-            // save this data to the answer object
1265
-            $this->_registration_answers[ $answer_cache_id ]->set_value($input_value);
1266
-            $result = $this->_registration_answers[ $answer_cache_id ]->save();
1267
-            return $result !== false;
1268
-        }
1269
-        foreach ($this->_registration_answers as $answer) {
1270
-            if ($answer instanceof EE_Answer && $answer->question_ID() === $answer_cache_id) {
1271
-                $answer->set_value($input_value);
1272
-                $result = $answer->save();
1273
-                return $result !== false;
1274
-            }
1275
-        }
1276
-        return false;
1277
-    }
1278
-
1279
-
1280
-    /**
1281
-     *    _verify_critical_attendee_details_are_set
1282
-     *
1283
-     * @param string $form_input
1284
-     * @param string $input_value
1285
-     * @return boolean
1286
-     */
1287
-    private function _verify_critical_attendee_details_are_set_and_validate_email(
1288
-        $form_input = '',
1289
-        $input_value = ''
1290
-    ) {
1291
-        if (empty($input_value)) {
1292
-            // if the form input isn't marked as being required, then just return
1293
-            if (! isset($this->_required_questions[ $form_input ]) || ! $this->_required_questions[ $form_input ]) {
1294
-                return true;
1295
-            }
1296
-            switch ($form_input) {
1297
-                case 'fname':
1298
-                    EE_Error::add_error(
1299
-                        esc_html__('First Name is a required value.', 'event_espresso'),
1300
-                        __FILE__,
1301
-                        __FUNCTION__,
1302
-                        __LINE__
1303
-                    );
1304
-                    return false;
1305
-                    break;
1306
-                case 'lname':
1307
-                    EE_Error::add_error(
1308
-                        esc_html__('Last Name is a required value.', 'event_espresso'),
1309
-                        __FILE__,
1310
-                        __FUNCTION__,
1311
-                        __LINE__
1312
-                    );
1313
-                    return false;
1314
-                    break;
1315
-                case 'email':
1316
-                    EE_Error::add_error(
1317
-                        esc_html__('Please enter a valid email address.', 'event_espresso'),
1318
-                        __FILE__,
1319
-                        __FUNCTION__,
1320
-                        __LINE__
1321
-                    );
1322
-                    return false;
1323
-                    break;
1324
-            }
1325
-        }
1326
-        return true;
1327
-    }
1328
-
1329
-
1330
-    /**
1331
-     *    _associate_attendee_with_registration
1332
-     *
1333
-     * @param EE_Registration $registration
1334
-     * @param EE_Attendee     $attendee
1335
-     * @return void
1336
-     * @throws EE_Error
1337
-     * @throws InvalidArgumentException
1338
-     * @throws ReflectionException
1339
-     * @throws RuntimeException
1340
-     * @throws InvalidDataTypeException
1341
-     * @throws InvalidInterfaceException
1342
-     */
1343
-    private function _associate_attendee_with_registration(EE_Registration $registration, EE_Attendee $attendee)
1344
-    {
1345
-        // add relation to attendee
1346
-        $registration->_add_relation_to($attendee, 'Attendee');
1347
-        $registration->set_attendee_id($attendee->ID());
1348
-        $registration->update_cache_after_object_save('Attendee', $attendee);
1349
-    }
1350
-
1351
-
1352
-    /**
1353
-     *    _associate_registration_with_transaction
1354
-     *
1355
-     * @param EE_Registration $registration
1356
-     * @return void
1357
-     * @throws EE_Error
1358
-     * @throws InvalidArgumentException
1359
-     * @throws ReflectionException
1360
-     * @throws InvalidDataTypeException
1361
-     * @throws InvalidInterfaceException
1362
-     */
1363
-    private function _associate_registration_with_transaction(EE_Registration $registration)
1364
-    {
1365
-        // add relation to registration
1366
-        $this->checkout->transaction->_add_relation_to($registration, 'Registration');
1367
-        $this->checkout->transaction->update_cache_after_object_save('Registration', $registration);
1368
-    }
1369
-
1370
-
1371
-    /**
1372
-     *    _copy_critical_attendee_details_from_primary_registrant
1373
-     *    ensures that all attendees at least have data for first name, last name, and email address
1374
-     *
1375
-     * @param array $attendee_data
1376
-     * @return array
1377
-     * @throws EE_Error
1378
-     * @throws InvalidArgumentException
1379
-     * @throws ReflectionException
1380
-     * @throws InvalidDataTypeException
1381
-     * @throws InvalidInterfaceException
1382
-     */
1383
-    private function _copy_critical_attendee_details_from_primary_registrant($attendee_data = array())
1384
-    {
1385
-        // bare minimum critical details include first name, last name, email address
1386
-        $critical_attendee_details = array('ATT_fname', 'ATT_lname', 'ATT_email');
1387
-        // add address info to critical details?
1388
-        if (apply_filters(
1389
-            'FHEE__EE_SPCO_Reg_Step_Attendee_Information__merge_address_details_with_critical_attendee_details',
1390
-            false
1391
-        )) {
1392
-            $address_details = array(
1393
-                'ATT_address',
1394
-                'ATT_address2',
1395
-                'ATT_city',
1396
-                'STA_ID',
1397
-                'CNT_ISO',
1398
-                'ATT_zip',
1399
-                'ATT_phone',
1400
-            );
1401
-            $critical_attendee_details = array_merge($critical_attendee_details, $address_details);
1402
-        }
1403
-        foreach ($critical_attendee_details as $critical_attendee_detail) {
1404
-            if (! isset($attendee_data[ $critical_attendee_detail ])
1405
-                || empty($attendee_data[ $critical_attendee_detail ])
1406
-            ) {
1407
-                $attendee_data[ $critical_attendee_detail ] = $this->checkout->primary_attendee_obj->get(
1408
-                    $critical_attendee_detail
1409
-                );
1410
-            }
1411
-        }
1412
-        return $attendee_data;
1413
-    }
1414
-
1415
-
1416
-    /**
1417
-     *    update_reg_step
1418
-     *    this is the final step after a user  revisits the site to edit their attendee information
1419
-     *    this gets called AFTER the process_reg_step() method above
1420
-     *
1421
-     * @return bool
1422
-     * @throws EE_Error
1423
-     * @throws InvalidArgumentException
1424
-     * @throws ReflectionException
1425
-     * @throws RuntimeException
1426
-     * @throws InvalidDataTypeException
1427
-     * @throws InvalidInterfaceException
1428
-     */
1429
-    public function update_reg_step()
1430
-    {
1431
-        // save everything
1432
-        if ($this->process_reg_step()) {
1433
-            $this->checkout->redirect = true;
1434
-            $this->checkout->redirect_url = add_query_arg(
1435
-                array(
1436
-                    'e_reg_url_link' => $this->checkout->reg_url_link,
1437
-                    'revisit'        => true,
1438
-                ),
1439
-                $this->checkout->thank_you_page_url
1440
-            );
1441
-            $this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
1442
-            return true;
1443
-        }
1444
-        return false;
1445
-    }
1225
+		$answer_cache_id = $this->checkout->reg_url_link
1226
+			? $form_input . '-' . $registration->reg_url_link()
1227
+			: $form_input;
1228
+		$answer_is_obj = isset($this->_registration_answers[ $answer_cache_id ])
1229
+						 && $this->_registration_answers[ $answer_cache_id ] instanceof EE_Answer;
1230
+		// rename form_inputs if they are EE_Attendee properties
1231
+		switch ((string) $form_input) {
1232
+			case 'state':
1233
+			case 'STA_ID':
1234
+				$attendee_property = true;
1235
+				$form_input = 'STA_ID';
1236
+				break;
1237
+
1238
+			case 'country':
1239
+			case 'CNT_ISO':
1240
+				$attendee_property = true;
1241
+				$form_input = 'CNT_ISO';
1242
+				break;
1243
+
1244
+			default:
1245
+				$ATT_input = 'ATT_' . $form_input;
1246
+				// EEH_Debug_Tools::printr( $ATT_input, '$ATT_input', __FILE__, __LINE__ );
1247
+				$attendee_property = EEM_Attendee::instance()->has_field($ATT_input) ? true : false;
1248
+				$form_input = $attendee_property ? 'ATT_' . $form_input : $form_input;
1249
+		}
1250
+		// EEH_Debug_Tools::printr( $answer_cache_id, '$answer_cache_id', __FILE__, __LINE__ );
1251
+		// EEH_Debug_Tools::printr( $attendee_property, '$attendee_property', __FILE__, __LINE__ );
1252
+		// EEH_Debug_Tools::printr( $answer_is_obj, '$answer_is_obj', __FILE__, __LINE__ );
1253
+		// if this form input has a corresponding attendee property
1254
+		if ($attendee_property) {
1255
+			$this->_attendee_data[ $registration->reg_url_link() ][ $form_input ] = $input_value;
1256
+			if ($answer_is_obj) {
1257
+				// and delete the corresponding answer since we won't be storing this data in that object
1258
+				$registration->_remove_relation_to($this->_registration_answers[ $answer_cache_id ], 'Answer');
1259
+				$this->_registration_answers[ $answer_cache_id ]->delete_permanently();
1260
+			}
1261
+			return true;
1262
+		}
1263
+		if ($answer_is_obj) {
1264
+			// save this data to the answer object
1265
+			$this->_registration_answers[ $answer_cache_id ]->set_value($input_value);
1266
+			$result = $this->_registration_answers[ $answer_cache_id ]->save();
1267
+			return $result !== false;
1268
+		}
1269
+		foreach ($this->_registration_answers as $answer) {
1270
+			if ($answer instanceof EE_Answer && $answer->question_ID() === $answer_cache_id) {
1271
+				$answer->set_value($input_value);
1272
+				$result = $answer->save();
1273
+				return $result !== false;
1274
+			}
1275
+		}
1276
+		return false;
1277
+	}
1278
+
1279
+
1280
+	/**
1281
+	 *    _verify_critical_attendee_details_are_set
1282
+	 *
1283
+	 * @param string $form_input
1284
+	 * @param string $input_value
1285
+	 * @return boolean
1286
+	 */
1287
+	private function _verify_critical_attendee_details_are_set_and_validate_email(
1288
+		$form_input = '',
1289
+		$input_value = ''
1290
+	) {
1291
+		if (empty($input_value)) {
1292
+			// if the form input isn't marked as being required, then just return
1293
+			if (! isset($this->_required_questions[ $form_input ]) || ! $this->_required_questions[ $form_input ]) {
1294
+				return true;
1295
+			}
1296
+			switch ($form_input) {
1297
+				case 'fname':
1298
+					EE_Error::add_error(
1299
+						esc_html__('First Name is a required value.', 'event_espresso'),
1300
+						__FILE__,
1301
+						__FUNCTION__,
1302
+						__LINE__
1303
+					);
1304
+					return false;
1305
+					break;
1306
+				case 'lname':
1307
+					EE_Error::add_error(
1308
+						esc_html__('Last Name is a required value.', 'event_espresso'),
1309
+						__FILE__,
1310
+						__FUNCTION__,
1311
+						__LINE__
1312
+					);
1313
+					return false;
1314
+					break;
1315
+				case 'email':
1316
+					EE_Error::add_error(
1317
+						esc_html__('Please enter a valid email address.', 'event_espresso'),
1318
+						__FILE__,
1319
+						__FUNCTION__,
1320
+						__LINE__
1321
+					);
1322
+					return false;
1323
+					break;
1324
+			}
1325
+		}
1326
+		return true;
1327
+	}
1328
+
1329
+
1330
+	/**
1331
+	 *    _associate_attendee_with_registration
1332
+	 *
1333
+	 * @param EE_Registration $registration
1334
+	 * @param EE_Attendee     $attendee
1335
+	 * @return void
1336
+	 * @throws EE_Error
1337
+	 * @throws InvalidArgumentException
1338
+	 * @throws ReflectionException
1339
+	 * @throws RuntimeException
1340
+	 * @throws InvalidDataTypeException
1341
+	 * @throws InvalidInterfaceException
1342
+	 */
1343
+	private function _associate_attendee_with_registration(EE_Registration $registration, EE_Attendee $attendee)
1344
+	{
1345
+		// add relation to attendee
1346
+		$registration->_add_relation_to($attendee, 'Attendee');
1347
+		$registration->set_attendee_id($attendee->ID());
1348
+		$registration->update_cache_after_object_save('Attendee', $attendee);
1349
+	}
1350
+
1351
+
1352
+	/**
1353
+	 *    _associate_registration_with_transaction
1354
+	 *
1355
+	 * @param EE_Registration $registration
1356
+	 * @return void
1357
+	 * @throws EE_Error
1358
+	 * @throws InvalidArgumentException
1359
+	 * @throws ReflectionException
1360
+	 * @throws InvalidDataTypeException
1361
+	 * @throws InvalidInterfaceException
1362
+	 */
1363
+	private function _associate_registration_with_transaction(EE_Registration $registration)
1364
+	{
1365
+		// add relation to registration
1366
+		$this->checkout->transaction->_add_relation_to($registration, 'Registration');
1367
+		$this->checkout->transaction->update_cache_after_object_save('Registration', $registration);
1368
+	}
1369
+
1370
+
1371
+	/**
1372
+	 *    _copy_critical_attendee_details_from_primary_registrant
1373
+	 *    ensures that all attendees at least have data for first name, last name, and email address
1374
+	 *
1375
+	 * @param array $attendee_data
1376
+	 * @return array
1377
+	 * @throws EE_Error
1378
+	 * @throws InvalidArgumentException
1379
+	 * @throws ReflectionException
1380
+	 * @throws InvalidDataTypeException
1381
+	 * @throws InvalidInterfaceException
1382
+	 */
1383
+	private function _copy_critical_attendee_details_from_primary_registrant($attendee_data = array())
1384
+	{
1385
+		// bare minimum critical details include first name, last name, email address
1386
+		$critical_attendee_details = array('ATT_fname', 'ATT_lname', 'ATT_email');
1387
+		// add address info to critical details?
1388
+		if (apply_filters(
1389
+			'FHEE__EE_SPCO_Reg_Step_Attendee_Information__merge_address_details_with_critical_attendee_details',
1390
+			false
1391
+		)) {
1392
+			$address_details = array(
1393
+				'ATT_address',
1394
+				'ATT_address2',
1395
+				'ATT_city',
1396
+				'STA_ID',
1397
+				'CNT_ISO',
1398
+				'ATT_zip',
1399
+				'ATT_phone',
1400
+			);
1401
+			$critical_attendee_details = array_merge($critical_attendee_details, $address_details);
1402
+		}
1403
+		foreach ($critical_attendee_details as $critical_attendee_detail) {
1404
+			if (! isset($attendee_data[ $critical_attendee_detail ])
1405
+				|| empty($attendee_data[ $critical_attendee_detail ])
1406
+			) {
1407
+				$attendee_data[ $critical_attendee_detail ] = $this->checkout->primary_attendee_obj->get(
1408
+					$critical_attendee_detail
1409
+				);
1410
+			}
1411
+		}
1412
+		return $attendee_data;
1413
+	}
1414
+
1415
+
1416
+	/**
1417
+	 *    update_reg_step
1418
+	 *    this is the final step after a user  revisits the site to edit their attendee information
1419
+	 *    this gets called AFTER the process_reg_step() method above
1420
+	 *
1421
+	 * @return bool
1422
+	 * @throws EE_Error
1423
+	 * @throws InvalidArgumentException
1424
+	 * @throws ReflectionException
1425
+	 * @throws RuntimeException
1426
+	 * @throws InvalidDataTypeException
1427
+	 * @throws InvalidInterfaceException
1428
+	 */
1429
+	public function update_reg_step()
1430
+	{
1431
+		// save everything
1432
+		if ($this->process_reg_step()) {
1433
+			$this->checkout->redirect = true;
1434
+			$this->checkout->redirect_url = add_query_arg(
1435
+				array(
1436
+					'e_reg_url_link' => $this->checkout->reg_url_link,
1437
+					'revisit'        => true,
1438
+				),
1439
+				$this->checkout->thank_you_page_url
1440
+			);
1441
+			$this->checkout->json_response->set_redirect_url($this->checkout->redirect_url);
1442
+			return true;
1443
+		}
1444
+		return false;
1445
+	}
1446 1446
 }
Please login to merge, or discard this patch.
core/domain/services/registration/CopyRegistrationService.php 1 patch
Indentation   +141 added lines, -141 removed lines patch added patch discarded remove patch
@@ -27,151 +27,151 @@
 block discarded – undo
27 27
 {
28 28
 
29 29
 
30
-    /**
31
-     * @param EE_Registration $target_registration
32
-     * @param EE_Registration $registration_to_copy
33
-     * @return bool
34
-     * @throws UnexpectedEntityException
35
-     * @throws EntityNotFoundException
36
-     * @throws RuntimeException
37
-     * @throws EE_Error
38
-     */
39
-    public function copyRegistrationDetails(
40
-        EE_Registration $target_registration,
41
-        EE_Registration $registration_to_copy
42
-    ) {
43
-        // copy attendee
44
-        $target_registration->set_attendee_id($registration_to_copy->attendee_ID());
45
-        $target_registration->updateStatusBasedOnTotalPaid(false);
46
-        $target_registration->save();
47
-        // get answers to previous reg questions
48
-        $answers = $this->reindexAnswersByQuestionId($registration_to_copy->answers());
49
-        // get questions to new event reg form
50
-        $new_event = $target_registration->event();
51
-        $field_name = 'Event_Question_Group.'
52
-            . EEM_Event_Question_Group::instance()->fieldNameForContext(
53
-                $registration_to_copy->is_primary_registrant()
54
-            );
55
-        $question_groups = $new_event->question_groups([
56
-                [
57
-                    'Event.EVT_ID' => $new_event->ID(),
58
-                    $field_name => true,
59
-                ],
60
-                'order_by' => ['QSG_order' => 'ASC'],
61
-            ]);
62
-        foreach ($question_groups as $question_group) {
63
-            if ($question_group instanceof \EE_Question_Group) {
64
-                foreach ($question_group->questions() as $question) {
65
-                    if ($question instanceof EE_Question) {
66
-                        $this->generateNewAnswer(
67
-                            $question,
68
-                            $target_registration,
69
-                            $answers
70
-                        );
71
-                    }
72
-                }
73
-            }
74
-        }
75
-        return true;
76
-    }
30
+	/**
31
+	 * @param EE_Registration $target_registration
32
+	 * @param EE_Registration $registration_to_copy
33
+	 * @return bool
34
+	 * @throws UnexpectedEntityException
35
+	 * @throws EntityNotFoundException
36
+	 * @throws RuntimeException
37
+	 * @throws EE_Error
38
+	 */
39
+	public function copyRegistrationDetails(
40
+		EE_Registration $target_registration,
41
+		EE_Registration $registration_to_copy
42
+	) {
43
+		// copy attendee
44
+		$target_registration->set_attendee_id($registration_to_copy->attendee_ID());
45
+		$target_registration->updateStatusBasedOnTotalPaid(false);
46
+		$target_registration->save();
47
+		// get answers to previous reg questions
48
+		$answers = $this->reindexAnswersByQuestionId($registration_to_copy->answers());
49
+		// get questions to new event reg form
50
+		$new_event = $target_registration->event();
51
+		$field_name = 'Event_Question_Group.'
52
+			. EEM_Event_Question_Group::instance()->fieldNameForContext(
53
+				$registration_to_copy->is_primary_registrant()
54
+			);
55
+		$question_groups = $new_event->question_groups([
56
+				[
57
+					'Event.EVT_ID' => $new_event->ID(),
58
+					$field_name => true,
59
+				],
60
+				'order_by' => ['QSG_order' => 'ASC'],
61
+			]);
62
+		foreach ($question_groups as $question_group) {
63
+			if ($question_group instanceof \EE_Question_Group) {
64
+				foreach ($question_group->questions() as $question) {
65
+					if ($question instanceof EE_Question) {
66
+						$this->generateNewAnswer(
67
+							$question,
68
+							$target_registration,
69
+							$answers
70
+						);
71
+					}
72
+				}
73
+			}
74
+		}
75
+		return true;
76
+	}
77 77
 
78 78
 
79
-    /**
80
-     * @param EE_Answer[] $answers
81
-     * @return array
82
-     * @throws EE_Error
83
-     */
84
-    protected function reindexAnswersByQuestionId(array $answers)
85
-    {
86
-        $reindexed_answers = array();
87
-        foreach ($answers as $answer) {
88
-            if ($answer instanceof EE_Answer) {
89
-                $reindexed_answers[ $answer->question_ID() ] = $answer->value();
90
-            }
91
-        }
92
-        return $reindexed_answers;
93
-    }
79
+	/**
80
+	 * @param EE_Answer[] $answers
81
+	 * @return array
82
+	 * @throws EE_Error
83
+	 */
84
+	protected function reindexAnswersByQuestionId(array $answers)
85
+	{
86
+		$reindexed_answers = array();
87
+		foreach ($answers as $answer) {
88
+			if ($answer instanceof EE_Answer) {
89
+				$reindexed_answers[ $answer->question_ID() ] = $answer->value();
90
+			}
91
+		}
92
+		return $reindexed_answers;
93
+	}
94 94
 
95 95
 
96
-    /**
97
-     * @param EE_Question      $question
98
-     * @param EE_Registration  $registration
99
-     * @param                  $previous_answers
100
-     * @return EE_Answer
101
-     * @throws UnexpectedEntityException
102
-     * @throws EE_Error
103
-     */
104
-    protected function generateNewAnswer(
105
-        EE_Question $question,
106
-        EE_Registration $registration,
107
-        $previous_answers
108
-    ) {
109
-        $old_answer_value = isset($previous_answers[ $question->ID() ])
110
-            ? $previous_answers[ $question->ID() ]
111
-            : '';
112
-        $new_answer = EE_Answer::new_instance(
113
-            array(
114
-                'QST_ID'    => $question->ID(),
115
-                'REG_ID'    => $registration->ID(),
116
-                'ANS_value' => $old_answer_value,
117
-            )
118
-        );
119
-        if (! $new_answer instanceof EE_Answer) {
120
-            throw new UnexpectedEntityException($new_answer, 'EE_Answer');
121
-        }
122
-        $new_answer->save();
123
-        return $new_answer;
124
-    }
96
+	/**
97
+	 * @param EE_Question      $question
98
+	 * @param EE_Registration  $registration
99
+	 * @param                  $previous_answers
100
+	 * @return EE_Answer
101
+	 * @throws UnexpectedEntityException
102
+	 * @throws EE_Error
103
+	 */
104
+	protected function generateNewAnswer(
105
+		EE_Question $question,
106
+		EE_Registration $registration,
107
+		$previous_answers
108
+	) {
109
+		$old_answer_value = isset($previous_answers[ $question->ID() ])
110
+			? $previous_answers[ $question->ID() ]
111
+			: '';
112
+		$new_answer = EE_Answer::new_instance(
113
+			array(
114
+				'QST_ID'    => $question->ID(),
115
+				'REG_ID'    => $registration->ID(),
116
+				'ANS_value' => $old_answer_value,
117
+			)
118
+		);
119
+		if (! $new_answer instanceof EE_Answer) {
120
+			throw new UnexpectedEntityException($new_answer, 'EE_Answer');
121
+		}
122
+		$new_answer->save();
123
+		return $new_answer;
124
+	}
125 125
 
126 126
 
127
-    /**
128
-     * @param EE_Registration $target_registration
129
-     * @param EE_Registration $registration_to_copy
130
-     * @return bool
131
-     * @throws RuntimeException
132
-     * @throws UnexpectedEntityException
133
-     * @throws EE_Error
134
-     */
135
-    public function copyPaymentDetails(
136
-        EE_Registration $target_registration,
137
-        EE_Registration $registration_to_copy
138
-    ) {
139
-        $save = false;
140
-        $previous_registration_payments = $registration_to_copy->registration_payments();
141
-        $new_registration_payment_total = 0;
142
-        $registration_to_copy_total = $registration_to_copy->paid();
143
-        foreach ($previous_registration_payments as $previous_registration_payment) {
144
-            if ($previous_registration_payment instanceof EE_Registration_Payment
145
-                && $previous_registration_payment->payment() instanceof EE_Payment
146
-                && $previous_registration_payment->payment()->is_approved()
147
-            ) {
148
-                $payment_amount = $previous_registration_payment->amount();
149
-                $new_registration_payment = EE_Registration_Payment::new_instance(
150
-                    array(
151
-                        'REG_ID'     => $target_registration->ID(),
152
-                        'PAY_ID'     => $previous_registration_payment->payment()->ID(),
153
-                        'RPY_amount' => $payment_amount,
154
-                    )
155
-                );
156
-                if (! $new_registration_payment instanceof EE_Registration_Payment) {
157
-                    throw new UnexpectedEntityException($new_registration_payment, 'EE_Registration_Payment');
158
-                }
159
-                $new_registration_payment->save();
160
-                // if new reg payment is good, then set old reg payment amount to zero
161
-                $previous_registration_payment->set_amount(0);
162
-                $previous_registration_payment->save();
163
-                // now  increment/decrement payment amounts
164
-                $new_registration_payment_total += $payment_amount;
165
-                $registration_to_copy_total -= $payment_amount;
166
-                $save = true;
167
-            }
168
-        }
169
-        if ($save) {
170
-            $target_registration->set_paid($new_registration_payment_total);
171
-            $target_registration->save();
172
-            $registration_to_copy->set_paid($registration_to_copy_total);
173
-            $registration_to_copy->save();
174
-        }
175
-        return true;
176
-    }
127
+	/**
128
+	 * @param EE_Registration $target_registration
129
+	 * @param EE_Registration $registration_to_copy
130
+	 * @return bool
131
+	 * @throws RuntimeException
132
+	 * @throws UnexpectedEntityException
133
+	 * @throws EE_Error
134
+	 */
135
+	public function copyPaymentDetails(
136
+		EE_Registration $target_registration,
137
+		EE_Registration $registration_to_copy
138
+	) {
139
+		$save = false;
140
+		$previous_registration_payments = $registration_to_copy->registration_payments();
141
+		$new_registration_payment_total = 0;
142
+		$registration_to_copy_total = $registration_to_copy->paid();
143
+		foreach ($previous_registration_payments as $previous_registration_payment) {
144
+			if ($previous_registration_payment instanceof EE_Registration_Payment
145
+				&& $previous_registration_payment->payment() instanceof EE_Payment
146
+				&& $previous_registration_payment->payment()->is_approved()
147
+			) {
148
+				$payment_amount = $previous_registration_payment->amount();
149
+				$new_registration_payment = EE_Registration_Payment::new_instance(
150
+					array(
151
+						'REG_ID'     => $target_registration->ID(),
152
+						'PAY_ID'     => $previous_registration_payment->payment()->ID(),
153
+						'RPY_amount' => $payment_amount,
154
+					)
155
+				);
156
+				if (! $new_registration_payment instanceof EE_Registration_Payment) {
157
+					throw new UnexpectedEntityException($new_registration_payment, 'EE_Registration_Payment');
158
+				}
159
+				$new_registration_payment->save();
160
+				// if new reg payment is good, then set old reg payment amount to zero
161
+				$previous_registration_payment->set_amount(0);
162
+				$previous_registration_payment->save();
163
+				// now  increment/decrement payment amounts
164
+				$new_registration_payment_total += $payment_amount;
165
+				$registration_to_copy_total -= $payment_amount;
166
+				$save = true;
167
+			}
168
+		}
169
+		if ($save) {
170
+			$target_registration->set_paid($new_registration_payment_total);
171
+			$target_registration->save();
172
+			$registration_to_copy->set_paid($registration_to_copy_total);
173
+			$registration_to_copy->save();
174
+		}
175
+		return true;
176
+	}
177 177
 }
Please login to merge, or discard this patch.
4_10_0_stages/EE_DMS_4_10_0_Event_Question_Group.dmsstage.php 2 patches
Spacing   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -42,15 +42,15 @@  discard block
 block discarded – undo
42 42
             global $wpdb;
43 43
             $success = $wpdb->update(
44 44
                 $this->_old_table,
45
-                ['EQG_additional' => true],  // data
45
+                ['EQG_additional' => true], // data
46 46
                 [
47 47
                     'EVT_ID' => $event_question_group['EVT_ID'],
48 48
                     'QSG_ID' => $event_question_group['QSG_ID']
49
-                ],  // where
50
-                array( '%d' ),   // data format
51
-                array( '%d', '%d' )  // where format
49
+                ], // where
50
+                array('%d'), // data format
51
+                array('%d', '%d')  // where format
52 52
             );
53
-            if (! $success) {
53
+            if ( ! $success) {
54 54
                 $this->add_error(
55 55
                     sprintf(
56 56
                         __('Could not update event-question group relation for event "%1$s" and question group "%2$s" because "%3$s"', 'event_espresso'),
@@ -68,7 +68,7 @@  discard block
 block discarded – undo
68 68
                 ],
69 69
                 ['%d']
70 70
             );
71
-            if (! $successful_delete) {
71
+            if ( ! $successful_delete) {
72 72
                 $this->add_error(
73 73
                     sprintf(
74 74
                         __('Could not delete old event-question group relation row "%1$s" because "%2$s"', 'event_espresso'),
@@ -92,7 +92,7 @@  discard block
 block discarded – undo
92 92
     protected function _get_rows($limit)
93 93
     {
94 94
         global $wpdb;
95
-        $query = "SELECT * FROM {$this->_old_table} {$this->_extra_where_sql} " . $wpdb->prepare(
95
+        $query = "SELECT * FROM {$this->_old_table} {$this->_extra_where_sql} ".$wpdb->prepare(
96 96
             "LIMIT %d",
97 97
             $limit
98 98
         );
Please login to merge, or discard this patch.
Indentation   +79 added lines, -79 removed lines patch added patch discarded remove patch
@@ -14,86 +14,86 @@
 block discarded – undo
14 14
 
15 15
 
16 16
 
17
-    /**
18
-     * Just initializes the status of the migration
19
-     */
20
-    public function __construct()
21
-    {
22
-        global $wpdb;
23
-        $this->_pretty_name = __('Event-Question Group Relations', 'event_espresso');
24
-        $this->_old_table = $wpdb->prefix.'esp_event_question_group';
25
-        $this->_extra_where_sql = "WHERE EQG_primary = 0 AND EQG_additional=0";
26
-        parent::__construct();
27
-    }
17
+	/**
18
+	 * Just initializes the status of the migration
19
+	 */
20
+	public function __construct()
21
+	{
22
+		global $wpdb;
23
+		$this->_pretty_name = __('Event-Question Group Relations', 'event_espresso');
24
+		$this->_old_table = $wpdb->prefix.'esp_event_question_group';
25
+		$this->_extra_where_sql = "WHERE EQG_primary = 0 AND EQG_additional=0";
26
+		parent::__construct();
27
+	}
28 28
 
29 29
 
30
-    /**
31
-     * Removes the duplicate event_question_group rows that only had EQG_primary=0. Now we just have one row
32
-     * joining event-to-question-groups with two columns: EQG_primary and EQG_additional, indicating which question
33
-     * groups apply to which category of registrant.
34
-     * @param array $event_question_group an associative array where keys are column names and values are their values.
35
-     * @return null
36
-     */
37
-    protected function _migrate_old_row($event_question_group)
38
-    {
39
-        if (isset($event_question_group['EVT_ID'], $event_question_group['QSG_ID'])) {
40
-            global $wpdb;
41
-            $success = $wpdb->update(
42
-                $this->_old_table,
43
-                ['EQG_additional' => true],  // data
44
-                [
45
-                    'EVT_ID' => $event_question_group['EVT_ID'],
46
-                    'QSG_ID' => $event_question_group['QSG_ID']
47
-                ],  // where
48
-                array( '%d' ),   // data format
49
-                array( '%d', '%d' )  // where format
50
-            );
51
-            if (! $success) {
52
-                $this->add_error(
53
-                    sprintf(
54
-                        __('Could not update event-question group relation for event "%1$s" and question group "%2$s" because "%3$s"', 'event_espresso'),
55
-                        $event_question_group['EVT_ID'],
56
-                        $event_question_group['QSG_ID'],
57
-                        $wpdb->last_error
58
-                    )
59
-                );
60
-            }
61
-            // and delete the old row
62
-            $successful_delete = $wpdb->delete(
63
-                $this->_old_table,
64
-                [
65
-                    'EQG_ID' => $event_question_group['EQG_ID']
66
-                ],
67
-                ['%d']
68
-            );
69
-            if (! $successful_delete) {
70
-                $this->add_error(
71
-                    sprintf(
72
-                        __('Could not delete old event-question group relation row "%1$s" because "%2$s"', 'event_espresso'),
73
-                        wp_json_encode($event_question_group),
74
-                        $wpdb->last_error
75
-                    )
76
-                );
77
-            }
78
-        }
79
-    }
30
+	/**
31
+	 * Removes the duplicate event_question_group rows that only had EQG_primary=0. Now we just have one row
32
+	 * joining event-to-question-groups with two columns: EQG_primary and EQG_additional, indicating which question
33
+	 * groups apply to which category of registrant.
34
+	 * @param array $event_question_group an associative array where keys are column names and values are their values.
35
+	 * @return null
36
+	 */
37
+	protected function _migrate_old_row($event_question_group)
38
+	{
39
+		if (isset($event_question_group['EVT_ID'], $event_question_group['QSG_ID'])) {
40
+			global $wpdb;
41
+			$success = $wpdb->update(
42
+				$this->_old_table,
43
+				['EQG_additional' => true],  // data
44
+				[
45
+					'EVT_ID' => $event_question_group['EVT_ID'],
46
+					'QSG_ID' => $event_question_group['QSG_ID']
47
+				],  // where
48
+				array( '%d' ),   // data format
49
+				array( '%d', '%d' )  // where format
50
+			);
51
+			if (! $success) {
52
+				$this->add_error(
53
+					sprintf(
54
+						__('Could not update event-question group relation for event "%1$s" and question group "%2$s" because "%3$s"', 'event_espresso'),
55
+						$event_question_group['EVT_ID'],
56
+						$event_question_group['QSG_ID'],
57
+						$wpdb->last_error
58
+					)
59
+				);
60
+			}
61
+			// and delete the old row
62
+			$successful_delete = $wpdb->delete(
63
+				$this->_old_table,
64
+				[
65
+					'EQG_ID' => $event_question_group['EQG_ID']
66
+				],
67
+				['%d']
68
+			);
69
+			if (! $successful_delete) {
70
+				$this->add_error(
71
+					sprintf(
72
+						__('Could not delete old event-question group relation row "%1$s" because "%2$s"', 'event_espresso'),
73
+						wp_json_encode($event_question_group),
74
+						$wpdb->last_error
75
+					)
76
+				);
77
+			}
78
+		}
79
+	}
80 80
 
81
-    /**
82
-     * Gets the rows for the existing table that shouldn't exist in 4.10.
83
-     * Specifically the rows where EQG_primary=false and EQG_additional=false.
84
-     * Gotcha: because the migration is REMOVING rows as it goes, we shouldn't use the offset.
85
-     *
86
-     * @global wpdb $wpdb
87
-     * @param int   $limit
88
-     * @return array of arrays like $wpdb->get_results($sql, ARRAY_A)
89
-     */
90
-    protected function _get_rows($limit)
91
-    {
92
-        global $wpdb;
93
-        $query = "SELECT * FROM {$this->_old_table} {$this->_extra_where_sql} " . $wpdb->prepare(
94
-            "LIMIT %d",
95
-            $limit
96
-        );
97
-        return $wpdb->get_results($query, ARRAY_A);
98
-    }
81
+	/**
82
+	 * Gets the rows for the existing table that shouldn't exist in 4.10.
83
+	 * Specifically the rows where EQG_primary=false and EQG_additional=false.
84
+	 * Gotcha: because the migration is REMOVING rows as it goes, we shouldn't use the offset.
85
+	 *
86
+	 * @global wpdb $wpdb
87
+	 * @param int   $limit
88
+	 * @return array of arrays like $wpdb->get_results($sql, ARRAY_A)
89
+	 */
90
+	protected function _get_rows($limit)
91
+	{
92
+		global $wpdb;
93
+		$query = "SELECT * FROM {$this->_old_table} {$this->_extra_where_sql} " . $wpdb->prepare(
94
+			"LIMIT %d",
95
+			$limit
96
+		);
97
+		return $wpdb->get_results($query, ARRAY_A);
98
+	}
99 99
 }
Please login to merge, or discard this patch.
4_1_0_stages/EE_DMS_4_1_0_event_question_group.dmsstage.php 2 patches
Indentation   +104 added lines, -106 removed lines patch added patch discarded remove patch
@@ -16,15 +16,13 @@  discard block
 block discarded – undo
16 16
             'EQG_primary'=>new EE_Boolean_Field('EQG_primary', __('Flag indicating question is only for primary attendees','event_espresso'), false, false)
17 17
         )
18 18
     );
19
-
20
-
21 19
  *
22 20
  */
23 21
 class EE_DMS_4_1_0_event_question_group extends EE_Data_Migration_Script_Stage_Table
24 22
 {
25
-    private $_new_table;
26
-    public function _migrate_old_row($old_row)
27
-    {
23
+	private $_new_table;
24
+	public function _migrate_old_row($old_row)
25
+	{
28 26
 //      $txn_id = $this->get_migration_script()->get_mapping_new_pk($this->_old_table, $old_row['id'], $this->_new_transaction_table);
29 27
 //          if ( ! $txn_id ){
30 28
 //              $this->add_error(sprintf(__("Could not find the transaction for the 3.1 attendee %d from row %s", "event_espresso"),$old_row['id'],$this->_json_encode($old_row)));
@@ -34,8 +32,8 @@  discard block
 block discarded – undo
34 32
 //          $new_line_items = $this->_insert_new_line_items($txn,$old_row);
35 33
 //          $this->get_migration_script()->set_mapping($this->_old_table,$old_row['id'],$this->_new_line_table,$new_line_items);
36 34
 
37
-            $this->_insert_new_event_question_groups($old_row);
38
-    }
35
+			$this->_insert_new_event_question_groups($old_row);
36
+	}
39 37
 //  function _migration_step($num_items=50){
40 38
 //      global $wpdb;
41 39
 //      $start_at_record = $this->count_records_migrated();
@@ -55,109 +53,109 @@  discard block
 block discarded – undo
55 53
 //      $count = $wpdb->get_var("SELECT COUNT(id) FROM ".$this->_old_table);
56 54
 //      return $count;
57 55
 //  }
58
-    public function __construct()
59
-    {
60
-        global $wpdb;
61
-        $this->_old_table = $wpdb->prefix."events_detail";
62
-        $this->_extra_where_sql = 'WHERE event_status!="D"';
63
-        $this->_new_table = $wpdb->prefix."esp_event_question_group";
64
-        $this->_pretty_name = __("Question Groups in each Event", "event_espresso");
65
-        parent::__construct();
66
-    }
56
+	public function __construct()
57
+	{
58
+		global $wpdb;
59
+		$this->_old_table = $wpdb->prefix."events_detail";
60
+		$this->_extra_where_sql = 'WHERE event_status!="D"';
61
+		$this->_new_table = $wpdb->prefix."esp_event_question_group";
62
+		$this->_pretty_name = __("Question Groups in each Event", "event_espresso");
63
+		parent::__construct();
64
+	}
67 65
 
68
-    /**
69
-     * Attempts to insert a new question group inthe new format given an old one
70
-     * @global type $wpdb
71
-     * @param array $old_event
72
-     * @return void
73
-     */
74
-    private function _insert_new_event_question_groups($old_event)
75
-    {
76
-        $new_event_question_group_ids = array();
77
-        $question_groups_for_primary = maybe_unserialize($old_event['question_groups']);
78
-        if (is_array($question_groups_for_primary)) {
79
-            foreach ($question_groups_for_primary as $old_question_group_id) {
80
-                $new_id = $this->_insert_event_question_group($old_event, $old_question_group_id, true);
81
-                if ($new_id) {
82
-                    $new_event_question_group_ids[] = $new_id;
83
-                }
84
-            }
85
-        }
86
-        $event_meta = maybe_unserialize($old_event['event_meta']);
87
-        if (isset($event_meta['add_attendee_question_groups'])) {
88
-            if (is_array($event_meta['add_attendee_question_groups'])) {
89
-                foreach ($event_meta['add_attendee_question_groups'] as $old_question_group_id) {
90
-                    $new_id = $this->_insert_event_question_group($old_event, $old_question_group_id, false);
91
-                    if ($new_id) {
92
-                        $new_event_question_group_ids[] = $new_id;
93
-                    }
94
-                }
95
-            }
96
-        }
66
+	/**
67
+	 * Attempts to insert a new question group inthe new format given an old one
68
+	 * @global type $wpdb
69
+	 * @param array $old_event
70
+	 * @return void
71
+	 */
72
+	private function _insert_new_event_question_groups($old_event)
73
+	{
74
+		$new_event_question_group_ids = array();
75
+		$question_groups_for_primary = maybe_unserialize($old_event['question_groups']);
76
+		if (is_array($question_groups_for_primary)) {
77
+			foreach ($question_groups_for_primary as $old_question_group_id) {
78
+				$new_id = $this->_insert_event_question_group($old_event, $old_question_group_id, true);
79
+				if ($new_id) {
80
+					$new_event_question_group_ids[] = $new_id;
81
+				}
82
+			}
83
+		}
84
+		$event_meta = maybe_unserialize($old_event['event_meta']);
85
+		if (isset($event_meta['add_attendee_question_groups'])) {
86
+			if (is_array($event_meta['add_attendee_question_groups'])) {
87
+				foreach ($event_meta['add_attendee_question_groups'] as $old_question_group_id) {
88
+					$new_id = $this->_insert_event_question_group($old_event, $old_question_group_id, false);
89
+					if ($new_id) {
90
+						$new_event_question_group_ids[] = $new_id;
91
+					}
92
+				}
93
+			}
94
+		}
97 95
 
98 96
 
99
-        $this->get_migration_script()->set_mapping($this->_old_table, $old_event['id'], $this->_new_table, $new_event_question_group_ids);
100
-    }
97
+		$this->get_migration_script()->set_mapping($this->_old_table, $old_event['id'], $this->_new_table, $new_event_question_group_ids);
98
+	}
101 99
 
102
-    private function _insert_event_question_group($old_event, $old_question_group_id, $primary)
103
-    {
104
-        global $wpdb;
105
-        $new_question_group_id = $this->get_migration_script()->get_mapping_new_pk(
106
-            $wpdb->prefix . "events_qst_group",
107
-            intval($old_question_group_id),
108
-            $wpdb->prefix . "esp_question_group"
109
-        );
100
+	private function _insert_event_question_group($old_event, $old_question_group_id, $primary)
101
+	{
102
+		global $wpdb;
103
+		$new_question_group_id = $this->get_migration_script()->get_mapping_new_pk(
104
+			$wpdb->prefix . "events_qst_group",
105
+			intval($old_question_group_id),
106
+			$wpdb->prefix . "esp_question_group"
107
+		);
110 108
 
111
-        if (! $new_question_group_id) {
112
-            $this->add_error(
113
-                sprintf(
114
-                    // translators: %s question ID, %s event ID
115
-                    __("Could not find 4.1 question ID for 3.1 question id #%s on event $%s", "event_espresso"),
116
-                    $old_question_group_id,
117
-                    $old_event['id']
118
-                )
119
-            );
120
-            return 0;
121
-        }
122
-        $new_event_id = $this->get_migration_script()->get_mapping_new_pk(
123
-            $wpdb->prefix . "events_detail",
124
-            intval($old_event['id']),
125
-            $wpdb->posts
126
-        );
127
-        if (! $new_question_group_id) {
128
-            $this->add_error(
129
-                sprintf(
130
-                    // translators: %s event ID
131
-                    __("Could not find 4.1 event 3.1 event id #%s", "event_espresso"),
132
-                    $old_event['id']
133
-                )
134
-            );
135
-            return 0;
136
-        }
137
-        $cols_n_values = array(
138
-            'EVT_ID'=>$new_event_id,
139
-            'QSG_ID'=>$new_question_group_id,
140
-            'EQG_primary' => $primary
141
-        );
109
+		if (! $new_question_group_id) {
110
+			$this->add_error(
111
+				sprintf(
112
+					// translators: %s question ID, %s event ID
113
+					__("Could not find 4.1 question ID for 3.1 question id #%s on event $%s", "event_espresso"),
114
+					$old_question_group_id,
115
+					$old_event['id']
116
+				)
117
+			);
118
+			return 0;
119
+		}
120
+		$new_event_id = $this->get_migration_script()->get_mapping_new_pk(
121
+			$wpdb->prefix . "events_detail",
122
+			intval($old_event['id']),
123
+			$wpdb->posts
124
+		);
125
+		if (! $new_question_group_id) {
126
+			$this->add_error(
127
+				sprintf(
128
+					// translators: %s event ID
129
+					__("Could not find 4.1 event 3.1 event id #%s", "event_espresso"),
130
+					$old_event['id']
131
+				)
132
+			);
133
+			return 0;
134
+		}
135
+		$cols_n_values = array(
136
+			'EVT_ID'=>$new_event_id,
137
+			'QSG_ID'=>$new_question_group_id,
138
+			'EQG_primary' => $primary
139
+		);
142 140
 
143
-        $datatypes = array(
144
-            '%d',// EVT_ID
145
-            '%d',// QSG_ID
146
-            '%d',// EQG_primary
147
-        );
148
-        $success = $wpdb->insert($this->_new_table, $cols_n_values, $datatypes);
149
-        if (! $success) {
150
-            $this->add_error(
151
-                $this->get_migration_script()->_create_error_message_for_db_insertion(
152
-                    $this->_old_table,
153
-                    $old_event,
154
-                    $this->_new_table,
155
-                    $cols_n_values,
156
-                    $datatypes
157
-                )
158
-            );
159
-            return 0;
160
-        }
161
-        return $wpdb->insert_id;
162
-    }
141
+		$datatypes = array(
142
+			'%d',// EVT_ID
143
+			'%d',// QSG_ID
144
+			'%d',// EQG_primary
145
+		);
146
+		$success = $wpdb->insert($this->_new_table, $cols_n_values, $datatypes);
147
+		if (! $success) {
148
+			$this->add_error(
149
+				$this->get_migration_script()->_create_error_message_for_db_insertion(
150
+					$this->_old_table,
151
+					$old_event,
152
+					$this->_new_table,
153
+					$cols_n_values,
154
+					$datatypes
155
+				)
156
+			);
157
+			return 0;
158
+		}
159
+		return $wpdb->insert_id;
160
+	}
163 161
 }
Please login to merge, or discard this patch.
Spacing   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -103,12 +103,12 @@  discard block
 block discarded – undo
103 103
     {
104 104
         global $wpdb;
105 105
         $new_question_group_id = $this->get_migration_script()->get_mapping_new_pk(
106
-            $wpdb->prefix . "events_qst_group",
106
+            $wpdb->prefix."events_qst_group",
107 107
             intval($old_question_group_id),
108
-            $wpdb->prefix . "esp_question_group"
108
+            $wpdb->prefix."esp_question_group"
109 109
         );
110 110
 
111
-        if (! $new_question_group_id) {
111
+        if ( ! $new_question_group_id) {
112 112
             $this->add_error(
113 113
                 sprintf(
114 114
                     // translators: %s question ID, %s event ID
@@ -120,11 +120,11 @@  discard block
 block discarded – undo
120 120
             return 0;
121 121
         }
122 122
         $new_event_id = $this->get_migration_script()->get_mapping_new_pk(
123
-            $wpdb->prefix . "events_detail",
123
+            $wpdb->prefix."events_detail",
124 124
             intval($old_event['id']),
125 125
             $wpdb->posts
126 126
         );
127
-        if (! $new_question_group_id) {
127
+        if ( ! $new_question_group_id) {
128 128
             $this->add_error(
129 129
                 sprintf(
130 130
                     // translators: %s event ID
@@ -141,12 +141,12 @@  discard block
 block discarded – undo
141 141
         );
142 142
 
143 143
         $datatypes = array(
144
-            '%d',// EVT_ID
145
-            '%d',// QSG_ID
146
-            '%d',// EQG_primary
144
+            '%d', // EVT_ID
145
+            '%d', // QSG_ID
146
+            '%d', // EQG_primary
147 147
         );
148 148
         $success = $wpdb->insert($this->_new_table, $cols_n_values, $datatypes);
149
-        if (! $success) {
149
+        if ( ! $success) {
150 150
             $this->add_error(
151 151
                 $this->get_migration_script()->_create_error_message_for_db_insertion(
152 152
                     $this->_old_table,
Please login to merge, or discard this patch.
core/db_classes/EE_Registration.class.php 1 patch
Indentation   +2062 added lines, -2062 removed lines patch added patch discarded remove patch
@@ -17,2066 +17,2066 @@
 block discarded – undo
17 17
 {
18 18
 
19 19
 
20
-    /**
21
-     * Used to reference when a registration has never been checked in.
22
-     *
23
-     * @deprecated use \EE_Checkin::status_checked_never instead
24
-     * @type int
25
-     */
26
-    const checkin_status_never = 2;
27
-
28
-    /**
29
-     * Used to reference when a registration has been checked in.
30
-     *
31
-     * @deprecated use \EE_Checkin::status_checked_in instead
32
-     * @type int
33
-     */
34
-    const checkin_status_in = 1;
35
-
36
-
37
-    /**
38
-     * Used to reference when a registration has been checked out.
39
-     *
40
-     * @deprecated use \EE_Checkin::status_checked_out instead
41
-     * @type int
42
-     */
43
-    const checkin_status_out = 0;
44
-
45
-
46
-    /**
47
-     * extra meta key for tracking reg status os trashed registrations
48
-     *
49
-     * @type string
50
-     */
51
-    const PRE_TRASH_REG_STATUS_KEY = 'pre_trash_registration_status';
52
-
53
-
54
-    /**
55
-     * extra meta key for tracking if registration has reserved ticket
56
-     *
57
-     * @type string
58
-     */
59
-    const HAS_RESERVED_TICKET_KEY = 'has_reserved_ticket';
60
-
61
-
62
-    /**
63
-     * @param array  $props_n_values          incoming values
64
-     * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
65
-     *                                        used.)
66
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
67
-     *                                        date_format and the second value is the time format
68
-     * @return EE_Registration
69
-     * @throws EE_Error
70
-     */
71
-    public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
72
-    {
73
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
74
-        return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
75
-    }
76
-
77
-
78
-    /**
79
-     * @param array  $props_n_values  incoming values from the database
80
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
81
-     *                                the website will be used.
82
-     * @return EE_Registration
83
-     */
84
-    public static function new_instance_from_db($props_n_values = array(), $timezone = null)
85
-    {
86
-        return new self($props_n_values, true, $timezone);
87
-    }
88
-
89
-
90
-    /**
91
-     *        Set Event ID
92
-     *
93
-     * @param        int $EVT_ID Event ID
94
-     * @throws EE_Error
95
-     * @throws RuntimeException
96
-     */
97
-    public function set_event($EVT_ID = 0)
98
-    {
99
-        $this->set('EVT_ID', $EVT_ID);
100
-    }
101
-
102
-
103
-    /**
104
-     * Overrides parent set() method so that all calls to set( 'REG_code', $REG_code ) OR set( 'STS_ID', $STS_ID ) can
105
-     * be routed to internal methods
106
-     *
107
-     * @param string $field_name
108
-     * @param mixed  $field_value
109
-     * @param bool   $use_default
110
-     * @throws EE_Error
111
-     * @throws EntityNotFoundException
112
-     * @throws InvalidArgumentException
113
-     * @throws InvalidDataTypeException
114
-     * @throws InvalidInterfaceException
115
-     * @throws ReflectionException
116
-     * @throws RuntimeException
117
-     */
118
-    public function set($field_name, $field_value, $use_default = false)
119
-    {
120
-        switch ($field_name) {
121
-            case 'REG_code':
122
-                if (! empty($field_value) && $this->reg_code() === null) {
123
-                    $this->set_reg_code($field_value, $use_default);
124
-                }
125
-                break;
126
-            case 'STS_ID':
127
-                $this->set_status($field_value, $use_default);
128
-                break;
129
-            default:
130
-                parent::set($field_name, $field_value, $use_default);
131
-        }
132
-    }
133
-
134
-
135
-    /**
136
-     * Set Status ID
137
-     * updates the registration status and ALSO...
138
-     * calls reserve_registration_space() if the reg status changes TO approved from any other reg status
139
-     * calls release_registration_space() if the reg status changes FROM approved to any other reg status
140
-     *
141
-     * @param string                $new_STS_ID
142
-     * @param boolean               $use_default
143
-     * @param ContextInterface|null $context
144
-     * @return bool
145
-     * @throws EE_Error
146
-     * @throws EntityNotFoundException
147
-     * @throws InvalidArgumentException
148
-     * @throws ReflectionException
149
-     * @throws RuntimeException
150
-     * @throws InvalidDataTypeException
151
-     * @throws InvalidInterfaceException
152
-     */
153
-    public function set_status($new_STS_ID = null, $use_default = false, ContextInterface $context = null)
154
-    {
155
-        // get current REG_Status
156
-        $old_STS_ID = $this->status_ID();
157
-        // if status has changed
158
-        if ($old_STS_ID !== $new_STS_ID // and that status has actually changed
159
-            && ! empty($old_STS_ID) // and that old status is actually set
160
-            && ! empty($new_STS_ID) // as well as the new status
161
-            && $this->ID() // ensure registration is in the db
162
-        ) {
163
-            // update internal status first
164
-            parent::set('STS_ID', $new_STS_ID, $use_default);
165
-            // THEN handle other changes that occur when reg status changes
166
-            // TO approved
167
-            if ($new_STS_ID === EEM_Registration::status_id_approved) {
168
-                // reserve a space by incrementing ticket and datetime sold values
169
-                $this->_reserve_registration_space();
170
-                do_action('AHEE__EE_Registration__set_status__to_approved', $this, $old_STS_ID, $new_STS_ID, $context);
171
-                // OR FROM  approved
172
-            } elseif ($old_STS_ID === EEM_Registration::status_id_approved) {
173
-                // release a space by decrementing ticket and datetime sold values
174
-                $this->_release_registration_space();
175
-                do_action(
176
-                    'AHEE__EE_Registration__set_status__from_approved',
177
-                    $this,
178
-                    $old_STS_ID,
179
-                    $new_STS_ID,
180
-                    $context
181
-                );
182
-            }
183
-            $this->_update_if_canceled_or_declined($new_STS_ID, $old_STS_ID, $context);
184
-            if ($this->statusChangeUpdatesTransaction($context)) {
185
-                $this->updateTransactionAfterStatusChange();
186
-            }
187
-            do_action('AHEE__EE_Registration__set_status__after_update', $this, $old_STS_ID, $new_STS_ID, $context);
188
-            return true;
189
-        }
190
-        // even though the old value matches the new value, it's still good to
191
-        // allow the parent set method to have a say
192
-        parent::set('STS_ID', $new_STS_ID, $use_default);
193
-        return true;
194
-    }
195
-
196
-
197
-    /**
198
-     * update REGs and TXN when cancelled or declined registrations involved
199
-     *
200
-     * @param string                $new_STS_ID
201
-     * @param string                $old_STS_ID
202
-     * @param ContextInterface|null $context
203
-     * @throws EE_Error
204
-     * @throws InvalidArgumentException
205
-     * @throws InvalidDataTypeException
206
-     * @throws InvalidInterfaceException
207
-     * @throws ReflectionException
208
-     */
209
-    private function _update_if_canceled_or_declined($new_STS_ID, $old_STS_ID, ContextInterface $context = null)
210
-    {
211
-        // these reg statuses should not be considered in any calculations involving monies owing
212
-        $closed_reg_statuses = EEM_Registration::closed_reg_statuses();
213
-        // true if registration has been cancelled or declined
214
-        $this->updateIfCanceled(
215
-            $closed_reg_statuses,
216
-            $new_STS_ID,
217
-            $old_STS_ID,
218
-            $context
219
-        );
220
-        $this->updateIfDeclined(
221
-            $closed_reg_statuses,
222
-            $new_STS_ID,
223
-            $old_STS_ID,
224
-            $context
225
-        );
226
-    }
227
-
228
-
229
-    /**
230
-     * update REGs and TXN when cancelled or declined registrations involved
231
-     *
232
-     * @param array                 $closed_reg_statuses
233
-     * @param string                $new_STS_ID
234
-     * @param string                $old_STS_ID
235
-     * @param ContextInterface|null $context
236
-     * @throws EE_Error
237
-     * @throws InvalidArgumentException
238
-     * @throws InvalidDataTypeException
239
-     * @throws InvalidInterfaceException
240
-     * @throws ReflectionException
241
-     */
242
-    private function updateIfCanceled(
243
-        array $closed_reg_statuses,
244
-        $new_STS_ID,
245
-        $old_STS_ID,
246
-        ContextInterface $context = null
247
-    ) {
248
-        // true if registration has been cancelled or declined
249
-        if (in_array($new_STS_ID, $closed_reg_statuses, true)
250
-            && ! in_array($old_STS_ID, $closed_reg_statuses, true)
251
-        ) {
252
-            /** @type EE_Registration_Processor $registration_processor */
253
-            $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
254
-            /** @type EE_Transaction_Processor $transaction_processor */
255
-            $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
256
-            // cancelled or declined registration
257
-            $registration_processor->update_registration_after_being_canceled_or_declined(
258
-                $this,
259
-                $closed_reg_statuses
260
-            );
261
-            $transaction_processor->update_transaction_after_canceled_or_declined_registration(
262
-                $this,
263
-                $closed_reg_statuses,
264
-                false
265
-            );
266
-            do_action(
267
-                'AHEE__EE_Registration__set_status__canceled_or_declined',
268
-                $this,
269
-                $old_STS_ID,
270
-                $new_STS_ID,
271
-                $context
272
-            );
273
-            return;
274
-        }
275
-    }
276
-
277
-
278
-    /**
279
-     * update REGs and TXN when cancelled or declined registrations involved
280
-     *
281
-     * @param array                 $closed_reg_statuses
282
-     * @param string                $new_STS_ID
283
-     * @param string                $old_STS_ID
284
-     * @param ContextInterface|null $context
285
-     * @throws EE_Error
286
-     * @throws InvalidArgumentException
287
-     * @throws InvalidDataTypeException
288
-     * @throws InvalidInterfaceException
289
-     * @throws ReflectionException
290
-     */
291
-    private function updateIfDeclined(
292
-        array $closed_reg_statuses,
293
-        $new_STS_ID,
294
-        $old_STS_ID,
295
-        ContextInterface $context = null
296
-    ) {
297
-        // true if reinstating cancelled or declined registration
298
-        if (in_array($old_STS_ID, $closed_reg_statuses, true)
299
-            && ! in_array($new_STS_ID, $closed_reg_statuses, true)
300
-        ) {
301
-            /** @type EE_Registration_Processor $registration_processor */
302
-            $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
303
-            /** @type EE_Transaction_Processor $transaction_processor */
304
-            $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
305
-            // reinstating cancelled or declined registration
306
-            $registration_processor->update_canceled_or_declined_registration_after_being_reinstated(
307
-                $this,
308
-                $closed_reg_statuses
309
-            );
310
-            $transaction_processor->update_transaction_after_reinstating_canceled_registration(
311
-                $this,
312
-                $closed_reg_statuses,
313
-                false
314
-            );
315
-            do_action(
316
-                'AHEE__EE_Registration__set_status__after_reinstated',
317
-                $this,
318
-                $old_STS_ID,
319
-                $new_STS_ID,
320
-                $context
321
-            );
322
-        }
323
-    }
324
-
325
-
326
-    /**
327
-     * @param ContextInterface|null $context
328
-     * @return bool
329
-     */
330
-    private function statusChangeUpdatesTransaction(ContextInterface $context = null)
331
-    {
332
-        $contexts_that_do_not_update_transaction = (array) apply_filters(
333
-            'AHEE__EE_Registration__statusChangeUpdatesTransaction__contexts_that_do_not_update_transaction',
334
-            array('spco_reg_step_attendee_information_process_registrations'),
335
-            $context,
336
-            $this
337
-        );
338
-        return ! (
339
-            $context instanceof ContextInterface
340
-            && in_array($context->slug(), $contexts_that_do_not_update_transaction, true)
341
-        );
342
-    }
343
-
344
-
345
-    /**
346
-     * @throws EE_Error
347
-     * @throws EntityNotFoundException
348
-     * @throws InvalidArgumentException
349
-     * @throws InvalidDataTypeException
350
-     * @throws InvalidInterfaceException
351
-     * @throws ReflectionException
352
-     * @throws RuntimeException
353
-     */
354
-    private function updateTransactionAfterStatusChange()
355
-    {
356
-        /** @type EE_Transaction_Payments $transaction_payments */
357
-        $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
358
-        $transaction_payments->recalculate_transaction_total($this->transaction(), false);
359
-        $this->transaction()->update_status_based_on_total_paid(true);
360
-    }
361
-
362
-
363
-    /**
364
-     *        get Status ID
365
-     */
366
-    public function status_ID()
367
-    {
368
-        return $this->get('STS_ID');
369
-    }
370
-
371
-
372
-    /**
373
-     * Gets the ticket this registration is for
374
-     *
375
-     * @param boolean $include_archived whether to include archived tickets or not.
376
-     *
377
-     * @return EE_Ticket|EE_Base_Class
378
-     * @throws EE_Error
379
-     */
380
-    public function ticket($include_archived = true)
381
-    {
382
-        $query_params = array();
383
-        if ($include_archived) {
384
-            $query_params['default_where_conditions'] = 'none';
385
-        }
386
-        return $this->get_first_related('Ticket', $query_params);
387
-    }
388
-
389
-
390
-    /**
391
-     * Gets the event this registration is for
392
-     *
393
-     * @return EE_Event
394
-     * @throws EE_Error
395
-     * @throws EntityNotFoundException
396
-     */
397
-    public function event()
398
-    {
399
-        $event = $this->get_first_related('Event');
400
-        if (! $event instanceof \EE_Event) {
401
-            throw new EntityNotFoundException('Event ID', $this->event_ID());
402
-        }
403
-        return $event;
404
-    }
405
-
406
-
407
-    /**
408
-     * Gets the "author" of the registration.  Note that for the purposes of registrations, the author will correspond
409
-     * with the author of the event this registration is for.
410
-     *
411
-     * @since 4.5.0
412
-     * @return int
413
-     * @throws EE_Error
414
-     * @throws EntityNotFoundException
415
-     */
416
-    public function wp_user()
417
-    {
418
-        $event = $this->event();
419
-        if ($event instanceof EE_Event) {
420
-            return $event->wp_user();
421
-        }
422
-        return 0;
423
-    }
424
-
425
-
426
-    /**
427
-     * increments this registration's related ticket sold and corresponding datetime sold values
428
-     *
429
-     * @return void
430
-     * @throws DomainException
431
-     * @throws EE_Error
432
-     * @throws EntityNotFoundException
433
-     * @throws InvalidArgumentException
434
-     * @throws InvalidDataTypeException
435
-     * @throws InvalidInterfaceException
436
-     * @throws ReflectionException
437
-     * @throws UnexpectedEntityException
438
-     */
439
-    private function _reserve_registration_space()
440
-    {
441
-        // reserved ticket and datetime counts will be decremented as sold counts are incremented
442
-        // so stop tracking that this reg has a ticket reserved
443
-        $this->release_reserved_ticket(false, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
444
-        $ticket = $this->ticket();
445
-        $ticket->increase_sold();
446
-        $ticket->save();
447
-        // possibly set event status to sold out
448
-        $this->event()->perform_sold_out_status_check();
449
-    }
450
-
451
-
452
-    /**
453
-     * decrements (subtracts) this registration's related ticket sold and corresponding datetime sold values
454
-     *
455
-     * @return void
456
-     * @throws DomainException
457
-     * @throws EE_Error
458
-     * @throws EntityNotFoundException
459
-     * @throws InvalidArgumentException
460
-     * @throws InvalidDataTypeException
461
-     * @throws InvalidInterfaceException
462
-     * @throws ReflectionException
463
-     * @throws UnexpectedEntityException
464
-     */
465
-    private function _release_registration_space()
466
-    {
467
-        $ticket = $this->ticket();
468
-        $ticket->decrease_sold();
469
-        $ticket->save();
470
-        // possibly change event status from sold out back to previous status
471
-        $this->event()->perform_sold_out_status_check();
472
-    }
473
-
474
-
475
-    /**
476
-     * tracks this registration's ticket reservation in extra meta
477
-     * and can increment related ticket reserved and corresponding datetime reserved values
478
-     *
479
-     * @param bool $update_ticket if true, will increment ticket and datetime reserved count
480
-     * @return void
481
-     * @throws EE_Error
482
-     * @throws InvalidArgumentException
483
-     * @throws InvalidDataTypeException
484
-     * @throws InvalidInterfaceException
485
-     * @throws ReflectionException
486
-     */
487
-    public function reserve_ticket($update_ticket = false, $source = 'unknown')
488
-    {
489
-        // only reserve ticket if space is not currently reserved
490
-        if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) !== true) {
491
-            $this->update_extra_meta('reserve_ticket', "{$this->ticket_ID()} from {$source}");
492
-            // IMPORTANT !!!
493
-            // although checking $update_ticket first would be more efficient,
494
-            // we NEED to ALWAYS call update_extra_meta(), which is why that is done first
495
-            if ($this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true)
496
-                && $update_ticket
497
-            ) {
498
-                $ticket = $this->ticket();
499
-                $ticket->increase_reserved(1, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
500
-                $ticket->save();
501
-            }
502
-        }
503
-    }
504
-
505
-
506
-    /**
507
-     * stops tracking this registration's ticket reservation in extra meta
508
-     * decrements (subtracts) related ticket reserved and corresponding datetime reserved values
509
-     *
510
-     * @param bool $update_ticket if true, will decrement ticket and datetime reserved count
511
-     * @return void
512
-     * @throws EE_Error
513
-     * @throws InvalidArgumentException
514
-     * @throws InvalidDataTypeException
515
-     * @throws InvalidInterfaceException
516
-     * @throws ReflectionException
517
-     */
518
-    public function release_reserved_ticket($update_ticket = false, $source = 'unknown')
519
-    {
520
-        // only release ticket if space is currently reserved
521
-        if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) === true) {
522
-            $this->update_extra_meta('release_reserved_ticket', "{$this->ticket_ID()} from {$source}");
523
-            // IMPORTANT !!!
524
-            // although checking $update_ticket first would be more efficient,
525
-            // we NEED to ALWAYS call update_extra_meta(), which is why that is done first
526
-            if ($this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, false)
527
-                && $update_ticket
528
-            ) {
529
-                $ticket = $this->ticket();
530
-                $ticket->decrease_reserved(1, true, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
531
-                $ticket->save();
532
-            }
533
-        }
534
-    }
535
-
536
-
537
-    /**
538
-     * Set Attendee ID
539
-     *
540
-     * @param        int $ATT_ID Attendee ID
541
-     * @throws EE_Error
542
-     * @throws RuntimeException
543
-     */
544
-    public function set_attendee_id($ATT_ID = 0)
545
-    {
546
-        $this->set('ATT_ID', $ATT_ID);
547
-    }
548
-
549
-
550
-    /**
551
-     *        Set Transaction ID
552
-     *
553
-     * @param        int $TXN_ID Transaction ID
554
-     * @throws EE_Error
555
-     * @throws RuntimeException
556
-     */
557
-    public function set_transaction_id($TXN_ID = 0)
558
-    {
559
-        $this->set('TXN_ID', $TXN_ID);
560
-    }
561
-
562
-
563
-    /**
564
-     *        Set Session
565
-     *
566
-     * @param    string $REG_session PHP Session ID
567
-     * @throws EE_Error
568
-     * @throws RuntimeException
569
-     */
570
-    public function set_session($REG_session = '')
571
-    {
572
-        $this->set('REG_session', $REG_session);
573
-    }
574
-
575
-
576
-    /**
577
-     *        Set Registration URL Link
578
-     *
579
-     * @param    string $REG_url_link Registration URL Link
580
-     * @throws EE_Error
581
-     * @throws RuntimeException
582
-     */
583
-    public function set_reg_url_link($REG_url_link = '')
584
-    {
585
-        $this->set('REG_url_link', $REG_url_link);
586
-    }
587
-
588
-
589
-    /**
590
-     *        Set Attendee Counter
591
-     *
592
-     * @param        int $REG_count Primary Attendee
593
-     * @throws EE_Error
594
-     * @throws RuntimeException
595
-     */
596
-    public function set_count($REG_count = 1)
597
-    {
598
-        $this->set('REG_count', $REG_count);
599
-    }
600
-
601
-
602
-    /**
603
-     *        Set Group Size
604
-     *
605
-     * @param        boolean $REG_group_size Group Registration
606
-     * @throws EE_Error
607
-     * @throws RuntimeException
608
-     */
609
-    public function set_group_size($REG_group_size = false)
610
-    {
611
-        $this->set('REG_group_size', $REG_group_size);
612
-    }
613
-
614
-
615
-    /**
616
-     *    is_not_approved -  convenience method that returns TRUE if REG status ID ==
617
-     *    EEM_Registration::status_id_not_approved
618
-     *
619
-     * @return        boolean
620
-     */
621
-    public function is_not_approved()
622
-    {
623
-        return $this->status_ID() == EEM_Registration::status_id_not_approved ? true : false;
624
-    }
625
-
626
-
627
-    /**
628
-     *    is_pending_payment -  convenience method that returns TRUE if REG status ID ==
629
-     *    EEM_Registration::status_id_pending_payment
630
-     *
631
-     * @return        boolean
632
-     */
633
-    public function is_pending_payment()
634
-    {
635
-        return $this->status_ID() == EEM_Registration::status_id_pending_payment ? true : false;
636
-    }
637
-
638
-
639
-    /**
640
-     *    is_approved -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_approved
641
-     *
642
-     * @return        boolean
643
-     */
644
-    public function is_approved()
645
-    {
646
-        return $this->status_ID() == EEM_Registration::status_id_approved ? true : false;
647
-    }
648
-
649
-
650
-    /**
651
-     *    is_cancelled -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_cancelled
652
-     *
653
-     * @return        boolean
654
-     */
655
-    public function is_cancelled()
656
-    {
657
-        return $this->status_ID() == EEM_Registration::status_id_cancelled ? true : false;
658
-    }
659
-
660
-
661
-    /**
662
-     *    is_declined -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_declined
663
-     *
664
-     * @return        boolean
665
-     */
666
-    public function is_declined()
667
-    {
668
-        return $this->status_ID() == EEM_Registration::status_id_declined ? true : false;
669
-    }
670
-
671
-
672
-    /**
673
-     *    is_incomplete -  convenience method that returns TRUE if REG status ID ==
674
-     *    EEM_Registration::status_id_incomplete
675
-     *
676
-     * @return        boolean
677
-     */
678
-    public function is_incomplete()
679
-    {
680
-        return $this->status_ID() == EEM_Registration::status_id_incomplete ? true : false;
681
-    }
682
-
683
-
684
-    /**
685
-     *        Set Registration Date
686
-     *
687
-     * @param        mixed ( int or string ) $REG_date Registration Date - Unix timestamp or string representation of
688
-     *                                                 Date
689
-     * @throws EE_Error
690
-     * @throws RuntimeException
691
-     */
692
-    public function set_reg_date($REG_date = false)
693
-    {
694
-        $this->set('REG_date', $REG_date);
695
-    }
696
-
697
-
698
-    /**
699
-     *    Set final price owing for this registration after all ticket/price modifications
700
-     *
701
-     * @access    public
702
-     * @param    float $REG_final_price
703
-     * @throws EE_Error
704
-     * @throws RuntimeException
705
-     */
706
-    public function set_final_price($REG_final_price = 0.00)
707
-    {
708
-        $this->set('REG_final_price', $REG_final_price);
709
-    }
710
-
711
-
712
-    /**
713
-     *    Set amount paid towards this registration's final price
714
-     *
715
-     * @access    public
716
-     * @param    float $REG_paid
717
-     * @throws EE_Error
718
-     * @throws RuntimeException
719
-     */
720
-    public function set_paid($REG_paid = 0.00)
721
-    {
722
-        $this->set('REG_paid', $REG_paid);
723
-    }
724
-
725
-
726
-    /**
727
-     *        Attendee Is Going
728
-     *
729
-     * @param        boolean $REG_att_is_going Attendee Is Going
730
-     * @throws EE_Error
731
-     * @throws RuntimeException
732
-     */
733
-    public function set_att_is_going($REG_att_is_going = false)
734
-    {
735
-        $this->set('REG_att_is_going', $REG_att_is_going);
736
-    }
737
-
738
-
739
-    /**
740
-     * Gets the related attendee
741
-     *
742
-     * @return EE_Attendee
743
-     * @throws EE_Error
744
-     */
745
-    public function attendee()
746
-    {
747
-        return $this->get_first_related('Attendee');
748
-    }
749
-
750
-
751
-    /**
752
-     *        get Event ID
753
-     */
754
-    public function event_ID()
755
-    {
756
-        return $this->get('EVT_ID');
757
-    }
758
-
759
-
760
-    /**
761
-     *        get Event ID
762
-     */
763
-    public function event_name()
764
-    {
765
-        $event = $this->event_obj();
766
-        if ($event) {
767
-            return $event->name();
768
-        } else {
769
-            return null;
770
-        }
771
-    }
772
-
773
-
774
-    /**
775
-     * Fetches the event this registration is for
776
-     *
777
-     * @return EE_Event
778
-     * @throws EE_Error
779
-     */
780
-    public function event_obj()
781
-    {
782
-        return $this->get_first_related('Event');
783
-    }
784
-
785
-
786
-    /**
787
-     *        get Attendee ID
788
-     */
789
-    public function attendee_ID()
790
-    {
791
-        return $this->get('ATT_ID');
792
-    }
793
-
794
-
795
-    /**
796
-     *        get PHP Session ID
797
-     */
798
-    public function session_ID()
799
-    {
800
-        return $this->get('REG_session');
801
-    }
802
-
803
-
804
-    /**
805
-     * Gets the string which represents the URL trigger for the receipt template in the message template system.
806
-     *
807
-     * @param string $messenger 'pdf' or 'html'.  Default 'html'.
808
-     * @return string
809
-     */
810
-    public function receipt_url($messenger = 'html')
811
-    {
812
-
813
-        /**
814
-         * The below will be deprecated one version after this.  We check first if there is a custom receipt template
815
-         * already in use on old system.  If there is then we just return the standard url for it.
816
-         *
817
-         * @since 4.5.0
818
-         */
819
-        $template_relative_path = 'modules/gateways/Invoice/lib/templates/receipt_body.template.php';
820
-        $has_custom = EEH_Template::locate_template(
821
-            $template_relative_path,
822
-            array(),
823
-            true,
824
-            true,
825
-            true
826
-        );
827
-
828
-        if ($has_custom) {
829
-            return add_query_arg(array('receipt' => 'true'), $this->invoice_url('launch'));
830
-        }
831
-        return apply_filters('FHEE__EE_Registration__receipt_url__receipt_url', '', $this, $messenger, 'receipt');
832
-    }
833
-
834
-
835
-    /**
836
-     * Gets the string which represents the URL trigger for the invoice template in the message template system.
837
-     *
838
-     * @param string $messenger 'pdf' or 'html'.  Default 'html'.
839
-     * @return string
840
-     * @throws EE_Error
841
-     */
842
-    public function invoice_url($messenger = 'html')
843
-    {
844
-        /**
845
-         * The below will be deprecated one version after this.  We check first if there is a custom invoice template
846
-         * already in use on old system.  If there is then we just return the standard url for it.
847
-         *
848
-         * @since 4.5.0
849
-         */
850
-        $template_relative_path = 'modules/gateways/Invoice/lib/templates/invoice_body.template.php';
851
-        $has_custom = EEH_Template::locate_template(
852
-            $template_relative_path,
853
-            array(),
854
-            true,
855
-            true,
856
-            true
857
-        );
858
-
859
-        if ($has_custom) {
860
-            if ($messenger == 'html') {
861
-                return $this->invoice_url('launch');
862
-            }
863
-            $route = $messenger == 'download' || $messenger == 'pdf' ? 'download_invoice' : 'launch_invoice';
864
-
865
-            $query_args = array('ee' => $route, 'id' => $this->reg_url_link());
866
-            if ($messenger == 'html') {
867
-                $query_args['html'] = true;
868
-            }
869
-            return add_query_arg($query_args, get_permalink(EE_Registry::instance()->CFG->core->thank_you_page_id));
870
-        }
871
-        return apply_filters('FHEE__EE_Registration__invoice_url__invoice_url', '', $this, $messenger, 'invoice');
872
-    }
873
-
874
-
875
-    /**
876
-     * get Registration URL Link
877
-     *
878
-     * @access public
879
-     * @return string
880
-     * @throws EE_Error
881
-     */
882
-    public function reg_url_link()
883
-    {
884
-        return (string) $this->get('REG_url_link');
885
-    }
886
-
887
-
888
-    /**
889
-     * Echoes out invoice_url()
890
-     *
891
-     * @param string $type 'download','launch', or 'html' (default is 'launch')
892
-     * @return void
893
-     * @throws EE_Error
894
-     */
895
-    public function e_invoice_url($type = 'launch')
896
-    {
897
-        echo $this->invoice_url($type);
898
-    }
899
-
900
-
901
-    /**
902
-     * Echoes out payment_overview_url
903
-     */
904
-    public function e_payment_overview_url()
905
-    {
906
-        echo $this->payment_overview_url();
907
-    }
908
-
909
-
910
-    /**
911
-     * Gets the URL for the checkout payment options reg step
912
-     * with this registration's REG_url_link added as a query parameter
913
-     *
914
-     * @param bool $clear_session Set to true when you want to clear the session on revisiting the
915
-     *                            payment overview url.
916
-     * @return string
917
-     * @throws InvalidInterfaceException
918
-     * @throws InvalidDataTypeException
919
-     * @throws EE_Error
920
-     * @throws InvalidArgumentException
921
-     */
922
-    public function payment_overview_url($clear_session = false)
923
-    {
924
-        return add_query_arg(
925
-            (array) apply_filters(
926
-                'FHEE__EE_Registration__payment_overview_url__query_args',
927
-                array(
928
-                    'e_reg_url_link' => $this->reg_url_link(),
929
-                    'step'           => 'payment_options',
930
-                    'revisit'        => true,
931
-                    'clear_session'  => (bool) $clear_session,
932
-                ),
933
-                $this
934
-            ),
935
-            EE_Registry::instance()->CFG->core->reg_page_url()
936
-        );
937
-    }
938
-
939
-
940
-    /**
941
-     * Gets the URL for the checkout attendee information reg step
942
-     * with this registration's REG_url_link added as a query parameter
943
-     *
944
-     * @return string
945
-     * @throws InvalidInterfaceException
946
-     * @throws InvalidDataTypeException
947
-     * @throws EE_Error
948
-     * @throws InvalidArgumentException
949
-     */
950
-    public function edit_attendee_information_url()
951
-    {
952
-        return add_query_arg(
953
-            (array) apply_filters(
954
-                'FHEE__EE_Registration__edit_attendee_information_url__query_args',
955
-                array(
956
-                    'e_reg_url_link' => $this->reg_url_link(),
957
-                    'step'           => 'attendee_information',
958
-                    'revisit'        => true,
959
-                ),
960
-                $this
961
-            ),
962
-            EE_Registry::instance()->CFG->core->reg_page_url()
963
-        );
964
-    }
965
-
966
-
967
-    /**
968
-     * Simply generates and returns the appropriate admin_url link to edit this registration
969
-     *
970
-     * @return string
971
-     * @throws EE_Error
972
-     */
973
-    public function get_admin_edit_url()
974
-    {
975
-        return EEH_URL::add_query_args_and_nonce(
976
-            array(
977
-                'page'    => 'espresso_registrations',
978
-                'action'  => 'view_registration',
979
-                '_REG_ID' => $this->ID(),
980
-            ),
981
-            admin_url('admin.php')
982
-        );
983
-    }
984
-
985
-
986
-    /**
987
-     *    is_primary_registrant?
988
-     */
989
-    public function is_primary_registrant()
990
-    {
991
-        return $this->get('REG_count') === 1 ? true : false;
992
-    }
993
-
994
-
995
-    /**
996
-     * This returns the primary registration object for this registration group (which may be this object).
997
-     *
998
-     * @return EE_Registration
999
-     * @throws EE_Error
1000
-     */
1001
-    public function get_primary_registration()
1002
-    {
1003
-        if ($this->is_primary_registrant()) {
1004
-            return $this;
1005
-        }
1006
-
1007
-        // k reg_count !== 1 so let's get the EE_Registration object matching this txn_id and reg_count == 1
1008
-        /** @var EE_Registration $primary_registrant */
1009
-        $primary_registrant = EEM_Registration::instance()->get_one(
1010
-            array(
1011
-                array(
1012
-                    'TXN_ID'    => $this->transaction_ID(),
1013
-                    'REG_count' => 1,
1014
-                ),
1015
-            )
1016
-        );
1017
-        return $primary_registrant;
1018
-    }
1019
-
1020
-
1021
-    /**
1022
-     *        get  Attendee Number
1023
-     *
1024
-     * @access        public
1025
-     */
1026
-    public function count()
1027
-    {
1028
-        return $this->get('REG_count');
1029
-    }
1030
-
1031
-
1032
-    /**
1033
-     *        get Group Size
1034
-     */
1035
-    public function group_size()
1036
-    {
1037
-        return $this->get('REG_group_size');
1038
-    }
1039
-
1040
-
1041
-    /**
1042
-     *        get Registration Date
1043
-     */
1044
-    public function date()
1045
-    {
1046
-        return $this->get('REG_date');
1047
-    }
1048
-
1049
-
1050
-    /**
1051
-     * gets a pretty date
1052
-     *
1053
-     * @param string $date_format
1054
-     * @param string $time_format
1055
-     * @return string
1056
-     * @throws EE_Error
1057
-     */
1058
-    public function pretty_date($date_format = null, $time_format = null)
1059
-    {
1060
-        return $this->get_datetime('REG_date', $date_format, $time_format);
1061
-    }
1062
-
1063
-
1064
-    /**
1065
-     * final_price
1066
-     * the registration's share of the transaction total, so that the
1067
-     * sum of all the transaction's REG_final_prices equal the transaction's total
1068
-     *
1069
-     * @return float
1070
-     * @throws EE_Error
1071
-     */
1072
-    public function final_price()
1073
-    {
1074
-        return $this->get('REG_final_price');
1075
-    }
1076
-
1077
-
1078
-    /**
1079
-     * pretty_final_price
1080
-     *  final price as formatted string, with correct decimal places and currency symbol
1081
-     *
1082
-     * @return string
1083
-     * @throws EE_Error
1084
-     */
1085
-    public function pretty_final_price()
1086
-    {
1087
-        return $this->get_pretty('REG_final_price');
1088
-    }
1089
-
1090
-
1091
-    /**
1092
-     * get paid (yeah)
1093
-     *
1094
-     * @return float
1095
-     * @throws EE_Error
1096
-     */
1097
-    public function paid()
1098
-    {
1099
-        return $this->get('REG_paid');
1100
-    }
1101
-
1102
-
1103
-    /**
1104
-     * pretty_paid
1105
-     *
1106
-     * @return float
1107
-     * @throws EE_Error
1108
-     */
1109
-    public function pretty_paid()
1110
-    {
1111
-        return $this->get_pretty('REG_paid');
1112
-    }
1113
-
1114
-
1115
-    /**
1116
-     * owes_monies_and_can_pay
1117
-     * whether or not this registration has monies owing and it's' status allows payment
1118
-     *
1119
-     * @param array $requires_payment
1120
-     * @return bool
1121
-     * @throws EE_Error
1122
-     */
1123
-    public function owes_monies_and_can_pay($requires_payment = array())
1124
-    {
1125
-        // these reg statuses require payment (if event is not free)
1126
-        $requires_payment = ! empty($requires_payment)
1127
-            ? $requires_payment
1128
-            : EEM_Registration::reg_statuses_that_allow_payment();
1129
-        if (in_array($this->status_ID(), $requires_payment) &&
1130
-            $this->final_price() != 0 &&
1131
-            $this->final_price() != $this->paid()
1132
-        ) {
1133
-            return true;
1134
-        } else {
1135
-            return false;
1136
-        }
1137
-    }
1138
-
1139
-
1140
-    /**
1141
-     * Prints out the return value of $this->pretty_status()
1142
-     *
1143
-     * @param bool $show_icons
1144
-     * @return void
1145
-     * @throws EE_Error
1146
-     */
1147
-    public function e_pretty_status($show_icons = false)
1148
-    {
1149
-        echo $this->pretty_status($show_icons);
1150
-    }
1151
-
1152
-
1153
-    /**
1154
-     * Returns a nice version of the status for displaying to customers
1155
-     *
1156
-     * @param bool $show_icons
1157
-     * @return string
1158
-     * @throws EE_Error
1159
-     */
1160
-    public function pretty_status($show_icons = false)
1161
-    {
1162
-        $status = EEM_Status::instance()->localized_status(
1163
-            array($this->status_ID() => esc_html__('unknown', 'event_espresso')),
1164
-            false,
1165
-            'sentence'
1166
-        );
1167
-        $icon = '';
1168
-        switch ($this->status_ID()) {
1169
-            case EEM_Registration::status_id_approved:
1170
-                $icon = $show_icons
1171
-                    ? '<span class="dashicons dashicons-star-filled ee-icon-size-16 green-text"></span>'
1172
-                    : '';
1173
-                break;
1174
-            case EEM_Registration::status_id_pending_payment:
1175
-                $icon = $show_icons
1176
-                    ? '<span class="dashicons dashicons-star-half ee-icon-size-16 orange-text"></span>'
1177
-                    : '';
1178
-                break;
1179
-            case EEM_Registration::status_id_not_approved:
1180
-                $icon = $show_icons
1181
-                    ? '<span class="dashicons dashicons-marker ee-icon-size-16 orange-text"></span>'
1182
-                    : '';
1183
-                break;
1184
-            case EEM_Registration::status_id_cancelled:
1185
-                $icon = $show_icons
1186
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 lt-grey-text"></span>'
1187
-                    : '';
1188
-                break;
1189
-            case EEM_Registration::status_id_incomplete:
1190
-                $icon = $show_icons
1191
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 lt-orange-text"></span>'
1192
-                    : '';
1193
-                break;
1194
-            case EEM_Registration::status_id_declined:
1195
-                $icon = $show_icons
1196
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>'
1197
-                    : '';
1198
-                break;
1199
-            case EEM_Registration::status_id_wait_list:
1200
-                $icon = $show_icons
1201
-                    ? '<span class="dashicons dashicons-clipboard ee-icon-size-16 purple-text"></span>'
1202
-                    : '';
1203
-                break;
1204
-        }
1205
-        return $icon . $status[ $this->status_ID() ];
1206
-    }
1207
-
1208
-
1209
-    /**
1210
-     *        get Attendee Is Going
1211
-     */
1212
-    public function att_is_going()
1213
-    {
1214
-        return $this->get('REG_att_is_going');
1215
-    }
1216
-
1217
-
1218
-    /**
1219
-     * Gets related answers
1220
-     *
1221
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1222
-     * @return EE_Answer[]
1223
-     * @throws EE_Error
1224
-     */
1225
-    public function answers($query_params = null)
1226
-    {
1227
-        return $this->get_many_related('Answer', $query_params);
1228
-    }
1229
-
1230
-
1231
-    /**
1232
-     * Gets the registration's answer value to the specified question
1233
-     * (either the question's ID or a question object)
1234
-     *
1235
-     * @param EE_Question|int $question
1236
-     * @param bool            $pretty_value
1237
-     * @return array|string if pretty_value= true, the result will always be a string
1238
-     * (because the answer might be an array of answer values, so passing pretty_value=true
1239
-     * will convert it into some kind of string)
1240
-     * @throws EE_Error
1241
-     */
1242
-    public function answer_value_to_question($question, $pretty_value = true)
1243
-    {
1244
-        $question_id = EEM_Question::instance()->ensure_is_ID($question);
1245
-        return EEM_Answer::instance()->get_answer_value_to_question($this, $question_id, $pretty_value);
1246
-    }
1247
-
1248
-
1249
-    /**
1250
-     * question_groups
1251
-     * returns an array of EE_Question_Group objects for this registration
1252
-     *
1253
-     * @return EE_Question_Group[]
1254
-     * @throws EE_Error
1255
-     * @throws InvalidArgumentException
1256
-     * @throws InvalidDataTypeException
1257
-     * @throws InvalidInterfaceException
1258
-     * @throws ReflectionException
1259
-     */
1260
-    public function question_groups()
1261
-    {
1262
-        return EEM_Event::instance()->get_question_groups_for_event($this->event_ID(), $this);
1263
-    }
1264
-
1265
-
1266
-    /**
1267
-     * count_question_groups
1268
-     * returns a count of the number of EE_Question_Group objects for this registration
1269
-     *
1270
-     * @return int
1271
-     * @throws EE_Error
1272
-     * @throws EntityNotFoundException
1273
-     * @throws InvalidArgumentException
1274
-     * @throws InvalidDataTypeException
1275
-     * @throws InvalidInterfaceException
1276
-     * @throws ReflectionException
1277
-     */
1278
-    public function count_question_groups()
1279
-    {
1280
-        return EEM_Event::instance()->count_related(
1281
-            $this->event_ID(),
1282
-            'Question_Group',
1283
-            [
1284
-                [
1285
-                    'Event_Question_Group.'
1286
-                    . EEM_Event_Question_Group::instance()->fieldNameForContext($this->is_primary_registrant()) => true,
1287
-                ]
1288
-            ]
1289
-        );
1290
-    }
1291
-
1292
-
1293
-    /**
1294
-     * Returns the registration date in the 'standard' string format
1295
-     * (function may be improved in the future to allow for different formats and timezones)
1296
-     *
1297
-     * @return string
1298
-     * @throws EE_Error
1299
-     */
1300
-    public function reg_date()
1301
-    {
1302
-        return $this->get_datetime('REG_date');
1303
-    }
1304
-
1305
-
1306
-    /**
1307
-     * Gets the datetime-ticket for this registration (ie, it can be used to isolate
1308
-     * the ticket this registration purchased, or the datetime they have registered
1309
-     * to attend)
1310
-     *
1311
-     * @return EE_Datetime_Ticket
1312
-     * @throws EE_Error
1313
-     */
1314
-    public function datetime_ticket()
1315
-    {
1316
-        return $this->get_first_related('Datetime_Ticket');
1317
-    }
1318
-
1319
-
1320
-    /**
1321
-     * Sets the registration's datetime_ticket.
1322
-     *
1323
-     * @param EE_Datetime_Ticket $datetime_ticket
1324
-     * @return EE_Datetime_Ticket
1325
-     * @throws EE_Error
1326
-     */
1327
-    public function set_datetime_ticket($datetime_ticket)
1328
-    {
1329
-        return $this->_add_relation_to($datetime_ticket, 'Datetime_Ticket');
1330
-    }
1331
-
1332
-    /**
1333
-     * Gets deleted
1334
-     *
1335
-     * @return bool
1336
-     * @throws EE_Error
1337
-     */
1338
-    public function deleted()
1339
-    {
1340
-        return $this->get('REG_deleted');
1341
-    }
1342
-
1343
-    /**
1344
-     * Sets deleted
1345
-     *
1346
-     * @param boolean $deleted
1347
-     * @return bool
1348
-     * @throws EE_Error
1349
-     * @throws RuntimeException
1350
-     */
1351
-    public function set_deleted($deleted)
1352
-    {
1353
-        if ($deleted) {
1354
-            $this->delete();
1355
-        } else {
1356
-            $this->restore();
1357
-        }
1358
-    }
1359
-
1360
-
1361
-    /**
1362
-     * Get the status object of this object
1363
-     *
1364
-     * @return EE_Status
1365
-     * @throws EE_Error
1366
-     */
1367
-    public function status_obj()
1368
-    {
1369
-        return $this->get_first_related('Status');
1370
-    }
1371
-
1372
-
1373
-    /**
1374
-     * Returns the number of times this registration has checked into any of the datetimes
1375
-     * its available for
1376
-     *
1377
-     * @return int
1378
-     * @throws EE_Error
1379
-     */
1380
-    public function count_checkins()
1381
-    {
1382
-        return $this->get_model()->count_related($this, 'Checkin');
1383
-    }
1384
-
1385
-
1386
-    /**
1387
-     * Returns the number of current Check-ins this registration is checked into for any of the datetimes the
1388
-     * registration is for.  Note, this is ONLY checked in (does not include checkedout)
1389
-     *
1390
-     * @return int
1391
-     * @throws EE_Error
1392
-     */
1393
-    public function count_checkins_not_checkedout()
1394
-    {
1395
-        return $this->get_model()->count_related($this, 'Checkin', array(array('CHK_in' => 1)));
1396
-    }
1397
-
1398
-
1399
-    /**
1400
-     * The purpose of this method is simply to check whether this registration can checkin to the given datetime.
1401
-     *
1402
-     * @param int | EE_Datetime $DTT_OR_ID      The datetime the registration is being checked against
1403
-     * @param bool              $check_approved This is used to indicate whether the caller wants can_checkin to also
1404
-     *                                          consider registration status as well as datetime access.
1405
-     * @return bool
1406
-     * @throws EE_Error
1407
-     */
1408
-    public function can_checkin($DTT_OR_ID, $check_approved = true)
1409
-    {
1410
-        $DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1411
-
1412
-        // first check registration status
1413
-        if (($check_approved && ! $this->is_approved()) || ! $DTT_ID) {
1414
-            return false;
1415
-        }
1416
-        // is there a datetime ticket that matches this dtt_ID?
1417
-        if (! (EEM_Datetime_Ticket::instance()->exists(
1418
-            array(
1419
-                array(
1420
-                    'TKT_ID' => $this->get('TKT_ID'),
1421
-                    'DTT_ID' => $DTT_ID,
1422
-                ),
1423
-            )
1424
-        ))
1425
-        ) {
1426
-            return false;
1427
-        }
1428
-
1429
-        // final check is against TKT_uses
1430
-        return $this->verify_can_checkin_against_TKT_uses($DTT_ID);
1431
-    }
1432
-
1433
-
1434
-    /**
1435
-     * This method verifies whether the user can checkin for the given datetime considering the max uses value set on
1436
-     * the ticket. To do this,  a query is done to get the count of the datetime records already checked into.  If the
1437
-     * datetime given does not have a check-in record and checking in for that datetime will exceed the allowed uses,
1438
-     * then return false.  Otherwise return true.
1439
-     *
1440
-     * @param int | EE_Datetime $DTT_OR_ID The datetime the registration is being checked against
1441
-     * @return bool true means can checkin.  false means cannot checkin.
1442
-     * @throws EE_Error
1443
-     */
1444
-    public function verify_can_checkin_against_TKT_uses($DTT_OR_ID)
1445
-    {
1446
-        $DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1447
-
1448
-        if (! $DTT_ID) {
1449
-            return false;
1450
-        }
1451
-
1452
-        $max_uses = $this->ticket() instanceof EE_Ticket ? $this->ticket()->uses() : EE_INF;
1453
-
1454
-        // if max uses is not set or equals infinity then return true cause its not a factor for whether user can
1455
-        // check-in or not.
1456
-        if (! $max_uses || $max_uses === EE_INF) {
1457
-            return true;
1458
-        }
1459
-
1460
-        // does this datetime have a checkin record?  If so, then the dtt count has already been verified so we can just
1461
-        // go ahead and toggle.
1462
-        if (EEM_Checkin::instance()->exists(array(array('REG_ID' => $this->ID(), 'DTT_ID' => $DTT_ID)))) {
1463
-            return true;
1464
-        }
1465
-
1466
-        // made it here so the last check is whether the number of checkins per unique datetime on this registration
1467
-        // disallows further check-ins.
1468
-        $count_unique_dtt_checkins = EEM_Checkin::instance()->count(
1469
-            array(
1470
-                array(
1471
-                    'REG_ID' => $this->ID(),
1472
-                    'CHK_in' => true,
1473
-                ),
1474
-            ),
1475
-            'DTT_ID',
1476
-            true
1477
-        );
1478
-        // checkins have already reached their max number of uses
1479
-        // so registrant can NOT checkin
1480
-        if ($count_unique_dtt_checkins >= $max_uses) {
1481
-            EE_Error::add_error(
1482
-                esc_html__(
1483
-                    'Check-in denied because number of datetime uses for the ticket has been reached or exceeded.',
1484
-                    'event_espresso'
1485
-                ),
1486
-                __FILE__,
1487
-                __FUNCTION__,
1488
-                __LINE__
1489
-            );
1490
-            return false;
1491
-        }
1492
-        return true;
1493
-    }
1494
-
1495
-
1496
-    /**
1497
-     * toggle Check-in status for this registration
1498
-     * Check-ins are toggled in the following order:
1499
-     * never checked in -> checked in
1500
-     * checked in -> checked out
1501
-     * checked out -> checked in
1502
-     *
1503
-     * @param  int $DTT_ID  include specific datetime to toggle Check-in for.
1504
-     *                      If not included or null, then it is assumed latest datetime is being toggled.
1505
-     * @param bool $verify  If true then can_checkin() is used to verify whether the person
1506
-     *                      can be checked in or not.  Otherwise this forces change in checkin status.
1507
-     * @return bool|int     the chk_in status toggled to OR false if nothing got changed.
1508
-     * @throws EE_Error
1509
-     */
1510
-    public function toggle_checkin_status($DTT_ID = null, $verify = false)
1511
-    {
1512
-        if (empty($DTT_ID)) {
1513
-            $datetime = $this->get_latest_related_datetime();
1514
-            $DTT_ID = $datetime instanceof EE_Datetime ? $datetime->ID() : 0;
1515
-            // verify the registration can checkin for the given DTT_ID
1516
-        } elseif (! $this->can_checkin($DTT_ID, $verify)) {
1517
-            EE_Error::add_error(
1518
-                sprintf(
1519
-                    esc_html__(
1520
-                        'The given registration (ID:%1$d) can not be checked in to the given DTT_ID (%2$d), because the registration does not have access',
1521
-                        'event_espresso'
1522
-                    ),
1523
-                    $this->ID(),
1524
-                    $DTT_ID
1525
-                ),
1526
-                __FILE__,
1527
-                __FUNCTION__,
1528
-                __LINE__
1529
-            );
1530
-            return false;
1531
-        }
1532
-        $status_paths = array(
1533
-            EE_Checkin::status_checked_never => EE_Checkin::status_checked_in,
1534
-            EE_Checkin::status_checked_in    => EE_Checkin::status_checked_out,
1535
-            EE_Checkin::status_checked_out   => EE_Checkin::status_checked_in,
1536
-        );
1537
-        // start by getting the current status so we know what status we'll be changing to.
1538
-        $cur_status = $this->check_in_status_for_datetime($DTT_ID, null);
1539
-        $status_to = $status_paths[ $cur_status ];
1540
-        // database only records true for checked IN or false for checked OUT
1541
-        // no record ( null ) means checked in NEVER, but we obviously don't save that
1542
-        $new_status = $status_to === EE_Checkin::status_checked_in ? true : false;
1543
-        // add relation - note Check-ins are always creating new rows
1544
-        // because we are keeping track of Check-ins over time.
1545
-        // Eventually we'll probably want to show a list table
1546
-        // for the individual Check-ins so that they can be managed.
1547
-        $checkin = EE_Checkin::new_instance(
1548
-            array(
1549
-                'REG_ID' => $this->ID(),
1550
-                'DTT_ID' => $DTT_ID,
1551
-                'CHK_in' => $new_status,
1552
-            )
1553
-        );
1554
-        // if the record could not be saved then return false
1555
-        if ($checkin->save() === 0) {
1556
-            if (WP_DEBUG) {
1557
-                global $wpdb;
1558
-                $error = sprintf(
1559
-                    esc_html__(
1560
-                        'Registration check in update failed because of the following database error: %1$s%2$s',
1561
-                        'event_espresso'
1562
-                    ),
1563
-                    '<br />',
1564
-                    $wpdb->last_error
1565
-                );
1566
-            } else {
1567
-                $error = esc_html__(
1568
-                    'Registration check in update failed because of an unknown database error',
1569
-                    'event_espresso'
1570
-                );
1571
-            }
1572
-            EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
1573
-            return false;
1574
-        }
1575
-        return $status_to;
1576
-    }
1577
-
1578
-
1579
-    /**
1580
-     * Returns the latest datetime related to this registration (via the ticket attached to the registration).
1581
-     * "Latest" is defined by the `DTT_EVT_start` column.
1582
-     *
1583
-     * @return EE_Datetime|null
1584
-     * @throws EE_Error
1585
-     */
1586
-    public function get_latest_related_datetime()
1587
-    {
1588
-        return EEM_Datetime::instance()->get_one(
1589
-            array(
1590
-                array(
1591
-                    'Ticket.Registration.REG_ID' => $this->ID(),
1592
-                ),
1593
-                'order_by' => array('DTT_EVT_start' => 'DESC'),
1594
-            )
1595
-        );
1596
-    }
1597
-
1598
-
1599
-    /**
1600
-     * Returns the earliest datetime related to this registration (via the ticket attached to the registration).
1601
-     * "Earliest" is defined by the `DTT_EVT_start` column.
1602
-     *
1603
-     * @throws EE_Error
1604
-     */
1605
-    public function get_earliest_related_datetime()
1606
-    {
1607
-        return EEM_Datetime::instance()->get_one(
1608
-            array(
1609
-                array(
1610
-                    'Ticket.Registration.REG_ID' => $this->ID(),
1611
-                ),
1612
-                'order_by' => array('DTT_EVT_start' => 'ASC'),
1613
-            )
1614
-        );
1615
-    }
1616
-
1617
-
1618
-    /**
1619
-     * This method simply returns the check-in status for this registration and the given datetime.
1620
-     * If neither the datetime nor the checkin values are provided as arguments,
1621
-     * then this will return the LATEST check-in status for the registration across all datetimes it belongs to.
1622
-     *
1623
-     * @param  int       $DTT_ID  The ID of the datetime we're checking against
1624
-     *                            (if empty we'll get the primary datetime for
1625
-     *                            this registration (via event) and use it's ID);
1626
-     * @param EE_Checkin $checkin If present, we use the given checkin object rather than the dtt_id.
1627
-     *
1628
-     * @return int                Integer representing Check-in status.
1629
-     * @throws EE_Error
1630
-     */
1631
-    public function check_in_status_for_datetime($DTT_ID = 0, $checkin = null)
1632
-    {
1633
-        $checkin_query_params = array(
1634
-            'order_by' => array('CHK_timestamp' => 'DESC'),
1635
-        );
1636
-
1637
-        if ($DTT_ID > 0) {
1638
-            $checkin_query_params[0] = array('DTT_ID' => $DTT_ID);
1639
-        }
1640
-
1641
-        // get checkin object (if exists)
1642
-        $checkin = $checkin instanceof EE_Checkin
1643
-            ? $checkin
1644
-            : $this->get_first_related('Checkin', $checkin_query_params);
1645
-        if ($checkin instanceof EE_Checkin) {
1646
-            if ($checkin->get('CHK_in')) {
1647
-                return EE_Checkin::status_checked_in; // checked in
1648
-            }
1649
-            return EE_Checkin::status_checked_out; // had checked in but is now checked out.
1650
-        }
1651
-        return EE_Checkin::status_checked_never; // never been checked in
1652
-    }
1653
-
1654
-
1655
-    /**
1656
-     * This method returns a localized message for the toggled Check-in message.
1657
-     *
1658
-     * @param  int $DTT_ID include specific datetime to get the correct Check-in message.  If not included or null,
1659
-     *                     then it is assumed Check-in for primary datetime was toggled.
1660
-     * @param bool $error  This just flags that you want an error message returned. This is put in so that the error
1661
-     *                     message can be customized with the attendee name.
1662
-     * @return string internationalized message
1663
-     * @throws EE_Error
1664
-     */
1665
-    public function get_checkin_msg($DTT_ID, $error = false)
1666
-    {
1667
-        // let's get the attendee first so we can include the name of the attendee
1668
-        $attendee = $this->get_first_related('Attendee');
1669
-        if ($attendee instanceof EE_Attendee) {
1670
-            if ($error) {
1671
-                return sprintf(__("%s's check-in status was not changed.", "event_espresso"), $attendee->full_name());
1672
-            }
1673
-            $cur_status = $this->check_in_status_for_datetime($DTT_ID);
1674
-            // what is the status message going to be?
1675
-            switch ($cur_status) {
1676
-                case EE_Checkin::status_checked_never:
1677
-                    return sprintf(
1678
-                        __("%s has been removed from Check-in records", "event_espresso"),
1679
-                        $attendee->full_name()
1680
-                    );
1681
-                    break;
1682
-                case EE_Checkin::status_checked_in:
1683
-                    return sprintf(__('%s has been checked in', 'event_espresso'), $attendee->full_name());
1684
-                    break;
1685
-                case EE_Checkin::status_checked_out:
1686
-                    return sprintf(__('%s has been checked out', 'event_espresso'), $attendee->full_name());
1687
-                    break;
1688
-            }
1689
-        }
1690
-        return esc_html__("The check-in status could not be determined.", "event_espresso");
1691
-    }
1692
-
1693
-
1694
-    /**
1695
-     * Returns the related EE_Transaction to this registration
1696
-     *
1697
-     * @return EE_Transaction
1698
-     * @throws EE_Error
1699
-     * @throws EntityNotFoundException
1700
-     */
1701
-    public function transaction()
1702
-    {
1703
-        $transaction = $this->get_first_related('Transaction');
1704
-        if (! $transaction instanceof \EE_Transaction) {
1705
-            throw new EntityNotFoundException('Transaction ID', $this->transaction_ID());
1706
-        }
1707
-        return $transaction;
1708
-    }
1709
-
1710
-
1711
-    /**
1712
-     *        get Registration Code
1713
-     */
1714
-    public function reg_code()
1715
-    {
1716
-        return $this->get('REG_code');
1717
-    }
1718
-
1719
-
1720
-    /**
1721
-     *        get Transaction ID
1722
-     */
1723
-    public function transaction_ID()
1724
-    {
1725
-        return $this->get('TXN_ID');
1726
-    }
1727
-
1728
-
1729
-    /**
1730
-     * @return int
1731
-     * @throws EE_Error
1732
-     */
1733
-    public function ticket_ID()
1734
-    {
1735
-        return $this->get('TKT_ID');
1736
-    }
1737
-
1738
-
1739
-    /**
1740
-     *        Set Registration Code
1741
-     *
1742
-     * @access    public
1743
-     * @param    string  $REG_code Registration Code
1744
-     * @param    boolean $use_default
1745
-     * @throws EE_Error
1746
-     */
1747
-    public function set_reg_code($REG_code, $use_default = false)
1748
-    {
1749
-        if (empty($REG_code)) {
1750
-            EE_Error::add_error(
1751
-                esc_html__('REG_code can not be empty.', 'event_espresso'),
1752
-                __FILE__,
1753
-                __FUNCTION__,
1754
-                __LINE__
1755
-            );
1756
-            return;
1757
-        }
1758
-        if (! $this->reg_code()) {
1759
-            parent::set('REG_code', $REG_code, $use_default);
1760
-        } else {
1761
-            EE_Error::doing_it_wrong(
1762
-                __CLASS__ . '::' . __FUNCTION__,
1763
-                esc_html__('Can not change a registration REG_code once it has been set.', 'event_espresso'),
1764
-                '4.6.0'
1765
-            );
1766
-        }
1767
-    }
1768
-
1769
-
1770
-    /**
1771
-     * Returns all other registrations in the same group as this registrant who have the same ticket option.
1772
-     * Note, if you want to just get all registrations in the same transaction (group), use:
1773
-     *    $registration->transaction()->registrations();
1774
-     *
1775
-     * @since 4.5.0
1776
-     * @return EE_Registration[] or empty array if this isn't a group registration.
1777
-     * @throws EE_Error
1778
-     */
1779
-    public function get_all_other_registrations_in_group()
1780
-    {
1781
-        if ($this->group_size() < 2) {
1782
-            return array();
1783
-        }
1784
-
1785
-        $query[0] = array(
1786
-            'TXN_ID' => $this->transaction_ID(),
1787
-            'REG_ID' => array('!=', $this->ID()),
1788
-            'TKT_ID' => $this->ticket_ID(),
1789
-        );
1790
-        /** @var EE_Registration[] $registrations */
1791
-        $registrations = $this->get_model()->get_all($query);
1792
-        return $registrations;
1793
-    }
1794
-
1795
-    /**
1796
-     * Return the link to the admin details for the object.
1797
-     *
1798
-     * @return string
1799
-     * @throws EE_Error
1800
-     */
1801
-    public function get_admin_details_link()
1802
-    {
1803
-        EE_Registry::instance()->load_helper('URL');
1804
-        return EEH_URL::add_query_args_and_nonce(
1805
-            array(
1806
-                'page'    => 'espresso_registrations',
1807
-                'action'  => 'view_registration',
1808
-                '_REG_ID' => $this->ID(),
1809
-            ),
1810
-            admin_url('admin.php')
1811
-        );
1812
-    }
1813
-
1814
-    /**
1815
-     * Returns the link to the editor for the object.  Sometimes this is the same as the details.
1816
-     *
1817
-     * @return string
1818
-     * @throws EE_Error
1819
-     */
1820
-    public function get_admin_edit_link()
1821
-    {
1822
-        return $this->get_admin_details_link();
1823
-    }
1824
-
1825
-    /**
1826
-     * Returns the link to a settings page for the object.
1827
-     *
1828
-     * @return string
1829
-     * @throws EE_Error
1830
-     */
1831
-    public function get_admin_settings_link()
1832
-    {
1833
-        return $this->get_admin_details_link();
1834
-    }
1835
-
1836
-    /**
1837
-     * Returns the link to the "overview" for the object (typically the "list table" view).
1838
-     *
1839
-     * @return string
1840
-     */
1841
-    public function get_admin_overview_link()
1842
-    {
1843
-        EE_Registry::instance()->load_helper('URL');
1844
-        return EEH_URL::add_query_args_and_nonce(
1845
-            array(
1846
-                'page' => 'espresso_registrations',
1847
-            ),
1848
-            admin_url('admin.php')
1849
-        );
1850
-    }
1851
-
1852
-
1853
-    /**
1854
-     * @param array $query_params
1855
-     *
1856
-     * @return \EE_Registration[]
1857
-     * @throws EE_Error
1858
-     */
1859
-    public function payments($query_params = array())
1860
-    {
1861
-        return $this->get_many_related('Payment', $query_params);
1862
-    }
1863
-
1864
-
1865
-    /**
1866
-     * @param array $query_params
1867
-     *
1868
-     * @return \EE_Registration_Payment[]
1869
-     * @throws EE_Error
1870
-     */
1871
-    public function registration_payments($query_params = array())
1872
-    {
1873
-        return $this->get_many_related('Registration_Payment', $query_params);
1874
-    }
1875
-
1876
-
1877
-    /**
1878
-     * This grabs the payment method corresponding to the last payment made for the amount owing on the registration.
1879
-     * Note: if there are no payments on the registration there will be no payment method returned.
1880
-     *
1881
-     * @return EE_Payment_Method|null
1882
-     */
1883
-    public function payment_method()
1884
-    {
1885
-        return EEM_Payment_Method::instance()->get_last_used_for_registration($this);
1886
-    }
1887
-
1888
-
1889
-    /**
1890
-     * @return \EE_Line_Item
1891
-     * @throws EntityNotFoundException
1892
-     * @throws EE_Error
1893
-     */
1894
-    public function ticket_line_item()
1895
-    {
1896
-        $ticket = $this->ticket();
1897
-        $transaction = $this->transaction();
1898
-        $line_item = null;
1899
-        $ticket_line_items = \EEH_Line_Item::get_line_items_by_object_type_and_IDs(
1900
-            $transaction->total_line_item(),
1901
-            'Ticket',
1902
-            array($ticket->ID())
1903
-        );
1904
-        foreach ($ticket_line_items as $ticket_line_item) {
1905
-            if ($ticket_line_item instanceof \EE_Line_Item
1906
-                && $ticket_line_item->OBJ_type() === 'Ticket'
1907
-                && $ticket_line_item->OBJ_ID() === $ticket->ID()
1908
-            ) {
1909
-                $line_item = $ticket_line_item;
1910
-                break;
1911
-            }
1912
-        }
1913
-        if (! ($line_item instanceof \EE_Line_Item && $line_item->OBJ_type() === 'Ticket')) {
1914
-            throw new EntityNotFoundException('Line Item Ticket ID', $ticket->ID());
1915
-        }
1916
-        return $line_item;
1917
-    }
1918
-
1919
-
1920
-    /**
1921
-     * Soft Deletes this model object.
1922
-     *
1923
-     * @return boolean | int
1924
-     * @throws RuntimeException
1925
-     * @throws EE_Error
1926
-     */
1927
-    public function delete()
1928
-    {
1929
-        if ($this->update_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY, $this->status_ID()) === true) {
1930
-            $this->set_status(EEM_Registration::status_id_cancelled);
1931
-        }
1932
-        return parent::delete();
1933
-    }
1934
-
1935
-
1936
-    /**
1937
-     * Restores whatever the previous status was on a registration before it was trashed (if possible)
1938
-     *
1939
-     * @throws EE_Error
1940
-     * @throws RuntimeException
1941
-     */
1942
-    public function restore()
1943
-    {
1944
-        $previous_status = $this->get_extra_meta(
1945
-            EE_Registration::PRE_TRASH_REG_STATUS_KEY,
1946
-            true,
1947
-            EEM_Registration::status_id_cancelled
1948
-        );
1949
-        if ($previous_status) {
1950
-            $this->delete_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY);
1951
-            $this->set_status($previous_status);
1952
-        }
1953
-        return parent::restore();
1954
-    }
1955
-
1956
-
1957
-    /**
1958
-     * possibly toggle Registration status based on comparison of REG_paid vs REG_final_price
1959
-     *
1960
-     * @param  boolean $trigger_set_status_logic EE_Registration::set_status() can trigger additional logic
1961
-     *                                           depending on whether the reg status changes to or from "Approved"
1962
-     * @return boolean whether the Registration status was updated
1963
-     * @throws EE_Error
1964
-     * @throws RuntimeException
1965
-     */
1966
-    public function updateStatusBasedOnTotalPaid($trigger_set_status_logic = true)
1967
-    {
1968
-        $paid = $this->paid();
1969
-        $price = $this->final_price();
1970
-        switch (true) {
1971
-            // overpaid or paid
1972
-            case EEH_Money::compare_floats($paid, $price, '>'):
1973
-            case EEH_Money::compare_floats($paid, $price):
1974
-                $new_status = EEM_Registration::status_id_approved;
1975
-                break;
1976
-            //  underpaid
1977
-            case EEH_Money::compare_floats($paid, $price, '<'):
1978
-                $new_status = EEM_Registration::status_id_pending_payment;
1979
-                break;
1980
-            // uhhh Houston...
1981
-            default:
1982
-                throw new RuntimeException(
1983
-                    esc_html__('The total paid calculation for this registration is inaccurate.', 'event_espresso')
1984
-                );
1985
-        }
1986
-        if ($new_status !== $this->status_ID()) {
1987
-            if ($trigger_set_status_logic) {
1988
-                return $this->set_status($new_status);
1989
-            }
1990
-            parent::set('STS_ID', $new_status);
1991
-            return true;
1992
-        }
1993
-        return false;
1994
-    }
1995
-
1996
-
1997
-    /*************************** DEPRECATED ***************************/
1998
-
1999
-
2000
-    /**
2001
-     * @deprecated
2002
-     * @since     4.7.0
2003
-     * @access    public
2004
-     */
2005
-    public function price_paid()
2006
-    {
2007
-        EE_Error::doing_it_wrong(
2008
-            'EE_Registration::price_paid()',
2009
-            esc_html__(
2010
-                'This method is deprecated, please use EE_Registration::final_price() instead.',
2011
-                'event_espresso'
2012
-            ),
2013
-            '4.7.0'
2014
-        );
2015
-        return $this->final_price();
2016
-    }
2017
-
2018
-
2019
-    /**
2020
-     * @deprecated
2021
-     * @since     4.7.0
2022
-     * @access    public
2023
-     * @param    float $REG_final_price
2024
-     * @throws EE_Error
2025
-     * @throws RuntimeException
2026
-     */
2027
-    public function set_price_paid($REG_final_price = 0.00)
2028
-    {
2029
-        EE_Error::doing_it_wrong(
2030
-            'EE_Registration::set_price_paid()',
2031
-            esc_html__(
2032
-                'This method is deprecated, please use EE_Registration::set_final_price() instead.',
2033
-                'event_espresso'
2034
-            ),
2035
-            '4.7.0'
2036
-        );
2037
-        $this->set_final_price($REG_final_price);
2038
-    }
2039
-
2040
-
2041
-    /**
2042
-     * @deprecated
2043
-     * @since 4.7.0
2044
-     * @return string
2045
-     * @throws EE_Error
2046
-     */
2047
-    public function pretty_price_paid()
2048
-    {
2049
-        EE_Error::doing_it_wrong(
2050
-            'EE_Registration::pretty_price_paid()',
2051
-            esc_html__(
2052
-                'This method is deprecated, please use EE_Registration::pretty_final_price() instead.',
2053
-                'event_espresso'
2054
-            ),
2055
-            '4.7.0'
2056
-        );
2057
-        return $this->pretty_final_price();
2058
-    }
2059
-
2060
-
2061
-    /**
2062
-     * Gets the primary datetime related to this registration via the related Event to this registration
2063
-     *
2064
-     * @deprecated 4.9.17
2065
-     * @return EE_Datetime
2066
-     * @throws EE_Error
2067
-     * @throws EntityNotFoundException
2068
-     */
2069
-    public function get_related_primary_datetime()
2070
-    {
2071
-        EE_Error::doing_it_wrong(
2072
-            __METHOD__,
2073
-            esc_html__(
2074
-                'Use EE_Registration::get_latest_related_datetime() or EE_Registration::get_earliest_related_datetime()',
2075
-                'event_espresso'
2076
-            ),
2077
-            '4.9.17',
2078
-            '5.0.0'
2079
-        );
2080
-        return $this->event()->primary_datetime();
2081
-    }
20
+	/**
21
+	 * Used to reference when a registration has never been checked in.
22
+	 *
23
+	 * @deprecated use \EE_Checkin::status_checked_never instead
24
+	 * @type int
25
+	 */
26
+	const checkin_status_never = 2;
27
+
28
+	/**
29
+	 * Used to reference when a registration has been checked in.
30
+	 *
31
+	 * @deprecated use \EE_Checkin::status_checked_in instead
32
+	 * @type int
33
+	 */
34
+	const checkin_status_in = 1;
35
+
36
+
37
+	/**
38
+	 * Used to reference when a registration has been checked out.
39
+	 *
40
+	 * @deprecated use \EE_Checkin::status_checked_out instead
41
+	 * @type int
42
+	 */
43
+	const checkin_status_out = 0;
44
+
45
+
46
+	/**
47
+	 * extra meta key for tracking reg status os trashed registrations
48
+	 *
49
+	 * @type string
50
+	 */
51
+	const PRE_TRASH_REG_STATUS_KEY = 'pre_trash_registration_status';
52
+
53
+
54
+	/**
55
+	 * extra meta key for tracking if registration has reserved ticket
56
+	 *
57
+	 * @type string
58
+	 */
59
+	const HAS_RESERVED_TICKET_KEY = 'has_reserved_ticket';
60
+
61
+
62
+	/**
63
+	 * @param array  $props_n_values          incoming values
64
+	 * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
65
+	 *                                        used.)
66
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
67
+	 *                                        date_format and the second value is the time format
68
+	 * @return EE_Registration
69
+	 * @throws EE_Error
70
+	 */
71
+	public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
72
+	{
73
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
74
+		return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
75
+	}
76
+
77
+
78
+	/**
79
+	 * @param array  $props_n_values  incoming values from the database
80
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
81
+	 *                                the website will be used.
82
+	 * @return EE_Registration
83
+	 */
84
+	public static function new_instance_from_db($props_n_values = array(), $timezone = null)
85
+	{
86
+		return new self($props_n_values, true, $timezone);
87
+	}
88
+
89
+
90
+	/**
91
+	 *        Set Event ID
92
+	 *
93
+	 * @param        int $EVT_ID Event ID
94
+	 * @throws EE_Error
95
+	 * @throws RuntimeException
96
+	 */
97
+	public function set_event($EVT_ID = 0)
98
+	{
99
+		$this->set('EVT_ID', $EVT_ID);
100
+	}
101
+
102
+
103
+	/**
104
+	 * Overrides parent set() method so that all calls to set( 'REG_code', $REG_code ) OR set( 'STS_ID', $STS_ID ) can
105
+	 * be routed to internal methods
106
+	 *
107
+	 * @param string $field_name
108
+	 * @param mixed  $field_value
109
+	 * @param bool   $use_default
110
+	 * @throws EE_Error
111
+	 * @throws EntityNotFoundException
112
+	 * @throws InvalidArgumentException
113
+	 * @throws InvalidDataTypeException
114
+	 * @throws InvalidInterfaceException
115
+	 * @throws ReflectionException
116
+	 * @throws RuntimeException
117
+	 */
118
+	public function set($field_name, $field_value, $use_default = false)
119
+	{
120
+		switch ($field_name) {
121
+			case 'REG_code':
122
+				if (! empty($field_value) && $this->reg_code() === null) {
123
+					$this->set_reg_code($field_value, $use_default);
124
+				}
125
+				break;
126
+			case 'STS_ID':
127
+				$this->set_status($field_value, $use_default);
128
+				break;
129
+			default:
130
+				parent::set($field_name, $field_value, $use_default);
131
+		}
132
+	}
133
+
134
+
135
+	/**
136
+	 * Set Status ID
137
+	 * updates the registration status and ALSO...
138
+	 * calls reserve_registration_space() if the reg status changes TO approved from any other reg status
139
+	 * calls release_registration_space() if the reg status changes FROM approved to any other reg status
140
+	 *
141
+	 * @param string                $new_STS_ID
142
+	 * @param boolean               $use_default
143
+	 * @param ContextInterface|null $context
144
+	 * @return bool
145
+	 * @throws EE_Error
146
+	 * @throws EntityNotFoundException
147
+	 * @throws InvalidArgumentException
148
+	 * @throws ReflectionException
149
+	 * @throws RuntimeException
150
+	 * @throws InvalidDataTypeException
151
+	 * @throws InvalidInterfaceException
152
+	 */
153
+	public function set_status($new_STS_ID = null, $use_default = false, ContextInterface $context = null)
154
+	{
155
+		// get current REG_Status
156
+		$old_STS_ID = $this->status_ID();
157
+		// if status has changed
158
+		if ($old_STS_ID !== $new_STS_ID // and that status has actually changed
159
+			&& ! empty($old_STS_ID) // and that old status is actually set
160
+			&& ! empty($new_STS_ID) // as well as the new status
161
+			&& $this->ID() // ensure registration is in the db
162
+		) {
163
+			// update internal status first
164
+			parent::set('STS_ID', $new_STS_ID, $use_default);
165
+			// THEN handle other changes that occur when reg status changes
166
+			// TO approved
167
+			if ($new_STS_ID === EEM_Registration::status_id_approved) {
168
+				// reserve a space by incrementing ticket and datetime sold values
169
+				$this->_reserve_registration_space();
170
+				do_action('AHEE__EE_Registration__set_status__to_approved', $this, $old_STS_ID, $new_STS_ID, $context);
171
+				// OR FROM  approved
172
+			} elseif ($old_STS_ID === EEM_Registration::status_id_approved) {
173
+				// release a space by decrementing ticket and datetime sold values
174
+				$this->_release_registration_space();
175
+				do_action(
176
+					'AHEE__EE_Registration__set_status__from_approved',
177
+					$this,
178
+					$old_STS_ID,
179
+					$new_STS_ID,
180
+					$context
181
+				);
182
+			}
183
+			$this->_update_if_canceled_or_declined($new_STS_ID, $old_STS_ID, $context);
184
+			if ($this->statusChangeUpdatesTransaction($context)) {
185
+				$this->updateTransactionAfterStatusChange();
186
+			}
187
+			do_action('AHEE__EE_Registration__set_status__after_update', $this, $old_STS_ID, $new_STS_ID, $context);
188
+			return true;
189
+		}
190
+		// even though the old value matches the new value, it's still good to
191
+		// allow the parent set method to have a say
192
+		parent::set('STS_ID', $new_STS_ID, $use_default);
193
+		return true;
194
+	}
195
+
196
+
197
+	/**
198
+	 * update REGs and TXN when cancelled or declined registrations involved
199
+	 *
200
+	 * @param string                $new_STS_ID
201
+	 * @param string                $old_STS_ID
202
+	 * @param ContextInterface|null $context
203
+	 * @throws EE_Error
204
+	 * @throws InvalidArgumentException
205
+	 * @throws InvalidDataTypeException
206
+	 * @throws InvalidInterfaceException
207
+	 * @throws ReflectionException
208
+	 */
209
+	private function _update_if_canceled_or_declined($new_STS_ID, $old_STS_ID, ContextInterface $context = null)
210
+	{
211
+		// these reg statuses should not be considered in any calculations involving monies owing
212
+		$closed_reg_statuses = EEM_Registration::closed_reg_statuses();
213
+		// true if registration has been cancelled or declined
214
+		$this->updateIfCanceled(
215
+			$closed_reg_statuses,
216
+			$new_STS_ID,
217
+			$old_STS_ID,
218
+			$context
219
+		);
220
+		$this->updateIfDeclined(
221
+			$closed_reg_statuses,
222
+			$new_STS_ID,
223
+			$old_STS_ID,
224
+			$context
225
+		);
226
+	}
227
+
228
+
229
+	/**
230
+	 * update REGs and TXN when cancelled or declined registrations involved
231
+	 *
232
+	 * @param array                 $closed_reg_statuses
233
+	 * @param string                $new_STS_ID
234
+	 * @param string                $old_STS_ID
235
+	 * @param ContextInterface|null $context
236
+	 * @throws EE_Error
237
+	 * @throws InvalidArgumentException
238
+	 * @throws InvalidDataTypeException
239
+	 * @throws InvalidInterfaceException
240
+	 * @throws ReflectionException
241
+	 */
242
+	private function updateIfCanceled(
243
+		array $closed_reg_statuses,
244
+		$new_STS_ID,
245
+		$old_STS_ID,
246
+		ContextInterface $context = null
247
+	) {
248
+		// true if registration has been cancelled or declined
249
+		if (in_array($new_STS_ID, $closed_reg_statuses, true)
250
+			&& ! in_array($old_STS_ID, $closed_reg_statuses, true)
251
+		) {
252
+			/** @type EE_Registration_Processor $registration_processor */
253
+			$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
254
+			/** @type EE_Transaction_Processor $transaction_processor */
255
+			$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
256
+			// cancelled or declined registration
257
+			$registration_processor->update_registration_after_being_canceled_or_declined(
258
+				$this,
259
+				$closed_reg_statuses
260
+			);
261
+			$transaction_processor->update_transaction_after_canceled_or_declined_registration(
262
+				$this,
263
+				$closed_reg_statuses,
264
+				false
265
+			);
266
+			do_action(
267
+				'AHEE__EE_Registration__set_status__canceled_or_declined',
268
+				$this,
269
+				$old_STS_ID,
270
+				$new_STS_ID,
271
+				$context
272
+			);
273
+			return;
274
+		}
275
+	}
276
+
277
+
278
+	/**
279
+	 * update REGs and TXN when cancelled or declined registrations involved
280
+	 *
281
+	 * @param array                 $closed_reg_statuses
282
+	 * @param string                $new_STS_ID
283
+	 * @param string                $old_STS_ID
284
+	 * @param ContextInterface|null $context
285
+	 * @throws EE_Error
286
+	 * @throws InvalidArgumentException
287
+	 * @throws InvalidDataTypeException
288
+	 * @throws InvalidInterfaceException
289
+	 * @throws ReflectionException
290
+	 */
291
+	private function updateIfDeclined(
292
+		array $closed_reg_statuses,
293
+		$new_STS_ID,
294
+		$old_STS_ID,
295
+		ContextInterface $context = null
296
+	) {
297
+		// true if reinstating cancelled or declined registration
298
+		if (in_array($old_STS_ID, $closed_reg_statuses, true)
299
+			&& ! in_array($new_STS_ID, $closed_reg_statuses, true)
300
+		) {
301
+			/** @type EE_Registration_Processor $registration_processor */
302
+			$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
303
+			/** @type EE_Transaction_Processor $transaction_processor */
304
+			$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
305
+			// reinstating cancelled or declined registration
306
+			$registration_processor->update_canceled_or_declined_registration_after_being_reinstated(
307
+				$this,
308
+				$closed_reg_statuses
309
+			);
310
+			$transaction_processor->update_transaction_after_reinstating_canceled_registration(
311
+				$this,
312
+				$closed_reg_statuses,
313
+				false
314
+			);
315
+			do_action(
316
+				'AHEE__EE_Registration__set_status__after_reinstated',
317
+				$this,
318
+				$old_STS_ID,
319
+				$new_STS_ID,
320
+				$context
321
+			);
322
+		}
323
+	}
324
+
325
+
326
+	/**
327
+	 * @param ContextInterface|null $context
328
+	 * @return bool
329
+	 */
330
+	private function statusChangeUpdatesTransaction(ContextInterface $context = null)
331
+	{
332
+		$contexts_that_do_not_update_transaction = (array) apply_filters(
333
+			'AHEE__EE_Registration__statusChangeUpdatesTransaction__contexts_that_do_not_update_transaction',
334
+			array('spco_reg_step_attendee_information_process_registrations'),
335
+			$context,
336
+			$this
337
+		);
338
+		return ! (
339
+			$context instanceof ContextInterface
340
+			&& in_array($context->slug(), $contexts_that_do_not_update_transaction, true)
341
+		);
342
+	}
343
+
344
+
345
+	/**
346
+	 * @throws EE_Error
347
+	 * @throws EntityNotFoundException
348
+	 * @throws InvalidArgumentException
349
+	 * @throws InvalidDataTypeException
350
+	 * @throws InvalidInterfaceException
351
+	 * @throws ReflectionException
352
+	 * @throws RuntimeException
353
+	 */
354
+	private function updateTransactionAfterStatusChange()
355
+	{
356
+		/** @type EE_Transaction_Payments $transaction_payments */
357
+		$transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
358
+		$transaction_payments->recalculate_transaction_total($this->transaction(), false);
359
+		$this->transaction()->update_status_based_on_total_paid(true);
360
+	}
361
+
362
+
363
+	/**
364
+	 *        get Status ID
365
+	 */
366
+	public function status_ID()
367
+	{
368
+		return $this->get('STS_ID');
369
+	}
370
+
371
+
372
+	/**
373
+	 * Gets the ticket this registration is for
374
+	 *
375
+	 * @param boolean $include_archived whether to include archived tickets or not.
376
+	 *
377
+	 * @return EE_Ticket|EE_Base_Class
378
+	 * @throws EE_Error
379
+	 */
380
+	public function ticket($include_archived = true)
381
+	{
382
+		$query_params = array();
383
+		if ($include_archived) {
384
+			$query_params['default_where_conditions'] = 'none';
385
+		}
386
+		return $this->get_first_related('Ticket', $query_params);
387
+	}
388
+
389
+
390
+	/**
391
+	 * Gets the event this registration is for
392
+	 *
393
+	 * @return EE_Event
394
+	 * @throws EE_Error
395
+	 * @throws EntityNotFoundException
396
+	 */
397
+	public function event()
398
+	{
399
+		$event = $this->get_first_related('Event');
400
+		if (! $event instanceof \EE_Event) {
401
+			throw new EntityNotFoundException('Event ID', $this->event_ID());
402
+		}
403
+		return $event;
404
+	}
405
+
406
+
407
+	/**
408
+	 * Gets the "author" of the registration.  Note that for the purposes of registrations, the author will correspond
409
+	 * with the author of the event this registration is for.
410
+	 *
411
+	 * @since 4.5.0
412
+	 * @return int
413
+	 * @throws EE_Error
414
+	 * @throws EntityNotFoundException
415
+	 */
416
+	public function wp_user()
417
+	{
418
+		$event = $this->event();
419
+		if ($event instanceof EE_Event) {
420
+			return $event->wp_user();
421
+		}
422
+		return 0;
423
+	}
424
+
425
+
426
+	/**
427
+	 * increments this registration's related ticket sold and corresponding datetime sold values
428
+	 *
429
+	 * @return void
430
+	 * @throws DomainException
431
+	 * @throws EE_Error
432
+	 * @throws EntityNotFoundException
433
+	 * @throws InvalidArgumentException
434
+	 * @throws InvalidDataTypeException
435
+	 * @throws InvalidInterfaceException
436
+	 * @throws ReflectionException
437
+	 * @throws UnexpectedEntityException
438
+	 */
439
+	private function _reserve_registration_space()
440
+	{
441
+		// reserved ticket and datetime counts will be decremented as sold counts are incremented
442
+		// so stop tracking that this reg has a ticket reserved
443
+		$this->release_reserved_ticket(false, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
444
+		$ticket = $this->ticket();
445
+		$ticket->increase_sold();
446
+		$ticket->save();
447
+		// possibly set event status to sold out
448
+		$this->event()->perform_sold_out_status_check();
449
+	}
450
+
451
+
452
+	/**
453
+	 * decrements (subtracts) this registration's related ticket sold and corresponding datetime sold values
454
+	 *
455
+	 * @return void
456
+	 * @throws DomainException
457
+	 * @throws EE_Error
458
+	 * @throws EntityNotFoundException
459
+	 * @throws InvalidArgumentException
460
+	 * @throws InvalidDataTypeException
461
+	 * @throws InvalidInterfaceException
462
+	 * @throws ReflectionException
463
+	 * @throws UnexpectedEntityException
464
+	 */
465
+	private function _release_registration_space()
466
+	{
467
+		$ticket = $this->ticket();
468
+		$ticket->decrease_sold();
469
+		$ticket->save();
470
+		// possibly change event status from sold out back to previous status
471
+		$this->event()->perform_sold_out_status_check();
472
+	}
473
+
474
+
475
+	/**
476
+	 * tracks this registration's ticket reservation in extra meta
477
+	 * and can increment related ticket reserved and corresponding datetime reserved values
478
+	 *
479
+	 * @param bool $update_ticket if true, will increment ticket and datetime reserved count
480
+	 * @return void
481
+	 * @throws EE_Error
482
+	 * @throws InvalidArgumentException
483
+	 * @throws InvalidDataTypeException
484
+	 * @throws InvalidInterfaceException
485
+	 * @throws ReflectionException
486
+	 */
487
+	public function reserve_ticket($update_ticket = false, $source = 'unknown')
488
+	{
489
+		// only reserve ticket if space is not currently reserved
490
+		if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) !== true) {
491
+			$this->update_extra_meta('reserve_ticket', "{$this->ticket_ID()} from {$source}");
492
+			// IMPORTANT !!!
493
+			// although checking $update_ticket first would be more efficient,
494
+			// we NEED to ALWAYS call update_extra_meta(), which is why that is done first
495
+			if ($this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true)
496
+				&& $update_ticket
497
+			) {
498
+				$ticket = $this->ticket();
499
+				$ticket->increase_reserved(1, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
500
+				$ticket->save();
501
+			}
502
+		}
503
+	}
504
+
505
+
506
+	/**
507
+	 * stops tracking this registration's ticket reservation in extra meta
508
+	 * decrements (subtracts) related ticket reserved and corresponding datetime reserved values
509
+	 *
510
+	 * @param bool $update_ticket if true, will decrement ticket and datetime reserved count
511
+	 * @return void
512
+	 * @throws EE_Error
513
+	 * @throws InvalidArgumentException
514
+	 * @throws InvalidDataTypeException
515
+	 * @throws InvalidInterfaceException
516
+	 * @throws ReflectionException
517
+	 */
518
+	public function release_reserved_ticket($update_ticket = false, $source = 'unknown')
519
+	{
520
+		// only release ticket if space is currently reserved
521
+		if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) === true) {
522
+			$this->update_extra_meta('release_reserved_ticket', "{$this->ticket_ID()} from {$source}");
523
+			// IMPORTANT !!!
524
+			// although checking $update_ticket first would be more efficient,
525
+			// we NEED to ALWAYS call update_extra_meta(), which is why that is done first
526
+			if ($this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, false)
527
+				&& $update_ticket
528
+			) {
529
+				$ticket = $this->ticket();
530
+				$ticket->decrease_reserved(1, true, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
531
+				$ticket->save();
532
+			}
533
+		}
534
+	}
535
+
536
+
537
+	/**
538
+	 * Set Attendee ID
539
+	 *
540
+	 * @param        int $ATT_ID Attendee ID
541
+	 * @throws EE_Error
542
+	 * @throws RuntimeException
543
+	 */
544
+	public function set_attendee_id($ATT_ID = 0)
545
+	{
546
+		$this->set('ATT_ID', $ATT_ID);
547
+	}
548
+
549
+
550
+	/**
551
+	 *        Set Transaction ID
552
+	 *
553
+	 * @param        int $TXN_ID Transaction ID
554
+	 * @throws EE_Error
555
+	 * @throws RuntimeException
556
+	 */
557
+	public function set_transaction_id($TXN_ID = 0)
558
+	{
559
+		$this->set('TXN_ID', $TXN_ID);
560
+	}
561
+
562
+
563
+	/**
564
+	 *        Set Session
565
+	 *
566
+	 * @param    string $REG_session PHP Session ID
567
+	 * @throws EE_Error
568
+	 * @throws RuntimeException
569
+	 */
570
+	public function set_session($REG_session = '')
571
+	{
572
+		$this->set('REG_session', $REG_session);
573
+	}
574
+
575
+
576
+	/**
577
+	 *        Set Registration URL Link
578
+	 *
579
+	 * @param    string $REG_url_link Registration URL Link
580
+	 * @throws EE_Error
581
+	 * @throws RuntimeException
582
+	 */
583
+	public function set_reg_url_link($REG_url_link = '')
584
+	{
585
+		$this->set('REG_url_link', $REG_url_link);
586
+	}
587
+
588
+
589
+	/**
590
+	 *        Set Attendee Counter
591
+	 *
592
+	 * @param        int $REG_count Primary Attendee
593
+	 * @throws EE_Error
594
+	 * @throws RuntimeException
595
+	 */
596
+	public function set_count($REG_count = 1)
597
+	{
598
+		$this->set('REG_count', $REG_count);
599
+	}
600
+
601
+
602
+	/**
603
+	 *        Set Group Size
604
+	 *
605
+	 * @param        boolean $REG_group_size Group Registration
606
+	 * @throws EE_Error
607
+	 * @throws RuntimeException
608
+	 */
609
+	public function set_group_size($REG_group_size = false)
610
+	{
611
+		$this->set('REG_group_size', $REG_group_size);
612
+	}
613
+
614
+
615
+	/**
616
+	 *    is_not_approved -  convenience method that returns TRUE if REG status ID ==
617
+	 *    EEM_Registration::status_id_not_approved
618
+	 *
619
+	 * @return        boolean
620
+	 */
621
+	public function is_not_approved()
622
+	{
623
+		return $this->status_ID() == EEM_Registration::status_id_not_approved ? true : false;
624
+	}
625
+
626
+
627
+	/**
628
+	 *    is_pending_payment -  convenience method that returns TRUE if REG status ID ==
629
+	 *    EEM_Registration::status_id_pending_payment
630
+	 *
631
+	 * @return        boolean
632
+	 */
633
+	public function is_pending_payment()
634
+	{
635
+		return $this->status_ID() == EEM_Registration::status_id_pending_payment ? true : false;
636
+	}
637
+
638
+
639
+	/**
640
+	 *    is_approved -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_approved
641
+	 *
642
+	 * @return        boolean
643
+	 */
644
+	public function is_approved()
645
+	{
646
+		return $this->status_ID() == EEM_Registration::status_id_approved ? true : false;
647
+	}
648
+
649
+
650
+	/**
651
+	 *    is_cancelled -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_cancelled
652
+	 *
653
+	 * @return        boolean
654
+	 */
655
+	public function is_cancelled()
656
+	{
657
+		return $this->status_ID() == EEM_Registration::status_id_cancelled ? true : false;
658
+	}
659
+
660
+
661
+	/**
662
+	 *    is_declined -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_declined
663
+	 *
664
+	 * @return        boolean
665
+	 */
666
+	public function is_declined()
667
+	{
668
+		return $this->status_ID() == EEM_Registration::status_id_declined ? true : false;
669
+	}
670
+
671
+
672
+	/**
673
+	 *    is_incomplete -  convenience method that returns TRUE if REG status ID ==
674
+	 *    EEM_Registration::status_id_incomplete
675
+	 *
676
+	 * @return        boolean
677
+	 */
678
+	public function is_incomplete()
679
+	{
680
+		return $this->status_ID() == EEM_Registration::status_id_incomplete ? true : false;
681
+	}
682
+
683
+
684
+	/**
685
+	 *        Set Registration Date
686
+	 *
687
+	 * @param        mixed ( int or string ) $REG_date Registration Date - Unix timestamp or string representation of
688
+	 *                                                 Date
689
+	 * @throws EE_Error
690
+	 * @throws RuntimeException
691
+	 */
692
+	public function set_reg_date($REG_date = false)
693
+	{
694
+		$this->set('REG_date', $REG_date);
695
+	}
696
+
697
+
698
+	/**
699
+	 *    Set final price owing for this registration after all ticket/price modifications
700
+	 *
701
+	 * @access    public
702
+	 * @param    float $REG_final_price
703
+	 * @throws EE_Error
704
+	 * @throws RuntimeException
705
+	 */
706
+	public function set_final_price($REG_final_price = 0.00)
707
+	{
708
+		$this->set('REG_final_price', $REG_final_price);
709
+	}
710
+
711
+
712
+	/**
713
+	 *    Set amount paid towards this registration's final price
714
+	 *
715
+	 * @access    public
716
+	 * @param    float $REG_paid
717
+	 * @throws EE_Error
718
+	 * @throws RuntimeException
719
+	 */
720
+	public function set_paid($REG_paid = 0.00)
721
+	{
722
+		$this->set('REG_paid', $REG_paid);
723
+	}
724
+
725
+
726
+	/**
727
+	 *        Attendee Is Going
728
+	 *
729
+	 * @param        boolean $REG_att_is_going Attendee Is Going
730
+	 * @throws EE_Error
731
+	 * @throws RuntimeException
732
+	 */
733
+	public function set_att_is_going($REG_att_is_going = false)
734
+	{
735
+		$this->set('REG_att_is_going', $REG_att_is_going);
736
+	}
737
+
738
+
739
+	/**
740
+	 * Gets the related attendee
741
+	 *
742
+	 * @return EE_Attendee
743
+	 * @throws EE_Error
744
+	 */
745
+	public function attendee()
746
+	{
747
+		return $this->get_first_related('Attendee');
748
+	}
749
+
750
+
751
+	/**
752
+	 *        get Event ID
753
+	 */
754
+	public function event_ID()
755
+	{
756
+		return $this->get('EVT_ID');
757
+	}
758
+
759
+
760
+	/**
761
+	 *        get Event ID
762
+	 */
763
+	public function event_name()
764
+	{
765
+		$event = $this->event_obj();
766
+		if ($event) {
767
+			return $event->name();
768
+		} else {
769
+			return null;
770
+		}
771
+	}
772
+
773
+
774
+	/**
775
+	 * Fetches the event this registration is for
776
+	 *
777
+	 * @return EE_Event
778
+	 * @throws EE_Error
779
+	 */
780
+	public function event_obj()
781
+	{
782
+		return $this->get_first_related('Event');
783
+	}
784
+
785
+
786
+	/**
787
+	 *        get Attendee ID
788
+	 */
789
+	public function attendee_ID()
790
+	{
791
+		return $this->get('ATT_ID');
792
+	}
793
+
794
+
795
+	/**
796
+	 *        get PHP Session ID
797
+	 */
798
+	public function session_ID()
799
+	{
800
+		return $this->get('REG_session');
801
+	}
802
+
803
+
804
+	/**
805
+	 * Gets the string which represents the URL trigger for the receipt template in the message template system.
806
+	 *
807
+	 * @param string $messenger 'pdf' or 'html'.  Default 'html'.
808
+	 * @return string
809
+	 */
810
+	public function receipt_url($messenger = 'html')
811
+	{
812
+
813
+		/**
814
+		 * The below will be deprecated one version after this.  We check first if there is a custom receipt template
815
+		 * already in use on old system.  If there is then we just return the standard url for it.
816
+		 *
817
+		 * @since 4.5.0
818
+		 */
819
+		$template_relative_path = 'modules/gateways/Invoice/lib/templates/receipt_body.template.php';
820
+		$has_custom = EEH_Template::locate_template(
821
+			$template_relative_path,
822
+			array(),
823
+			true,
824
+			true,
825
+			true
826
+		);
827
+
828
+		if ($has_custom) {
829
+			return add_query_arg(array('receipt' => 'true'), $this->invoice_url('launch'));
830
+		}
831
+		return apply_filters('FHEE__EE_Registration__receipt_url__receipt_url', '', $this, $messenger, 'receipt');
832
+	}
833
+
834
+
835
+	/**
836
+	 * Gets the string which represents the URL trigger for the invoice template in the message template system.
837
+	 *
838
+	 * @param string $messenger 'pdf' or 'html'.  Default 'html'.
839
+	 * @return string
840
+	 * @throws EE_Error
841
+	 */
842
+	public function invoice_url($messenger = 'html')
843
+	{
844
+		/**
845
+		 * The below will be deprecated one version after this.  We check first if there is a custom invoice template
846
+		 * already in use on old system.  If there is then we just return the standard url for it.
847
+		 *
848
+		 * @since 4.5.0
849
+		 */
850
+		$template_relative_path = 'modules/gateways/Invoice/lib/templates/invoice_body.template.php';
851
+		$has_custom = EEH_Template::locate_template(
852
+			$template_relative_path,
853
+			array(),
854
+			true,
855
+			true,
856
+			true
857
+		);
858
+
859
+		if ($has_custom) {
860
+			if ($messenger == 'html') {
861
+				return $this->invoice_url('launch');
862
+			}
863
+			$route = $messenger == 'download' || $messenger == 'pdf' ? 'download_invoice' : 'launch_invoice';
864
+
865
+			$query_args = array('ee' => $route, 'id' => $this->reg_url_link());
866
+			if ($messenger == 'html') {
867
+				$query_args['html'] = true;
868
+			}
869
+			return add_query_arg($query_args, get_permalink(EE_Registry::instance()->CFG->core->thank_you_page_id));
870
+		}
871
+		return apply_filters('FHEE__EE_Registration__invoice_url__invoice_url', '', $this, $messenger, 'invoice');
872
+	}
873
+
874
+
875
+	/**
876
+	 * get Registration URL Link
877
+	 *
878
+	 * @access public
879
+	 * @return string
880
+	 * @throws EE_Error
881
+	 */
882
+	public function reg_url_link()
883
+	{
884
+		return (string) $this->get('REG_url_link');
885
+	}
886
+
887
+
888
+	/**
889
+	 * Echoes out invoice_url()
890
+	 *
891
+	 * @param string $type 'download','launch', or 'html' (default is 'launch')
892
+	 * @return void
893
+	 * @throws EE_Error
894
+	 */
895
+	public function e_invoice_url($type = 'launch')
896
+	{
897
+		echo $this->invoice_url($type);
898
+	}
899
+
900
+
901
+	/**
902
+	 * Echoes out payment_overview_url
903
+	 */
904
+	public function e_payment_overview_url()
905
+	{
906
+		echo $this->payment_overview_url();
907
+	}
908
+
909
+
910
+	/**
911
+	 * Gets the URL for the checkout payment options reg step
912
+	 * with this registration's REG_url_link added as a query parameter
913
+	 *
914
+	 * @param bool $clear_session Set to true when you want to clear the session on revisiting the
915
+	 *                            payment overview url.
916
+	 * @return string
917
+	 * @throws InvalidInterfaceException
918
+	 * @throws InvalidDataTypeException
919
+	 * @throws EE_Error
920
+	 * @throws InvalidArgumentException
921
+	 */
922
+	public function payment_overview_url($clear_session = false)
923
+	{
924
+		return add_query_arg(
925
+			(array) apply_filters(
926
+				'FHEE__EE_Registration__payment_overview_url__query_args',
927
+				array(
928
+					'e_reg_url_link' => $this->reg_url_link(),
929
+					'step'           => 'payment_options',
930
+					'revisit'        => true,
931
+					'clear_session'  => (bool) $clear_session,
932
+				),
933
+				$this
934
+			),
935
+			EE_Registry::instance()->CFG->core->reg_page_url()
936
+		);
937
+	}
938
+
939
+
940
+	/**
941
+	 * Gets the URL for the checkout attendee information reg step
942
+	 * with this registration's REG_url_link added as a query parameter
943
+	 *
944
+	 * @return string
945
+	 * @throws InvalidInterfaceException
946
+	 * @throws InvalidDataTypeException
947
+	 * @throws EE_Error
948
+	 * @throws InvalidArgumentException
949
+	 */
950
+	public function edit_attendee_information_url()
951
+	{
952
+		return add_query_arg(
953
+			(array) apply_filters(
954
+				'FHEE__EE_Registration__edit_attendee_information_url__query_args',
955
+				array(
956
+					'e_reg_url_link' => $this->reg_url_link(),
957
+					'step'           => 'attendee_information',
958
+					'revisit'        => true,
959
+				),
960
+				$this
961
+			),
962
+			EE_Registry::instance()->CFG->core->reg_page_url()
963
+		);
964
+	}
965
+
966
+
967
+	/**
968
+	 * Simply generates and returns the appropriate admin_url link to edit this registration
969
+	 *
970
+	 * @return string
971
+	 * @throws EE_Error
972
+	 */
973
+	public function get_admin_edit_url()
974
+	{
975
+		return EEH_URL::add_query_args_and_nonce(
976
+			array(
977
+				'page'    => 'espresso_registrations',
978
+				'action'  => 'view_registration',
979
+				'_REG_ID' => $this->ID(),
980
+			),
981
+			admin_url('admin.php')
982
+		);
983
+	}
984
+
985
+
986
+	/**
987
+	 *    is_primary_registrant?
988
+	 */
989
+	public function is_primary_registrant()
990
+	{
991
+		return $this->get('REG_count') === 1 ? true : false;
992
+	}
993
+
994
+
995
+	/**
996
+	 * This returns the primary registration object for this registration group (which may be this object).
997
+	 *
998
+	 * @return EE_Registration
999
+	 * @throws EE_Error
1000
+	 */
1001
+	public function get_primary_registration()
1002
+	{
1003
+		if ($this->is_primary_registrant()) {
1004
+			return $this;
1005
+		}
1006
+
1007
+		// k reg_count !== 1 so let's get the EE_Registration object matching this txn_id and reg_count == 1
1008
+		/** @var EE_Registration $primary_registrant */
1009
+		$primary_registrant = EEM_Registration::instance()->get_one(
1010
+			array(
1011
+				array(
1012
+					'TXN_ID'    => $this->transaction_ID(),
1013
+					'REG_count' => 1,
1014
+				),
1015
+			)
1016
+		);
1017
+		return $primary_registrant;
1018
+	}
1019
+
1020
+
1021
+	/**
1022
+	 *        get  Attendee Number
1023
+	 *
1024
+	 * @access        public
1025
+	 */
1026
+	public function count()
1027
+	{
1028
+		return $this->get('REG_count');
1029
+	}
1030
+
1031
+
1032
+	/**
1033
+	 *        get Group Size
1034
+	 */
1035
+	public function group_size()
1036
+	{
1037
+		return $this->get('REG_group_size');
1038
+	}
1039
+
1040
+
1041
+	/**
1042
+	 *        get Registration Date
1043
+	 */
1044
+	public function date()
1045
+	{
1046
+		return $this->get('REG_date');
1047
+	}
1048
+
1049
+
1050
+	/**
1051
+	 * gets a pretty date
1052
+	 *
1053
+	 * @param string $date_format
1054
+	 * @param string $time_format
1055
+	 * @return string
1056
+	 * @throws EE_Error
1057
+	 */
1058
+	public function pretty_date($date_format = null, $time_format = null)
1059
+	{
1060
+		return $this->get_datetime('REG_date', $date_format, $time_format);
1061
+	}
1062
+
1063
+
1064
+	/**
1065
+	 * final_price
1066
+	 * the registration's share of the transaction total, so that the
1067
+	 * sum of all the transaction's REG_final_prices equal the transaction's total
1068
+	 *
1069
+	 * @return float
1070
+	 * @throws EE_Error
1071
+	 */
1072
+	public function final_price()
1073
+	{
1074
+		return $this->get('REG_final_price');
1075
+	}
1076
+
1077
+
1078
+	/**
1079
+	 * pretty_final_price
1080
+	 *  final price as formatted string, with correct decimal places and currency symbol
1081
+	 *
1082
+	 * @return string
1083
+	 * @throws EE_Error
1084
+	 */
1085
+	public function pretty_final_price()
1086
+	{
1087
+		return $this->get_pretty('REG_final_price');
1088
+	}
1089
+
1090
+
1091
+	/**
1092
+	 * get paid (yeah)
1093
+	 *
1094
+	 * @return float
1095
+	 * @throws EE_Error
1096
+	 */
1097
+	public function paid()
1098
+	{
1099
+		return $this->get('REG_paid');
1100
+	}
1101
+
1102
+
1103
+	/**
1104
+	 * pretty_paid
1105
+	 *
1106
+	 * @return float
1107
+	 * @throws EE_Error
1108
+	 */
1109
+	public function pretty_paid()
1110
+	{
1111
+		return $this->get_pretty('REG_paid');
1112
+	}
1113
+
1114
+
1115
+	/**
1116
+	 * owes_monies_and_can_pay
1117
+	 * whether or not this registration has monies owing and it's' status allows payment
1118
+	 *
1119
+	 * @param array $requires_payment
1120
+	 * @return bool
1121
+	 * @throws EE_Error
1122
+	 */
1123
+	public function owes_monies_and_can_pay($requires_payment = array())
1124
+	{
1125
+		// these reg statuses require payment (if event is not free)
1126
+		$requires_payment = ! empty($requires_payment)
1127
+			? $requires_payment
1128
+			: EEM_Registration::reg_statuses_that_allow_payment();
1129
+		if (in_array($this->status_ID(), $requires_payment) &&
1130
+			$this->final_price() != 0 &&
1131
+			$this->final_price() != $this->paid()
1132
+		) {
1133
+			return true;
1134
+		} else {
1135
+			return false;
1136
+		}
1137
+	}
1138
+
1139
+
1140
+	/**
1141
+	 * Prints out the return value of $this->pretty_status()
1142
+	 *
1143
+	 * @param bool $show_icons
1144
+	 * @return void
1145
+	 * @throws EE_Error
1146
+	 */
1147
+	public function e_pretty_status($show_icons = false)
1148
+	{
1149
+		echo $this->pretty_status($show_icons);
1150
+	}
1151
+
1152
+
1153
+	/**
1154
+	 * Returns a nice version of the status for displaying to customers
1155
+	 *
1156
+	 * @param bool $show_icons
1157
+	 * @return string
1158
+	 * @throws EE_Error
1159
+	 */
1160
+	public function pretty_status($show_icons = false)
1161
+	{
1162
+		$status = EEM_Status::instance()->localized_status(
1163
+			array($this->status_ID() => esc_html__('unknown', 'event_espresso')),
1164
+			false,
1165
+			'sentence'
1166
+		);
1167
+		$icon = '';
1168
+		switch ($this->status_ID()) {
1169
+			case EEM_Registration::status_id_approved:
1170
+				$icon = $show_icons
1171
+					? '<span class="dashicons dashicons-star-filled ee-icon-size-16 green-text"></span>'
1172
+					: '';
1173
+				break;
1174
+			case EEM_Registration::status_id_pending_payment:
1175
+				$icon = $show_icons
1176
+					? '<span class="dashicons dashicons-star-half ee-icon-size-16 orange-text"></span>'
1177
+					: '';
1178
+				break;
1179
+			case EEM_Registration::status_id_not_approved:
1180
+				$icon = $show_icons
1181
+					? '<span class="dashicons dashicons-marker ee-icon-size-16 orange-text"></span>'
1182
+					: '';
1183
+				break;
1184
+			case EEM_Registration::status_id_cancelled:
1185
+				$icon = $show_icons
1186
+					? '<span class="dashicons dashicons-no ee-icon-size-16 lt-grey-text"></span>'
1187
+					: '';
1188
+				break;
1189
+			case EEM_Registration::status_id_incomplete:
1190
+				$icon = $show_icons
1191
+					? '<span class="dashicons dashicons-no ee-icon-size-16 lt-orange-text"></span>'
1192
+					: '';
1193
+				break;
1194
+			case EEM_Registration::status_id_declined:
1195
+				$icon = $show_icons
1196
+					? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>'
1197
+					: '';
1198
+				break;
1199
+			case EEM_Registration::status_id_wait_list:
1200
+				$icon = $show_icons
1201
+					? '<span class="dashicons dashicons-clipboard ee-icon-size-16 purple-text"></span>'
1202
+					: '';
1203
+				break;
1204
+		}
1205
+		return $icon . $status[ $this->status_ID() ];
1206
+	}
1207
+
1208
+
1209
+	/**
1210
+	 *        get Attendee Is Going
1211
+	 */
1212
+	public function att_is_going()
1213
+	{
1214
+		return $this->get('REG_att_is_going');
1215
+	}
1216
+
1217
+
1218
+	/**
1219
+	 * Gets related answers
1220
+	 *
1221
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1222
+	 * @return EE_Answer[]
1223
+	 * @throws EE_Error
1224
+	 */
1225
+	public function answers($query_params = null)
1226
+	{
1227
+		return $this->get_many_related('Answer', $query_params);
1228
+	}
1229
+
1230
+
1231
+	/**
1232
+	 * Gets the registration's answer value to the specified question
1233
+	 * (either the question's ID or a question object)
1234
+	 *
1235
+	 * @param EE_Question|int $question
1236
+	 * @param bool            $pretty_value
1237
+	 * @return array|string if pretty_value= true, the result will always be a string
1238
+	 * (because the answer might be an array of answer values, so passing pretty_value=true
1239
+	 * will convert it into some kind of string)
1240
+	 * @throws EE_Error
1241
+	 */
1242
+	public function answer_value_to_question($question, $pretty_value = true)
1243
+	{
1244
+		$question_id = EEM_Question::instance()->ensure_is_ID($question);
1245
+		return EEM_Answer::instance()->get_answer_value_to_question($this, $question_id, $pretty_value);
1246
+	}
1247
+
1248
+
1249
+	/**
1250
+	 * question_groups
1251
+	 * returns an array of EE_Question_Group objects for this registration
1252
+	 *
1253
+	 * @return EE_Question_Group[]
1254
+	 * @throws EE_Error
1255
+	 * @throws InvalidArgumentException
1256
+	 * @throws InvalidDataTypeException
1257
+	 * @throws InvalidInterfaceException
1258
+	 * @throws ReflectionException
1259
+	 */
1260
+	public function question_groups()
1261
+	{
1262
+		return EEM_Event::instance()->get_question_groups_for_event($this->event_ID(), $this);
1263
+	}
1264
+
1265
+
1266
+	/**
1267
+	 * count_question_groups
1268
+	 * returns a count of the number of EE_Question_Group objects for this registration
1269
+	 *
1270
+	 * @return int
1271
+	 * @throws EE_Error
1272
+	 * @throws EntityNotFoundException
1273
+	 * @throws InvalidArgumentException
1274
+	 * @throws InvalidDataTypeException
1275
+	 * @throws InvalidInterfaceException
1276
+	 * @throws ReflectionException
1277
+	 */
1278
+	public function count_question_groups()
1279
+	{
1280
+		return EEM_Event::instance()->count_related(
1281
+			$this->event_ID(),
1282
+			'Question_Group',
1283
+			[
1284
+				[
1285
+					'Event_Question_Group.'
1286
+					. EEM_Event_Question_Group::instance()->fieldNameForContext($this->is_primary_registrant()) => true,
1287
+				]
1288
+			]
1289
+		);
1290
+	}
1291
+
1292
+
1293
+	/**
1294
+	 * Returns the registration date in the 'standard' string format
1295
+	 * (function may be improved in the future to allow for different formats and timezones)
1296
+	 *
1297
+	 * @return string
1298
+	 * @throws EE_Error
1299
+	 */
1300
+	public function reg_date()
1301
+	{
1302
+		return $this->get_datetime('REG_date');
1303
+	}
1304
+
1305
+
1306
+	/**
1307
+	 * Gets the datetime-ticket for this registration (ie, it can be used to isolate
1308
+	 * the ticket this registration purchased, or the datetime they have registered
1309
+	 * to attend)
1310
+	 *
1311
+	 * @return EE_Datetime_Ticket
1312
+	 * @throws EE_Error
1313
+	 */
1314
+	public function datetime_ticket()
1315
+	{
1316
+		return $this->get_first_related('Datetime_Ticket');
1317
+	}
1318
+
1319
+
1320
+	/**
1321
+	 * Sets the registration's datetime_ticket.
1322
+	 *
1323
+	 * @param EE_Datetime_Ticket $datetime_ticket
1324
+	 * @return EE_Datetime_Ticket
1325
+	 * @throws EE_Error
1326
+	 */
1327
+	public function set_datetime_ticket($datetime_ticket)
1328
+	{
1329
+		return $this->_add_relation_to($datetime_ticket, 'Datetime_Ticket');
1330
+	}
1331
+
1332
+	/**
1333
+	 * Gets deleted
1334
+	 *
1335
+	 * @return bool
1336
+	 * @throws EE_Error
1337
+	 */
1338
+	public function deleted()
1339
+	{
1340
+		return $this->get('REG_deleted');
1341
+	}
1342
+
1343
+	/**
1344
+	 * Sets deleted
1345
+	 *
1346
+	 * @param boolean $deleted
1347
+	 * @return bool
1348
+	 * @throws EE_Error
1349
+	 * @throws RuntimeException
1350
+	 */
1351
+	public function set_deleted($deleted)
1352
+	{
1353
+		if ($deleted) {
1354
+			$this->delete();
1355
+		} else {
1356
+			$this->restore();
1357
+		}
1358
+	}
1359
+
1360
+
1361
+	/**
1362
+	 * Get the status object of this object
1363
+	 *
1364
+	 * @return EE_Status
1365
+	 * @throws EE_Error
1366
+	 */
1367
+	public function status_obj()
1368
+	{
1369
+		return $this->get_first_related('Status');
1370
+	}
1371
+
1372
+
1373
+	/**
1374
+	 * Returns the number of times this registration has checked into any of the datetimes
1375
+	 * its available for
1376
+	 *
1377
+	 * @return int
1378
+	 * @throws EE_Error
1379
+	 */
1380
+	public function count_checkins()
1381
+	{
1382
+		return $this->get_model()->count_related($this, 'Checkin');
1383
+	}
1384
+
1385
+
1386
+	/**
1387
+	 * Returns the number of current Check-ins this registration is checked into for any of the datetimes the
1388
+	 * registration is for.  Note, this is ONLY checked in (does not include checkedout)
1389
+	 *
1390
+	 * @return int
1391
+	 * @throws EE_Error
1392
+	 */
1393
+	public function count_checkins_not_checkedout()
1394
+	{
1395
+		return $this->get_model()->count_related($this, 'Checkin', array(array('CHK_in' => 1)));
1396
+	}
1397
+
1398
+
1399
+	/**
1400
+	 * The purpose of this method is simply to check whether this registration can checkin to the given datetime.
1401
+	 *
1402
+	 * @param int | EE_Datetime $DTT_OR_ID      The datetime the registration is being checked against
1403
+	 * @param bool              $check_approved This is used to indicate whether the caller wants can_checkin to also
1404
+	 *                                          consider registration status as well as datetime access.
1405
+	 * @return bool
1406
+	 * @throws EE_Error
1407
+	 */
1408
+	public function can_checkin($DTT_OR_ID, $check_approved = true)
1409
+	{
1410
+		$DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1411
+
1412
+		// first check registration status
1413
+		if (($check_approved && ! $this->is_approved()) || ! $DTT_ID) {
1414
+			return false;
1415
+		}
1416
+		// is there a datetime ticket that matches this dtt_ID?
1417
+		if (! (EEM_Datetime_Ticket::instance()->exists(
1418
+			array(
1419
+				array(
1420
+					'TKT_ID' => $this->get('TKT_ID'),
1421
+					'DTT_ID' => $DTT_ID,
1422
+				),
1423
+			)
1424
+		))
1425
+		) {
1426
+			return false;
1427
+		}
1428
+
1429
+		// final check is against TKT_uses
1430
+		return $this->verify_can_checkin_against_TKT_uses($DTT_ID);
1431
+	}
1432
+
1433
+
1434
+	/**
1435
+	 * This method verifies whether the user can checkin for the given datetime considering the max uses value set on
1436
+	 * the ticket. To do this,  a query is done to get the count of the datetime records already checked into.  If the
1437
+	 * datetime given does not have a check-in record and checking in for that datetime will exceed the allowed uses,
1438
+	 * then return false.  Otherwise return true.
1439
+	 *
1440
+	 * @param int | EE_Datetime $DTT_OR_ID The datetime the registration is being checked against
1441
+	 * @return bool true means can checkin.  false means cannot checkin.
1442
+	 * @throws EE_Error
1443
+	 */
1444
+	public function verify_can_checkin_against_TKT_uses($DTT_OR_ID)
1445
+	{
1446
+		$DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1447
+
1448
+		if (! $DTT_ID) {
1449
+			return false;
1450
+		}
1451
+
1452
+		$max_uses = $this->ticket() instanceof EE_Ticket ? $this->ticket()->uses() : EE_INF;
1453
+
1454
+		// if max uses is not set or equals infinity then return true cause its not a factor for whether user can
1455
+		// check-in or not.
1456
+		if (! $max_uses || $max_uses === EE_INF) {
1457
+			return true;
1458
+		}
1459
+
1460
+		// does this datetime have a checkin record?  If so, then the dtt count has already been verified so we can just
1461
+		// go ahead and toggle.
1462
+		if (EEM_Checkin::instance()->exists(array(array('REG_ID' => $this->ID(), 'DTT_ID' => $DTT_ID)))) {
1463
+			return true;
1464
+		}
1465
+
1466
+		// made it here so the last check is whether the number of checkins per unique datetime on this registration
1467
+		// disallows further check-ins.
1468
+		$count_unique_dtt_checkins = EEM_Checkin::instance()->count(
1469
+			array(
1470
+				array(
1471
+					'REG_ID' => $this->ID(),
1472
+					'CHK_in' => true,
1473
+				),
1474
+			),
1475
+			'DTT_ID',
1476
+			true
1477
+		);
1478
+		// checkins have already reached their max number of uses
1479
+		// so registrant can NOT checkin
1480
+		if ($count_unique_dtt_checkins >= $max_uses) {
1481
+			EE_Error::add_error(
1482
+				esc_html__(
1483
+					'Check-in denied because number of datetime uses for the ticket has been reached or exceeded.',
1484
+					'event_espresso'
1485
+				),
1486
+				__FILE__,
1487
+				__FUNCTION__,
1488
+				__LINE__
1489
+			);
1490
+			return false;
1491
+		}
1492
+		return true;
1493
+	}
1494
+
1495
+
1496
+	/**
1497
+	 * toggle Check-in status for this registration
1498
+	 * Check-ins are toggled in the following order:
1499
+	 * never checked in -> checked in
1500
+	 * checked in -> checked out
1501
+	 * checked out -> checked in
1502
+	 *
1503
+	 * @param  int $DTT_ID  include specific datetime to toggle Check-in for.
1504
+	 *                      If not included or null, then it is assumed latest datetime is being toggled.
1505
+	 * @param bool $verify  If true then can_checkin() is used to verify whether the person
1506
+	 *                      can be checked in or not.  Otherwise this forces change in checkin status.
1507
+	 * @return bool|int     the chk_in status toggled to OR false if nothing got changed.
1508
+	 * @throws EE_Error
1509
+	 */
1510
+	public function toggle_checkin_status($DTT_ID = null, $verify = false)
1511
+	{
1512
+		if (empty($DTT_ID)) {
1513
+			$datetime = $this->get_latest_related_datetime();
1514
+			$DTT_ID = $datetime instanceof EE_Datetime ? $datetime->ID() : 0;
1515
+			// verify the registration can checkin for the given DTT_ID
1516
+		} elseif (! $this->can_checkin($DTT_ID, $verify)) {
1517
+			EE_Error::add_error(
1518
+				sprintf(
1519
+					esc_html__(
1520
+						'The given registration (ID:%1$d) can not be checked in to the given DTT_ID (%2$d), because the registration does not have access',
1521
+						'event_espresso'
1522
+					),
1523
+					$this->ID(),
1524
+					$DTT_ID
1525
+				),
1526
+				__FILE__,
1527
+				__FUNCTION__,
1528
+				__LINE__
1529
+			);
1530
+			return false;
1531
+		}
1532
+		$status_paths = array(
1533
+			EE_Checkin::status_checked_never => EE_Checkin::status_checked_in,
1534
+			EE_Checkin::status_checked_in    => EE_Checkin::status_checked_out,
1535
+			EE_Checkin::status_checked_out   => EE_Checkin::status_checked_in,
1536
+		);
1537
+		// start by getting the current status so we know what status we'll be changing to.
1538
+		$cur_status = $this->check_in_status_for_datetime($DTT_ID, null);
1539
+		$status_to = $status_paths[ $cur_status ];
1540
+		// database only records true for checked IN or false for checked OUT
1541
+		// no record ( null ) means checked in NEVER, but we obviously don't save that
1542
+		$new_status = $status_to === EE_Checkin::status_checked_in ? true : false;
1543
+		// add relation - note Check-ins are always creating new rows
1544
+		// because we are keeping track of Check-ins over time.
1545
+		// Eventually we'll probably want to show a list table
1546
+		// for the individual Check-ins so that they can be managed.
1547
+		$checkin = EE_Checkin::new_instance(
1548
+			array(
1549
+				'REG_ID' => $this->ID(),
1550
+				'DTT_ID' => $DTT_ID,
1551
+				'CHK_in' => $new_status,
1552
+			)
1553
+		);
1554
+		// if the record could not be saved then return false
1555
+		if ($checkin->save() === 0) {
1556
+			if (WP_DEBUG) {
1557
+				global $wpdb;
1558
+				$error = sprintf(
1559
+					esc_html__(
1560
+						'Registration check in update failed because of the following database error: %1$s%2$s',
1561
+						'event_espresso'
1562
+					),
1563
+					'<br />',
1564
+					$wpdb->last_error
1565
+				);
1566
+			} else {
1567
+				$error = esc_html__(
1568
+					'Registration check in update failed because of an unknown database error',
1569
+					'event_espresso'
1570
+				);
1571
+			}
1572
+			EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
1573
+			return false;
1574
+		}
1575
+		return $status_to;
1576
+	}
1577
+
1578
+
1579
+	/**
1580
+	 * Returns the latest datetime related to this registration (via the ticket attached to the registration).
1581
+	 * "Latest" is defined by the `DTT_EVT_start` column.
1582
+	 *
1583
+	 * @return EE_Datetime|null
1584
+	 * @throws EE_Error
1585
+	 */
1586
+	public function get_latest_related_datetime()
1587
+	{
1588
+		return EEM_Datetime::instance()->get_one(
1589
+			array(
1590
+				array(
1591
+					'Ticket.Registration.REG_ID' => $this->ID(),
1592
+				),
1593
+				'order_by' => array('DTT_EVT_start' => 'DESC'),
1594
+			)
1595
+		);
1596
+	}
1597
+
1598
+
1599
+	/**
1600
+	 * Returns the earliest datetime related to this registration (via the ticket attached to the registration).
1601
+	 * "Earliest" is defined by the `DTT_EVT_start` column.
1602
+	 *
1603
+	 * @throws EE_Error
1604
+	 */
1605
+	public function get_earliest_related_datetime()
1606
+	{
1607
+		return EEM_Datetime::instance()->get_one(
1608
+			array(
1609
+				array(
1610
+					'Ticket.Registration.REG_ID' => $this->ID(),
1611
+				),
1612
+				'order_by' => array('DTT_EVT_start' => 'ASC'),
1613
+			)
1614
+		);
1615
+	}
1616
+
1617
+
1618
+	/**
1619
+	 * This method simply returns the check-in status for this registration and the given datetime.
1620
+	 * If neither the datetime nor the checkin values are provided as arguments,
1621
+	 * then this will return the LATEST check-in status for the registration across all datetimes it belongs to.
1622
+	 *
1623
+	 * @param  int       $DTT_ID  The ID of the datetime we're checking against
1624
+	 *                            (if empty we'll get the primary datetime for
1625
+	 *                            this registration (via event) and use it's ID);
1626
+	 * @param EE_Checkin $checkin If present, we use the given checkin object rather than the dtt_id.
1627
+	 *
1628
+	 * @return int                Integer representing Check-in status.
1629
+	 * @throws EE_Error
1630
+	 */
1631
+	public function check_in_status_for_datetime($DTT_ID = 0, $checkin = null)
1632
+	{
1633
+		$checkin_query_params = array(
1634
+			'order_by' => array('CHK_timestamp' => 'DESC'),
1635
+		);
1636
+
1637
+		if ($DTT_ID > 0) {
1638
+			$checkin_query_params[0] = array('DTT_ID' => $DTT_ID);
1639
+		}
1640
+
1641
+		// get checkin object (if exists)
1642
+		$checkin = $checkin instanceof EE_Checkin
1643
+			? $checkin
1644
+			: $this->get_first_related('Checkin', $checkin_query_params);
1645
+		if ($checkin instanceof EE_Checkin) {
1646
+			if ($checkin->get('CHK_in')) {
1647
+				return EE_Checkin::status_checked_in; // checked in
1648
+			}
1649
+			return EE_Checkin::status_checked_out; // had checked in but is now checked out.
1650
+		}
1651
+		return EE_Checkin::status_checked_never; // never been checked in
1652
+	}
1653
+
1654
+
1655
+	/**
1656
+	 * This method returns a localized message for the toggled Check-in message.
1657
+	 *
1658
+	 * @param  int $DTT_ID include specific datetime to get the correct Check-in message.  If not included or null,
1659
+	 *                     then it is assumed Check-in for primary datetime was toggled.
1660
+	 * @param bool $error  This just flags that you want an error message returned. This is put in so that the error
1661
+	 *                     message can be customized with the attendee name.
1662
+	 * @return string internationalized message
1663
+	 * @throws EE_Error
1664
+	 */
1665
+	public function get_checkin_msg($DTT_ID, $error = false)
1666
+	{
1667
+		// let's get the attendee first so we can include the name of the attendee
1668
+		$attendee = $this->get_first_related('Attendee');
1669
+		if ($attendee instanceof EE_Attendee) {
1670
+			if ($error) {
1671
+				return sprintf(__("%s's check-in status was not changed.", "event_espresso"), $attendee->full_name());
1672
+			}
1673
+			$cur_status = $this->check_in_status_for_datetime($DTT_ID);
1674
+			// what is the status message going to be?
1675
+			switch ($cur_status) {
1676
+				case EE_Checkin::status_checked_never:
1677
+					return sprintf(
1678
+						__("%s has been removed from Check-in records", "event_espresso"),
1679
+						$attendee->full_name()
1680
+					);
1681
+					break;
1682
+				case EE_Checkin::status_checked_in:
1683
+					return sprintf(__('%s has been checked in', 'event_espresso'), $attendee->full_name());
1684
+					break;
1685
+				case EE_Checkin::status_checked_out:
1686
+					return sprintf(__('%s has been checked out', 'event_espresso'), $attendee->full_name());
1687
+					break;
1688
+			}
1689
+		}
1690
+		return esc_html__("The check-in status could not be determined.", "event_espresso");
1691
+	}
1692
+
1693
+
1694
+	/**
1695
+	 * Returns the related EE_Transaction to this registration
1696
+	 *
1697
+	 * @return EE_Transaction
1698
+	 * @throws EE_Error
1699
+	 * @throws EntityNotFoundException
1700
+	 */
1701
+	public function transaction()
1702
+	{
1703
+		$transaction = $this->get_first_related('Transaction');
1704
+		if (! $transaction instanceof \EE_Transaction) {
1705
+			throw new EntityNotFoundException('Transaction ID', $this->transaction_ID());
1706
+		}
1707
+		return $transaction;
1708
+	}
1709
+
1710
+
1711
+	/**
1712
+	 *        get Registration Code
1713
+	 */
1714
+	public function reg_code()
1715
+	{
1716
+		return $this->get('REG_code');
1717
+	}
1718
+
1719
+
1720
+	/**
1721
+	 *        get Transaction ID
1722
+	 */
1723
+	public function transaction_ID()
1724
+	{
1725
+		return $this->get('TXN_ID');
1726
+	}
1727
+
1728
+
1729
+	/**
1730
+	 * @return int
1731
+	 * @throws EE_Error
1732
+	 */
1733
+	public function ticket_ID()
1734
+	{
1735
+		return $this->get('TKT_ID');
1736
+	}
1737
+
1738
+
1739
+	/**
1740
+	 *        Set Registration Code
1741
+	 *
1742
+	 * @access    public
1743
+	 * @param    string  $REG_code Registration Code
1744
+	 * @param    boolean $use_default
1745
+	 * @throws EE_Error
1746
+	 */
1747
+	public function set_reg_code($REG_code, $use_default = false)
1748
+	{
1749
+		if (empty($REG_code)) {
1750
+			EE_Error::add_error(
1751
+				esc_html__('REG_code can not be empty.', 'event_espresso'),
1752
+				__FILE__,
1753
+				__FUNCTION__,
1754
+				__LINE__
1755
+			);
1756
+			return;
1757
+		}
1758
+		if (! $this->reg_code()) {
1759
+			parent::set('REG_code', $REG_code, $use_default);
1760
+		} else {
1761
+			EE_Error::doing_it_wrong(
1762
+				__CLASS__ . '::' . __FUNCTION__,
1763
+				esc_html__('Can not change a registration REG_code once it has been set.', 'event_espresso'),
1764
+				'4.6.0'
1765
+			);
1766
+		}
1767
+	}
1768
+
1769
+
1770
+	/**
1771
+	 * Returns all other registrations in the same group as this registrant who have the same ticket option.
1772
+	 * Note, if you want to just get all registrations in the same transaction (group), use:
1773
+	 *    $registration->transaction()->registrations();
1774
+	 *
1775
+	 * @since 4.5.0
1776
+	 * @return EE_Registration[] or empty array if this isn't a group registration.
1777
+	 * @throws EE_Error
1778
+	 */
1779
+	public function get_all_other_registrations_in_group()
1780
+	{
1781
+		if ($this->group_size() < 2) {
1782
+			return array();
1783
+		}
1784
+
1785
+		$query[0] = array(
1786
+			'TXN_ID' => $this->transaction_ID(),
1787
+			'REG_ID' => array('!=', $this->ID()),
1788
+			'TKT_ID' => $this->ticket_ID(),
1789
+		);
1790
+		/** @var EE_Registration[] $registrations */
1791
+		$registrations = $this->get_model()->get_all($query);
1792
+		return $registrations;
1793
+	}
1794
+
1795
+	/**
1796
+	 * Return the link to the admin details for the object.
1797
+	 *
1798
+	 * @return string
1799
+	 * @throws EE_Error
1800
+	 */
1801
+	public function get_admin_details_link()
1802
+	{
1803
+		EE_Registry::instance()->load_helper('URL');
1804
+		return EEH_URL::add_query_args_and_nonce(
1805
+			array(
1806
+				'page'    => 'espresso_registrations',
1807
+				'action'  => 'view_registration',
1808
+				'_REG_ID' => $this->ID(),
1809
+			),
1810
+			admin_url('admin.php')
1811
+		);
1812
+	}
1813
+
1814
+	/**
1815
+	 * Returns the link to the editor for the object.  Sometimes this is the same as the details.
1816
+	 *
1817
+	 * @return string
1818
+	 * @throws EE_Error
1819
+	 */
1820
+	public function get_admin_edit_link()
1821
+	{
1822
+		return $this->get_admin_details_link();
1823
+	}
1824
+
1825
+	/**
1826
+	 * Returns the link to a settings page for the object.
1827
+	 *
1828
+	 * @return string
1829
+	 * @throws EE_Error
1830
+	 */
1831
+	public function get_admin_settings_link()
1832
+	{
1833
+		return $this->get_admin_details_link();
1834
+	}
1835
+
1836
+	/**
1837
+	 * Returns the link to the "overview" for the object (typically the "list table" view).
1838
+	 *
1839
+	 * @return string
1840
+	 */
1841
+	public function get_admin_overview_link()
1842
+	{
1843
+		EE_Registry::instance()->load_helper('URL');
1844
+		return EEH_URL::add_query_args_and_nonce(
1845
+			array(
1846
+				'page' => 'espresso_registrations',
1847
+			),
1848
+			admin_url('admin.php')
1849
+		);
1850
+	}
1851
+
1852
+
1853
+	/**
1854
+	 * @param array $query_params
1855
+	 *
1856
+	 * @return \EE_Registration[]
1857
+	 * @throws EE_Error
1858
+	 */
1859
+	public function payments($query_params = array())
1860
+	{
1861
+		return $this->get_many_related('Payment', $query_params);
1862
+	}
1863
+
1864
+
1865
+	/**
1866
+	 * @param array $query_params
1867
+	 *
1868
+	 * @return \EE_Registration_Payment[]
1869
+	 * @throws EE_Error
1870
+	 */
1871
+	public function registration_payments($query_params = array())
1872
+	{
1873
+		return $this->get_many_related('Registration_Payment', $query_params);
1874
+	}
1875
+
1876
+
1877
+	/**
1878
+	 * This grabs the payment method corresponding to the last payment made for the amount owing on the registration.
1879
+	 * Note: if there are no payments on the registration there will be no payment method returned.
1880
+	 *
1881
+	 * @return EE_Payment_Method|null
1882
+	 */
1883
+	public function payment_method()
1884
+	{
1885
+		return EEM_Payment_Method::instance()->get_last_used_for_registration($this);
1886
+	}
1887
+
1888
+
1889
+	/**
1890
+	 * @return \EE_Line_Item
1891
+	 * @throws EntityNotFoundException
1892
+	 * @throws EE_Error
1893
+	 */
1894
+	public function ticket_line_item()
1895
+	{
1896
+		$ticket = $this->ticket();
1897
+		$transaction = $this->transaction();
1898
+		$line_item = null;
1899
+		$ticket_line_items = \EEH_Line_Item::get_line_items_by_object_type_and_IDs(
1900
+			$transaction->total_line_item(),
1901
+			'Ticket',
1902
+			array($ticket->ID())
1903
+		);
1904
+		foreach ($ticket_line_items as $ticket_line_item) {
1905
+			if ($ticket_line_item instanceof \EE_Line_Item
1906
+				&& $ticket_line_item->OBJ_type() === 'Ticket'
1907
+				&& $ticket_line_item->OBJ_ID() === $ticket->ID()
1908
+			) {
1909
+				$line_item = $ticket_line_item;
1910
+				break;
1911
+			}
1912
+		}
1913
+		if (! ($line_item instanceof \EE_Line_Item && $line_item->OBJ_type() === 'Ticket')) {
1914
+			throw new EntityNotFoundException('Line Item Ticket ID', $ticket->ID());
1915
+		}
1916
+		return $line_item;
1917
+	}
1918
+
1919
+
1920
+	/**
1921
+	 * Soft Deletes this model object.
1922
+	 *
1923
+	 * @return boolean | int
1924
+	 * @throws RuntimeException
1925
+	 * @throws EE_Error
1926
+	 */
1927
+	public function delete()
1928
+	{
1929
+		if ($this->update_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY, $this->status_ID()) === true) {
1930
+			$this->set_status(EEM_Registration::status_id_cancelled);
1931
+		}
1932
+		return parent::delete();
1933
+	}
1934
+
1935
+
1936
+	/**
1937
+	 * Restores whatever the previous status was on a registration before it was trashed (if possible)
1938
+	 *
1939
+	 * @throws EE_Error
1940
+	 * @throws RuntimeException
1941
+	 */
1942
+	public function restore()
1943
+	{
1944
+		$previous_status = $this->get_extra_meta(
1945
+			EE_Registration::PRE_TRASH_REG_STATUS_KEY,
1946
+			true,
1947
+			EEM_Registration::status_id_cancelled
1948
+		);
1949
+		if ($previous_status) {
1950
+			$this->delete_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY);
1951
+			$this->set_status($previous_status);
1952
+		}
1953
+		return parent::restore();
1954
+	}
1955
+
1956
+
1957
+	/**
1958
+	 * possibly toggle Registration status based on comparison of REG_paid vs REG_final_price
1959
+	 *
1960
+	 * @param  boolean $trigger_set_status_logic EE_Registration::set_status() can trigger additional logic
1961
+	 *                                           depending on whether the reg status changes to or from "Approved"
1962
+	 * @return boolean whether the Registration status was updated
1963
+	 * @throws EE_Error
1964
+	 * @throws RuntimeException
1965
+	 */
1966
+	public function updateStatusBasedOnTotalPaid($trigger_set_status_logic = true)
1967
+	{
1968
+		$paid = $this->paid();
1969
+		$price = $this->final_price();
1970
+		switch (true) {
1971
+			// overpaid or paid
1972
+			case EEH_Money::compare_floats($paid, $price, '>'):
1973
+			case EEH_Money::compare_floats($paid, $price):
1974
+				$new_status = EEM_Registration::status_id_approved;
1975
+				break;
1976
+			//  underpaid
1977
+			case EEH_Money::compare_floats($paid, $price, '<'):
1978
+				$new_status = EEM_Registration::status_id_pending_payment;
1979
+				break;
1980
+			// uhhh Houston...
1981
+			default:
1982
+				throw new RuntimeException(
1983
+					esc_html__('The total paid calculation for this registration is inaccurate.', 'event_espresso')
1984
+				);
1985
+		}
1986
+		if ($new_status !== $this->status_ID()) {
1987
+			if ($trigger_set_status_logic) {
1988
+				return $this->set_status($new_status);
1989
+			}
1990
+			parent::set('STS_ID', $new_status);
1991
+			return true;
1992
+		}
1993
+		return false;
1994
+	}
1995
+
1996
+
1997
+	/*************************** DEPRECATED ***************************/
1998
+
1999
+
2000
+	/**
2001
+	 * @deprecated
2002
+	 * @since     4.7.0
2003
+	 * @access    public
2004
+	 */
2005
+	public function price_paid()
2006
+	{
2007
+		EE_Error::doing_it_wrong(
2008
+			'EE_Registration::price_paid()',
2009
+			esc_html__(
2010
+				'This method is deprecated, please use EE_Registration::final_price() instead.',
2011
+				'event_espresso'
2012
+			),
2013
+			'4.7.0'
2014
+		);
2015
+		return $this->final_price();
2016
+	}
2017
+
2018
+
2019
+	/**
2020
+	 * @deprecated
2021
+	 * @since     4.7.0
2022
+	 * @access    public
2023
+	 * @param    float $REG_final_price
2024
+	 * @throws EE_Error
2025
+	 * @throws RuntimeException
2026
+	 */
2027
+	public function set_price_paid($REG_final_price = 0.00)
2028
+	{
2029
+		EE_Error::doing_it_wrong(
2030
+			'EE_Registration::set_price_paid()',
2031
+			esc_html__(
2032
+				'This method is deprecated, please use EE_Registration::set_final_price() instead.',
2033
+				'event_espresso'
2034
+			),
2035
+			'4.7.0'
2036
+		);
2037
+		$this->set_final_price($REG_final_price);
2038
+	}
2039
+
2040
+
2041
+	/**
2042
+	 * @deprecated
2043
+	 * @since 4.7.0
2044
+	 * @return string
2045
+	 * @throws EE_Error
2046
+	 */
2047
+	public function pretty_price_paid()
2048
+	{
2049
+		EE_Error::doing_it_wrong(
2050
+			'EE_Registration::pretty_price_paid()',
2051
+			esc_html__(
2052
+				'This method is deprecated, please use EE_Registration::pretty_final_price() instead.',
2053
+				'event_espresso'
2054
+			),
2055
+			'4.7.0'
2056
+		);
2057
+		return $this->pretty_final_price();
2058
+	}
2059
+
2060
+
2061
+	/**
2062
+	 * Gets the primary datetime related to this registration via the related Event to this registration
2063
+	 *
2064
+	 * @deprecated 4.9.17
2065
+	 * @return EE_Datetime
2066
+	 * @throws EE_Error
2067
+	 * @throws EntityNotFoundException
2068
+	 */
2069
+	public function get_related_primary_datetime()
2070
+	{
2071
+		EE_Error::doing_it_wrong(
2072
+			__METHOD__,
2073
+			esc_html__(
2074
+				'Use EE_Registration::get_latest_related_datetime() or EE_Registration::get_earliest_related_datetime()',
2075
+				'event_espresso'
2076
+			),
2077
+			'4.9.17',
2078
+			'5.0.0'
2079
+		);
2080
+		return $this->event()->primary_datetime();
2081
+	}
2082 2082
 }
Please login to merge, or discard this patch.