Completed
Branch FET/extra-logging-when-trashin... (688a5d)
by
unknown
14:57 queued 12:44
created
core/EED_Module.module.php 1 patch
Indentation   +137 added lines, -137 removed lines patch added patch discarded remove patch
@@ -15,141 +15,141 @@
 block discarded – undo
15 15
 abstract class EED_Module extends EE_Configurable implements ResettableInterface
16 16
 {
17 17
 
18
-    /**
19
-     * rendered output to be returned to WP
20
-     *
21
-     * @var    string $output
22
-     */
23
-    protected $output = '';
24
-
25
-    /**
26
-     * the current active espresso template theme
27
-     *
28
-     * @var    string $theme
29
-     */
30
-    protected $theme = '';
31
-
32
-
33
-    /**
34
-     * @return void
35
-     */
36
-    public static function reset()
37
-    {
38
-        $module_name = get_called_class();
39
-        new $module_name();
40
-    }
41
-
42
-
43
-    /**
44
-     *    set_hooks - for hooking into EE Core, other modules, etc
45
-     *
46
-     * @access    public
47
-     * @return    void
48
-     */
49
-    public static function set_hooks()
50
-    {
51
-    }
52
-
53
-
54
-    /**
55
-     *    set_hooks_admin - for hooking into EE Admin Core, other modules, etc
56
-     *
57
-     * @access    public
58
-     * @return    void
59
-     */
60
-    public static function set_hooks_admin()
61
-    {
62
-    }
63
-
64
-
65
-    /**
66
-     *    run - initial module setup
67
-     *    this method is primarily used for activating resources in the EE_Front_Controller thru the use of filters
68
-     *
69
-     * @access    public
70
-     * @var            WP $WP
71
-     * @return    void
72
-     */
73
-    abstract public function run($WP);
74
-
75
-
76
-    /**
77
-     * EED_Module constructor.
78
-     */
79
-    final public function __construct()
80
-    {
81
-        $this->theme = EE_Config::get_current_theme();
82
-        $module_name = $this->module_name();
83
-        EE_Registry::instance()->modules->{$module_name} = $this;
84
-    }
85
-
86
-
87
-    /**
88
-     * @param string $module_name
89
-     * @return EED_Module|mixed
90
-     * @throws EE_Error
91
-     * @throws ReflectionException
92
-     */
93
-    protected static function get_instance($module_name = '')
94
-    {
95
-        $module_name = ! empty($module_name)
96
-            ? $module_name
97
-            : get_called_class();
98
-        if (
99
-            ! isset(EE_Registry::instance()->modules->{$module_name})
100
-            || ! EE_Registry::instance()->modules->{$module_name} instanceof EED_Module
101
-        ) {
102
-            EE_Registry::instance()->add_module($module_name);
103
-        }
104
-        return EE_Registry::instance()->get_module($module_name);
105
-    }
106
-
107
-
108
-    /**
109
-     *    module_name
110
-     *
111
-     * @access    public
112
-     * @return    string
113
-     */
114
-    public function module_name()
115
-    {
116
-        return get_class($this);
117
-    }
118
-
119
-
120
-    /**
121
-     * @return string
122
-     */
123
-    public function theme()
124
-    {
125
-        return $this->theme;
126
-    }
127
-
128
-
129
-    /**
130
-     * @return RequestInterface
131
-     * @since   4.10.14.p
132
-     */
133
-    protected static function getRequest()
134
-    {
135
-        static $request;
136
-        if (! $request instanceof RequestInterface) {
137
-            $request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
138
-        }
139
-        return $request;
140
-    }
141
-
142
-
143
-    /**
144
-     * @return ResponseInterface
145
-     * @since   4.10.14.p
146
-     */
147
-    protected static function getResponse()
148
-    {
149
-        static $response;
150
-        if (! $response instanceof RequestInterface) {
151
-            $response = LoaderFactory::getLoader()->getShared(ResponseInterface::class);
152
-        }
153
-        return $response;
154
-    }
18
+	/**
19
+	 * rendered output to be returned to WP
20
+	 *
21
+	 * @var    string $output
22
+	 */
23
+	protected $output = '';
24
+
25
+	/**
26
+	 * the current active espresso template theme
27
+	 *
28
+	 * @var    string $theme
29
+	 */
30
+	protected $theme = '';
31
+
32
+
33
+	/**
34
+	 * @return void
35
+	 */
36
+	public static function reset()
37
+	{
38
+		$module_name = get_called_class();
39
+		new $module_name();
40
+	}
41
+
42
+
43
+	/**
44
+	 *    set_hooks - for hooking into EE Core, other modules, etc
45
+	 *
46
+	 * @access    public
47
+	 * @return    void
48
+	 */
49
+	public static function set_hooks()
50
+	{
51
+	}
52
+
53
+
54
+	/**
55
+	 *    set_hooks_admin - for hooking into EE Admin Core, other modules, etc
56
+	 *
57
+	 * @access    public
58
+	 * @return    void
59
+	 */
60
+	public static function set_hooks_admin()
61
+	{
62
+	}
63
+
64
+
65
+	/**
66
+	 *    run - initial module setup
67
+	 *    this method is primarily used for activating resources in the EE_Front_Controller thru the use of filters
68
+	 *
69
+	 * @access    public
70
+	 * @var            WP $WP
71
+	 * @return    void
72
+	 */
73
+	abstract public function run($WP);
74
+
75
+
76
+	/**
77
+	 * EED_Module constructor.
78
+	 */
79
+	final public function __construct()
80
+	{
81
+		$this->theme = EE_Config::get_current_theme();
82
+		$module_name = $this->module_name();
83
+		EE_Registry::instance()->modules->{$module_name} = $this;
84
+	}
85
+
86
+
87
+	/**
88
+	 * @param string $module_name
89
+	 * @return EED_Module|mixed
90
+	 * @throws EE_Error
91
+	 * @throws ReflectionException
92
+	 */
93
+	protected static function get_instance($module_name = '')
94
+	{
95
+		$module_name = ! empty($module_name)
96
+			? $module_name
97
+			: get_called_class();
98
+		if (
99
+			! isset(EE_Registry::instance()->modules->{$module_name})
100
+			|| ! EE_Registry::instance()->modules->{$module_name} instanceof EED_Module
101
+		) {
102
+			EE_Registry::instance()->add_module($module_name);
103
+		}
104
+		return EE_Registry::instance()->get_module($module_name);
105
+	}
106
+
107
+
108
+	/**
109
+	 *    module_name
110
+	 *
111
+	 * @access    public
112
+	 * @return    string
113
+	 */
114
+	public function module_name()
115
+	{
116
+		return get_class($this);
117
+	}
118
+
119
+
120
+	/**
121
+	 * @return string
122
+	 */
123
+	public function theme()
124
+	{
125
+		return $this->theme;
126
+	}
127
+
128
+
129
+	/**
130
+	 * @return RequestInterface
131
+	 * @since   4.10.14.p
132
+	 */
133
+	protected static function getRequest()
134
+	{
135
+		static $request;
136
+		if (! $request instanceof RequestInterface) {
137
+			$request = LoaderFactory::getLoader()->getShared(RequestInterface::class);
138
+		}
139
+		return $request;
140
+	}
141
+
142
+
143
+	/**
144
+	 * @return ResponseInterface
145
+	 * @since   4.10.14.p
146
+	 */
147
+	protected static function getResponse()
148
+	{
149
+		static $response;
150
+		if (! $response instanceof RequestInterface) {
151
+			$response = LoaderFactory::getLoader()->getShared(ResponseInterface::class);
152
+		}
153
+		return $response;
154
+	}
155 155
 }
Please login to merge, or discard this patch.
modules/events_archive/EED_Events_Archive.module.php 2 patches
Indentation   +1052 added lines, -1052 removed lines patch added patch discarded remove patch
@@ -17,1047 +17,1047 @@  discard block
 block discarded – undo
17 17
 class EED_Events_Archive extends EED_Module
18 18
 {
19 19
 
20
-    const EVENT_DETAILS_PRIORITY   = 100;
21
-
22
-    const EVENT_DATETIMES_PRIORITY = 110;
23
-
24
-    const EVENT_TICKETS_PRIORITY   = 120;
25
-
26
-    const EVENT_VENUES_PRIORITY    = 130;
27
-
28
-
29
-    public static $espresso_event_list_ID    = 0;
30
-
31
-    public static $espresso_grid_event_lists = [];
32
-
33
-    /**
34
-     * @type bool $using_get_the_excerpt
35
-     */
36
-    protected static $using_get_the_excerpt = false;
37
-
38
-    /**
39
-     * Used to flag when the event list is being called from an external iframe.
40
-     *
41
-     * @var bool $iframe
42
-     */
43
-    protected static $iframe = false;
44
-
45
-    /**
46
-     * @var EventListIframeEmbedButton $_iframe_embed_button
47
-     */
48
-    private static $_iframe_embed_button;
49
-
50
-    /**
51
-     * @type EE_Template_Part_Manager $template_parts
52
-     */
53
-    protected $template_parts;
54
-
55
-
56
-    /**
57
-     * @return EED_Events_Archive
58
-     * @throws EE_Error
59
-     * @throws ReflectionException
60
-     */
61
-    public static function instance()
62
-    {
63
-        return parent::get_instance(__CLASS__);
64
-    }
65
-
66
-
67
-    /**
68
-     * for hooking into EE Core, other modules, etc
69
-     *
70
-     * @return void
71
-     * @throws InvalidArgumentException
72
-     * @throws InvalidDataTypeException
73
-     * @throws InvalidInterfaceException
74
-     */
75
-    public static function set_hooks()
76
-    {
77
-        /** @var CustomPostTypeDefinitions $custom_post_type_definitions */
78
-        $custom_post_type_definitions = LoaderFactory::getLoader()->getShared(CustomPostTypeDefinitions::class);
79
-        $custom_post_types            = $custom_post_type_definitions->getDefinitions();
80
-        EE_Config::register_route(
81
-            $custom_post_types['espresso_events']['plural_slug'],
82
-            'Events_Archive',
83
-            'run'
84
-        );
85
-        EE_Config::register_route(
86
-            'event_list',
87
-            'Events_Archive',
88
-            'event_list'
89
-        );
90
-        EE_Config::register_route(
91
-            'iframe',
92
-            'Events_Archive',
93
-            'event_list_iframe',
94
-            'event_list'
95
-        );
96
-        add_action('wp_loaded', ['EED_Events_Archive', 'set_definitions'], 2);
97
-    }
98
-
99
-
100
-    /**
101
-     * for hooking into EE Admin Core, other modules, etc
102
-     *
103
-     * @return void
104
-     */
105
-    public static function set_hooks_admin()
106
-    {
107
-        add_action('wp_loaded', ['EED_Events_Archive', 'set_definitions'], 2);
108
-        // hook into the end of the \EE_Admin_Page::_load_page_dependencies()
109
-        // to load assets for "espresso_events" page on the "default" route (action)
110
-        add_action(
111
-            'FHEE__EE_Admin_Page___load_page_dependencies__after_load__espresso_events__default',
112
-            ['EED_Events_Archive', 'event_list_iframe_embed_button'],
113
-            10
114
-        );
115
-    }
116
-
117
-
118
-    /**
119
-     * @return void
120
-     */
121
-    public static function set_definitions()
122
-    {
123
-        define('EVENTS_ARCHIVE_ASSETS_URL', plugin_dir_url(__FILE__) . 'assets/');
124
-        define('EVENTS_ARCHIVE_TEMPLATES_PATH', str_replace('\\', '/', plugin_dir_path(__FILE__)) . 'templates/');
125
-    }
126
-
127
-
128
-    /**
129
-     * set up EE_Events_Archive_Config
130
-     */
131
-    protected function set_config()
132
-    {
133
-        $this->set_config_section('template_settings');
134
-        $this->set_config_class('EE_Events_Archive_Config');
135
-        $this->set_config_name('EED_Events_Archive');
136
-    }
137
-
138
-
139
-    /**
140
-     * @return EventListIframeEmbedButton
141
-     */
142
-    public static function get_iframe_embed_button()
143
-    {
144
-        if (! self::$_iframe_embed_button instanceof EventListIframeEmbedButton) {
145
-            self::$_iframe_embed_button = new EventListIframeEmbedButton();
146
-        }
147
-        return self::$_iframe_embed_button;
148
-    }
149
-
150
-
151
-    /**
152
-     * @return void
153
-     */
154
-    public static function event_list_iframe_embed_button()
155
-    {
156
-        $iframe_embed_button = EED_Events_Archive::get_iframe_embed_button();
157
-        $iframe_embed_button->addEmbedButton();
158
-    }
159
-
160
-
161
-    /**
162
-     * @param EE_Events_Archive_Config|null $config
163
-     * @return EE_Template_Part_Manager
164
-     * @throws EE_Error
165
-     */
166
-    public function initialize_template_parts(EE_Events_Archive_Config $config = null)
167
-    {
168
-        $config = $config instanceof EE_Events_Archive_Config ? $config : $this->config();
169
-        EEH_Autoloader::instance()->register_template_part_autoloaders();
170
-        $template_parts = new EE_Template_Part_Manager();
171
-        $template_parts->add_template_part(
172
-            'tickets',
173
-            esc_html__('Ticket Selector', 'event_espresso'),
174
-            'content-espresso_events-tickets.php',
175
-            $config->display_order_tickets
176
-        );
177
-        $template_parts->add_template_part(
178
-            'datetimes',
179
-            esc_html__('Dates and Times', 'event_espresso'),
180
-            'content-espresso_events-datetimes.php',
181
-            $config->display_order_datetimes
182
-        );
183
-        $template_parts->add_template_part(
184
-            'event',
185
-            esc_html__('Event Description', 'event_espresso'),
186
-            'content-espresso_events-details.php',
187
-            $config->display_order_event
188
-        );
189
-        $template_parts->add_template_part(
190
-            'venue',
191
-            esc_html__('Venue Information', 'event_espresso'),
192
-            'content-espresso_events-venues.php',
193
-            $config->display_order_venue
194
-        );
195
-        do_action('AHEE__EED_Event_Archive__initialize_template_parts', $template_parts);
196
-        return $template_parts;
197
-    }
198
-
199
-
200
-    /**
201
-     * initial module setup
202
-     * this gets called by the EE_Front_Controller if the module route is found in the incoming request
203
-     *
204
-     * @param WP $WP
205
-     * @return void
206
-     */
207
-    public function run($WP)
208
-    {
209
-        do_action('AHEE__EED_Events_Archive__before_run');
210
-        // ensure valid EE_Events_Archive_Config() object exists
211
-        $this->set_config();
212
-        /** @type EE_Events_Archive_Config $config */
213
-        $config = $this->config();
214
-        // load other required components
215
-        $this->load_event_list_assets();
216
-        // filter the WP posts_join, posts_where, and posts_orderby SQL clauses
217
-        // add query filters
218
-        EEH_Event_Query::add_query_filters();
219
-        // set params that will get used by the filters
220
-        EEH_Event_Query::set_query_params(
221
-            '',                             // month
222
-            '',                             // category
223
-            $config->display_expired_events // show_expired
224
-        );
225
-        // check what template is loaded
226
-        add_filter('template_include', [$this, 'template_include'], 999, 1);
227
-    }
228
-
229
-
230
-    /**
231
-     * most likely called by the ESPRESSO_EVENTS shortcode which uses this module to do some of it's lifting
232
-     *
233
-     * @return void
234
-     */
235
-    public function event_list()
236
-    {
237
-        // ensure valid EE_Events_Archive_Config() object exists
238
-        $this->set_config();
239
-        // load other required components
240
-        $this->load_event_list_assets();
241
-    }
242
-
243
-
244
-    /**
245
-     * @return void
246
-     * @throws EE_Error
247
-     * @throws ReflectionException
248
-     */
249
-    public function event_list_iframe()
250
-    {
251
-        EED_Events_Archive::$iframe = true;
252
-        $event_list_iframe          = new EventsArchiveIframe($this);
253
-        $event_list_iframe->display();
254
-    }
255
-
256
-
257
-    /**
258
-     * @return bool
259
-     */
260
-    public static function is_iframe()
261
-    {
262
-        return EED_Events_Archive::$iframe;
263
-    }
264
-
265
-
266
-    /**
267
-     * @return string
268
-     */
269
-    public static function link_target()
270
-    {
271
-        return EED_Events_Archive::$iframe ? ' target="_blank"' : '';
272
-    }
273
-
274
-
275
-    /**
276
-     * @param string $template
277
-     * @return string
278
-     * @throws EE_Error
279
-     * @throws ReflectionException
280
-     */
281
-    public function template_include($template = '')
282
-    {
283
-        // don't add content filter for dedicated EE child themes or private posts
284
-        if (! EEH_Template::is_espresso_theme()) {
285
-            /** @type EE_Events_Archive_Config $config */
286
-            $config = $this->config();
287
-            // add status banner ?
288
-            if ($config->display_status_banner) {
289
-                add_filter('the_title', ['EED_Events_Archive', 'the_title'], 100, 2);
290
-            }
291
-            // if NOT a custom template
292
-            if (
293
-                apply_filters('FHEE__EED_Event_Archive__template_include__allow_custom_selected_template', false)
294
-                || EE_Registry::instance()
295
-                              ->load_core('Front_Controller')
296
-                              ->get_selected_template() !== 'archive-espresso_events.php'
297
-            ) {
298
-                add_filter('FHEE__EED_Events_Archive__template_include__events_list_active', '__return_true');
299
-                // load functions.php file for the theme (loaded by WP if using child theme)
300
-                EEH_Template::load_espresso_theme_functions();
301
-                EED_Events_Archive::addEventDetailsFilters();
302
-                // don't display entry meta because the existing theme will take care of that
303
-                add_filter('FHEE__content_espresso_events_details_template__display_entry_meta', '__return_false');
304
-            }
305
-        }
306
-        return $template;
307
-    }
308
-
309
-
310
-    /**
311
-     * kinda hacky, but if a theme is using get_the_excerpt(),
312
-     * then we need to remove our filters on the_content()
313
-     *
314
-     * @param string $excerpt
315
-     * @return string
316
-     * @throws EE_Error
317
-     * @throws ReflectionException
318
-     */
319
-    public static function get_the_excerpt($excerpt = '')
320
-    {
321
-        if (post_password_required()) {
322
-            return $excerpt;
323
-        }
324
-        if (apply_filters('FHEE__EED_Events_Archive__get_the_excerpt__theme_uses_get_the_excerpt', false)) {
325
-            EED_Events_Archive::removeEventDetailsFilters(false);
326
-            $excerpt = EED_Events_Archive::event_details($excerpt);
327
-        } else {
328
-            EED_Events_Archive::$using_get_the_excerpt = true;
329
-            add_filter('wp_trim_excerpt', ['EED_Events_Archive', 'end_get_the_excerpt'], 999, 1);
330
-        }
331
-        return $excerpt;
332
-    }
333
-
334
-
335
-    /**
336
-     * @param string $text
337
-     * @return string
338
-     */
339
-    public static function end_get_the_excerpt($text = '')
340
-    {
341
-        EED_Events_Archive::$using_get_the_excerpt = false;
342
-        return $text;
343
-    }
344
-
345
-
346
-    /**
347
-     * @param string $title
348
-     * @param string $id
349
-     * @return string
350
-     * @throws EE_Error
351
-     * @throws ReflectionException
352
-     */
353
-    public static function the_title($title = '', $id = '')
354
-    {
355
-        global $post;
356
-        if ($post instanceof WP_Post) {
357
-            return (EED_Events_Archive::isBlockTheme() || in_the_loop()) && $post->ID == $id
358
-                ? espresso_event_status_banner($post->ID) . $title
359
-                : $title;
360
-        }
361
-        return $title;
362
-    }
363
-
364
-
365
-    /**
366
-     * @param string $content
367
-     * @return string
368
-     * @throws EE_Error
369
-     * @throws ReflectionException
370
-     */
371
-    public static function event_details($content)
372
-    {
373
-        global $post;
374
-        static $current_post_ID = 0;
375
-        if (
376
-            $current_post_ID !== $post->ID
377
-            && $post->post_type === 'espresso_events'
378
-            && ! EED_Events_Archive::$using_get_the_excerpt
379
-            && ! post_password_required()
380
-            && (
381
-                apply_filters('FHEE__EES_Espresso_Events__process_shortcode__true', false)
382
-                || ! apply_filters('FHEE__content_espresso_events__template_loaded', false)
383
-            )
384
-        ) {
385
-            // Set current post ID to prevent showing content twice, but only if headers have definitely been sent.
386
-            // Reason being is that some plugins, like Yoast, need to run through a copy of the loop early
387
-            // BEFORE headers are sent in order to examine the post content and generate content for the HTML header.
388
-            // We want to allow those plugins to still do their thing and have access to our content, but depending on
389
-            // how your event content is being displayed (shortcode, CPT route, etc), this filter can get applied twice,
390
-            // so the following allows this filter to be applied multiple times, but only once for real
391
-            $current_post_ID = did_action('loop_start') ? $post->ID : 0;
392
-            if (EE_Registry::instance()->CFG->template_settings->EED_Events_Archive->use_sortable_display_order) {
393
-                $content = EED_Events_Archive::use_sortable_display_order();
394
-            } else {
395
-                $content = EED_Events_Archive::use_filterable_display_order();
396
-            }
397
-        }
398
-        return $content;
399
-    }
400
-
401
-
402
-    /**
403
-     * @return string
404
-     * @throws EE_Error
405
-     * @throws ReflectionException
406
-     */
407
-    protected static function use_sortable_display_order()
408
-    {
409
-        // no further password checks required atm
410
-        add_filter('FHEE__EED_Events_Archive__event_details__no_post_password_required', '__return_true');
411
-        // remove this callback from being applied to the_content()
412
-        EED_Events_Archive::removeEventDetailsFilters();
413
-        // now add additional content depending on whether event is using the_excerpt() or the_content()
414
-        EED_Events_Archive::instance()->template_parts = EED_Events_Archive::instance()->initialize_template_parts();
415
-        $content = EEH_Template::locate_template('content-espresso_events-details.php');
416
-        $content = EED_Events_Archive::instance()->template_parts->apply_template_part_filters($content);
417
-        // re-add our main filters (or else the next event won't have them)
418
-        EED_Events_Archive::addEventDetailsFilters();
419
-        remove_filter(
420
-            'FHEE__EED_Events_Archive__event_details__no_post_password_required',
421
-            '__return_true'
422
-        );
423
-        return $content;
424
-    }
425
-
426
-
427
-    /**
428
-     * @return string
429
-     */
430
-    protected static function use_filterable_display_order()
431
-    {
432
-        // remove this callback from being applied to the_content()
433
-        EED_Events_Archive::removeEventDetailsFilters();
434
-        // now add additional content depending on whether event is using the_excerpt() or the_content()
435
-        EED_Events_Archive::_add_additional_excerpt_filters();
436
-        EED_Events_Archive::_add_additional_content_filters();
437
-        do_action('AHEE__EED_Events_Archive__use_filterable_display_order__after_add_filters');
438
-        // now load our template
439
-        $content = EEH_Template::locate_template('content-espresso_events-details.php');
440
-        // re-add our main filters (or else the next event won't have them)
441
-        EED_Events_Archive::addEventDetailsFilters();
442
-        // but remove the other filters so that they don't get applied to the next post
443
-        EED_Events_Archive::_remove_additional_events_archive_filters();
444
-        do_action('AHEE__EED_Events_Archive__use_filterable_display_order__after_remove_filters');
445
-        // we're not returning the $content directly because the template we are loading uses the_content (or the_excerpt)
446
-        // return ! empty( $template ) ? $template : $content;
447
-        return $content;
448
-    }
449
-
450
-
451
-    /**
452
-     * adds datetimes ABOVE content
453
-     *
454
-     * @param string $content
455
-     * @return string
456
-     */
457
-    public static function event_datetimes($content)
458
-    {
459
-        if (post_password_required()) {
460
-            return $content;
461
-        }
462
-        return EEH_Template::locate_template('content-espresso_events-datetimes.php') . $content;
463
-    }
464
-
465
-
466
-    /**
467
-     * adds tickets ABOVE content (which includes datetimes)
468
-     *
469
-     * @param string $content
470
-     * @return string
471
-     */
472
-    public static function event_tickets($content)
473
-    {
474
-        if (post_password_required()) {
475
-            return $content;
476
-        }
477
-        return EEH_Template::locate_template('content-espresso_events-tickets.php') . $content;
478
-    }
479
-
480
-
481
-    /**
482
-     * adds venues BELOW content
483
-     *
484
-     * @param string $content
485
-     * @return string
486
-     */
487
-    public static function event_venue($content)
488
-    {
489
-        return EED_Events_Archive::event_venues($content);
490
-    }
491
-
492
-
493
-    /**
494
-     * adds venues BELOW content
495
-     *
496
-     * @param string $content
497
-     * @return string
498
-     */
499
-    public static function event_venues($content)
500
-    {
501
-        if (post_password_required()) {
502
-            return $content;
503
-        }
504
-        return $content . EEH_Template::locate_template('content-espresso_events-venues.php');
505
-    }
506
-
507
-
508
-    /**
509
-     * @return bool
510
-     * @since $VID:$
511
-     */
512
-    public static function isBlockTheme()
513
-    {
514
-        return function_exists('wp_is_block_theme') && wp_is_block_theme();
515
-    }
516
-
517
-
518
-    /**
519
-     * @return string
520
-     * @since $VID:$
521
-     */
522
-    public static function getExcerptFilter()
523
-    {
524
-        static $excerpt_filter = null;
525
-        if ($excerpt_filter === null) {
526
-            $excerpt_filter = EED_Events_Archive::isBlockTheme() ? 'get_the_excerpt' : 'the_excerpt';
527
-        }
528
-        return $excerpt_filter;
529
-    }
530
-
531
-
532
-    /**
533
-     * @since $VID:$
534
-     */
535
-    protected static function addEventDetailsFilters()
536
-    {
537
-        add_filter(
538
-            'the_content',
539
-            ['EED_Events_Archive', 'event_details'],
540
-            EED_Events_Archive::EVENT_DETAILS_PRIORITY
541
-        );
542
-        // but because we don't know if the theme is using the_excerpt()
543
-        add_filter(
544
-            EED_Events_Archive::getExcerptFilter(),
545
-            ['EED_Events_Archive', 'event_details'],
546
-            EED_Events_Archive::EVENT_DETAILS_PRIORITY
547
-        );
548
-        // and just in case they are running get_the_excerpt() which DESTROYS things
549
-        add_filter('get_the_excerpt', ['EED_Events_Archive', 'get_the_excerpt'], 1, 1);
550
-    }
551
-
552
-
553
-    /**
554
-     * @param bool $and_get_the_excerpt
555
-     * @since $VID:$
556
-     */
557
-    protected static function removeEventDetailsFilters($and_get_the_excerpt = true)
558
-    {
559
-        // we need to first remove all callbacks from being applied to the_content()
560
-        // (otherwise it will recurse and blow up the interweb)
561
-        remove_filter(
562
-            'the_content',
563
-            ['EED_Events_Archive', 'event_details'],
564
-            EED_Events_Archive::EVENT_DETAILS_PRIORITY
565
-        );
566
-        remove_filter(
567
-            EED_Events_Archive::getExcerptFilter(),
568
-            ['EED_Events_Archive', 'event_details'],
569
-            EED_Events_Archive::EVENT_DETAILS_PRIORITY
570
-        );
571
-        if ($and_get_the_excerpt) {
572
-            remove_filter('get_the_excerpt', ['EED_Events_Archive', 'get_the_excerpt'], 1);
573
-        }
574
-    }
575
-
576
-
577
-    /**
578
-     * @return void
579
-     */
580
-    private static function _add_additional_excerpt_filters()
581
-    {
582
-        add_filter(
583
-            EED_Events_Archive::getExcerptFilter(),
584
-            ['EED_Events_Archive', 'event_datetimes'],
585
-            EED_Events_Archive::EVENT_DATETIMES_PRIORITY
586
-        );
587
-        add_filter(
588
-            EED_Events_Archive::getExcerptFilter(),
589
-            ['EED_Events_Archive', 'event_tickets'],
590
-            EED_Events_Archive::EVENT_TICKETS_PRIORITY
591
-        );
592
-        add_filter(
593
-            EED_Events_Archive::getExcerptFilter(),
594
-            ['EED_Events_Archive', 'event_venues'],
595
-            EED_Events_Archive::EVENT_VENUES_PRIORITY
596
-        );
597
-    }
598
-
599
-
600
-    /**
601
-     * @return void
602
-     */
603
-    private static function _add_additional_content_filters()
604
-    {
605
-        add_filter(
606
-            'the_content',
607
-            ['EED_Events_Archive', 'event_datetimes'],
608
-            EED_Events_Archive::EVENT_DATETIMES_PRIORITY
609
-        );
610
-        add_filter(
611
-            'the_content',
612
-            ['EED_Events_Archive', 'event_tickets'],
613
-            EED_Events_Archive::EVENT_TICKETS_PRIORITY
614
-        );
615
-        add_filter(
616
-            'the_content',
617
-            ['EED_Events_Archive', 'event_venues'],
618
-            EED_Events_Archive::EVENT_VENUES_PRIORITY
619
-        );
620
-    }
621
-
622
-
623
-    /**
624
-     * @return void
625
-     */
626
-    private static function _remove_additional_events_archive_filters()
627
-    {
628
-        remove_filter(
629
-            EED_Events_Archive::getExcerptFilter(),
630
-            ['EED_Events_Archive', 'event_datetimes'],
631
-            EED_Events_Archive::EVENT_DATETIMES_PRIORITY
632
-        );
633
-        remove_filter(
634
-            EED_Events_Archive::getExcerptFilter(),
635
-            ['EED_Events_Archive', 'event_tickets'],
636
-            EED_Events_Archive::EVENT_TICKETS_PRIORITY
637
-        );
638
-        remove_filter(
639
-            EED_Events_Archive::getExcerptFilter(),
640
-            ['EED_Events_Archive', 'event_venues'],
641
-            EED_Events_Archive::EVENT_VENUES_PRIORITY
642
-        );
643
-        remove_filter(
644
-            'the_content',
645
-            ['EED_Events_Archive', 'event_datetimes'],
646
-            EED_Events_Archive::EVENT_DATETIMES_PRIORITY
647
-        );
648
-        remove_filter(
649
-            'the_content',
650
-            ['EED_Events_Archive', 'event_tickets'],
651
-            EED_Events_Archive::EVENT_TICKETS_PRIORITY
652
-        );
653
-        remove_filter(
654
-            'the_content',
655
-            ['EED_Events_Archive', 'event_venues'],
656
-            EED_Events_Archive::EVENT_VENUES_PRIORITY
657
-        );
658
-    }
659
-
660
-
661
-    /**
662
-     * @return void
663
-     */
664
-    public static function remove_all_events_archive_filters()
665
-    {
666
-        // remove_filter( 'get_the_excerpt', array( 'EED_Events_Archive', 'get_the_excerpt' ), 1 );
667
-        remove_filter('the_title', ['EED_Events_Archive', 'the_title'], 1);
668
-        remove_filter(
669
-            EED_Events_Archive::getExcerptFilter(),
670
-            ['EED_Events_Archive', 'event_details'],
671
-            EED_Events_Archive::EVENT_DETAILS_PRIORITY
672
-        );
673
-        remove_filter(
674
-            EED_Events_Archive::getExcerptFilter(),
675
-            ['EED_Events_Archive', 'event_datetimes'],
676
-            EED_Events_Archive::EVENT_DATETIMES_PRIORITY
677
-        );
678
-        remove_filter(
679
-            EED_Events_Archive::getExcerptFilter(),
680
-            ['EED_Events_Archive', 'event_tickets'],
681
-            EED_Events_Archive::EVENT_TICKETS_PRIORITY
682
-        );
683
-        remove_filter(
684
-            EED_Events_Archive::getExcerptFilter(),
685
-            ['EED_Events_Archive', 'event_venues'],
686
-            EED_Events_Archive::EVENT_VENUES_PRIORITY
687
-        );
688
-        remove_filter(
689
-            'the_content',
690
-            ['EED_Events_Archive', 'event_details'],
691
-            EED_Events_Archive::EVENT_DETAILS_PRIORITY
692
-        );
693
-        remove_filter(
694
-            'the_content',
695
-            ['EED_Events_Archive', 'event_datetimes'],
696
-            EED_Events_Archive::EVENT_DATETIMES_PRIORITY
697
-        );
698
-        remove_filter(
699
-            'the_content',
700
-            ['EED_Events_Archive', 'event_tickets'],
701
-            EED_Events_Archive::EVENT_TICKETS_PRIORITY
702
-        );
703
-        remove_filter(
704
-            'the_content',
705
-            ['EED_Events_Archive', 'event_venues'],
706
-            EED_Events_Archive::EVENT_VENUES_PRIORITY
707
-        );
708
-        // don't display entry meta because the existing theme will take care of that
709
-        remove_filter(
710
-            'FHEE__content_espresso_events_details_template__display_entry_meta',
711
-            '__return_false'
712
-        );
713
-    }
714
-
715
-
716
-    /**
717
-     * @return void
718
-     */
719
-    public function load_event_list_assets()
720
-    {
721
-        do_action('AHEE__EED_Events_Archive__before_load_assets');
722
-        add_filter('FHEE_load_EE_Session', '__return_true');
723
-        add_filter('FHEE__EED_Ticket_Selector__load_tckt_slctr_assets', '__return_true');
724
-        add_action('wp_enqueue_scripts', [$this, 'wp_enqueue_scripts'], 10);
725
-        if (EE_Registry::instance()->CFG->map_settings->use_google_maps) {
726
-            add_action('wp_enqueue_scripts', ['EEH_Maps', 'espresso_google_map_js'], 11);
727
-        }
728
-    }
729
-
730
-
731
-    /**
732
-     * @return void
733
-     * @throws EE_Error
734
-     */
735
-    public function wp_enqueue_scripts()
736
-    {
737
-        // get some style
738
-        if (apply_filters('FHEE_enable_default_espresso_css', false)) {
739
-            // first check uploads folder
740
-            if (EEH_File::is_readable(get_stylesheet_directory() . $this->theme . '/style.css')) {
741
-                wp_register_style(
742
-                    $this->theme,
743
-                    get_stylesheet_directory_uri() . $this->theme . '/style.css',
744
-                    ['dashicons', 'espresso_default']
745
-                );
746
-            }
747
-            wp_enqueue_style($this->theme);
748
-        }
749
-    }
750
-
751
-
752
-    /**
753
-     * @static
754
-     * @return void
755
-     */
756
-    public static function template_settings_form()
757
-    {
758
-        $template_settings                     = EE_Registry::instance()->CFG->template_settings;
759
-        $template_settings->EED_Events_Archive = isset($template_settings->EED_Events_Archive)
760
-            ? $template_settings->EED_Events_Archive : new EE_Events_Archive_Config();
761
-        $template_settings->EED_Events_Archive = apply_filters(
762
-            'FHEE__EED_Events_Archive__template_settings_form__event_list_config',
763
-            $template_settings->EED_Events_Archive
764
-        );
765
-        $events_archive_settings               = [
766
-            'display_status_banner'   => 0,
767
-            'display_description'     => 1,
768
-            'display_ticket_selector' => 0,
769
-            'display_datetimes'       => 1,
770
-            'display_venue'           => 0,
771
-            'display_expired_events'  => 0,
772
-        ];
773
-        $events_archive_settings               = array_merge(
774
-            $events_archive_settings,
775
-            (array) $template_settings->EED_Events_Archive
776
-        );
777
-        EEH_Template::display_template(
778
-            EVENTS_ARCHIVE_TEMPLATES_PATH . 'admin-event-list-settings.template.php',
779
-            $events_archive_settings
780
-        );
781
-    }
782
-
783
-
784
-    /**
785
-     * @param EE_Template_Config $CFG
786
-     * @param array              $REQ
787
-     * @return EE_Template_Config
788
-     */
789
-    public static function update_template_settings($CFG, $REQ)
790
-    {
791
-        $CFG->EED_Events_Archive = new EE_Events_Archive_Config();
792
-        // unless we are resetting the config...
793
-        if (
794
-            ! isset($REQ['EED_Events_Archive_reset_event_list_settings'])
795
-            || absint($REQ['EED_Events_Archive_reset_event_list_settings']) !== 1
796
-        ) {
797
-            $CFG->EED_Events_Archive->display_status_banner   = isset($REQ['EED_Events_Archive_display_status_banner'])
798
-                ? absint($REQ['EED_Events_Archive_display_status_banner'])
799
-                : 0;
800
-            $CFG->EED_Events_Archive->display_description     = isset($REQ['EED_Events_Archive_display_description'])
801
-                ? absint($REQ['EED_Events_Archive_display_description'])
802
-                : 1;
803
-            $CFG->EED_Events_Archive->display_ticket_selector = isset($REQ['EED_Events_Archive_display_ticket_selector'])
804
-                ? absint($REQ['EED_Events_Archive_display_ticket_selector'])
805
-                : 0;
806
-            $CFG->EED_Events_Archive->display_datetimes       = isset($REQ['EED_Events_Archive_display_datetimes'])
807
-                ? absint($REQ['EED_Events_Archive_display_datetimes'])
808
-                : 1;
809
-            $CFG->EED_Events_Archive->display_venue           = isset($REQ['EED_Events_Archive_display_venue'])
810
-                ? absint($REQ['EED_Events_Archive_display_venue'])
811
-                : 0;
812
-            $CFG->EED_Events_Archive->display_expired_events  = isset($REQ['EED_Events_Archive_display_expired_events'])
813
-                ? absint($REQ['EED_Events_Archive_display_expired_events'])
814
-                : 0;
815
-        }
816
-        return $CFG;
817
-    }
818
-
819
-
820
-    /**
821
-     * @param string $extra_class
822
-     * @return string
823
-     */
824
-    public static function event_list_css($extra_class = '')
825
-    {
826
-        $event_list_css   = ! empty($extra_class) ? [$extra_class] : [];
827
-        $event_list_css[] = 'espresso-event-list-event';
828
-        return implode(' ', $event_list_css);
829
-    }
830
-
831
-
832
-    /**
833
-     * @return array
834
-     * @throws EE_Error
835
-     * @throws ReflectionException
836
-     */
837
-    public static function event_categories()
838
-    {
839
-        return EE_Registry::instance()->load_model('Term')->get_all_ee_categories();
840
-    }
841
-
842
-
843
-    /**
844
-     * @param $value
845
-     * @return bool
846
-     */
847
-    public static function display_description($value)
848
-    {
849
-        $config              = EE_Registry::instance()->CFG->template_settings->EED_Events_Archive;
850
-        $display_description = isset($config->display_description) ? $config->display_description : 1;
851
-        return $display_description === $value;
852
-    }
853
-
854
-
855
-    /**
856
-     * @return bool
857
-     */
858
-    public static function display_ticket_selector()
859
-    {
860
-        $config = EE_Registry::instance()->CFG->template_settings->EED_Events_Archive;
861
-        return isset($config->display_ticket_selector) && $config->display_ticket_selector;
862
-    }
863
-
864
-
865
-    /**
866
-     * @return bool
867
-     * @throws EE_Error
868
-     * @throws ReflectionException
869
-     */
870
-    public static function display_venue()
871
-    {
872
-        $config = EE_Registry::instance()->CFG->template_settings->EED_Events_Archive;
873
-        return isset($config->display_venue) && $config->display_venue && EEH_Venue_View::venue_name();
874
-    }
875
-
876
-
877
-    /**
878
-     * @return bool
879
-     */
880
-    public static function display_datetimes()
881
-    {
882
-        $config = EE_Registry::instance()->CFG->template_settings->EED_Events_Archive;
883
-        return isset($config->display_datetimes) && $config->display_datetimes;
884
-    }
885
-
886
-
887
-    /**
888
-     * @return string
889
-     */
890
-    public static function event_list_title()
891
-    {
892
-        return apply_filters(
893
-            'FHEE__archive_espresso_events_template__upcoming_events_h1',
894
-            esc_html__('Upcoming Events', 'event_espresso')
895
-        );
896
-    }
897
-
898
-
899
-    // GRAVEYARD
900
-
901
-
902
-    /**
903
-     * @since 4.4.0
904
-     */
905
-    public static function _doing_it_wrong_notice($function = '')
906
-    {
907
-        EE_Error::doing_it_wrong(
908
-            __FUNCTION__,
909
-            sprintf(
910
-                esc_html__(
911
-                    'EED_Events_Archive::%1$s was moved to EEH_Event_Query::%1$s:%2$sPlease update your existing code because the method it calls will be removed in version %3$s',
912
-                    'event_espresso'
913
-                ),
914
-                $function,
915
-                '<br />',
916
-                '4.6.0'
917
-            ),
918
-            '4.4.0'
919
-        );
920
-    }
921
-
922
-
923
-    /**
924
-     * @deprecated
925
-     * @since 4.4.0
926
-     */
927
-    public function get_post_data()
928
-    {
929
-        EEH_Event_Query::set_query_params();
930
-    }
931
-
932
-
933
-    /**
934
-     * @throws EE_Error
935
-     * @since 4.4.0
936
-     * @deprecated
937
-     */
938
-    public function posts_fields($SQL, WP_Query $wp_query)
939
-    {
940
-        EED_Events_Archive::_doing_it_wrong_notice(__FUNCTION__);
941
-        return EEH_Event_Query::posts_fields($SQL, $wp_query);
942
-    }
943
-
944
-
945
-    /**
946
-     * @throws EE_Error
947
-     * @since 4.4.0
948
-     * @deprecated
949
-     */
950
-    public static function posts_fields_sql_for_orderby($orderby_params = [])
951
-    {
952
-        EED_Events_Archive::_doing_it_wrong_notice(__FUNCTION__);
953
-        return EEH_Event_Query::posts_fields_sql_for_orderby($orderby_params);
954
-    }
955
-
956
-
957
-    /**
958
-     * @throws EE_Error
959
-     * @since 4.4.0
960
-     * @deprecated
961
-     */
962
-    public function posts_join($SQL, WP_Query $wp_query)
963
-    {
964
-        EED_Events_Archive::_doing_it_wrong_notice(__FUNCTION__);
965
-        return EEH_Event_Query::posts_join($SQL, $wp_query);
966
-    }
967
-
968
-
969
-    /**
970
-     * @deprecated
971
-     * @since 4.4.0
972
-     */
973
-    public static function posts_join_sql_for_terms($join_terms = null)
974
-    {
975
-        EED_Events_Archive::_doing_it_wrong_notice(__FUNCTION__);
976
-        return EEH_Event_Query::posts_join_sql_for_terms($join_terms);
977
-    }
978
-
979
-
980
-    /**
981
-     * @throws EE_Error
982
-     * @since 4.4.0
983
-     * @deprecated
984
-     */
985
-    public static function posts_join_for_orderby($orderby_params = [])
986
-    {
987
-        EED_Events_Archive::_doing_it_wrong_notice(__FUNCTION__);
988
-        return EEH_Event_Query::posts_join_for_orderby($orderby_params);
989
-    }
990
-
991
-
992
-    /**
993
-     * @throws EE_Error
994
-     * @since 4.4.0
995
-     * @deprecated
996
-     */
997
-    public function posts_where($SQL, WP_Query $wp_query)
998
-    {
999
-        EED_Events_Archive::_doing_it_wrong_notice(__FUNCTION__);
1000
-        return EEH_Event_Query::posts_where($SQL, $wp_query);
1001
-    }
1002
-
1003
-
1004
-    /**
1005
-     * @throws EE_Error
1006
-     * @since 4.4.0
1007
-     * @deprecated
1008
-     */
1009
-    public static function posts_where_sql_for_show_expired($show_expired = false)
1010
-    {
1011
-        EED_Events_Archive::_doing_it_wrong_notice(__FUNCTION__);
1012
-        return EEH_Event_Query::posts_where_sql_for_show_expired($show_expired);
1013
-    }
1014
-
1015
-
1016
-    /**
1017
-     * @deprecated
1018
-     * @since 4.4.0
1019
-     */
1020
-    public static function posts_where_sql_for_event_category_slug($event_category_slug = null)
1021
-    {
1022
-        EED_Events_Archive::_doing_it_wrong_notice(__FUNCTION__);
1023
-        return EEH_Event_Query::posts_where_sql_for_event_category_slug($event_category_slug);
1024
-    }
1025
-
1026
-
1027
-    /**
1028
-     * @throws EE_Error
1029
-     * @since 4.4.0
1030
-     * @deprecated
1031
-     */
1032
-    public static function posts_where_sql_for_event_list_month($month = null)
1033
-    {
1034
-        EED_Events_Archive::_doing_it_wrong_notice(__FUNCTION__);
1035
-        return EEH_Event_Query::posts_where_sql_for_event_list_month($month);
1036
-    }
1037
-
1038
-
1039
-    /**
1040
-     * @throws EE_Error
1041
-     * @since 4.4.0
1042
-     * @deprecated
1043
-     */
1044
-    public function posts_orderby($SQL, WP_Query $wp_query)
1045
-    {
1046
-        EED_Events_Archive::_doing_it_wrong_notice(__FUNCTION__);
1047
-        return EEH_Event_Query::posts_orderby($SQL, $wp_query);
1048
-    }
1049
-
1050
-
1051
-    /**
1052
-     * @throws EE_Error
1053
-     * @since 4.4.0
1054
-     * @deprecated
1055
-     */
1056
-    public static function posts_orderby_sql($orderby_params = [], $sort = 'ASC')
1057
-    {
1058
-        EED_Events_Archive::_doing_it_wrong_notice(__FUNCTION__);
1059
-        return EEH_Event_Query::posts_orderby_sql($orderby_params, $sort);
1060
-    }
20
+	const EVENT_DETAILS_PRIORITY   = 100;
21
+
22
+	const EVENT_DATETIMES_PRIORITY = 110;
23
+
24
+	const EVENT_TICKETS_PRIORITY   = 120;
25
+
26
+	const EVENT_VENUES_PRIORITY    = 130;
27
+
28
+
29
+	public static $espresso_event_list_ID    = 0;
30
+
31
+	public static $espresso_grid_event_lists = [];
32
+
33
+	/**
34
+	 * @type bool $using_get_the_excerpt
35
+	 */
36
+	protected static $using_get_the_excerpt = false;
37
+
38
+	/**
39
+	 * Used to flag when the event list is being called from an external iframe.
40
+	 *
41
+	 * @var bool $iframe
42
+	 */
43
+	protected static $iframe = false;
44
+
45
+	/**
46
+	 * @var EventListIframeEmbedButton $_iframe_embed_button
47
+	 */
48
+	private static $_iframe_embed_button;
49
+
50
+	/**
51
+	 * @type EE_Template_Part_Manager $template_parts
52
+	 */
53
+	protected $template_parts;
54
+
55
+
56
+	/**
57
+	 * @return EED_Events_Archive
58
+	 * @throws EE_Error
59
+	 * @throws ReflectionException
60
+	 */
61
+	public static function instance()
62
+	{
63
+		return parent::get_instance(__CLASS__);
64
+	}
65
+
66
+
67
+	/**
68
+	 * for hooking into EE Core, other modules, etc
69
+	 *
70
+	 * @return void
71
+	 * @throws InvalidArgumentException
72
+	 * @throws InvalidDataTypeException
73
+	 * @throws InvalidInterfaceException
74
+	 */
75
+	public static function set_hooks()
76
+	{
77
+		/** @var CustomPostTypeDefinitions $custom_post_type_definitions */
78
+		$custom_post_type_definitions = LoaderFactory::getLoader()->getShared(CustomPostTypeDefinitions::class);
79
+		$custom_post_types            = $custom_post_type_definitions->getDefinitions();
80
+		EE_Config::register_route(
81
+			$custom_post_types['espresso_events']['plural_slug'],
82
+			'Events_Archive',
83
+			'run'
84
+		);
85
+		EE_Config::register_route(
86
+			'event_list',
87
+			'Events_Archive',
88
+			'event_list'
89
+		);
90
+		EE_Config::register_route(
91
+			'iframe',
92
+			'Events_Archive',
93
+			'event_list_iframe',
94
+			'event_list'
95
+		);
96
+		add_action('wp_loaded', ['EED_Events_Archive', 'set_definitions'], 2);
97
+	}
98
+
99
+
100
+	/**
101
+	 * for hooking into EE Admin Core, other modules, etc
102
+	 *
103
+	 * @return void
104
+	 */
105
+	public static function set_hooks_admin()
106
+	{
107
+		add_action('wp_loaded', ['EED_Events_Archive', 'set_definitions'], 2);
108
+		// hook into the end of the \EE_Admin_Page::_load_page_dependencies()
109
+		// to load assets for "espresso_events" page on the "default" route (action)
110
+		add_action(
111
+			'FHEE__EE_Admin_Page___load_page_dependencies__after_load__espresso_events__default',
112
+			['EED_Events_Archive', 'event_list_iframe_embed_button'],
113
+			10
114
+		);
115
+	}
116
+
117
+
118
+	/**
119
+	 * @return void
120
+	 */
121
+	public static function set_definitions()
122
+	{
123
+		define('EVENTS_ARCHIVE_ASSETS_URL', plugin_dir_url(__FILE__) . 'assets/');
124
+		define('EVENTS_ARCHIVE_TEMPLATES_PATH', str_replace('\\', '/', plugin_dir_path(__FILE__)) . 'templates/');
125
+	}
126
+
127
+
128
+	/**
129
+	 * set up EE_Events_Archive_Config
130
+	 */
131
+	protected function set_config()
132
+	{
133
+		$this->set_config_section('template_settings');
134
+		$this->set_config_class('EE_Events_Archive_Config');
135
+		$this->set_config_name('EED_Events_Archive');
136
+	}
137
+
138
+
139
+	/**
140
+	 * @return EventListIframeEmbedButton
141
+	 */
142
+	public static function get_iframe_embed_button()
143
+	{
144
+		if (! self::$_iframe_embed_button instanceof EventListIframeEmbedButton) {
145
+			self::$_iframe_embed_button = new EventListIframeEmbedButton();
146
+		}
147
+		return self::$_iframe_embed_button;
148
+	}
149
+
150
+
151
+	/**
152
+	 * @return void
153
+	 */
154
+	public static function event_list_iframe_embed_button()
155
+	{
156
+		$iframe_embed_button = EED_Events_Archive::get_iframe_embed_button();
157
+		$iframe_embed_button->addEmbedButton();
158
+	}
159
+
160
+
161
+	/**
162
+	 * @param EE_Events_Archive_Config|null $config
163
+	 * @return EE_Template_Part_Manager
164
+	 * @throws EE_Error
165
+	 */
166
+	public function initialize_template_parts(EE_Events_Archive_Config $config = null)
167
+	{
168
+		$config = $config instanceof EE_Events_Archive_Config ? $config : $this->config();
169
+		EEH_Autoloader::instance()->register_template_part_autoloaders();
170
+		$template_parts = new EE_Template_Part_Manager();
171
+		$template_parts->add_template_part(
172
+			'tickets',
173
+			esc_html__('Ticket Selector', 'event_espresso'),
174
+			'content-espresso_events-tickets.php',
175
+			$config->display_order_tickets
176
+		);
177
+		$template_parts->add_template_part(
178
+			'datetimes',
179
+			esc_html__('Dates and Times', 'event_espresso'),
180
+			'content-espresso_events-datetimes.php',
181
+			$config->display_order_datetimes
182
+		);
183
+		$template_parts->add_template_part(
184
+			'event',
185
+			esc_html__('Event Description', 'event_espresso'),
186
+			'content-espresso_events-details.php',
187
+			$config->display_order_event
188
+		);
189
+		$template_parts->add_template_part(
190
+			'venue',
191
+			esc_html__('Venue Information', 'event_espresso'),
192
+			'content-espresso_events-venues.php',
193
+			$config->display_order_venue
194
+		);
195
+		do_action('AHEE__EED_Event_Archive__initialize_template_parts', $template_parts);
196
+		return $template_parts;
197
+	}
198
+
199
+
200
+	/**
201
+	 * initial module setup
202
+	 * this gets called by the EE_Front_Controller if the module route is found in the incoming request
203
+	 *
204
+	 * @param WP $WP
205
+	 * @return void
206
+	 */
207
+	public function run($WP)
208
+	{
209
+		do_action('AHEE__EED_Events_Archive__before_run');
210
+		// ensure valid EE_Events_Archive_Config() object exists
211
+		$this->set_config();
212
+		/** @type EE_Events_Archive_Config $config */
213
+		$config = $this->config();
214
+		// load other required components
215
+		$this->load_event_list_assets();
216
+		// filter the WP posts_join, posts_where, and posts_orderby SQL clauses
217
+		// add query filters
218
+		EEH_Event_Query::add_query_filters();
219
+		// set params that will get used by the filters
220
+		EEH_Event_Query::set_query_params(
221
+			'',                             // month
222
+			'',                             // category
223
+			$config->display_expired_events // show_expired
224
+		);
225
+		// check what template is loaded
226
+		add_filter('template_include', [$this, 'template_include'], 999, 1);
227
+	}
228
+
229
+
230
+	/**
231
+	 * most likely called by the ESPRESSO_EVENTS shortcode which uses this module to do some of it's lifting
232
+	 *
233
+	 * @return void
234
+	 */
235
+	public function event_list()
236
+	{
237
+		// ensure valid EE_Events_Archive_Config() object exists
238
+		$this->set_config();
239
+		// load other required components
240
+		$this->load_event_list_assets();
241
+	}
242
+
243
+
244
+	/**
245
+	 * @return void
246
+	 * @throws EE_Error
247
+	 * @throws ReflectionException
248
+	 */
249
+	public function event_list_iframe()
250
+	{
251
+		EED_Events_Archive::$iframe = true;
252
+		$event_list_iframe          = new EventsArchiveIframe($this);
253
+		$event_list_iframe->display();
254
+	}
255
+
256
+
257
+	/**
258
+	 * @return bool
259
+	 */
260
+	public static function is_iframe()
261
+	{
262
+		return EED_Events_Archive::$iframe;
263
+	}
264
+
265
+
266
+	/**
267
+	 * @return string
268
+	 */
269
+	public static function link_target()
270
+	{
271
+		return EED_Events_Archive::$iframe ? ' target="_blank"' : '';
272
+	}
273
+
274
+
275
+	/**
276
+	 * @param string $template
277
+	 * @return string
278
+	 * @throws EE_Error
279
+	 * @throws ReflectionException
280
+	 */
281
+	public function template_include($template = '')
282
+	{
283
+		// don't add content filter for dedicated EE child themes or private posts
284
+		if (! EEH_Template::is_espresso_theme()) {
285
+			/** @type EE_Events_Archive_Config $config */
286
+			$config = $this->config();
287
+			// add status banner ?
288
+			if ($config->display_status_banner) {
289
+				add_filter('the_title', ['EED_Events_Archive', 'the_title'], 100, 2);
290
+			}
291
+			// if NOT a custom template
292
+			if (
293
+				apply_filters('FHEE__EED_Event_Archive__template_include__allow_custom_selected_template', false)
294
+				|| EE_Registry::instance()
295
+							  ->load_core('Front_Controller')
296
+							  ->get_selected_template() !== 'archive-espresso_events.php'
297
+			) {
298
+				add_filter('FHEE__EED_Events_Archive__template_include__events_list_active', '__return_true');
299
+				// load functions.php file for the theme (loaded by WP if using child theme)
300
+				EEH_Template::load_espresso_theme_functions();
301
+				EED_Events_Archive::addEventDetailsFilters();
302
+				// don't display entry meta because the existing theme will take care of that
303
+				add_filter('FHEE__content_espresso_events_details_template__display_entry_meta', '__return_false');
304
+			}
305
+		}
306
+		return $template;
307
+	}
308
+
309
+
310
+	/**
311
+	 * kinda hacky, but if a theme is using get_the_excerpt(),
312
+	 * then we need to remove our filters on the_content()
313
+	 *
314
+	 * @param string $excerpt
315
+	 * @return string
316
+	 * @throws EE_Error
317
+	 * @throws ReflectionException
318
+	 */
319
+	public static function get_the_excerpt($excerpt = '')
320
+	{
321
+		if (post_password_required()) {
322
+			return $excerpt;
323
+		}
324
+		if (apply_filters('FHEE__EED_Events_Archive__get_the_excerpt__theme_uses_get_the_excerpt', false)) {
325
+			EED_Events_Archive::removeEventDetailsFilters(false);
326
+			$excerpt = EED_Events_Archive::event_details($excerpt);
327
+		} else {
328
+			EED_Events_Archive::$using_get_the_excerpt = true;
329
+			add_filter('wp_trim_excerpt', ['EED_Events_Archive', 'end_get_the_excerpt'], 999, 1);
330
+		}
331
+		return $excerpt;
332
+	}
333
+
334
+
335
+	/**
336
+	 * @param string $text
337
+	 * @return string
338
+	 */
339
+	public static function end_get_the_excerpt($text = '')
340
+	{
341
+		EED_Events_Archive::$using_get_the_excerpt = false;
342
+		return $text;
343
+	}
344
+
345
+
346
+	/**
347
+	 * @param string $title
348
+	 * @param string $id
349
+	 * @return string
350
+	 * @throws EE_Error
351
+	 * @throws ReflectionException
352
+	 */
353
+	public static function the_title($title = '', $id = '')
354
+	{
355
+		global $post;
356
+		if ($post instanceof WP_Post) {
357
+			return (EED_Events_Archive::isBlockTheme() || in_the_loop()) && $post->ID == $id
358
+				? espresso_event_status_banner($post->ID) . $title
359
+				: $title;
360
+		}
361
+		return $title;
362
+	}
363
+
364
+
365
+	/**
366
+	 * @param string $content
367
+	 * @return string
368
+	 * @throws EE_Error
369
+	 * @throws ReflectionException
370
+	 */
371
+	public static function event_details($content)
372
+	{
373
+		global $post;
374
+		static $current_post_ID = 0;
375
+		if (
376
+			$current_post_ID !== $post->ID
377
+			&& $post->post_type === 'espresso_events'
378
+			&& ! EED_Events_Archive::$using_get_the_excerpt
379
+			&& ! post_password_required()
380
+			&& (
381
+				apply_filters('FHEE__EES_Espresso_Events__process_shortcode__true', false)
382
+				|| ! apply_filters('FHEE__content_espresso_events__template_loaded', false)
383
+			)
384
+		) {
385
+			// Set current post ID to prevent showing content twice, but only if headers have definitely been sent.
386
+			// Reason being is that some plugins, like Yoast, need to run through a copy of the loop early
387
+			// BEFORE headers are sent in order to examine the post content and generate content for the HTML header.
388
+			// We want to allow those plugins to still do their thing and have access to our content, but depending on
389
+			// how your event content is being displayed (shortcode, CPT route, etc), this filter can get applied twice,
390
+			// so the following allows this filter to be applied multiple times, but only once for real
391
+			$current_post_ID = did_action('loop_start') ? $post->ID : 0;
392
+			if (EE_Registry::instance()->CFG->template_settings->EED_Events_Archive->use_sortable_display_order) {
393
+				$content = EED_Events_Archive::use_sortable_display_order();
394
+			} else {
395
+				$content = EED_Events_Archive::use_filterable_display_order();
396
+			}
397
+		}
398
+		return $content;
399
+	}
400
+
401
+
402
+	/**
403
+	 * @return string
404
+	 * @throws EE_Error
405
+	 * @throws ReflectionException
406
+	 */
407
+	protected static function use_sortable_display_order()
408
+	{
409
+		// no further password checks required atm
410
+		add_filter('FHEE__EED_Events_Archive__event_details__no_post_password_required', '__return_true');
411
+		// remove this callback from being applied to the_content()
412
+		EED_Events_Archive::removeEventDetailsFilters();
413
+		// now add additional content depending on whether event is using the_excerpt() or the_content()
414
+		EED_Events_Archive::instance()->template_parts = EED_Events_Archive::instance()->initialize_template_parts();
415
+		$content = EEH_Template::locate_template('content-espresso_events-details.php');
416
+		$content = EED_Events_Archive::instance()->template_parts->apply_template_part_filters($content);
417
+		// re-add our main filters (or else the next event won't have them)
418
+		EED_Events_Archive::addEventDetailsFilters();
419
+		remove_filter(
420
+			'FHEE__EED_Events_Archive__event_details__no_post_password_required',
421
+			'__return_true'
422
+		);
423
+		return $content;
424
+	}
425
+
426
+
427
+	/**
428
+	 * @return string
429
+	 */
430
+	protected static function use_filterable_display_order()
431
+	{
432
+		// remove this callback from being applied to the_content()
433
+		EED_Events_Archive::removeEventDetailsFilters();
434
+		// now add additional content depending on whether event is using the_excerpt() or the_content()
435
+		EED_Events_Archive::_add_additional_excerpt_filters();
436
+		EED_Events_Archive::_add_additional_content_filters();
437
+		do_action('AHEE__EED_Events_Archive__use_filterable_display_order__after_add_filters');
438
+		// now load our template
439
+		$content = EEH_Template::locate_template('content-espresso_events-details.php');
440
+		// re-add our main filters (or else the next event won't have them)
441
+		EED_Events_Archive::addEventDetailsFilters();
442
+		// but remove the other filters so that they don't get applied to the next post
443
+		EED_Events_Archive::_remove_additional_events_archive_filters();
444
+		do_action('AHEE__EED_Events_Archive__use_filterable_display_order__after_remove_filters');
445
+		// we're not returning the $content directly because the template we are loading uses the_content (or the_excerpt)
446
+		// return ! empty( $template ) ? $template : $content;
447
+		return $content;
448
+	}
449
+
450
+
451
+	/**
452
+	 * adds datetimes ABOVE content
453
+	 *
454
+	 * @param string $content
455
+	 * @return string
456
+	 */
457
+	public static function event_datetimes($content)
458
+	{
459
+		if (post_password_required()) {
460
+			return $content;
461
+		}
462
+		return EEH_Template::locate_template('content-espresso_events-datetimes.php') . $content;
463
+	}
464
+
465
+
466
+	/**
467
+	 * adds tickets ABOVE content (which includes datetimes)
468
+	 *
469
+	 * @param string $content
470
+	 * @return string
471
+	 */
472
+	public static function event_tickets($content)
473
+	{
474
+		if (post_password_required()) {
475
+			return $content;
476
+		}
477
+		return EEH_Template::locate_template('content-espresso_events-tickets.php') . $content;
478
+	}
479
+
480
+
481
+	/**
482
+	 * adds venues BELOW content
483
+	 *
484
+	 * @param string $content
485
+	 * @return string
486
+	 */
487
+	public static function event_venue($content)
488
+	{
489
+		return EED_Events_Archive::event_venues($content);
490
+	}
491
+
492
+
493
+	/**
494
+	 * adds venues BELOW content
495
+	 *
496
+	 * @param string $content
497
+	 * @return string
498
+	 */
499
+	public static function event_venues($content)
500
+	{
501
+		if (post_password_required()) {
502
+			return $content;
503
+		}
504
+		return $content . EEH_Template::locate_template('content-espresso_events-venues.php');
505
+	}
506
+
507
+
508
+	/**
509
+	 * @return bool
510
+	 * @since $VID:$
511
+	 */
512
+	public static function isBlockTheme()
513
+	{
514
+		return function_exists('wp_is_block_theme') && wp_is_block_theme();
515
+	}
516
+
517
+
518
+	/**
519
+	 * @return string
520
+	 * @since $VID:$
521
+	 */
522
+	public static function getExcerptFilter()
523
+	{
524
+		static $excerpt_filter = null;
525
+		if ($excerpt_filter === null) {
526
+			$excerpt_filter = EED_Events_Archive::isBlockTheme() ? 'get_the_excerpt' : 'the_excerpt';
527
+		}
528
+		return $excerpt_filter;
529
+	}
530
+
531
+
532
+	/**
533
+	 * @since $VID:$
534
+	 */
535
+	protected static function addEventDetailsFilters()
536
+	{
537
+		add_filter(
538
+			'the_content',
539
+			['EED_Events_Archive', 'event_details'],
540
+			EED_Events_Archive::EVENT_DETAILS_PRIORITY
541
+		);
542
+		// but because we don't know if the theme is using the_excerpt()
543
+		add_filter(
544
+			EED_Events_Archive::getExcerptFilter(),
545
+			['EED_Events_Archive', 'event_details'],
546
+			EED_Events_Archive::EVENT_DETAILS_PRIORITY
547
+		);
548
+		// and just in case they are running get_the_excerpt() which DESTROYS things
549
+		add_filter('get_the_excerpt', ['EED_Events_Archive', 'get_the_excerpt'], 1, 1);
550
+	}
551
+
552
+
553
+	/**
554
+	 * @param bool $and_get_the_excerpt
555
+	 * @since $VID:$
556
+	 */
557
+	protected static function removeEventDetailsFilters($and_get_the_excerpt = true)
558
+	{
559
+		// we need to first remove all callbacks from being applied to the_content()
560
+		// (otherwise it will recurse and blow up the interweb)
561
+		remove_filter(
562
+			'the_content',
563
+			['EED_Events_Archive', 'event_details'],
564
+			EED_Events_Archive::EVENT_DETAILS_PRIORITY
565
+		);
566
+		remove_filter(
567
+			EED_Events_Archive::getExcerptFilter(),
568
+			['EED_Events_Archive', 'event_details'],
569
+			EED_Events_Archive::EVENT_DETAILS_PRIORITY
570
+		);
571
+		if ($and_get_the_excerpt) {
572
+			remove_filter('get_the_excerpt', ['EED_Events_Archive', 'get_the_excerpt'], 1);
573
+		}
574
+	}
575
+
576
+
577
+	/**
578
+	 * @return void
579
+	 */
580
+	private static function _add_additional_excerpt_filters()
581
+	{
582
+		add_filter(
583
+			EED_Events_Archive::getExcerptFilter(),
584
+			['EED_Events_Archive', 'event_datetimes'],
585
+			EED_Events_Archive::EVENT_DATETIMES_PRIORITY
586
+		);
587
+		add_filter(
588
+			EED_Events_Archive::getExcerptFilter(),
589
+			['EED_Events_Archive', 'event_tickets'],
590
+			EED_Events_Archive::EVENT_TICKETS_PRIORITY
591
+		);
592
+		add_filter(
593
+			EED_Events_Archive::getExcerptFilter(),
594
+			['EED_Events_Archive', 'event_venues'],
595
+			EED_Events_Archive::EVENT_VENUES_PRIORITY
596
+		);
597
+	}
598
+
599
+
600
+	/**
601
+	 * @return void
602
+	 */
603
+	private static function _add_additional_content_filters()
604
+	{
605
+		add_filter(
606
+			'the_content',
607
+			['EED_Events_Archive', 'event_datetimes'],
608
+			EED_Events_Archive::EVENT_DATETIMES_PRIORITY
609
+		);
610
+		add_filter(
611
+			'the_content',
612
+			['EED_Events_Archive', 'event_tickets'],
613
+			EED_Events_Archive::EVENT_TICKETS_PRIORITY
614
+		);
615
+		add_filter(
616
+			'the_content',
617
+			['EED_Events_Archive', 'event_venues'],
618
+			EED_Events_Archive::EVENT_VENUES_PRIORITY
619
+		);
620
+	}
621
+
622
+
623
+	/**
624
+	 * @return void
625
+	 */
626
+	private static function _remove_additional_events_archive_filters()
627
+	{
628
+		remove_filter(
629
+			EED_Events_Archive::getExcerptFilter(),
630
+			['EED_Events_Archive', 'event_datetimes'],
631
+			EED_Events_Archive::EVENT_DATETIMES_PRIORITY
632
+		);
633
+		remove_filter(
634
+			EED_Events_Archive::getExcerptFilter(),
635
+			['EED_Events_Archive', 'event_tickets'],
636
+			EED_Events_Archive::EVENT_TICKETS_PRIORITY
637
+		);
638
+		remove_filter(
639
+			EED_Events_Archive::getExcerptFilter(),
640
+			['EED_Events_Archive', 'event_venues'],
641
+			EED_Events_Archive::EVENT_VENUES_PRIORITY
642
+		);
643
+		remove_filter(
644
+			'the_content',
645
+			['EED_Events_Archive', 'event_datetimes'],
646
+			EED_Events_Archive::EVENT_DATETIMES_PRIORITY
647
+		);
648
+		remove_filter(
649
+			'the_content',
650
+			['EED_Events_Archive', 'event_tickets'],
651
+			EED_Events_Archive::EVENT_TICKETS_PRIORITY
652
+		);
653
+		remove_filter(
654
+			'the_content',
655
+			['EED_Events_Archive', 'event_venues'],
656
+			EED_Events_Archive::EVENT_VENUES_PRIORITY
657
+		);
658
+	}
659
+
660
+
661
+	/**
662
+	 * @return void
663
+	 */
664
+	public static function remove_all_events_archive_filters()
665
+	{
666
+		// remove_filter( 'get_the_excerpt', array( 'EED_Events_Archive', 'get_the_excerpt' ), 1 );
667
+		remove_filter('the_title', ['EED_Events_Archive', 'the_title'], 1);
668
+		remove_filter(
669
+			EED_Events_Archive::getExcerptFilter(),
670
+			['EED_Events_Archive', 'event_details'],
671
+			EED_Events_Archive::EVENT_DETAILS_PRIORITY
672
+		);
673
+		remove_filter(
674
+			EED_Events_Archive::getExcerptFilter(),
675
+			['EED_Events_Archive', 'event_datetimes'],
676
+			EED_Events_Archive::EVENT_DATETIMES_PRIORITY
677
+		);
678
+		remove_filter(
679
+			EED_Events_Archive::getExcerptFilter(),
680
+			['EED_Events_Archive', 'event_tickets'],
681
+			EED_Events_Archive::EVENT_TICKETS_PRIORITY
682
+		);
683
+		remove_filter(
684
+			EED_Events_Archive::getExcerptFilter(),
685
+			['EED_Events_Archive', 'event_venues'],
686
+			EED_Events_Archive::EVENT_VENUES_PRIORITY
687
+		);
688
+		remove_filter(
689
+			'the_content',
690
+			['EED_Events_Archive', 'event_details'],
691
+			EED_Events_Archive::EVENT_DETAILS_PRIORITY
692
+		);
693
+		remove_filter(
694
+			'the_content',
695
+			['EED_Events_Archive', 'event_datetimes'],
696
+			EED_Events_Archive::EVENT_DATETIMES_PRIORITY
697
+		);
698
+		remove_filter(
699
+			'the_content',
700
+			['EED_Events_Archive', 'event_tickets'],
701
+			EED_Events_Archive::EVENT_TICKETS_PRIORITY
702
+		);
703
+		remove_filter(
704
+			'the_content',
705
+			['EED_Events_Archive', 'event_venues'],
706
+			EED_Events_Archive::EVENT_VENUES_PRIORITY
707
+		);
708
+		// don't display entry meta because the existing theme will take care of that
709
+		remove_filter(
710
+			'FHEE__content_espresso_events_details_template__display_entry_meta',
711
+			'__return_false'
712
+		);
713
+	}
714
+
715
+
716
+	/**
717
+	 * @return void
718
+	 */
719
+	public function load_event_list_assets()
720
+	{
721
+		do_action('AHEE__EED_Events_Archive__before_load_assets');
722
+		add_filter('FHEE_load_EE_Session', '__return_true');
723
+		add_filter('FHEE__EED_Ticket_Selector__load_tckt_slctr_assets', '__return_true');
724
+		add_action('wp_enqueue_scripts', [$this, 'wp_enqueue_scripts'], 10);
725
+		if (EE_Registry::instance()->CFG->map_settings->use_google_maps) {
726
+			add_action('wp_enqueue_scripts', ['EEH_Maps', 'espresso_google_map_js'], 11);
727
+		}
728
+	}
729
+
730
+
731
+	/**
732
+	 * @return void
733
+	 * @throws EE_Error
734
+	 */
735
+	public function wp_enqueue_scripts()
736
+	{
737
+		// get some style
738
+		if (apply_filters('FHEE_enable_default_espresso_css', false)) {
739
+			// first check uploads folder
740
+			if (EEH_File::is_readable(get_stylesheet_directory() . $this->theme . '/style.css')) {
741
+				wp_register_style(
742
+					$this->theme,
743
+					get_stylesheet_directory_uri() . $this->theme . '/style.css',
744
+					['dashicons', 'espresso_default']
745
+				);
746
+			}
747
+			wp_enqueue_style($this->theme);
748
+		}
749
+	}
750
+
751
+
752
+	/**
753
+	 * @static
754
+	 * @return void
755
+	 */
756
+	public static function template_settings_form()
757
+	{
758
+		$template_settings                     = EE_Registry::instance()->CFG->template_settings;
759
+		$template_settings->EED_Events_Archive = isset($template_settings->EED_Events_Archive)
760
+			? $template_settings->EED_Events_Archive : new EE_Events_Archive_Config();
761
+		$template_settings->EED_Events_Archive = apply_filters(
762
+			'FHEE__EED_Events_Archive__template_settings_form__event_list_config',
763
+			$template_settings->EED_Events_Archive
764
+		);
765
+		$events_archive_settings               = [
766
+			'display_status_banner'   => 0,
767
+			'display_description'     => 1,
768
+			'display_ticket_selector' => 0,
769
+			'display_datetimes'       => 1,
770
+			'display_venue'           => 0,
771
+			'display_expired_events'  => 0,
772
+		];
773
+		$events_archive_settings               = array_merge(
774
+			$events_archive_settings,
775
+			(array) $template_settings->EED_Events_Archive
776
+		);
777
+		EEH_Template::display_template(
778
+			EVENTS_ARCHIVE_TEMPLATES_PATH . 'admin-event-list-settings.template.php',
779
+			$events_archive_settings
780
+		);
781
+	}
782
+
783
+
784
+	/**
785
+	 * @param EE_Template_Config $CFG
786
+	 * @param array              $REQ
787
+	 * @return EE_Template_Config
788
+	 */
789
+	public static function update_template_settings($CFG, $REQ)
790
+	{
791
+		$CFG->EED_Events_Archive = new EE_Events_Archive_Config();
792
+		// unless we are resetting the config...
793
+		if (
794
+			! isset($REQ['EED_Events_Archive_reset_event_list_settings'])
795
+			|| absint($REQ['EED_Events_Archive_reset_event_list_settings']) !== 1
796
+		) {
797
+			$CFG->EED_Events_Archive->display_status_banner   = isset($REQ['EED_Events_Archive_display_status_banner'])
798
+				? absint($REQ['EED_Events_Archive_display_status_banner'])
799
+				: 0;
800
+			$CFG->EED_Events_Archive->display_description     = isset($REQ['EED_Events_Archive_display_description'])
801
+				? absint($REQ['EED_Events_Archive_display_description'])
802
+				: 1;
803
+			$CFG->EED_Events_Archive->display_ticket_selector = isset($REQ['EED_Events_Archive_display_ticket_selector'])
804
+				? absint($REQ['EED_Events_Archive_display_ticket_selector'])
805
+				: 0;
806
+			$CFG->EED_Events_Archive->display_datetimes       = isset($REQ['EED_Events_Archive_display_datetimes'])
807
+				? absint($REQ['EED_Events_Archive_display_datetimes'])
808
+				: 1;
809
+			$CFG->EED_Events_Archive->display_venue           = isset($REQ['EED_Events_Archive_display_venue'])
810
+				? absint($REQ['EED_Events_Archive_display_venue'])
811
+				: 0;
812
+			$CFG->EED_Events_Archive->display_expired_events  = isset($REQ['EED_Events_Archive_display_expired_events'])
813
+				? absint($REQ['EED_Events_Archive_display_expired_events'])
814
+				: 0;
815
+		}
816
+		return $CFG;
817
+	}
818
+
819
+
820
+	/**
821
+	 * @param string $extra_class
822
+	 * @return string
823
+	 */
824
+	public static function event_list_css($extra_class = '')
825
+	{
826
+		$event_list_css   = ! empty($extra_class) ? [$extra_class] : [];
827
+		$event_list_css[] = 'espresso-event-list-event';
828
+		return implode(' ', $event_list_css);
829
+	}
830
+
831
+
832
+	/**
833
+	 * @return array
834
+	 * @throws EE_Error
835
+	 * @throws ReflectionException
836
+	 */
837
+	public static function event_categories()
838
+	{
839
+		return EE_Registry::instance()->load_model('Term')->get_all_ee_categories();
840
+	}
841
+
842
+
843
+	/**
844
+	 * @param $value
845
+	 * @return bool
846
+	 */
847
+	public static function display_description($value)
848
+	{
849
+		$config              = EE_Registry::instance()->CFG->template_settings->EED_Events_Archive;
850
+		$display_description = isset($config->display_description) ? $config->display_description : 1;
851
+		return $display_description === $value;
852
+	}
853
+
854
+
855
+	/**
856
+	 * @return bool
857
+	 */
858
+	public static function display_ticket_selector()
859
+	{
860
+		$config = EE_Registry::instance()->CFG->template_settings->EED_Events_Archive;
861
+		return isset($config->display_ticket_selector) && $config->display_ticket_selector;
862
+	}
863
+
864
+
865
+	/**
866
+	 * @return bool
867
+	 * @throws EE_Error
868
+	 * @throws ReflectionException
869
+	 */
870
+	public static function display_venue()
871
+	{
872
+		$config = EE_Registry::instance()->CFG->template_settings->EED_Events_Archive;
873
+		return isset($config->display_venue) && $config->display_venue && EEH_Venue_View::venue_name();
874
+	}
875
+
876
+
877
+	/**
878
+	 * @return bool
879
+	 */
880
+	public static function display_datetimes()
881
+	{
882
+		$config = EE_Registry::instance()->CFG->template_settings->EED_Events_Archive;
883
+		return isset($config->display_datetimes) && $config->display_datetimes;
884
+	}
885
+
886
+
887
+	/**
888
+	 * @return string
889
+	 */
890
+	public static function event_list_title()
891
+	{
892
+		return apply_filters(
893
+			'FHEE__archive_espresso_events_template__upcoming_events_h1',
894
+			esc_html__('Upcoming Events', 'event_espresso')
895
+		);
896
+	}
897
+
898
+
899
+	// GRAVEYARD
900
+
901
+
902
+	/**
903
+	 * @since 4.4.0
904
+	 */
905
+	public static function _doing_it_wrong_notice($function = '')
906
+	{
907
+		EE_Error::doing_it_wrong(
908
+			__FUNCTION__,
909
+			sprintf(
910
+				esc_html__(
911
+					'EED_Events_Archive::%1$s was moved to EEH_Event_Query::%1$s:%2$sPlease update your existing code because the method it calls will be removed in version %3$s',
912
+					'event_espresso'
913
+				),
914
+				$function,
915
+				'<br />',
916
+				'4.6.0'
917
+			),
918
+			'4.4.0'
919
+		);
920
+	}
921
+
922
+
923
+	/**
924
+	 * @deprecated
925
+	 * @since 4.4.0
926
+	 */
927
+	public function get_post_data()
928
+	{
929
+		EEH_Event_Query::set_query_params();
930
+	}
931
+
932
+
933
+	/**
934
+	 * @throws EE_Error
935
+	 * @since 4.4.0
936
+	 * @deprecated
937
+	 */
938
+	public function posts_fields($SQL, WP_Query $wp_query)
939
+	{
940
+		EED_Events_Archive::_doing_it_wrong_notice(__FUNCTION__);
941
+		return EEH_Event_Query::posts_fields($SQL, $wp_query);
942
+	}
943
+
944
+
945
+	/**
946
+	 * @throws EE_Error
947
+	 * @since 4.4.0
948
+	 * @deprecated
949
+	 */
950
+	public static function posts_fields_sql_for_orderby($orderby_params = [])
951
+	{
952
+		EED_Events_Archive::_doing_it_wrong_notice(__FUNCTION__);
953
+		return EEH_Event_Query::posts_fields_sql_for_orderby($orderby_params);
954
+	}
955
+
956
+
957
+	/**
958
+	 * @throws EE_Error
959
+	 * @since 4.4.0
960
+	 * @deprecated
961
+	 */
962
+	public function posts_join($SQL, WP_Query $wp_query)
963
+	{
964
+		EED_Events_Archive::_doing_it_wrong_notice(__FUNCTION__);
965
+		return EEH_Event_Query::posts_join($SQL, $wp_query);
966
+	}
967
+
968
+
969
+	/**
970
+	 * @deprecated
971
+	 * @since 4.4.0
972
+	 */
973
+	public static function posts_join_sql_for_terms($join_terms = null)
974
+	{
975
+		EED_Events_Archive::_doing_it_wrong_notice(__FUNCTION__);
976
+		return EEH_Event_Query::posts_join_sql_for_terms($join_terms);
977
+	}
978
+
979
+
980
+	/**
981
+	 * @throws EE_Error
982
+	 * @since 4.4.0
983
+	 * @deprecated
984
+	 */
985
+	public static function posts_join_for_orderby($orderby_params = [])
986
+	{
987
+		EED_Events_Archive::_doing_it_wrong_notice(__FUNCTION__);
988
+		return EEH_Event_Query::posts_join_for_orderby($orderby_params);
989
+	}
990
+
991
+
992
+	/**
993
+	 * @throws EE_Error
994
+	 * @since 4.4.0
995
+	 * @deprecated
996
+	 */
997
+	public function posts_where($SQL, WP_Query $wp_query)
998
+	{
999
+		EED_Events_Archive::_doing_it_wrong_notice(__FUNCTION__);
1000
+		return EEH_Event_Query::posts_where($SQL, $wp_query);
1001
+	}
1002
+
1003
+
1004
+	/**
1005
+	 * @throws EE_Error
1006
+	 * @since 4.4.0
1007
+	 * @deprecated
1008
+	 */
1009
+	public static function posts_where_sql_for_show_expired($show_expired = false)
1010
+	{
1011
+		EED_Events_Archive::_doing_it_wrong_notice(__FUNCTION__);
1012
+		return EEH_Event_Query::posts_where_sql_for_show_expired($show_expired);
1013
+	}
1014
+
1015
+
1016
+	/**
1017
+	 * @deprecated
1018
+	 * @since 4.4.0
1019
+	 */
1020
+	public static function posts_where_sql_for_event_category_slug($event_category_slug = null)
1021
+	{
1022
+		EED_Events_Archive::_doing_it_wrong_notice(__FUNCTION__);
1023
+		return EEH_Event_Query::posts_where_sql_for_event_category_slug($event_category_slug);
1024
+	}
1025
+
1026
+
1027
+	/**
1028
+	 * @throws EE_Error
1029
+	 * @since 4.4.0
1030
+	 * @deprecated
1031
+	 */
1032
+	public static function posts_where_sql_for_event_list_month($month = null)
1033
+	{
1034
+		EED_Events_Archive::_doing_it_wrong_notice(__FUNCTION__);
1035
+		return EEH_Event_Query::posts_where_sql_for_event_list_month($month);
1036
+	}
1037
+
1038
+
1039
+	/**
1040
+	 * @throws EE_Error
1041
+	 * @since 4.4.0
1042
+	 * @deprecated
1043
+	 */
1044
+	public function posts_orderby($SQL, WP_Query $wp_query)
1045
+	{
1046
+		EED_Events_Archive::_doing_it_wrong_notice(__FUNCTION__);
1047
+		return EEH_Event_Query::posts_orderby($SQL, $wp_query);
1048
+	}
1049
+
1050
+
1051
+	/**
1052
+	 * @throws EE_Error
1053
+	 * @since 4.4.0
1054
+	 * @deprecated
1055
+	 */
1056
+	public static function posts_orderby_sql($orderby_params = [], $sort = 'ASC')
1057
+	{
1058
+		EED_Events_Archive::_doing_it_wrong_notice(__FUNCTION__);
1059
+		return EEH_Event_Query::posts_orderby_sql($orderby_params, $sort);
1060
+	}
1061 1061
 }
1062 1062
 
1063 1063
 
@@ -1066,9 +1066,9 @@  discard block
 block discarded – undo
1066 1066
  */
1067 1067
 function espresso_get_event_list_ID()
1068 1068
 {
1069
-    EED_Events_Archive::$espresso_event_list_ID++;
1070
-    EED_Events_Archive::$espresso_grid_event_lists[] = EED_Events_Archive::$espresso_event_list_ID;
1071
-    return EED_Events_Archive::$espresso_event_list_ID;
1069
+	EED_Events_Archive::$espresso_event_list_ID++;
1070
+	EED_Events_Archive::$espresso_grid_event_lists[] = EED_Events_Archive::$espresso_event_list_ID;
1071
+	return EED_Events_Archive::$espresso_event_list_ID;
1072 1072
 }
1073 1073
 
1074 1074
 
@@ -1077,7 +1077,7 @@  discard block
 block discarded – undo
1077 1077
  */
1078 1078
 function espresso_event_list_title()
1079 1079
 {
1080
-    return EED_Events_Archive::event_list_title();
1080
+	return EED_Events_Archive::event_list_title();
1081 1081
 }
1082 1082
 
1083 1083
 
@@ -1087,7 +1087,7 @@  discard block
 block discarded – undo
1087 1087
  */
1088 1088
 function espresso_event_list_css($extra_class = '')
1089 1089
 {
1090
-    return EED_Events_Archive::event_list_css($extra_class);
1090
+	return EED_Events_Archive::event_list_css($extra_class);
1091 1091
 }
1092 1092
 
1093 1093
 
@@ -1098,7 +1098,7 @@  discard block
 block discarded – undo
1098 1098
  */
1099 1099
 function espresso_get_event_categories()
1100 1100
 {
1101
-    return EED_Events_Archive::event_categories();
1101
+	return EED_Events_Archive::event_categories();
1102 1102
 }
1103 1103
 
1104 1104
 
@@ -1107,7 +1107,7 @@  discard block
 block discarded – undo
1107 1107
  */
1108 1108
 function espresso_display_full_description_in_event_list()
1109 1109
 {
1110
-    return EED_Events_Archive::display_description(2);
1110
+	return EED_Events_Archive::display_description(2);
1111 1111
 }
1112 1112
 
1113 1113
 
@@ -1116,7 +1116,7 @@  discard block
 block discarded – undo
1116 1116
  */
1117 1117
 function espresso_display_excerpt_in_event_list()
1118 1118
 {
1119
-    return EED_Events_Archive::display_description(1);
1119
+	return EED_Events_Archive::display_description(1);
1120 1120
 }
1121 1121
 
1122 1122
 
@@ -1125,7 +1125,7 @@  discard block
 block discarded – undo
1125 1125
  */
1126 1126
 function espresso_display_ticket_selector_in_event_list()
1127 1127
 {
1128
-    return EED_Events_Archive::display_ticket_selector();
1128
+	return EED_Events_Archive::display_ticket_selector();
1129 1129
 }
1130 1130
 
1131 1131
 
@@ -1136,7 +1136,7 @@  discard block
 block discarded – undo
1136 1136
  */
1137 1137
 function espresso_display_venue_in_event_list()
1138 1138
 {
1139
-    return EED_Events_Archive::display_venue();
1139
+	return EED_Events_Archive::display_venue();
1140 1140
 }
1141 1141
 
1142 1142
 
@@ -1145,5 +1145,5 @@  discard block
 block discarded – undo
1145 1145
  */
1146 1146
 function espresso_display_datetimes_in_event_list()
1147 1147
 {
1148
-    return EED_Events_Archive::display_datetimes();
1148
+	return EED_Events_Archive::display_datetimes();
1149 1149
 }
Please login to merge, or discard this patch.
Spacing   +15 added lines, -15 removed lines patch added patch discarded remove patch
@@ -120,8 +120,8 @@  discard block
 block discarded – undo
120 120
      */
121 121
     public static function set_definitions()
122 122
     {
123
-        define('EVENTS_ARCHIVE_ASSETS_URL', plugin_dir_url(__FILE__) . 'assets/');
124
-        define('EVENTS_ARCHIVE_TEMPLATES_PATH', str_replace('\\', '/', plugin_dir_path(__FILE__)) . 'templates/');
123
+        define('EVENTS_ARCHIVE_ASSETS_URL', plugin_dir_url(__FILE__).'assets/');
124
+        define('EVENTS_ARCHIVE_TEMPLATES_PATH', str_replace('\\', '/', plugin_dir_path(__FILE__)).'templates/');
125 125
     }
126 126
 
127 127
 
@@ -141,7 +141,7 @@  discard block
 block discarded – undo
141 141
      */
142 142
     public static function get_iframe_embed_button()
143 143
     {
144
-        if (! self::$_iframe_embed_button instanceof EventListIframeEmbedButton) {
144
+        if ( ! self::$_iframe_embed_button instanceof EventListIframeEmbedButton) {
145 145
             self::$_iframe_embed_button = new EventListIframeEmbedButton();
146 146
         }
147 147
         return self::$_iframe_embed_button;
@@ -218,8 +218,8 @@  discard block
 block discarded – undo
218 218
         EEH_Event_Query::add_query_filters();
219 219
         // set params that will get used by the filters
220 220
         EEH_Event_Query::set_query_params(
221
-            '',                             // month
222
-            '',                             // category
221
+            '', // month
222
+            '', // category
223 223
             $config->display_expired_events // show_expired
224 224
         );
225 225
         // check what template is loaded
@@ -281,7 +281,7 @@  discard block
 block discarded – undo
281 281
     public function template_include($template = '')
282 282
     {
283 283
         // don't add content filter for dedicated EE child themes or private posts
284
-        if (! EEH_Template::is_espresso_theme()) {
284
+        if ( ! EEH_Template::is_espresso_theme()) {
285 285
             /** @type EE_Events_Archive_Config $config */
286 286
             $config = $this->config();
287 287
             // add status banner ?
@@ -355,7 +355,7 @@  discard block
 block discarded – undo
355 355
         global $post;
356 356
         if ($post instanceof WP_Post) {
357 357
             return (EED_Events_Archive::isBlockTheme() || in_the_loop()) && $post->ID == $id
358
-                ? espresso_event_status_banner($post->ID) . $title
358
+                ? espresso_event_status_banner($post->ID).$title
359 359
                 : $title;
360 360
         }
361 361
         return $title;
@@ -459,7 +459,7 @@  discard block
 block discarded – undo
459 459
         if (post_password_required()) {
460 460
             return $content;
461 461
         }
462
-        return EEH_Template::locate_template('content-espresso_events-datetimes.php') . $content;
462
+        return EEH_Template::locate_template('content-espresso_events-datetimes.php').$content;
463 463
     }
464 464
 
465 465
 
@@ -474,7 +474,7 @@  discard block
 block discarded – undo
474 474
         if (post_password_required()) {
475 475
             return $content;
476 476
         }
477
-        return EEH_Template::locate_template('content-espresso_events-tickets.php') . $content;
477
+        return EEH_Template::locate_template('content-espresso_events-tickets.php').$content;
478 478
     }
479 479
 
480 480
 
@@ -501,7 +501,7 @@  discard block
 block discarded – undo
501 501
         if (post_password_required()) {
502 502
             return $content;
503 503
         }
504
-        return $content . EEH_Template::locate_template('content-espresso_events-venues.php');
504
+        return $content.EEH_Template::locate_template('content-espresso_events-venues.php');
505 505
     }
506 506
 
507 507
 
@@ -737,10 +737,10 @@  discard block
 block discarded – undo
737 737
         // get some style
738 738
         if (apply_filters('FHEE_enable_default_espresso_css', false)) {
739 739
             // first check uploads folder
740
-            if (EEH_File::is_readable(get_stylesheet_directory() . $this->theme . '/style.css')) {
740
+            if (EEH_File::is_readable(get_stylesheet_directory().$this->theme.'/style.css')) {
741 741
                 wp_register_style(
742 742
                     $this->theme,
743
-                    get_stylesheet_directory_uri() . $this->theme . '/style.css',
743
+                    get_stylesheet_directory_uri().$this->theme.'/style.css',
744 744
                     ['dashicons', 'espresso_default']
745 745
                 );
746 746
             }
@@ -762,7 +762,7 @@  discard block
 block discarded – undo
762 762
             'FHEE__EED_Events_Archive__template_settings_form__event_list_config',
763 763
             $template_settings->EED_Events_Archive
764 764
         );
765
-        $events_archive_settings               = [
765
+        $events_archive_settings = [
766 766
             'display_status_banner'   => 0,
767 767
             'display_description'     => 1,
768 768
             'display_ticket_selector' => 0,
@@ -770,12 +770,12 @@  discard block
 block discarded – undo
770 770
             'display_venue'           => 0,
771 771
             'display_expired_events'  => 0,
772 772
         ];
773
-        $events_archive_settings               = array_merge(
773
+        $events_archive_settings = array_merge(
774 774
             $events_archive_settings,
775 775
             (array) $template_settings->EED_Events_Archive
776 776
         );
777 777
         EEH_Template::display_template(
778
-            EVENTS_ARCHIVE_TEMPLATES_PATH . 'admin-event-list-settings.template.php',
778
+            EVENTS_ARCHIVE_TEMPLATES_PATH.'admin-event-list-settings.template.php',
779 779
             $events_archive_settings
780 780
         );
781 781
     }
Please login to merge, or discard this patch.
espresso.php 1 patch
Indentation   +80 added lines, -80 removed lines patch added patch discarded remove patch
@@ -38,103 +38,103 @@
 block discarded – undo
38 38
  * @since           4.0
39 39
  */
40 40
 if (function_exists('espresso_version')) {
41
-    if (! function_exists('espresso_duplicate_plugin_error')) {
42
-        /**
43
-         *    espresso_duplicate_plugin_error
44
-         *    displays if more than one version of EE is activated at the same time
45
-         */
46
-        function espresso_duplicate_plugin_error()
47
-        {
48
-            ?>
41
+	if (! function_exists('espresso_duplicate_plugin_error')) {
42
+		/**
43
+		 *    espresso_duplicate_plugin_error
44
+		 *    displays if more than one version of EE is activated at the same time
45
+		 */
46
+		function espresso_duplicate_plugin_error()
47
+		{
48
+			?>
49 49
             <div class="error">
50 50
                 <p>
51 51
                     <?php
52
-                    echo esc_html__(
53
-                        'Can not run multiple versions of Event Espresso! One version has been automatically deactivated. Please verify that you have the correct version you want still active.',
54
-                        'event_espresso'
55
-                    ); ?>
52
+					echo esc_html__(
53
+						'Can not run multiple versions of Event Espresso! One version has been automatically deactivated. Please verify that you have the correct version you want still active.',
54
+						'event_espresso'
55
+					); ?>
56 56
                 </p>
57 57
             </div>
58 58
             <?php
59
-            espresso_deactivate_plugin(plugin_basename(__FILE__));
60
-        }
61
-    }
62
-    add_action('admin_notices', 'espresso_duplicate_plugin_error', 1);
59
+			espresso_deactivate_plugin(plugin_basename(__FILE__));
60
+		}
61
+	}
62
+	add_action('admin_notices', 'espresso_duplicate_plugin_error', 1);
63 63
 } else {
64
-    define('EE_MIN_PHP_VER_REQUIRED', '5.6.2');
65
-    if (! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) {
66
-        /**
67
-         * espresso_minimum_php_version_error
68
-         *
69
-         * @return void
70
-         */
71
-        function espresso_minimum_php_version_error()
72
-        {
73
-            ?>
64
+	define('EE_MIN_PHP_VER_REQUIRED', '5.6.2');
65
+	if (! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) {
66
+		/**
67
+		 * espresso_minimum_php_version_error
68
+		 *
69
+		 * @return void
70
+		 */
71
+		function espresso_minimum_php_version_error()
72
+		{
73
+			?>
74 74
             <div class="error">
75 75
                 <p>
76 76
                     <?php
77
-                    printf(
78
-                        esc_html__(
79
-                            'We\'re sorry, but Event Espresso requires PHP version %1$s or greater in order to operate. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.',
80
-                            'event_espresso'
81
-                        ),
82
-                        EE_MIN_PHP_VER_REQUIRED,
83
-                        PHP_VERSION,
84
-                        '<br/>',
85
-                        '<a href="http://php.net/downloads.php">http://php.net/downloads.php</a>'
86
-                    );
87
-                    ?>
77
+					printf(
78
+						esc_html__(
79
+							'We\'re sorry, but Event Espresso requires PHP version %1$s or greater in order to operate. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.',
80
+							'event_espresso'
81
+						),
82
+						EE_MIN_PHP_VER_REQUIRED,
83
+						PHP_VERSION,
84
+						'<br/>',
85
+						'<a href="http://php.net/downloads.php">http://php.net/downloads.php</a>'
86
+					);
87
+					?>
88 88
                 </p>
89 89
             </div>
90 90
             <?php
91
-            espresso_deactivate_plugin(plugin_basename(__FILE__));
92
-        }
91
+			espresso_deactivate_plugin(plugin_basename(__FILE__));
92
+		}
93 93
 
94
-        add_action('admin_notices', 'espresso_minimum_php_version_error', 1);
95
-    } else {
96
-        define('EVENT_ESPRESSO_MAIN_FILE', __FILE__);
97
-        /**
98
-         * espresso_version
99
-         * Returns the plugin version
100
-         *
101
-         * @return string
102
-         */
103
-        function espresso_version()
104
-        {
105
-            return apply_filters('FHEE__espresso__espresso_version', '4.10.33.rc.011');
106
-        }
94
+		add_action('admin_notices', 'espresso_minimum_php_version_error', 1);
95
+	} else {
96
+		define('EVENT_ESPRESSO_MAIN_FILE', __FILE__);
97
+		/**
98
+		 * espresso_version
99
+		 * Returns the plugin version
100
+		 *
101
+		 * @return string
102
+		 */
103
+		function espresso_version()
104
+		{
105
+			return apply_filters('FHEE__espresso__espresso_version', '4.10.33.rc.011');
106
+		}
107 107
 
108
-        /**
109
-         * espresso_plugin_activation
110
-         * adds a wp-option to indicate that EE has been activated via the WP admin plugins page
111
-         */
112
-        function espresso_plugin_activation()
113
-        {
114
-            update_option('ee_espresso_activation', true);
115
-        }
108
+		/**
109
+		 * espresso_plugin_activation
110
+		 * adds a wp-option to indicate that EE has been activated via the WP admin plugins page
111
+		 */
112
+		function espresso_plugin_activation()
113
+		{
114
+			update_option('ee_espresso_activation', true);
115
+		}
116 116
 
117
-        register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation');
117
+		register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation');
118 118
 
119
-        require_once __DIR__ . '/core/bootstrap_espresso.php';
120
-        bootstrap_espresso();
121
-    }
119
+		require_once __DIR__ . '/core/bootstrap_espresso.php';
120
+		bootstrap_espresso();
121
+	}
122 122
 }
123 123
 if (! function_exists('espresso_deactivate_plugin')) {
124
-    /**
125
-     *    deactivate_plugin
126
-     * usage:  espresso_deactivate_plugin( plugin_basename( __FILE__ ));
127
-     *
128
-     * @access public
129
-     * @param string $plugin_basename - the results of plugin_basename( __FILE__ ) for the plugin's main file
130
-     * @return    void
131
-     */
132
-    function espresso_deactivate_plugin($plugin_basename = '')
133
-    {
134
-        if (! function_exists('deactivate_plugins')) {
135
-            require_once ABSPATH . 'wp-admin/includes/plugin.php';
136
-        }
137
-        unset($_GET['activate'], $_REQUEST['activate']);
138
-        deactivate_plugins($plugin_basename);
139
-    }
124
+	/**
125
+	 *    deactivate_plugin
126
+	 * usage:  espresso_deactivate_plugin( plugin_basename( __FILE__ ));
127
+	 *
128
+	 * @access public
129
+	 * @param string $plugin_basename - the results of plugin_basename( __FILE__ ) for the plugin's main file
130
+	 * @return    void
131
+	 */
132
+	function espresso_deactivate_plugin($plugin_basename = '')
133
+	{
134
+		if (! function_exists('deactivate_plugins')) {
135
+			require_once ABSPATH . 'wp-admin/includes/plugin.php';
136
+		}
137
+		unset($_GET['activate'], $_REQUEST['activate']);
138
+		deactivate_plugins($plugin_basename);
139
+	}
140 140
 }
141 141
\ No newline at end of file
Please login to merge, or discard this patch.
core/db_classes/EE_Transaction.class.php 1 patch
Indentation   +1730 added lines, -1730 removed lines patch added patch discarded remove patch
@@ -14,1734 +14,1734 @@
 block discarded – undo
14 14
 class EE_Transaction extends EE_Base_Class implements EEI_Transaction
15 15
 {
16 16
 
17
-    /**
18
-     * The length of time in seconds that a lock is applied before being considered expired.
19
-     * It is not long because a transaction should only be locked for the duration of the request that locked it
20
-     */
21
-    const LOCK_EXPIRATION = 2;
22
-
23
-    /**
24
-     * extra meta key for tracking when transactions are deleted and by who
25
-     *
26
-     * @type string
27
-     */
28
-    const EXTRA_META_KEY_TXN_DELETED = 'transaction-deleted';
29
-
30
-    /**
31
-     * txn status upon initial construction.
32
-     *
33
-     * @var string
34
-     */
35
-    protected $_old_txn_status;
36
-
37
-
38
-    /**
39
-     * @param array  $props_n_values          incoming values
40
-     * @param string $timezone                incoming timezone
41
-     *                                        (if not set the timezone set for the website will be used.)
42
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
43
-     *                                        date_format and the second value is the time format
44
-     * @return EE_Transaction
45
-     * @throws EE_Error
46
-     * @throws InvalidArgumentException
47
-     * @throws InvalidDataTypeException
48
-     * @throws InvalidInterfaceException
49
-     * @throws ReflectionException
50
-     */
51
-    public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
52
-    {
53
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
54
-        $txn = $has_object
55
-            ? $has_object
56
-            : new self($props_n_values, false, $timezone, $date_formats);
57
-        if (! $has_object) {
58
-            $txn->set_old_txn_status($txn->status_ID());
59
-        }
60
-        return $txn;
61
-    }
62
-
63
-
64
-    /**
65
-     * @param array  $props_n_values  incoming values from the database
66
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
67
-     *                                the website will be used.
68
-     * @return EE_Transaction
69
-     * @throws EE_Error
70
-     * @throws InvalidArgumentException
71
-     * @throws InvalidDataTypeException
72
-     * @throws InvalidInterfaceException
73
-     * @throws ReflectionException
74
-     */
75
-    public static function new_instance_from_db($props_n_values = array(), $timezone = null)
76
-    {
77
-        $txn = new self($props_n_values, true, $timezone);
78
-        $txn->set_old_txn_status($txn->status_ID());
79
-        return $txn;
80
-    }
81
-
82
-
83
-    /**
84
-     * Sets a meta field indicating that this TXN is locked and should not be updated in the db.
85
-     * If a lock has already been set, then we will attempt to remove it in case it has expired.
86
-     * If that also fails, then an exception is thrown.
87
-     *
88
-     * @throws EE_Error
89
-     * @throws InvalidArgumentException
90
-     * @throws InvalidDataTypeException
91
-     * @throws InvalidInterfaceException
92
-     * @throws ReflectionException
93
-     */
94
-    public function lock()
95
-    {
96
-        // attempt to set lock, but if that fails...
97
-        if (! $this->add_extra_meta('lock', time(), true)) {
98
-            // then attempt to remove the lock in case it is expired
99
-            if ($this->_remove_expired_lock()) {
100
-                // if removal was successful, then try setting lock again
101
-                $this->lock();
102
-            } else {
103
-                // but if the lock can not be removed, then throw an exception
104
-                throw new EE_Error(
105
-                    sprintf(
106
-                        esc_html__(
107
-                            'Could not lock Transaction %1$d because it is already locked, meaning another part of the system is currently editing it. It should already be unlocked by the time you read this, so please refresh the page and try again.',
108
-                            'event_espresso'
109
-                        ),
110
-                        $this->ID()
111
-                    )
112
-                );
113
-            }
114
-        }
115
-    }
116
-
117
-
118
-    /**
119
-     * removes transaction lock applied in EE_Transaction::lock()
120
-     *
121
-     * @return int
122
-     * @throws EE_Error
123
-     * @throws InvalidArgumentException
124
-     * @throws InvalidDataTypeException
125
-     * @throws InvalidInterfaceException
126
-     * @throws ReflectionException
127
-     */
128
-    public function unlock()
129
-    {
130
-        return $this->delete_extra_meta('lock');
131
-    }
132
-
133
-
134
-    /**
135
-     * Decides whether or not now is the right time to update the transaction.
136
-     * This is useful because we don't always know if it is safe to update the transaction
137
-     * and its related data. why?
138
-     * because it's possible that the transaction is being used in another
139
-     * request and could overwrite anything we save.
140
-     * So we want to only update the txn once we know that won't happen.
141
-     * We also check that the lock isn't expired, and remove it if it is
142
-     *
143
-     * @return boolean
144
-     * @throws EE_Error
145
-     * @throws InvalidArgumentException
146
-     * @throws InvalidDataTypeException
147
-     * @throws InvalidInterfaceException
148
-     * @throws ReflectionException
149
-     */
150
-    public function is_locked()
151
-    {
152
-        // if TXN is not locked, then return false immediately
153
-        if (! $this->_get_lock()) {
154
-            return false;
155
-        }
156
-        // if not, then let's try and remove the lock in case it's expired...
157
-        // _remove_expired_lock() returns 0 when lock is valid (ie: removed = false)
158
-        // and a positive number if the lock was removed (ie: number of locks deleted),
159
-        // so we need to return the opposite
160
-        return ! $this->_remove_expired_lock() ? true : false;
161
-    }
162
-
163
-
164
-    /**
165
-     * Gets the meta field indicating that this TXN is locked
166
-     *
167
-     * @return int
168
-     * @throws EE_Error
169
-     * @throws InvalidArgumentException
170
-     * @throws InvalidDataTypeException
171
-     * @throws InvalidInterfaceException
172
-     * @throws ReflectionException
173
-     */
174
-    protected function _get_lock()
175
-    {
176
-        return (int) $this->get_extra_meta('lock', true, 0);
177
-    }
178
-
179
-
180
-    /**
181
-     * If the lock on this transaction is expired, then we want to remove it so that the transaction can be updated
182
-     *
183
-     * @return int
184
-     * @throws EE_Error
185
-     * @throws InvalidArgumentException
186
-     * @throws InvalidDataTypeException
187
-     * @throws InvalidInterfaceException
188
-     * @throws ReflectionException
189
-     */
190
-    protected function _remove_expired_lock()
191
-    {
192
-        $locked = $this->_get_lock();
193
-        if ($locked && time() - EE_Transaction::LOCK_EXPIRATION > $locked) {
194
-            return $this->unlock();
195
-        }
196
-        return 0;
197
-    }
198
-
199
-
200
-    /**
201
-     * Set transaction total
202
-     *
203
-     * @param float $total total value of transaction
204
-     * @throws EE_Error
205
-     * @throws InvalidArgumentException
206
-     * @throws InvalidDataTypeException
207
-     * @throws InvalidInterfaceException
208
-     * @throws ReflectionException
209
-     */
210
-    public function set_total($total = 0.00)
211
-    {
212
-        $this->set('TXN_total', (float) $total);
213
-    }
214
-
215
-
216
-    /**
217
-     * Set Total Amount Paid to Date
218
-     *
219
-     * @param float $total_paid total amount paid to date (sum of all payments)
220
-     * @throws EE_Error
221
-     * @throws InvalidArgumentException
222
-     * @throws InvalidDataTypeException
223
-     * @throws InvalidInterfaceException
224
-     * @throws ReflectionException
225
-     */
226
-    public function set_paid($total_paid = 0.00)
227
-    {
228
-        $this->set('TXN_paid', (float) $total_paid);
229
-    }
230
-
231
-
232
-    /**
233
-     * Set transaction status
234
-     *
235
-     * @param string $status        whether the transaction is open, declined, accepted,
236
-     *                              or any number of custom values that can be set
237
-     * @throws EE_Error
238
-     * @throws InvalidArgumentException
239
-     * @throws InvalidDataTypeException
240
-     * @throws InvalidInterfaceException
241
-     * @throws ReflectionException
242
-     */
243
-    public function set_status($status = '')
244
-    {
245
-        $this->set('STS_ID', $status);
246
-    }
247
-
248
-
249
-    /**
250
-     * Set hash salt
251
-     *
252
-     * @param string $hash_salt required for some payment gateways
253
-     * @throws EE_Error
254
-     * @throws InvalidArgumentException
255
-     * @throws InvalidDataTypeException
256
-     * @throws InvalidInterfaceException
257
-     * @throws ReflectionException
258
-     */
259
-    public function set_hash_salt($hash_salt = '')
260
-    {
261
-        $this->set('TXN_hash_salt', $hash_salt);
262
-    }
263
-
264
-
265
-    /**
266
-     * Sets TXN_reg_steps array
267
-     *
268
-     * @param array $txn_reg_steps
269
-     * @throws EE_Error
270
-     * @throws InvalidArgumentException
271
-     * @throws InvalidDataTypeException
272
-     * @throws InvalidInterfaceException
273
-     * @throws ReflectionException
274
-     */
275
-    public function set_reg_steps(array $txn_reg_steps)
276
-    {
277
-        $this->set('TXN_reg_steps', $txn_reg_steps);
278
-    }
279
-
280
-
281
-    /**
282
-     * Gets TXN_reg_steps
283
-     *
284
-     * @return array
285
-     * @throws EE_Error
286
-     * @throws InvalidArgumentException
287
-     * @throws InvalidDataTypeException
288
-     * @throws InvalidInterfaceException
289
-     * @throws ReflectionException
290
-     */
291
-    public function reg_steps()
292
-    {
293
-        $TXN_reg_steps = $this->get('TXN_reg_steps');
294
-        return is_array($TXN_reg_steps) ? (array) $TXN_reg_steps : array();
295
-    }
296
-
297
-
298
-    /**
299
-     * @return string of transaction's total cost, with currency symbol and decimal
300
-     * @throws EE_Error
301
-     * @throws InvalidArgumentException
302
-     * @throws InvalidDataTypeException
303
-     * @throws InvalidInterfaceException
304
-     * @throws ReflectionException
305
-     */
306
-    public function pretty_total()
307
-    {
308
-        return $this->get_pretty('TXN_total');
309
-    }
310
-
311
-
312
-    /**
313
-     * Gets the amount paid in a pretty string (formatted and with currency symbol)
314
-     *
315
-     * @return string
316
-     * @throws EE_Error
317
-     * @throws InvalidArgumentException
318
-     * @throws InvalidDataTypeException
319
-     * @throws InvalidInterfaceException
320
-     * @throws ReflectionException
321
-     */
322
-    public function pretty_paid()
323
-    {
324
-        return $this->get_pretty('TXN_paid');
325
-    }
326
-
327
-
328
-    /**
329
-     * calculate the amount remaining for this transaction and return;
330
-     *
331
-     * @return float amount remaining
332
-     * @throws EE_Error
333
-     * @throws InvalidArgumentException
334
-     * @throws InvalidDataTypeException
335
-     * @throws InvalidInterfaceException
336
-     * @throws ReflectionException
337
-     */
338
-    public function remaining()
339
-    {
340
-        return $this->total() - $this->paid();
341
-    }
342
-
343
-
344
-    /**
345
-     * get Transaction Total
346
-     *
347
-     * @return float
348
-     * @throws EE_Error
349
-     * @throws InvalidArgumentException
350
-     * @throws InvalidDataTypeException
351
-     * @throws InvalidInterfaceException
352
-     * @throws ReflectionException
353
-     */
354
-    public function total()
355
-    {
356
-        return (float) $this->get('TXN_total');
357
-    }
358
-
359
-
360
-    /**
361
-     * get Total Amount Paid to Date
362
-     *
363
-     * @return float
364
-     * @throws EE_Error
365
-     * @throws InvalidArgumentException
366
-     * @throws InvalidDataTypeException
367
-     * @throws InvalidInterfaceException
368
-     * @throws ReflectionException
369
-     */
370
-    public function paid()
371
-    {
372
-        return (float) $this->get('TXN_paid');
373
-    }
374
-
375
-
376
-    /**
377
-     * @return mixed|null
378
-     * @throws EE_Error
379
-     * @throws InvalidArgumentException
380
-     * @throws InvalidDataTypeException
381
-     * @throws InvalidInterfaceException
382
-     * @throws ReflectionException
383
-     */
384
-    public function get_cart_session()
385
-    {
386
-        $session_data = (array) $this->get('TXN_session_data');
387
-        return isset($session_data['cart']) && $session_data['cart'] instanceof EE_Cart
388
-            ? $session_data['cart']
389
-            : null;
390
-    }
391
-
392
-
393
-    /**
394
-     * get Transaction session data
395
-     *
396
-     * @return array|mixed
397
-     * @throws EE_Error
398
-     * @throws InvalidArgumentException
399
-     * @throws InvalidDataTypeException
400
-     * @throws InvalidInterfaceException
401
-     * @throws ReflectionException
402
-     */
403
-    public function session_data()
404
-    {
405
-        $session_data = $this->get('TXN_session_data');
406
-        if (empty($session_data)) {
407
-            $session_data = array(
408
-                'id'            => null,
409
-                'user_id'       => null,
410
-                'ip_address'    => null,
411
-                'user_agent'    => null,
412
-                'init_access'   => null,
413
-                'last_access'   => null,
414
-                'pages_visited' => array(),
415
-            );
416
-        }
417
-        return $session_data;
418
-    }
419
-
420
-
421
-    /**
422
-     * Set session data within the TXN object
423
-     *
424
-     * @param EE_Session|array $session_data
425
-     * @throws EE_Error
426
-     * @throws InvalidArgumentException
427
-     * @throws InvalidDataTypeException
428
-     * @throws InvalidInterfaceException
429
-     * @throws ReflectionException
430
-     */
431
-    public function set_txn_session_data($session_data)
432
-    {
433
-        if ($session_data instanceof EE_Session) {
434
-            $this->set('TXN_session_data', $session_data->get_session_data(null, true));
435
-        } else {
436
-            $this->set('TXN_session_data', $session_data);
437
-        }
438
-    }
439
-
440
-
441
-    /**
442
-     * get Transaction hash salt
443
-     *
444
-     * @return mixed
445
-     * @throws EE_Error
446
-     * @throws InvalidArgumentException
447
-     * @throws InvalidDataTypeException
448
-     * @throws InvalidInterfaceException
449
-     * @throws ReflectionException
450
-     */
451
-    public function hash_salt_()
452
-    {
453
-        return $this->get('TXN_hash_salt');
454
-    }
455
-
456
-
457
-    /**
458
-     * Returns the transaction datetime as either:
459
-     *            - unix timestamp format ($format = false, $gmt = true)
460
-     *            - formatted date string including the UTC (timezone) offset ($format = true ($gmt
461
-     *              has no affect with this option)), this also may include a timezone abbreviation if the
462
-     *              set timezone in this class differs from what the timezone is on the blog.
463
-     *            - formatted date string including the UTC (timezone) offset (default).
464
-     *
465
-     * @param boolean $format   - whether to return a unix timestamp (default) or formatted date string
466
-     * @param boolean $gmt      - whether to return a unix timestamp with UTC offset applied (default)
467
-     *                          or no UTC offset applied
468
-     * @return string | int
469
-     * @throws EE_Error
470
-     * @throws InvalidArgumentException
471
-     * @throws InvalidDataTypeException
472
-     * @throws InvalidInterfaceException
473
-     * @throws ReflectionException
474
-     */
475
-    public function datetime($format = false, $gmt = false)
476
-    {
477
-        if ($format) {
478
-            return $this->get_pretty('TXN_timestamp');
479
-        }
480
-        if ($gmt) {
481
-            return $this->get_raw('TXN_timestamp');
482
-        }
483
-        return $this->get('TXN_timestamp');
484
-    }
485
-
486
-
487
-    /**
488
-     * Gets registrations on this transaction
489
-     *
490
-     * @param array   $query_params array of query parameters
491
-     * @param boolean $get_cached   TRUE to retrieve cached registrations or FALSE to pull from the db
492
-     * @return EE_Base_Class[]|EE_Registration[]
493
-     * @throws EE_Error
494
-     * @throws InvalidArgumentException
495
-     * @throws InvalidDataTypeException
496
-     * @throws InvalidInterfaceException
497
-     * @throws ReflectionException
498
-     */
499
-    public function registrations($query_params = array(), $get_cached = false)
500
-    {
501
-        $query_params = (empty($query_params) || ! is_array($query_params))
502
-            ? array(
503
-                'order_by' => array(
504
-                    'Event.EVT_name'     => 'ASC',
505
-                    'Attendee.ATT_lname' => 'ASC',
506
-                    'Attendee.ATT_fname' => 'ASC',
507
-                ),
508
-            )
509
-            : $query_params;
510
-        $query_params = $get_cached ? array() : $query_params;
511
-        return $this->get_many_related('Registration', $query_params);
512
-    }
513
-
514
-
515
-    /**
516
-     * Gets all the attendees for this transaction (handy for use with EE_Attendee's get_registrations_for_event
517
-     * function for getting attendees and how many registrations they each have for an event)
518
-     *
519
-     * @return mixed EE_Attendee[] by default, int if $output is set to 'COUNT'
520
-     * @throws EE_Error
521
-     * @throws InvalidArgumentException
522
-     * @throws InvalidDataTypeException
523
-     * @throws InvalidInterfaceException
524
-     * @throws ReflectionException
525
-     */
526
-    public function attendees()
527
-    {
528
-        return $this->get_many_related('Attendee', array(array('Registration.Transaction.TXN_ID' => $this->ID())));
529
-    }
530
-
531
-
532
-    /**
533
-     * Gets payments for this transaction. Unlike other such functions, order by 'DESC' by default
534
-     *
535
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
536
-     * @return EE_Base_Class[]|EE_Payment[]
537
-     * @throws EE_Error
538
-     * @throws InvalidArgumentException
539
-     * @throws InvalidDataTypeException
540
-     * @throws InvalidInterfaceException
541
-     * @throws ReflectionException
542
-     */
543
-    public function payments($query_params = array())
544
-    {
545
-        return $this->get_many_related('Payment', $query_params);
546
-    }
547
-
548
-
549
-    /**
550
-     * gets only approved payments for this transaction
551
-     *
552
-     * @return EE_Base_Class[]|EE_Payment[]
553
-     * @throws EE_Error
554
-     * @throws InvalidArgumentException
555
-     * @throws ReflectionException
556
-     * @throws InvalidDataTypeException
557
-     * @throws InvalidInterfaceException
558
-     */
559
-    public function approved_payments()
560
-    {
561
-        EE_Registry::instance()->load_model('Payment');
562
-        return $this->get_many_related(
563
-            'Payment',
564
-            array(
565
-                array('STS_ID' => EEM_Payment::status_id_approved),
566
-                'order_by' => array('PAY_timestamp' => 'DESC'),
567
-            )
568
-        );
569
-    }
570
-
571
-
572
-    /**
573
-     * Gets all payments which have not been approved
574
-     *
575
-     * @return EE_Base_Class[]|EEI_Payment[]
576
-     * @throws EE_Error if a model is misconfigured somehow
577
-     * @throws InvalidArgumentException
578
-     * @throws InvalidDataTypeException
579
-     * @throws InvalidInterfaceException
580
-     * @throws ReflectionException
581
-     */
582
-    public function pending_payments()
583
-    {
584
-        return $this->get_many_related(
585
-            'Payment',
586
-            array(
587
-                array(
588
-                    'STS_ID' => EEM_Payment::status_id_pending,
589
-                ),
590
-                'order_by' => array(
591
-                    'PAY_timestamp' => 'DESC',
592
-                ),
593
-            )
594
-        );
595
-    }
596
-
597
-
598
-    /**
599
-     * echoes $this->pretty_status()
600
-     *
601
-     * @param bool $show_icons
602
-     * @throws EE_Error
603
-     * @throws InvalidArgumentException
604
-     * @throws InvalidDataTypeException
605
-     * @throws InvalidInterfaceException
606
-     * @throws ReflectionException
607
-     */
608
-    public function e_pretty_status($show_icons = false)
609
-    {
610
-        echo wp_kses($this->pretty_status($show_icons), AllowedTags::getAllowedTags());
611
-    }
612
-
613
-
614
-    /**
615
-     * returns a pretty version of the status, good for displaying to users
616
-     *
617
-     * @param bool $show_icons
618
-     * @return string
619
-     * @throws EE_Error
620
-     * @throws InvalidArgumentException
621
-     * @throws InvalidDataTypeException
622
-     * @throws InvalidInterfaceException
623
-     * @throws ReflectionException
624
-     */
625
-    public function pretty_status($show_icons = false)
626
-    {
627
-        $status = EEM_Status::instance()->localized_status(
628
-            array($this->status_ID() => esc_html__('unknown', 'event_espresso')),
629
-            false,
630
-            'sentence'
631
-        );
632
-        $icon = '';
633
-        switch ($this->status_ID()) {
634
-            case EEM_Transaction::complete_status_code:
635
-                $icon = $show_icons ? '<span class="dashicons dashicons-yes ee-icon-size-24 green-text"></span>' : '';
636
-                break;
637
-            case EEM_Transaction::incomplete_status_code:
638
-                $icon = $show_icons ? '<span class="dashicons dashicons-marker ee-icon-size-16 lt-blue-text"></span>'
639
-                    : '';
640
-                break;
641
-            case EEM_Transaction::abandoned_status_code:
642
-                $icon = $show_icons ? '<span class="dashicons dashicons-marker ee-icon-size-16 red-text"></span>' : '';
643
-                break;
644
-            case EEM_Transaction::failed_status_code:
645
-                $icon = $show_icons ? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>' : '';
646
-                break;
647
-            case EEM_Transaction::overpaid_status_code:
648
-                $icon = $show_icons ? '<span class="dashicons dashicons-plus ee-icon-size-16 orange-text"></span>' : '';
649
-                break;
650
-        }
651
-        return $icon . $status[ $this->status_ID() ];
652
-    }
653
-
654
-
655
-    /**
656
-     * get Transaction Status
657
-     *
658
-     * @return mixed
659
-     * @throws EE_Error
660
-     * @throws InvalidArgumentException
661
-     * @throws InvalidDataTypeException
662
-     * @throws InvalidInterfaceException
663
-     * @throws ReflectionException
664
-     */
665
-    public function status_ID()
666
-    {
667
-        return $this->get('STS_ID');
668
-    }
669
-
670
-
671
-    /**
672
-     * Returns TRUE or FALSE for whether or not this transaction cost any money
673
-     *
674
-     * @return boolean
675
-     * @throws EE_Error
676
-     * @throws InvalidArgumentException
677
-     * @throws InvalidDataTypeException
678
-     * @throws InvalidInterfaceException
679
-     * @throws ReflectionException
680
-     */
681
-    public function is_free()
682
-    {
683
-        return EEH_Money::compare_floats($this->get('TXN_total'), 0, '==');
684
-    }
685
-
686
-
687
-    /**
688
-     * Returns whether this transaction is complete
689
-     * Useful in templates and other logic for deciding if we should ask for another payment...
690
-     *
691
-     * @return boolean
692
-     * @throws EE_Error
693
-     * @throws InvalidArgumentException
694
-     * @throws InvalidDataTypeException
695
-     * @throws InvalidInterfaceException
696
-     * @throws ReflectionException
697
-     */
698
-    public function is_completed()
699
-    {
700
-        return $this->status_ID() === EEM_Transaction::complete_status_code;
701
-    }
702
-
703
-
704
-    /**
705
-     * Returns whether this transaction is incomplete
706
-     * Useful in templates and other logic for deciding if we should ask for another payment...
707
-     *
708
-     * @return boolean
709
-     * @throws EE_Error
710
-     * @throws InvalidArgumentException
711
-     * @throws InvalidDataTypeException
712
-     * @throws InvalidInterfaceException
713
-     * @throws ReflectionException
714
-     */
715
-    public function is_incomplete()
716
-    {
717
-        return $this->status_ID() === EEM_Transaction::incomplete_status_code;
718
-    }
719
-
720
-
721
-    /**
722
-     * Returns whether this transaction is overpaid
723
-     * Useful in templates and other logic for deciding if monies need to be refunded
724
-     *
725
-     * @return boolean
726
-     * @throws EE_Error
727
-     * @throws InvalidArgumentException
728
-     * @throws InvalidDataTypeException
729
-     * @throws InvalidInterfaceException
730
-     * @throws ReflectionException
731
-     */
732
-    public function is_overpaid()
733
-    {
734
-        return $this->status_ID() === EEM_Transaction::overpaid_status_code;
735
-    }
736
-
737
-
738
-    /**
739
-     * Returns whether this transaction was abandoned
740
-     * meaning that the transaction/registration process was somehow interrupted and never completed
741
-     * but that contact information exists for at least one registrant
742
-     *
743
-     * @return boolean
744
-     * @throws EE_Error
745
-     * @throws InvalidArgumentException
746
-     * @throws InvalidDataTypeException
747
-     * @throws InvalidInterfaceException
748
-     * @throws ReflectionException
749
-     */
750
-    public function is_abandoned()
751
-    {
752
-        return $this->status_ID() === EEM_Transaction::abandoned_status_code;
753
-    }
754
-
755
-
756
-    /**
757
-     * Returns whether this transaction failed
758
-     * meaning that the transaction/registration process was somehow interrupted and never completed
759
-     * and that NO contact information exists for any registrants
760
-     *
761
-     * @return boolean
762
-     * @throws EE_Error
763
-     * @throws InvalidArgumentException
764
-     * @throws InvalidDataTypeException
765
-     * @throws InvalidInterfaceException
766
-     * @throws ReflectionException
767
-     */
768
-    public function failed()
769
-    {
770
-        return $this->status_ID() === EEM_Transaction::failed_status_code;
771
-    }
772
-
773
-
774
-    /**
775
-     * This returns the url for the invoice of this transaction
776
-     *
777
-     * @param string $type 'html' or 'pdf' (default is pdf)
778
-     * @return string
779
-     * @throws DomainException
780
-     * @throws EE_Error
781
-     * @throws InvalidArgumentException
782
-     * @throws InvalidDataTypeException
783
-     * @throws InvalidInterfaceException
784
-     * @throws ReflectionException
785
-     */
786
-    public function invoice_url($type = 'html')
787
-    {
788
-        $REG = $this->primary_registration();
789
-        if (! $REG instanceof EE_Registration) {
790
-            return '';
791
-        }
792
-        return $REG->invoice_url($type);
793
-    }
794
-
795
-
796
-    /**
797
-     * Gets the primary registration only
798
-     *
799
-     * @return EE_Base_Class|EE_Registration
800
-     * @throws EE_Error
801
-     * @throws InvalidArgumentException
802
-     * @throws InvalidDataTypeException
803
-     * @throws InvalidInterfaceException
804
-     * @throws ReflectionException
805
-     */
806
-    public function primary_registration()
807
-    {
808
-        $registrations = (array) $this->get_many_related(
809
-            'Registration',
810
-            array(array('REG_count' => EEM_Registration::PRIMARY_REGISTRANT_COUNT))
811
-        );
812
-        foreach ($registrations as $registration) {
813
-            // valid registration that is NOT cancelled or declined ?
814
-            if (
815
-                $registration instanceof EE_Registration
816
-                && ! in_array($registration->status_ID(), EEM_Registration::closed_reg_statuses(), true)
817
-            ) {
818
-                return $registration;
819
-            }
820
-        }
821
-        // nothing valid found, so just return first thing from array of results
822
-        return reset($registrations);
823
-    }
824
-
825
-
826
-    /**
827
-     * Gets the URL for viewing the receipt
828
-     *
829
-     * @param string $type 'pdf' or 'html' (default is 'html')
830
-     * @return string
831
-     * @throws DomainException
832
-     * @throws EE_Error
833
-     * @throws InvalidArgumentException
834
-     * @throws InvalidDataTypeException
835
-     * @throws InvalidInterfaceException
836
-     * @throws ReflectionException
837
-     */
838
-    public function receipt_url($type = 'html')
839
-    {
840
-        $REG = $this->primary_registration();
841
-        if (! $REG instanceof EE_Registration) {
842
-            return '';
843
-        }
844
-        return $REG->receipt_url($type);
845
-    }
846
-
847
-
848
-    /**
849
-     * Gets the URL of the thank you page with this registration REG_url_link added as
850
-     * a query parameter
851
-     *
852
-     * @return string
853
-     * @throws EE_Error
854
-     * @throws InvalidArgumentException
855
-     * @throws InvalidDataTypeException
856
-     * @throws InvalidInterfaceException
857
-     * @throws ReflectionException
858
-     */
859
-    public function payment_overview_url()
860
-    {
861
-        $primary_registration = $this->primary_registration();
862
-        return $primary_registration instanceof EE_Registration ? $primary_registration->payment_overview_url() : false;
863
-    }
864
-
865
-
866
-    /**
867
-     * @return string
868
-     * @throws EE_Error
869
-     * @throws InvalidArgumentException
870
-     * @throws InvalidDataTypeException
871
-     * @throws InvalidInterfaceException
872
-     * @throws ReflectionException
873
-     */
874
-    public function gateway_response_on_transaction()
875
-    {
876
-        $payment = $this->get_first_related('Payment');
877
-        return $payment instanceof EE_Payment ? $payment->gateway_response() : '';
878
-    }
879
-
880
-
881
-    /**
882
-     * Get the status object of this object
883
-     *
884
-     * @return EE_Base_Class|EE_Status
885
-     * @throws EE_Error
886
-     * @throws InvalidArgumentException
887
-     * @throws InvalidDataTypeException
888
-     * @throws InvalidInterfaceException
889
-     * @throws ReflectionException
890
-     */
891
-    public function status_obj()
892
-    {
893
-        return $this->get_first_related('Status');
894
-    }
895
-
896
-
897
-    /**
898
-     * Gets all the extra meta info on this payment
899
-     *
900
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
901
-     * @return EE_Base_Class[]|EE_Extra_Meta
902
-     * @throws EE_Error
903
-     * @throws InvalidArgumentException
904
-     * @throws InvalidDataTypeException
905
-     * @throws InvalidInterfaceException
906
-     * @throws ReflectionException
907
-     */
908
-    public function extra_meta($query_params = array())
909
-    {
910
-        return $this->get_many_related('Extra_Meta', $query_params);
911
-    }
912
-
913
-
914
-    /**
915
-     * Wrapper for _add_relation_to
916
-     *
917
-     * @param EE_Registration $registration
918
-     * @return EE_Base_Class the relation was added to
919
-     * @throws EE_Error
920
-     * @throws InvalidArgumentException
921
-     * @throws InvalidDataTypeException
922
-     * @throws InvalidInterfaceException
923
-     * @throws ReflectionException
924
-     */
925
-    public function add_registration(EE_Registration $registration)
926
-    {
927
-        return $this->_add_relation_to($registration, 'Registration');
928
-    }
929
-
930
-
931
-    /**
932
-     * Removes the given registration from being related (even before saving this transaction).
933
-     * If an ID/index is provided and this transaction isn't saved yet, removes it from list of cached relations
934
-     *
935
-     * @param int $registration_or_id
936
-     * @return EE_Base_Class that was removed from being related
937
-     * @throws EE_Error
938
-     * @throws InvalidArgumentException
939
-     * @throws InvalidDataTypeException
940
-     * @throws InvalidInterfaceException
941
-     * @throws ReflectionException
942
-     */
943
-    public function remove_registration_with_id($registration_or_id)
944
-    {
945
-        return $this->_remove_relation_to($registration_or_id, 'Registration');
946
-    }
947
-
948
-
949
-    /**
950
-     * Gets all the line items which are for ACTUAL items
951
-     *
952
-     * @return EE_Line_Item[]
953
-     * @throws EE_Error
954
-     * @throws InvalidArgumentException
955
-     * @throws InvalidDataTypeException
956
-     * @throws InvalidInterfaceException
957
-     * @throws ReflectionException
958
-     */
959
-    public function items_purchased()
960
-    {
961
-        return $this->line_items(array(array('LIN_type' => EEM_Line_Item::type_line_item)));
962
-    }
963
-
964
-
965
-    /**
966
-     * Wrapper for _add_relation_to
967
-     *
968
-     * @param EE_Line_Item $line_item
969
-     * @return EE_Base_Class the relation was added to
970
-     * @throws EE_Error
971
-     * @throws InvalidArgumentException
972
-     * @throws InvalidDataTypeException
973
-     * @throws InvalidInterfaceException
974
-     * @throws ReflectionException
975
-     */
976
-    public function add_line_item(EE_Line_Item $line_item)
977
-    {
978
-        return $this->_add_relation_to($line_item, 'Line_Item');
979
-    }
980
-
981
-
982
-    /**
983
-     * Gets ALL the line items related to this transaction (unstructured)
984
-     *
985
-     * @param array $query_params
986
-     * @return EE_Base_Class[]|EE_Line_Item[]
987
-     * @throws EE_Error
988
-     * @throws InvalidArgumentException
989
-     * @throws InvalidDataTypeException
990
-     * @throws InvalidInterfaceException
991
-     * @throws ReflectionException
992
-     */
993
-    public function line_items($query_params = array())
994
-    {
995
-        return $this->get_many_related('Line_Item', $query_params);
996
-    }
997
-
998
-
999
-    /**
1000
-     * Gets all the line items which are taxes on the total
1001
-     *
1002
-     * @return EE_Line_Item[]
1003
-     * @throws EE_Error
1004
-     * @throws InvalidArgumentException
1005
-     * @throws InvalidDataTypeException
1006
-     * @throws InvalidInterfaceException
1007
-     * @throws ReflectionException
1008
-     */
1009
-    public function tax_items()
1010
-    {
1011
-        return $this->line_items(array(array('LIN_type' => EEM_Line_Item::type_tax)));
1012
-    }
1013
-
1014
-
1015
-    /**
1016
-     * Gets the total line item (which is a parent of all other related line items,
1017
-     * meaning it takes them all into account on its total)
1018
-     *
1019
-     * @param bool $create_if_not_found
1020
-     * @return \EE_Line_Item
1021
-     * @throws EE_Error
1022
-     * @throws InvalidArgumentException
1023
-     * @throws InvalidDataTypeException
1024
-     * @throws InvalidInterfaceException
1025
-     * @throws ReflectionException
1026
-     */
1027
-    public function total_line_item($create_if_not_found = true)
1028
-    {
1029
-        $item = $this->get_first_related('Line_Item', array(array('LIN_type' => EEM_Line_Item::type_total)));
1030
-        if (! $item && $create_if_not_found) {
1031
-            $item = EEH_Line_Item::create_total_line_item($this);
1032
-        }
1033
-        return $item;
1034
-    }
1035
-
1036
-
1037
-    /**
1038
-     * Returns the total amount of tax on this transaction
1039
-     * (assumes there's only one tax subtotal line item)
1040
-     *
1041
-     * @return float
1042
-     * @throws EE_Error
1043
-     * @throws InvalidArgumentException
1044
-     * @throws InvalidDataTypeException
1045
-     * @throws InvalidInterfaceException
1046
-     * @throws ReflectionException
1047
-     */
1048
-    public function tax_total()
1049
-    {
1050
-        $tax_line_item = $this->tax_total_line_item();
1051
-        if ($tax_line_item) {
1052
-            return (float) $tax_line_item->total();
1053
-        }
1054
-        return (float) 0;
1055
-    }
1056
-
1057
-
1058
-    /**
1059
-     * Gets the tax subtotal line item (assumes there's only one)
1060
-     *
1061
-     * @return EE_Line_Item
1062
-     * @throws EE_Error
1063
-     * @throws InvalidArgumentException
1064
-     * @throws InvalidDataTypeException
1065
-     * @throws InvalidInterfaceException
1066
-     * @throws ReflectionException
1067
-     */
1068
-    public function tax_total_line_item()
1069
-    {
1070
-        return EEH_Line_Item::get_taxes_subtotal($this->total_line_item());
1071
-    }
1072
-
1073
-
1074
-    /**
1075
-     * Gets the array of billing info for the gateway and for this transaction's primary registration's attendee.
1076
-     *
1077
-     * @return EE_Form_Section_Proper
1078
-     * @throws EE_Error
1079
-     * @throws InvalidArgumentException
1080
-     * @throws InvalidDataTypeException
1081
-     * @throws InvalidInterfaceException
1082
-     * @throws ReflectionException
1083
-     */
1084
-    public function billing_info()
1085
-    {
1086
-        $payment_method = $this->payment_method();
1087
-        if (! $payment_method) {
1088
-            EE_Error::add_error(
1089
-                esc_html__(
1090
-                    'Could not find billing info for transaction because no gateway has been used for it yet',
1091
-                    'event_espresso'
1092
-                ),
1093
-                __FILE__,
1094
-                __FUNCTION__,
1095
-                __LINE__
1096
-            );
1097
-            return null;
1098
-        }
1099
-        $primary_reg = $this->primary_registration();
1100
-        if (! $primary_reg) {
1101
-            EE_Error::add_error(
1102
-                esc_html__(
1103
-                    'Cannot get billing info for gateway %s on transaction because no primary registration exists',
1104
-                    'event_espresso'
1105
-                ),
1106
-                __FILE__,
1107
-                __FUNCTION__,
1108
-                __LINE__
1109
-            );
1110
-            return null;
1111
-        }
1112
-        $attendee = $primary_reg->attendee();
1113
-        if (! $attendee) {
1114
-            EE_Error::add_error(
1115
-                esc_html__(
1116
-                    'Cannot get billing info for gateway %s on transaction because the primary registration has no attendee exists',
1117
-                    'event_espresso'
1118
-                ),
1119
-                __FILE__,
1120
-                __FUNCTION__,
1121
-                __LINE__
1122
-            );
1123
-            return null;
1124
-        }
1125
-        return $attendee->billing_info_for_payment_method($payment_method);
1126
-    }
1127
-
1128
-
1129
-    /**
1130
-     * Gets PMD_ID
1131
-     *
1132
-     * @return int
1133
-     * @throws EE_Error
1134
-     * @throws InvalidArgumentException
1135
-     * @throws InvalidDataTypeException
1136
-     * @throws InvalidInterfaceException
1137
-     * @throws ReflectionException
1138
-     */
1139
-    public function payment_method_ID()
1140
-    {
1141
-        return $this->get('PMD_ID');
1142
-    }
1143
-
1144
-
1145
-    /**
1146
-     * Sets PMD_ID
1147
-     *
1148
-     * @param int $PMD_ID
1149
-     * @throws EE_Error
1150
-     * @throws InvalidArgumentException
1151
-     * @throws InvalidDataTypeException
1152
-     * @throws InvalidInterfaceException
1153
-     * @throws ReflectionException
1154
-     */
1155
-    public function set_payment_method_ID($PMD_ID)
1156
-    {
1157
-        $this->set('PMD_ID', $PMD_ID);
1158
-    }
1159
-
1160
-
1161
-    /**
1162
-     * Gets the last-used payment method on this transaction
1163
-     * (we COULD just use the last-made payment, but some payment methods, namely
1164
-     * offline ones, dont' create payments)
1165
-     *
1166
-     * @return EE_Payment_Method
1167
-     * @throws EE_Error
1168
-     * @throws InvalidArgumentException
1169
-     * @throws InvalidDataTypeException
1170
-     * @throws InvalidInterfaceException
1171
-     * @throws ReflectionException
1172
-     */
1173
-    public function payment_method()
1174
-    {
1175
-        $pm = $this->get_first_related('Payment_Method');
1176
-        if ($pm instanceof EE_Payment_Method) {
1177
-            return $pm;
1178
-        }
1179
-        $last_payment = $this->last_payment();
1180
-        if ($last_payment instanceof EE_Payment && $last_payment->payment_method()) {
1181
-            return $last_payment->payment_method();
1182
-        }
1183
-        return null;
1184
-    }
1185
-
1186
-
1187
-    /**
1188
-     * Gets the last payment made
1189
-     *
1190
-     * @return EE_Base_Class|EE_Payment
1191
-     * @throws EE_Error
1192
-     * @throws InvalidArgumentException
1193
-     * @throws InvalidDataTypeException
1194
-     * @throws InvalidInterfaceException
1195
-     * @throws ReflectionException
1196
-     */
1197
-    public function last_payment()
1198
-    {
1199
-        return $this->get_first_related('Payment', array('order_by' => array('PAY_ID' => 'desc')));
1200
-    }
1201
-
1202
-
1203
-    /**
1204
-     * Gets all the line items which are unrelated to tickets on this transaction
1205
-     *
1206
-     * @return EE_Line_Item[]
1207
-     * @throws EE_Error
1208
-     * @throws InvalidArgumentException
1209
-     * @throws InvalidDataTypeException
1210
-     * @throws InvalidInterfaceException
1211
-     * @throws ReflectionException
1212
-     */
1213
-    public function non_ticket_line_items()
1214
-    {
1215
-        return EEM_Line_Item::instance()->get_all_non_ticket_line_items_for_transaction($this->ID());
1216
-    }
1217
-
1218
-
1219
-    /**
1220
-     * possibly toggles TXN status
1221
-     *
1222
-     * @param  boolean $update whether to save the TXN
1223
-     * @return bool whether the TXN was saved
1224
-     * @throws EE_Error
1225
-     * @throws InvalidArgumentException
1226
-     * @throws InvalidDataTypeException
1227
-     * @throws InvalidInterfaceException
1228
-     * @throws ReflectionException
1229
-     * @throws RuntimeException
1230
-     */
1231
-    public function update_status_based_on_total_paid($update = true)
1232
-    {
1233
-        // set transaction status based on comparison of TXN_paid vs TXN_total
1234
-        if (EEH_Money::compare_floats($this->paid(), $this->total(), '>')) {
1235
-            $new_txn_status = EEM_Transaction::overpaid_status_code;
1236
-        } elseif (EEH_Money::compare_floats($this->paid(), $this->total())) {
1237
-            $new_txn_status = EEM_Transaction::complete_status_code;
1238
-        } elseif (EEH_Money::compare_floats($this->paid(), $this->total(), '<')) {
1239
-            $new_txn_status = EEM_Transaction::incomplete_status_code;
1240
-        } else {
1241
-            throw new RuntimeException(
1242
-                esc_html__('The total paid calculation for this transaction is inaccurate.', 'event_espresso')
1243
-            );
1244
-        }
1245
-        if ($new_txn_status !== $this->status_ID()) {
1246
-            $this->set_status($new_txn_status);
1247
-            if ($update) {
1248
-                return $this->save() ? true : false;
1249
-            }
1250
-        }
1251
-        return false;
1252
-    }
1253
-
1254
-
1255
-    /**
1256
-     * Updates the transaction's status and total_paid based on all the payments
1257
-     * that apply to it
1258
-     *
1259
-     * @deprecated
1260
-     * @return array|bool
1261
-     * @throws EE_Error
1262
-     * @throws InvalidArgumentException
1263
-     * @throws ReflectionException
1264
-     * @throws InvalidDataTypeException
1265
-     * @throws InvalidInterfaceException
1266
-     */
1267
-    public function update_based_on_payments()
1268
-    {
1269
-        EE_Error::doing_it_wrong(
1270
-            __CLASS__ . '::' . __FUNCTION__,
1271
-            sprintf(
1272
-                esc_html__('This method is deprecated. Please use "%s" instead', 'event_espresso'),
1273
-                'EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()'
1274
-            ),
1275
-            '4.6.0'
1276
-        );
1277
-        /** @type EE_Transaction_Processor $transaction_processor */
1278
-        $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
1279
-        return $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment($this);
1280
-    }
1281
-
1282
-
1283
-    /**
1284
-     * @return string
1285
-     */
1286
-    public function old_txn_status()
1287
-    {
1288
-        return $this->_old_txn_status;
1289
-    }
1290
-
1291
-
1292
-    /**
1293
-     * @param string $old_txn_status
1294
-     */
1295
-    public function set_old_txn_status($old_txn_status)
1296
-    {
1297
-        // only set the first time
1298
-        if ($this->_old_txn_status === null) {
1299
-            $this->_old_txn_status = $old_txn_status;
1300
-        }
1301
-    }
1302
-
1303
-
1304
-    /**
1305
-     * reg_status_updated
1306
-     *
1307
-     * @return bool
1308
-     * @throws EE_Error
1309
-     * @throws InvalidArgumentException
1310
-     * @throws InvalidDataTypeException
1311
-     * @throws InvalidInterfaceException
1312
-     * @throws ReflectionException
1313
-     */
1314
-    public function txn_status_updated()
1315
-    {
1316
-        return $this->status_ID() !== $this->_old_txn_status && $this->_old_txn_status !== null;
1317
-    }
1318
-
1319
-
1320
-    /**
1321
-     * _reg_steps_completed
1322
-     * if $check_all is TRUE, then returns TRUE if ALL reg steps have been marked as completed,
1323
-     * if a $reg_step_slug is provided, then this step will be skipped when testing for completion
1324
-     * if $check_all is FALSE and a $reg_step_slug is provided, then ONLY that reg step will be tested for completion
1325
-     *
1326
-     * @param string $reg_step_slug
1327
-     * @param bool   $check_all
1328
-     * @return bool|int
1329
-     * @throws EE_Error
1330
-     * @throws InvalidArgumentException
1331
-     * @throws InvalidDataTypeException
1332
-     * @throws InvalidInterfaceException
1333
-     * @throws ReflectionException
1334
-     */
1335
-    private function _reg_steps_completed($reg_step_slug = '', $check_all = true)
1336
-    {
1337
-        $reg_steps = $this->reg_steps();
1338
-        if (! is_array($reg_steps) || empty($reg_steps)) {
1339
-            return false;
1340
-        }
1341
-        // loop thru reg steps array)
1342
-        foreach ($reg_steps as $slug => $reg_step_completed) {
1343
-            // if NOT checking ALL steps (only checking one step)
1344
-            if (! $check_all) {
1345
-                // and this is the one
1346
-                if ($slug === $reg_step_slug) {
1347
-                    return $reg_step_completed;
1348
-                }
1349
-                // skip to next reg step in loop
1350
-                continue;
1351
-            }
1352
-            // $check_all must be true, else we would never have gotten to this point
1353
-            if ($slug === $reg_step_slug) {
1354
-                // if we reach this point, then we are testing either:
1355
-                // all_reg_steps_completed_except() or
1356
-                // all_reg_steps_completed_except_final_step(),
1357
-                // and since this is the reg step EXCEPTION being tested
1358
-                // we want to return true (yes true) if this reg step is NOT completed
1359
-                // ie: "is everything completed except the final step?"
1360
-                // "that is correct... the final step is not completed, but all others are."
1361
-                return $reg_step_completed !== true;
1362
-            }
1363
-            if ($reg_step_completed !== true) {
1364
-                // if any reg step is NOT completed, then ALL steps are not completed
1365
-                return false;
1366
-            }
1367
-        }
1368
-        return true;
1369
-    }
1370
-
1371
-
1372
-    /**
1373
-     * all_reg_steps_completed
1374
-     * returns:
1375
-     *    true if ALL reg steps have been marked as completed
1376
-     *        or false if any step is not completed
1377
-     *
1378
-     * @return bool
1379
-     * @throws EE_Error
1380
-     * @throws InvalidArgumentException
1381
-     * @throws InvalidDataTypeException
1382
-     * @throws InvalidInterfaceException
1383
-     * @throws ReflectionException
1384
-     */
1385
-    public function all_reg_steps_completed()
1386
-    {
1387
-        return $this->_reg_steps_completed();
1388
-    }
1389
-
1390
-
1391
-    /**
1392
-     * all_reg_steps_completed_except
1393
-     * returns:
1394
-     *        true if ALL reg steps, except a particular step that you wish to skip over, have been marked as completed
1395
-     *        or false if any other step is not completed
1396
-     *        or false if ALL steps are completed including the exception you are testing !!!
1397
-     *
1398
-     * @param string $exception
1399
-     * @return bool
1400
-     * @throws EE_Error
1401
-     * @throws InvalidArgumentException
1402
-     * @throws InvalidDataTypeException
1403
-     * @throws InvalidInterfaceException
1404
-     * @throws ReflectionException
1405
-     */
1406
-    public function all_reg_steps_completed_except($exception = '')
1407
-    {
1408
-        return $this->_reg_steps_completed($exception);
1409
-    }
1410
-
1411
-
1412
-    /**
1413
-     * all_reg_steps_completed_except
1414
-     * returns:
1415
-     *        true if ALL reg steps, except the final step, have been marked as completed
1416
-     *        or false if any step is not completed
1417
-     *    or false if ALL steps are completed including the final step !!!
1418
-     *
1419
-     * @return bool
1420
-     * @throws EE_Error
1421
-     * @throws InvalidArgumentException
1422
-     * @throws InvalidDataTypeException
1423
-     * @throws InvalidInterfaceException
1424
-     * @throws ReflectionException
1425
-     */
1426
-    public function all_reg_steps_completed_except_final_step()
1427
-    {
1428
-        return $this->_reg_steps_completed('finalize_registration');
1429
-    }
1430
-
1431
-
1432
-    /**
1433
-     * reg_step_completed
1434
-     * returns:
1435
-     *    true if a specific reg step has been marked as completed
1436
-     *    a Unix timestamp if it has been initialized but not yet completed,
1437
-     *    or false if it has not yet been initialized
1438
-     *
1439
-     * @param string $reg_step_slug
1440
-     * @return bool|int
1441
-     * @throws EE_Error
1442
-     * @throws InvalidArgumentException
1443
-     * @throws InvalidDataTypeException
1444
-     * @throws InvalidInterfaceException
1445
-     * @throws ReflectionException
1446
-     */
1447
-    public function reg_step_completed($reg_step_slug)
1448
-    {
1449
-        return $this->_reg_steps_completed($reg_step_slug, false);
1450
-    }
1451
-
1452
-
1453
-    /**
1454
-     * completed_final_reg_step
1455
-     * returns:
1456
-     *    true if the finalize_registration reg step has been marked as completed
1457
-     *    a Unix timestamp if it has been initialized but not yet completed,
1458
-     *    or false if it has not yet been initialized
1459
-     *
1460
-     * @return bool|int
1461
-     * @throws EE_Error
1462
-     * @throws InvalidArgumentException
1463
-     * @throws InvalidDataTypeException
1464
-     * @throws InvalidInterfaceException
1465
-     * @throws ReflectionException
1466
-     */
1467
-    public function final_reg_step_completed()
1468
-    {
1469
-        return $this->_reg_steps_completed('finalize_registration', false);
1470
-    }
1471
-
1472
-
1473
-    /**
1474
-     * set_reg_step_initiated
1475
-     * given a valid TXN_reg_step, this sets it's value to a unix timestamp
1476
-     *
1477
-     * @param string $reg_step_slug
1478
-     * @return boolean
1479
-     * @throws EE_Error
1480
-     * @throws InvalidArgumentException
1481
-     * @throws InvalidDataTypeException
1482
-     * @throws InvalidInterfaceException
1483
-     * @throws ReflectionException
1484
-     */
1485
-    public function set_reg_step_initiated($reg_step_slug)
1486
-    {
1487
-        return $this->_set_reg_step_completed_status($reg_step_slug, time());
1488
-    }
1489
-
1490
-
1491
-    /**
1492
-     * set_reg_step_completed
1493
-     * given a valid TXN_reg_step, this sets the step as completed
1494
-     *
1495
-     * @param string $reg_step_slug
1496
-     * @return boolean
1497
-     * @throws EE_Error
1498
-     * @throws InvalidArgumentException
1499
-     * @throws InvalidDataTypeException
1500
-     * @throws InvalidInterfaceException
1501
-     * @throws ReflectionException
1502
-     */
1503
-    public function set_reg_step_completed($reg_step_slug)
1504
-    {
1505
-        return $this->_set_reg_step_completed_status($reg_step_slug, true);
1506
-    }
1507
-
1508
-
1509
-    /**
1510
-     * set_reg_step_completed
1511
-     * given a valid TXN_reg_step slug, this sets the step as NOT completed
1512
-     *
1513
-     * @param string $reg_step_slug
1514
-     * @return boolean
1515
-     * @throws EE_Error
1516
-     * @throws InvalidArgumentException
1517
-     * @throws InvalidDataTypeException
1518
-     * @throws InvalidInterfaceException
1519
-     * @throws ReflectionException
1520
-     */
1521
-    public function set_reg_step_not_completed($reg_step_slug)
1522
-    {
1523
-        return $this->_set_reg_step_completed_status($reg_step_slug, false);
1524
-    }
1525
-
1526
-
1527
-    /**
1528
-     * set_reg_step_completed
1529
-     * given a valid reg step slug, this sets the TXN_reg_step completed status which is either:
1530
-     *
1531
-     * @param  string      $reg_step_slug
1532
-     * @param  boolean|int $status
1533
-     * @return boolean
1534
-     * @throws EE_Error
1535
-     * @throws InvalidArgumentException
1536
-     * @throws InvalidDataTypeException
1537
-     * @throws InvalidInterfaceException
1538
-     * @throws ReflectionException
1539
-     */
1540
-    private function _set_reg_step_completed_status($reg_step_slug, $status)
1541
-    {
1542
-        // validate status
1543
-        $status = is_bool($status) || is_int($status) ? $status : false;
1544
-        // get reg steps array
1545
-        $txn_reg_steps = $this->reg_steps();
1546
-        // if reg step does NOT exist
1547
-        if (! isset($txn_reg_steps[ $reg_step_slug ])) {
1548
-            return false;
1549
-        }
1550
-        // if  we're trying to complete a step that is already completed
1551
-        if ($txn_reg_steps[ $reg_step_slug ] === true) {
1552
-            return true;
1553
-        }
1554
-        // if  we're trying to complete a step that hasn't even started
1555
-        if ($status === true && $txn_reg_steps[ $reg_step_slug ] === false) {
1556
-            return false;
1557
-        }
1558
-        // if current status value matches the incoming value (no change)
1559
-        // type casting as int means values should collapse to either 0, 1, or a timestamp like 1234567890
1560
-        if ((int) $txn_reg_steps[ $reg_step_slug ] === (int) $status) {
1561
-            // this will happen in cases where multiple AJAX requests occur during the same step
1562
-            return true;
1563
-        }
1564
-        // if we're trying to set a start time, but it has already been set...
1565
-        if (is_numeric($status) && is_numeric($txn_reg_steps[ $reg_step_slug ])) {
1566
-            // skip the update below, but don't return FALSE so that errors won't be displayed
1567
-            return true;
1568
-        }
1569
-        // update completed status
1570
-        $txn_reg_steps[ $reg_step_slug ] = $status;
1571
-        $this->set_reg_steps($txn_reg_steps);
1572
-        $this->save();
1573
-        return true;
1574
-    }
1575
-
1576
-
1577
-    /**
1578
-     * remove_reg_step
1579
-     * given a valid TXN_reg_step slug, this will remove (unset)
1580
-     * the reg step from the TXN reg step array
1581
-     *
1582
-     * @param string $reg_step_slug
1583
-     * @return void
1584
-     * @throws EE_Error
1585
-     * @throws InvalidArgumentException
1586
-     * @throws InvalidDataTypeException
1587
-     * @throws InvalidInterfaceException
1588
-     * @throws ReflectionException
1589
-     */
1590
-    public function remove_reg_step($reg_step_slug)
1591
-    {
1592
-        // get reg steps array
1593
-        $txn_reg_steps = $this->reg_steps();
1594
-        unset($txn_reg_steps[ $reg_step_slug ]);
1595
-        $this->set_reg_steps($txn_reg_steps);
1596
-    }
1597
-
1598
-
1599
-    /**
1600
-     * toggle_failed_transaction_status
1601
-     * upgrades a TXNs status from failed to abandoned,
1602
-     * meaning that contact information has been captured for at least one registrant
1603
-     *
1604
-     * @param bool $save
1605
-     * @return bool
1606
-     * @throws EE_Error
1607
-     * @throws InvalidArgumentException
1608
-     * @throws InvalidDataTypeException
1609
-     * @throws InvalidInterfaceException
1610
-     * @throws ReflectionException
1611
-     */
1612
-    public function toggle_failed_transaction_status($save = true)
1613
-    {
1614
-        // if TXN status is still set as "failed"...
1615
-        if ($this->status_ID() === EEM_Transaction::failed_status_code) {
1616
-            $this->set_status(EEM_Transaction::abandoned_status_code);
1617
-            if ($save) {
1618
-                $this->save();
1619
-            }
1620
-            return true;
1621
-        }
1622
-        return false;
1623
-    }
1624
-
1625
-
1626
-    /**
1627
-     * toggle_abandoned_transaction_status
1628
-     * upgrades a TXNs status from failed or abandoned to incomplete
1629
-     *
1630
-     * @return bool
1631
-     * @throws EE_Error
1632
-     * @throws InvalidArgumentException
1633
-     * @throws InvalidDataTypeException
1634
-     * @throws InvalidInterfaceException
1635
-     * @throws ReflectionException
1636
-     */
1637
-    public function toggle_abandoned_transaction_status()
1638
-    {
1639
-        // if TXN status has not been updated already due to a payment, and is still set as "failed" or "abandoned"...
1640
-        $txn_status = $this->status_ID();
1641
-        if (
1642
-            $txn_status === EEM_Transaction::failed_status_code
1643
-            || $txn_status === EEM_Transaction::abandoned_status_code
1644
-        ) {
1645
-            // if a contact record for the primary registrant has been created
1646
-            if (
1647
-                $this->primary_registration() instanceof EE_Registration
1648
-                && $this->primary_registration()->attendee() instanceof EE_Attendee
1649
-            ) {
1650
-                $this->set_status(EEM_Transaction::incomplete_status_code);
1651
-            } else {
1652
-                // no contact record? yer abandoned!
1653
-                $this->set_status(EEM_Transaction::abandoned_status_code);
1654
-            }
1655
-            return true;
1656
-        }
1657
-        return false;
1658
-    }
1659
-
1660
-
1661
-    /**
1662
-     * checks if an Abandoned TXN has any related payments, and if so,
1663
-     * updates the TXN status based on the amount paid
1664
-     *
1665
-     * @throws EE_Error
1666
-     * @throws InvalidArgumentException
1667
-     * @throws InvalidDataTypeException
1668
-     * @throws InvalidInterfaceException
1669
-     * @throws ReflectionException
1670
-     * @throws RuntimeException
1671
-     * @throws ReflectionException
1672
-     */
1673
-    public function verify_abandoned_transaction_status()
1674
-    {
1675
-        if ($this->status_ID() !== EEM_Transaction::abandoned_status_code) {
1676
-            return;
1677
-        }
1678
-        $payments = $this->get_many_related('Payment');
1679
-        if (! empty($payments)) {
1680
-            foreach ($payments as $payment) {
1681
-                if ($payment instanceof EE_Payment) {
1682
-                    // kk this TXN should NOT be abandoned
1683
-                    $this->update_status_based_on_total_paid();
1684
-                    if (! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) {
1685
-                        EE_Error::add_attention(
1686
-                            sprintf(
1687
-                                esc_html__(
1688
-                                    'The status for Transaction #%1$d has been updated from "Abandoned" to "%2$s", because at least one payment has been made towards it. If the payment appears in the "Payment Details" table below, you may need to edit its status and/or other details as well.',
1689
-                                    'event_espresso'
1690
-                                ),
1691
-                                $this->ID(),
1692
-                                $this->pretty_status()
1693
-                            )
1694
-                        );
1695
-                    }
1696
-                    // get final reg step status
1697
-                    $finalized = $this->final_reg_step_completed();
1698
-                    // if the 'finalize_registration' step has been initiated (has a timestamp)
1699
-                    // but has not yet been fully completed (TRUE)
1700
-                    if (is_int($finalized) && $finalized !== false && $finalized !== true) {
1701
-                        $this->set_reg_step_completed('finalize_registration');
1702
-                        $this->save();
1703
-                    }
1704
-                }
1705
-            }
1706
-        }
1707
-    }
1708
-
1709
-
1710
-    /**
1711
-     * @since 4.10.4.p
1712
-     * @throws EE_Error
1713
-     * @throws InvalidArgumentException
1714
-     * @throws InvalidDataTypeException
1715
-     * @throws InvalidInterfaceException
1716
-     * @throws ReflectionException
1717
-     * @throws RuntimeException
1718
-     */
1719
-    public function recalculateLineItems()
1720
-    {
1721
-        $total_line_item = $this->total_line_item(false);
1722
-        if ($total_line_item instanceof EE_Line_Item) {
1723
-            EEH_Line_Item::resetIsTaxableForTickets($total_line_item);
1724
-            return EEH_Line_Item::apply_taxes($total_line_item, true);
1725
-        }
1726
-        return false;
1727
-	}
1728
-
1729
-
1730
-    /**
1731
-     * @param string $source function name that called this method
1732
-     * @return boolean | int
1733
-     */
1734
-    public function delete($source = 'unknown')
1735
-    {
1736
-        $current_user = wp_get_current_user();
1737
-        $this->add_extra_meta(
1738
-            EE_Transaction::EXTRA_META_KEY_TXN_DELETED,
1739
-            array(
1740
-                'deleted-by' => $current_user->ID ? $current_user->display_name : 'unauthed user',
1741
-                'timestamp'  => time(),
1742
-                'source'     => $source,
1743
-            )
1744
-        );
1745
-        return parent::delete();
1746
-    }
17
+	/**
18
+	 * The length of time in seconds that a lock is applied before being considered expired.
19
+	 * It is not long because a transaction should only be locked for the duration of the request that locked it
20
+	 */
21
+	const LOCK_EXPIRATION = 2;
22
+
23
+	/**
24
+	 * extra meta key for tracking when transactions are deleted and by who
25
+	 *
26
+	 * @type string
27
+	 */
28
+	const EXTRA_META_KEY_TXN_DELETED = 'transaction-deleted';
29
+
30
+	/**
31
+	 * txn status upon initial construction.
32
+	 *
33
+	 * @var string
34
+	 */
35
+	protected $_old_txn_status;
36
+
37
+
38
+	/**
39
+	 * @param array  $props_n_values          incoming values
40
+	 * @param string $timezone                incoming timezone
41
+	 *                                        (if not set the timezone set for the website will be used.)
42
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
43
+	 *                                        date_format and the second value is the time format
44
+	 * @return EE_Transaction
45
+	 * @throws EE_Error
46
+	 * @throws InvalidArgumentException
47
+	 * @throws InvalidDataTypeException
48
+	 * @throws InvalidInterfaceException
49
+	 * @throws ReflectionException
50
+	 */
51
+	public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
52
+	{
53
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
54
+		$txn = $has_object
55
+			? $has_object
56
+			: new self($props_n_values, false, $timezone, $date_formats);
57
+		if (! $has_object) {
58
+			$txn->set_old_txn_status($txn->status_ID());
59
+		}
60
+		return $txn;
61
+	}
62
+
63
+
64
+	/**
65
+	 * @param array  $props_n_values  incoming values from the database
66
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
67
+	 *                                the website will be used.
68
+	 * @return EE_Transaction
69
+	 * @throws EE_Error
70
+	 * @throws InvalidArgumentException
71
+	 * @throws InvalidDataTypeException
72
+	 * @throws InvalidInterfaceException
73
+	 * @throws ReflectionException
74
+	 */
75
+	public static function new_instance_from_db($props_n_values = array(), $timezone = null)
76
+	{
77
+		$txn = new self($props_n_values, true, $timezone);
78
+		$txn->set_old_txn_status($txn->status_ID());
79
+		return $txn;
80
+	}
81
+
82
+
83
+	/**
84
+	 * Sets a meta field indicating that this TXN is locked and should not be updated in the db.
85
+	 * If a lock has already been set, then we will attempt to remove it in case it has expired.
86
+	 * If that also fails, then an exception is thrown.
87
+	 *
88
+	 * @throws EE_Error
89
+	 * @throws InvalidArgumentException
90
+	 * @throws InvalidDataTypeException
91
+	 * @throws InvalidInterfaceException
92
+	 * @throws ReflectionException
93
+	 */
94
+	public function lock()
95
+	{
96
+		// attempt to set lock, but if that fails...
97
+		if (! $this->add_extra_meta('lock', time(), true)) {
98
+			// then attempt to remove the lock in case it is expired
99
+			if ($this->_remove_expired_lock()) {
100
+				// if removal was successful, then try setting lock again
101
+				$this->lock();
102
+			} else {
103
+				// but if the lock can not be removed, then throw an exception
104
+				throw new EE_Error(
105
+					sprintf(
106
+						esc_html__(
107
+							'Could not lock Transaction %1$d because it is already locked, meaning another part of the system is currently editing it. It should already be unlocked by the time you read this, so please refresh the page and try again.',
108
+							'event_espresso'
109
+						),
110
+						$this->ID()
111
+					)
112
+				);
113
+			}
114
+		}
115
+	}
116
+
117
+
118
+	/**
119
+	 * removes transaction lock applied in EE_Transaction::lock()
120
+	 *
121
+	 * @return int
122
+	 * @throws EE_Error
123
+	 * @throws InvalidArgumentException
124
+	 * @throws InvalidDataTypeException
125
+	 * @throws InvalidInterfaceException
126
+	 * @throws ReflectionException
127
+	 */
128
+	public function unlock()
129
+	{
130
+		return $this->delete_extra_meta('lock');
131
+	}
132
+
133
+
134
+	/**
135
+	 * Decides whether or not now is the right time to update the transaction.
136
+	 * This is useful because we don't always know if it is safe to update the transaction
137
+	 * and its related data. why?
138
+	 * because it's possible that the transaction is being used in another
139
+	 * request and could overwrite anything we save.
140
+	 * So we want to only update the txn once we know that won't happen.
141
+	 * We also check that the lock isn't expired, and remove it if it is
142
+	 *
143
+	 * @return boolean
144
+	 * @throws EE_Error
145
+	 * @throws InvalidArgumentException
146
+	 * @throws InvalidDataTypeException
147
+	 * @throws InvalidInterfaceException
148
+	 * @throws ReflectionException
149
+	 */
150
+	public function is_locked()
151
+	{
152
+		// if TXN is not locked, then return false immediately
153
+		if (! $this->_get_lock()) {
154
+			return false;
155
+		}
156
+		// if not, then let's try and remove the lock in case it's expired...
157
+		// _remove_expired_lock() returns 0 when lock is valid (ie: removed = false)
158
+		// and a positive number if the lock was removed (ie: number of locks deleted),
159
+		// so we need to return the opposite
160
+		return ! $this->_remove_expired_lock() ? true : false;
161
+	}
162
+
163
+
164
+	/**
165
+	 * Gets the meta field indicating that this TXN is locked
166
+	 *
167
+	 * @return int
168
+	 * @throws EE_Error
169
+	 * @throws InvalidArgumentException
170
+	 * @throws InvalidDataTypeException
171
+	 * @throws InvalidInterfaceException
172
+	 * @throws ReflectionException
173
+	 */
174
+	protected function _get_lock()
175
+	{
176
+		return (int) $this->get_extra_meta('lock', true, 0);
177
+	}
178
+
179
+
180
+	/**
181
+	 * If the lock on this transaction is expired, then we want to remove it so that the transaction can be updated
182
+	 *
183
+	 * @return int
184
+	 * @throws EE_Error
185
+	 * @throws InvalidArgumentException
186
+	 * @throws InvalidDataTypeException
187
+	 * @throws InvalidInterfaceException
188
+	 * @throws ReflectionException
189
+	 */
190
+	protected function _remove_expired_lock()
191
+	{
192
+		$locked = $this->_get_lock();
193
+		if ($locked && time() - EE_Transaction::LOCK_EXPIRATION > $locked) {
194
+			return $this->unlock();
195
+		}
196
+		return 0;
197
+	}
198
+
199
+
200
+	/**
201
+	 * Set transaction total
202
+	 *
203
+	 * @param float $total total value of transaction
204
+	 * @throws EE_Error
205
+	 * @throws InvalidArgumentException
206
+	 * @throws InvalidDataTypeException
207
+	 * @throws InvalidInterfaceException
208
+	 * @throws ReflectionException
209
+	 */
210
+	public function set_total($total = 0.00)
211
+	{
212
+		$this->set('TXN_total', (float) $total);
213
+	}
214
+
215
+
216
+	/**
217
+	 * Set Total Amount Paid to Date
218
+	 *
219
+	 * @param float $total_paid total amount paid to date (sum of all payments)
220
+	 * @throws EE_Error
221
+	 * @throws InvalidArgumentException
222
+	 * @throws InvalidDataTypeException
223
+	 * @throws InvalidInterfaceException
224
+	 * @throws ReflectionException
225
+	 */
226
+	public function set_paid($total_paid = 0.00)
227
+	{
228
+		$this->set('TXN_paid', (float) $total_paid);
229
+	}
230
+
231
+
232
+	/**
233
+	 * Set transaction status
234
+	 *
235
+	 * @param string $status        whether the transaction is open, declined, accepted,
236
+	 *                              or any number of custom values that can be set
237
+	 * @throws EE_Error
238
+	 * @throws InvalidArgumentException
239
+	 * @throws InvalidDataTypeException
240
+	 * @throws InvalidInterfaceException
241
+	 * @throws ReflectionException
242
+	 */
243
+	public function set_status($status = '')
244
+	{
245
+		$this->set('STS_ID', $status);
246
+	}
247
+
248
+
249
+	/**
250
+	 * Set hash salt
251
+	 *
252
+	 * @param string $hash_salt required for some payment gateways
253
+	 * @throws EE_Error
254
+	 * @throws InvalidArgumentException
255
+	 * @throws InvalidDataTypeException
256
+	 * @throws InvalidInterfaceException
257
+	 * @throws ReflectionException
258
+	 */
259
+	public function set_hash_salt($hash_salt = '')
260
+	{
261
+		$this->set('TXN_hash_salt', $hash_salt);
262
+	}
263
+
264
+
265
+	/**
266
+	 * Sets TXN_reg_steps array
267
+	 *
268
+	 * @param array $txn_reg_steps
269
+	 * @throws EE_Error
270
+	 * @throws InvalidArgumentException
271
+	 * @throws InvalidDataTypeException
272
+	 * @throws InvalidInterfaceException
273
+	 * @throws ReflectionException
274
+	 */
275
+	public function set_reg_steps(array $txn_reg_steps)
276
+	{
277
+		$this->set('TXN_reg_steps', $txn_reg_steps);
278
+	}
279
+
280
+
281
+	/**
282
+	 * Gets TXN_reg_steps
283
+	 *
284
+	 * @return array
285
+	 * @throws EE_Error
286
+	 * @throws InvalidArgumentException
287
+	 * @throws InvalidDataTypeException
288
+	 * @throws InvalidInterfaceException
289
+	 * @throws ReflectionException
290
+	 */
291
+	public function reg_steps()
292
+	{
293
+		$TXN_reg_steps = $this->get('TXN_reg_steps');
294
+		return is_array($TXN_reg_steps) ? (array) $TXN_reg_steps : array();
295
+	}
296
+
297
+
298
+	/**
299
+	 * @return string of transaction's total cost, with currency symbol and decimal
300
+	 * @throws EE_Error
301
+	 * @throws InvalidArgumentException
302
+	 * @throws InvalidDataTypeException
303
+	 * @throws InvalidInterfaceException
304
+	 * @throws ReflectionException
305
+	 */
306
+	public function pretty_total()
307
+	{
308
+		return $this->get_pretty('TXN_total');
309
+	}
310
+
311
+
312
+	/**
313
+	 * Gets the amount paid in a pretty string (formatted and with currency symbol)
314
+	 *
315
+	 * @return string
316
+	 * @throws EE_Error
317
+	 * @throws InvalidArgumentException
318
+	 * @throws InvalidDataTypeException
319
+	 * @throws InvalidInterfaceException
320
+	 * @throws ReflectionException
321
+	 */
322
+	public function pretty_paid()
323
+	{
324
+		return $this->get_pretty('TXN_paid');
325
+	}
326
+
327
+
328
+	/**
329
+	 * calculate the amount remaining for this transaction and return;
330
+	 *
331
+	 * @return float amount remaining
332
+	 * @throws EE_Error
333
+	 * @throws InvalidArgumentException
334
+	 * @throws InvalidDataTypeException
335
+	 * @throws InvalidInterfaceException
336
+	 * @throws ReflectionException
337
+	 */
338
+	public function remaining()
339
+	{
340
+		return $this->total() - $this->paid();
341
+	}
342
+
343
+
344
+	/**
345
+	 * get Transaction Total
346
+	 *
347
+	 * @return float
348
+	 * @throws EE_Error
349
+	 * @throws InvalidArgumentException
350
+	 * @throws InvalidDataTypeException
351
+	 * @throws InvalidInterfaceException
352
+	 * @throws ReflectionException
353
+	 */
354
+	public function total()
355
+	{
356
+		return (float) $this->get('TXN_total');
357
+	}
358
+
359
+
360
+	/**
361
+	 * get Total Amount Paid to Date
362
+	 *
363
+	 * @return float
364
+	 * @throws EE_Error
365
+	 * @throws InvalidArgumentException
366
+	 * @throws InvalidDataTypeException
367
+	 * @throws InvalidInterfaceException
368
+	 * @throws ReflectionException
369
+	 */
370
+	public function paid()
371
+	{
372
+		return (float) $this->get('TXN_paid');
373
+	}
374
+
375
+
376
+	/**
377
+	 * @return mixed|null
378
+	 * @throws EE_Error
379
+	 * @throws InvalidArgumentException
380
+	 * @throws InvalidDataTypeException
381
+	 * @throws InvalidInterfaceException
382
+	 * @throws ReflectionException
383
+	 */
384
+	public function get_cart_session()
385
+	{
386
+		$session_data = (array) $this->get('TXN_session_data');
387
+		return isset($session_data['cart']) && $session_data['cart'] instanceof EE_Cart
388
+			? $session_data['cart']
389
+			: null;
390
+	}
391
+
392
+
393
+	/**
394
+	 * get Transaction session data
395
+	 *
396
+	 * @return array|mixed
397
+	 * @throws EE_Error
398
+	 * @throws InvalidArgumentException
399
+	 * @throws InvalidDataTypeException
400
+	 * @throws InvalidInterfaceException
401
+	 * @throws ReflectionException
402
+	 */
403
+	public function session_data()
404
+	{
405
+		$session_data = $this->get('TXN_session_data');
406
+		if (empty($session_data)) {
407
+			$session_data = array(
408
+				'id'            => null,
409
+				'user_id'       => null,
410
+				'ip_address'    => null,
411
+				'user_agent'    => null,
412
+				'init_access'   => null,
413
+				'last_access'   => null,
414
+				'pages_visited' => array(),
415
+			);
416
+		}
417
+		return $session_data;
418
+	}
419
+
420
+
421
+	/**
422
+	 * Set session data within the TXN object
423
+	 *
424
+	 * @param EE_Session|array $session_data
425
+	 * @throws EE_Error
426
+	 * @throws InvalidArgumentException
427
+	 * @throws InvalidDataTypeException
428
+	 * @throws InvalidInterfaceException
429
+	 * @throws ReflectionException
430
+	 */
431
+	public function set_txn_session_data($session_data)
432
+	{
433
+		if ($session_data instanceof EE_Session) {
434
+			$this->set('TXN_session_data', $session_data->get_session_data(null, true));
435
+		} else {
436
+			$this->set('TXN_session_data', $session_data);
437
+		}
438
+	}
439
+
440
+
441
+	/**
442
+	 * get Transaction hash salt
443
+	 *
444
+	 * @return mixed
445
+	 * @throws EE_Error
446
+	 * @throws InvalidArgumentException
447
+	 * @throws InvalidDataTypeException
448
+	 * @throws InvalidInterfaceException
449
+	 * @throws ReflectionException
450
+	 */
451
+	public function hash_salt_()
452
+	{
453
+		return $this->get('TXN_hash_salt');
454
+	}
455
+
456
+
457
+	/**
458
+	 * Returns the transaction datetime as either:
459
+	 *            - unix timestamp format ($format = false, $gmt = true)
460
+	 *            - formatted date string including the UTC (timezone) offset ($format = true ($gmt
461
+	 *              has no affect with this option)), this also may include a timezone abbreviation if the
462
+	 *              set timezone in this class differs from what the timezone is on the blog.
463
+	 *            - formatted date string including the UTC (timezone) offset (default).
464
+	 *
465
+	 * @param boolean $format   - whether to return a unix timestamp (default) or formatted date string
466
+	 * @param boolean $gmt      - whether to return a unix timestamp with UTC offset applied (default)
467
+	 *                          or no UTC offset applied
468
+	 * @return string | int
469
+	 * @throws EE_Error
470
+	 * @throws InvalidArgumentException
471
+	 * @throws InvalidDataTypeException
472
+	 * @throws InvalidInterfaceException
473
+	 * @throws ReflectionException
474
+	 */
475
+	public function datetime($format = false, $gmt = false)
476
+	{
477
+		if ($format) {
478
+			return $this->get_pretty('TXN_timestamp');
479
+		}
480
+		if ($gmt) {
481
+			return $this->get_raw('TXN_timestamp');
482
+		}
483
+		return $this->get('TXN_timestamp');
484
+	}
485
+
486
+
487
+	/**
488
+	 * Gets registrations on this transaction
489
+	 *
490
+	 * @param array   $query_params array of query parameters
491
+	 * @param boolean $get_cached   TRUE to retrieve cached registrations or FALSE to pull from the db
492
+	 * @return EE_Base_Class[]|EE_Registration[]
493
+	 * @throws EE_Error
494
+	 * @throws InvalidArgumentException
495
+	 * @throws InvalidDataTypeException
496
+	 * @throws InvalidInterfaceException
497
+	 * @throws ReflectionException
498
+	 */
499
+	public function registrations($query_params = array(), $get_cached = false)
500
+	{
501
+		$query_params = (empty($query_params) || ! is_array($query_params))
502
+			? array(
503
+				'order_by' => array(
504
+					'Event.EVT_name'     => 'ASC',
505
+					'Attendee.ATT_lname' => 'ASC',
506
+					'Attendee.ATT_fname' => 'ASC',
507
+				),
508
+			)
509
+			: $query_params;
510
+		$query_params = $get_cached ? array() : $query_params;
511
+		return $this->get_many_related('Registration', $query_params);
512
+	}
513
+
514
+
515
+	/**
516
+	 * Gets all the attendees for this transaction (handy for use with EE_Attendee's get_registrations_for_event
517
+	 * function for getting attendees and how many registrations they each have for an event)
518
+	 *
519
+	 * @return mixed EE_Attendee[] by default, int if $output is set to 'COUNT'
520
+	 * @throws EE_Error
521
+	 * @throws InvalidArgumentException
522
+	 * @throws InvalidDataTypeException
523
+	 * @throws InvalidInterfaceException
524
+	 * @throws ReflectionException
525
+	 */
526
+	public function attendees()
527
+	{
528
+		return $this->get_many_related('Attendee', array(array('Registration.Transaction.TXN_ID' => $this->ID())));
529
+	}
530
+
531
+
532
+	/**
533
+	 * Gets payments for this transaction. Unlike other such functions, order by 'DESC' by default
534
+	 *
535
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
536
+	 * @return EE_Base_Class[]|EE_Payment[]
537
+	 * @throws EE_Error
538
+	 * @throws InvalidArgumentException
539
+	 * @throws InvalidDataTypeException
540
+	 * @throws InvalidInterfaceException
541
+	 * @throws ReflectionException
542
+	 */
543
+	public function payments($query_params = array())
544
+	{
545
+		return $this->get_many_related('Payment', $query_params);
546
+	}
547
+
548
+
549
+	/**
550
+	 * gets only approved payments for this transaction
551
+	 *
552
+	 * @return EE_Base_Class[]|EE_Payment[]
553
+	 * @throws EE_Error
554
+	 * @throws InvalidArgumentException
555
+	 * @throws ReflectionException
556
+	 * @throws InvalidDataTypeException
557
+	 * @throws InvalidInterfaceException
558
+	 */
559
+	public function approved_payments()
560
+	{
561
+		EE_Registry::instance()->load_model('Payment');
562
+		return $this->get_many_related(
563
+			'Payment',
564
+			array(
565
+				array('STS_ID' => EEM_Payment::status_id_approved),
566
+				'order_by' => array('PAY_timestamp' => 'DESC'),
567
+			)
568
+		);
569
+	}
570
+
571
+
572
+	/**
573
+	 * Gets all payments which have not been approved
574
+	 *
575
+	 * @return EE_Base_Class[]|EEI_Payment[]
576
+	 * @throws EE_Error if a model is misconfigured somehow
577
+	 * @throws InvalidArgumentException
578
+	 * @throws InvalidDataTypeException
579
+	 * @throws InvalidInterfaceException
580
+	 * @throws ReflectionException
581
+	 */
582
+	public function pending_payments()
583
+	{
584
+		return $this->get_many_related(
585
+			'Payment',
586
+			array(
587
+				array(
588
+					'STS_ID' => EEM_Payment::status_id_pending,
589
+				),
590
+				'order_by' => array(
591
+					'PAY_timestamp' => 'DESC',
592
+				),
593
+			)
594
+		);
595
+	}
596
+
597
+
598
+	/**
599
+	 * echoes $this->pretty_status()
600
+	 *
601
+	 * @param bool $show_icons
602
+	 * @throws EE_Error
603
+	 * @throws InvalidArgumentException
604
+	 * @throws InvalidDataTypeException
605
+	 * @throws InvalidInterfaceException
606
+	 * @throws ReflectionException
607
+	 */
608
+	public function e_pretty_status($show_icons = false)
609
+	{
610
+		echo wp_kses($this->pretty_status($show_icons), AllowedTags::getAllowedTags());
611
+	}
612
+
613
+
614
+	/**
615
+	 * returns a pretty version of the status, good for displaying to users
616
+	 *
617
+	 * @param bool $show_icons
618
+	 * @return string
619
+	 * @throws EE_Error
620
+	 * @throws InvalidArgumentException
621
+	 * @throws InvalidDataTypeException
622
+	 * @throws InvalidInterfaceException
623
+	 * @throws ReflectionException
624
+	 */
625
+	public function pretty_status($show_icons = false)
626
+	{
627
+		$status = EEM_Status::instance()->localized_status(
628
+			array($this->status_ID() => esc_html__('unknown', 'event_espresso')),
629
+			false,
630
+			'sentence'
631
+		);
632
+		$icon = '';
633
+		switch ($this->status_ID()) {
634
+			case EEM_Transaction::complete_status_code:
635
+				$icon = $show_icons ? '<span class="dashicons dashicons-yes ee-icon-size-24 green-text"></span>' : '';
636
+				break;
637
+			case EEM_Transaction::incomplete_status_code:
638
+				$icon = $show_icons ? '<span class="dashicons dashicons-marker ee-icon-size-16 lt-blue-text"></span>'
639
+					: '';
640
+				break;
641
+			case EEM_Transaction::abandoned_status_code:
642
+				$icon = $show_icons ? '<span class="dashicons dashicons-marker ee-icon-size-16 red-text"></span>' : '';
643
+				break;
644
+			case EEM_Transaction::failed_status_code:
645
+				$icon = $show_icons ? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>' : '';
646
+				break;
647
+			case EEM_Transaction::overpaid_status_code:
648
+				$icon = $show_icons ? '<span class="dashicons dashicons-plus ee-icon-size-16 orange-text"></span>' : '';
649
+				break;
650
+		}
651
+		return $icon . $status[ $this->status_ID() ];
652
+	}
653
+
654
+
655
+	/**
656
+	 * get Transaction Status
657
+	 *
658
+	 * @return mixed
659
+	 * @throws EE_Error
660
+	 * @throws InvalidArgumentException
661
+	 * @throws InvalidDataTypeException
662
+	 * @throws InvalidInterfaceException
663
+	 * @throws ReflectionException
664
+	 */
665
+	public function status_ID()
666
+	{
667
+		return $this->get('STS_ID');
668
+	}
669
+
670
+
671
+	/**
672
+	 * Returns TRUE or FALSE for whether or not this transaction cost any money
673
+	 *
674
+	 * @return boolean
675
+	 * @throws EE_Error
676
+	 * @throws InvalidArgumentException
677
+	 * @throws InvalidDataTypeException
678
+	 * @throws InvalidInterfaceException
679
+	 * @throws ReflectionException
680
+	 */
681
+	public function is_free()
682
+	{
683
+		return EEH_Money::compare_floats($this->get('TXN_total'), 0, '==');
684
+	}
685
+
686
+
687
+	/**
688
+	 * Returns whether this transaction is complete
689
+	 * Useful in templates and other logic for deciding if we should ask for another payment...
690
+	 *
691
+	 * @return boolean
692
+	 * @throws EE_Error
693
+	 * @throws InvalidArgumentException
694
+	 * @throws InvalidDataTypeException
695
+	 * @throws InvalidInterfaceException
696
+	 * @throws ReflectionException
697
+	 */
698
+	public function is_completed()
699
+	{
700
+		return $this->status_ID() === EEM_Transaction::complete_status_code;
701
+	}
702
+
703
+
704
+	/**
705
+	 * Returns whether this transaction is incomplete
706
+	 * Useful in templates and other logic for deciding if we should ask for another payment...
707
+	 *
708
+	 * @return boolean
709
+	 * @throws EE_Error
710
+	 * @throws InvalidArgumentException
711
+	 * @throws InvalidDataTypeException
712
+	 * @throws InvalidInterfaceException
713
+	 * @throws ReflectionException
714
+	 */
715
+	public function is_incomplete()
716
+	{
717
+		return $this->status_ID() === EEM_Transaction::incomplete_status_code;
718
+	}
719
+
720
+
721
+	/**
722
+	 * Returns whether this transaction is overpaid
723
+	 * Useful in templates and other logic for deciding if monies need to be refunded
724
+	 *
725
+	 * @return boolean
726
+	 * @throws EE_Error
727
+	 * @throws InvalidArgumentException
728
+	 * @throws InvalidDataTypeException
729
+	 * @throws InvalidInterfaceException
730
+	 * @throws ReflectionException
731
+	 */
732
+	public function is_overpaid()
733
+	{
734
+		return $this->status_ID() === EEM_Transaction::overpaid_status_code;
735
+	}
736
+
737
+
738
+	/**
739
+	 * Returns whether this transaction was abandoned
740
+	 * meaning that the transaction/registration process was somehow interrupted and never completed
741
+	 * but that contact information exists for at least one registrant
742
+	 *
743
+	 * @return boolean
744
+	 * @throws EE_Error
745
+	 * @throws InvalidArgumentException
746
+	 * @throws InvalidDataTypeException
747
+	 * @throws InvalidInterfaceException
748
+	 * @throws ReflectionException
749
+	 */
750
+	public function is_abandoned()
751
+	{
752
+		return $this->status_ID() === EEM_Transaction::abandoned_status_code;
753
+	}
754
+
755
+
756
+	/**
757
+	 * Returns whether this transaction failed
758
+	 * meaning that the transaction/registration process was somehow interrupted and never completed
759
+	 * and that NO contact information exists for any registrants
760
+	 *
761
+	 * @return boolean
762
+	 * @throws EE_Error
763
+	 * @throws InvalidArgumentException
764
+	 * @throws InvalidDataTypeException
765
+	 * @throws InvalidInterfaceException
766
+	 * @throws ReflectionException
767
+	 */
768
+	public function failed()
769
+	{
770
+		return $this->status_ID() === EEM_Transaction::failed_status_code;
771
+	}
772
+
773
+
774
+	/**
775
+	 * This returns the url for the invoice of this transaction
776
+	 *
777
+	 * @param string $type 'html' or 'pdf' (default is pdf)
778
+	 * @return string
779
+	 * @throws DomainException
780
+	 * @throws EE_Error
781
+	 * @throws InvalidArgumentException
782
+	 * @throws InvalidDataTypeException
783
+	 * @throws InvalidInterfaceException
784
+	 * @throws ReflectionException
785
+	 */
786
+	public function invoice_url($type = 'html')
787
+	{
788
+		$REG = $this->primary_registration();
789
+		if (! $REG instanceof EE_Registration) {
790
+			return '';
791
+		}
792
+		return $REG->invoice_url($type);
793
+	}
794
+
795
+
796
+	/**
797
+	 * Gets the primary registration only
798
+	 *
799
+	 * @return EE_Base_Class|EE_Registration
800
+	 * @throws EE_Error
801
+	 * @throws InvalidArgumentException
802
+	 * @throws InvalidDataTypeException
803
+	 * @throws InvalidInterfaceException
804
+	 * @throws ReflectionException
805
+	 */
806
+	public function primary_registration()
807
+	{
808
+		$registrations = (array) $this->get_many_related(
809
+			'Registration',
810
+			array(array('REG_count' => EEM_Registration::PRIMARY_REGISTRANT_COUNT))
811
+		);
812
+		foreach ($registrations as $registration) {
813
+			// valid registration that is NOT cancelled or declined ?
814
+			if (
815
+				$registration instanceof EE_Registration
816
+				&& ! in_array($registration->status_ID(), EEM_Registration::closed_reg_statuses(), true)
817
+			) {
818
+				return $registration;
819
+			}
820
+		}
821
+		// nothing valid found, so just return first thing from array of results
822
+		return reset($registrations);
823
+	}
824
+
825
+
826
+	/**
827
+	 * Gets the URL for viewing the receipt
828
+	 *
829
+	 * @param string $type 'pdf' or 'html' (default is 'html')
830
+	 * @return string
831
+	 * @throws DomainException
832
+	 * @throws EE_Error
833
+	 * @throws InvalidArgumentException
834
+	 * @throws InvalidDataTypeException
835
+	 * @throws InvalidInterfaceException
836
+	 * @throws ReflectionException
837
+	 */
838
+	public function receipt_url($type = 'html')
839
+	{
840
+		$REG = $this->primary_registration();
841
+		if (! $REG instanceof EE_Registration) {
842
+			return '';
843
+		}
844
+		return $REG->receipt_url($type);
845
+	}
846
+
847
+
848
+	/**
849
+	 * Gets the URL of the thank you page with this registration REG_url_link added as
850
+	 * a query parameter
851
+	 *
852
+	 * @return string
853
+	 * @throws EE_Error
854
+	 * @throws InvalidArgumentException
855
+	 * @throws InvalidDataTypeException
856
+	 * @throws InvalidInterfaceException
857
+	 * @throws ReflectionException
858
+	 */
859
+	public function payment_overview_url()
860
+	{
861
+		$primary_registration = $this->primary_registration();
862
+		return $primary_registration instanceof EE_Registration ? $primary_registration->payment_overview_url() : false;
863
+	}
864
+
865
+
866
+	/**
867
+	 * @return string
868
+	 * @throws EE_Error
869
+	 * @throws InvalidArgumentException
870
+	 * @throws InvalidDataTypeException
871
+	 * @throws InvalidInterfaceException
872
+	 * @throws ReflectionException
873
+	 */
874
+	public function gateway_response_on_transaction()
875
+	{
876
+		$payment = $this->get_first_related('Payment');
877
+		return $payment instanceof EE_Payment ? $payment->gateway_response() : '';
878
+	}
879
+
880
+
881
+	/**
882
+	 * Get the status object of this object
883
+	 *
884
+	 * @return EE_Base_Class|EE_Status
885
+	 * @throws EE_Error
886
+	 * @throws InvalidArgumentException
887
+	 * @throws InvalidDataTypeException
888
+	 * @throws InvalidInterfaceException
889
+	 * @throws ReflectionException
890
+	 */
891
+	public function status_obj()
892
+	{
893
+		return $this->get_first_related('Status');
894
+	}
895
+
896
+
897
+	/**
898
+	 * Gets all the extra meta info on this payment
899
+	 *
900
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
901
+	 * @return EE_Base_Class[]|EE_Extra_Meta
902
+	 * @throws EE_Error
903
+	 * @throws InvalidArgumentException
904
+	 * @throws InvalidDataTypeException
905
+	 * @throws InvalidInterfaceException
906
+	 * @throws ReflectionException
907
+	 */
908
+	public function extra_meta($query_params = array())
909
+	{
910
+		return $this->get_many_related('Extra_Meta', $query_params);
911
+	}
912
+
913
+
914
+	/**
915
+	 * Wrapper for _add_relation_to
916
+	 *
917
+	 * @param EE_Registration $registration
918
+	 * @return EE_Base_Class the relation was added to
919
+	 * @throws EE_Error
920
+	 * @throws InvalidArgumentException
921
+	 * @throws InvalidDataTypeException
922
+	 * @throws InvalidInterfaceException
923
+	 * @throws ReflectionException
924
+	 */
925
+	public function add_registration(EE_Registration $registration)
926
+	{
927
+		return $this->_add_relation_to($registration, 'Registration');
928
+	}
929
+
930
+
931
+	/**
932
+	 * Removes the given registration from being related (even before saving this transaction).
933
+	 * If an ID/index is provided and this transaction isn't saved yet, removes it from list of cached relations
934
+	 *
935
+	 * @param int $registration_or_id
936
+	 * @return EE_Base_Class that was removed from being related
937
+	 * @throws EE_Error
938
+	 * @throws InvalidArgumentException
939
+	 * @throws InvalidDataTypeException
940
+	 * @throws InvalidInterfaceException
941
+	 * @throws ReflectionException
942
+	 */
943
+	public function remove_registration_with_id($registration_or_id)
944
+	{
945
+		return $this->_remove_relation_to($registration_or_id, 'Registration');
946
+	}
947
+
948
+
949
+	/**
950
+	 * Gets all the line items which are for ACTUAL items
951
+	 *
952
+	 * @return EE_Line_Item[]
953
+	 * @throws EE_Error
954
+	 * @throws InvalidArgumentException
955
+	 * @throws InvalidDataTypeException
956
+	 * @throws InvalidInterfaceException
957
+	 * @throws ReflectionException
958
+	 */
959
+	public function items_purchased()
960
+	{
961
+		return $this->line_items(array(array('LIN_type' => EEM_Line_Item::type_line_item)));
962
+	}
963
+
964
+
965
+	/**
966
+	 * Wrapper for _add_relation_to
967
+	 *
968
+	 * @param EE_Line_Item $line_item
969
+	 * @return EE_Base_Class the relation was added to
970
+	 * @throws EE_Error
971
+	 * @throws InvalidArgumentException
972
+	 * @throws InvalidDataTypeException
973
+	 * @throws InvalidInterfaceException
974
+	 * @throws ReflectionException
975
+	 */
976
+	public function add_line_item(EE_Line_Item $line_item)
977
+	{
978
+		return $this->_add_relation_to($line_item, 'Line_Item');
979
+	}
980
+
981
+
982
+	/**
983
+	 * Gets ALL the line items related to this transaction (unstructured)
984
+	 *
985
+	 * @param array $query_params
986
+	 * @return EE_Base_Class[]|EE_Line_Item[]
987
+	 * @throws EE_Error
988
+	 * @throws InvalidArgumentException
989
+	 * @throws InvalidDataTypeException
990
+	 * @throws InvalidInterfaceException
991
+	 * @throws ReflectionException
992
+	 */
993
+	public function line_items($query_params = array())
994
+	{
995
+		return $this->get_many_related('Line_Item', $query_params);
996
+	}
997
+
998
+
999
+	/**
1000
+	 * Gets all the line items which are taxes on the total
1001
+	 *
1002
+	 * @return EE_Line_Item[]
1003
+	 * @throws EE_Error
1004
+	 * @throws InvalidArgumentException
1005
+	 * @throws InvalidDataTypeException
1006
+	 * @throws InvalidInterfaceException
1007
+	 * @throws ReflectionException
1008
+	 */
1009
+	public function tax_items()
1010
+	{
1011
+		return $this->line_items(array(array('LIN_type' => EEM_Line_Item::type_tax)));
1012
+	}
1013
+
1014
+
1015
+	/**
1016
+	 * Gets the total line item (which is a parent of all other related line items,
1017
+	 * meaning it takes them all into account on its total)
1018
+	 *
1019
+	 * @param bool $create_if_not_found
1020
+	 * @return \EE_Line_Item
1021
+	 * @throws EE_Error
1022
+	 * @throws InvalidArgumentException
1023
+	 * @throws InvalidDataTypeException
1024
+	 * @throws InvalidInterfaceException
1025
+	 * @throws ReflectionException
1026
+	 */
1027
+	public function total_line_item($create_if_not_found = true)
1028
+	{
1029
+		$item = $this->get_first_related('Line_Item', array(array('LIN_type' => EEM_Line_Item::type_total)));
1030
+		if (! $item && $create_if_not_found) {
1031
+			$item = EEH_Line_Item::create_total_line_item($this);
1032
+		}
1033
+		return $item;
1034
+	}
1035
+
1036
+
1037
+	/**
1038
+	 * Returns the total amount of tax on this transaction
1039
+	 * (assumes there's only one tax subtotal line item)
1040
+	 *
1041
+	 * @return float
1042
+	 * @throws EE_Error
1043
+	 * @throws InvalidArgumentException
1044
+	 * @throws InvalidDataTypeException
1045
+	 * @throws InvalidInterfaceException
1046
+	 * @throws ReflectionException
1047
+	 */
1048
+	public function tax_total()
1049
+	{
1050
+		$tax_line_item = $this->tax_total_line_item();
1051
+		if ($tax_line_item) {
1052
+			return (float) $tax_line_item->total();
1053
+		}
1054
+		return (float) 0;
1055
+	}
1056
+
1057
+
1058
+	/**
1059
+	 * Gets the tax subtotal line item (assumes there's only one)
1060
+	 *
1061
+	 * @return EE_Line_Item
1062
+	 * @throws EE_Error
1063
+	 * @throws InvalidArgumentException
1064
+	 * @throws InvalidDataTypeException
1065
+	 * @throws InvalidInterfaceException
1066
+	 * @throws ReflectionException
1067
+	 */
1068
+	public function tax_total_line_item()
1069
+	{
1070
+		return EEH_Line_Item::get_taxes_subtotal($this->total_line_item());
1071
+	}
1072
+
1073
+
1074
+	/**
1075
+	 * Gets the array of billing info for the gateway and for this transaction's primary registration's attendee.
1076
+	 *
1077
+	 * @return EE_Form_Section_Proper
1078
+	 * @throws EE_Error
1079
+	 * @throws InvalidArgumentException
1080
+	 * @throws InvalidDataTypeException
1081
+	 * @throws InvalidInterfaceException
1082
+	 * @throws ReflectionException
1083
+	 */
1084
+	public function billing_info()
1085
+	{
1086
+		$payment_method = $this->payment_method();
1087
+		if (! $payment_method) {
1088
+			EE_Error::add_error(
1089
+				esc_html__(
1090
+					'Could not find billing info for transaction because no gateway has been used for it yet',
1091
+					'event_espresso'
1092
+				),
1093
+				__FILE__,
1094
+				__FUNCTION__,
1095
+				__LINE__
1096
+			);
1097
+			return null;
1098
+		}
1099
+		$primary_reg = $this->primary_registration();
1100
+		if (! $primary_reg) {
1101
+			EE_Error::add_error(
1102
+				esc_html__(
1103
+					'Cannot get billing info for gateway %s on transaction because no primary registration exists',
1104
+					'event_espresso'
1105
+				),
1106
+				__FILE__,
1107
+				__FUNCTION__,
1108
+				__LINE__
1109
+			);
1110
+			return null;
1111
+		}
1112
+		$attendee = $primary_reg->attendee();
1113
+		if (! $attendee) {
1114
+			EE_Error::add_error(
1115
+				esc_html__(
1116
+					'Cannot get billing info for gateway %s on transaction because the primary registration has no attendee exists',
1117
+					'event_espresso'
1118
+				),
1119
+				__FILE__,
1120
+				__FUNCTION__,
1121
+				__LINE__
1122
+			);
1123
+			return null;
1124
+		}
1125
+		return $attendee->billing_info_for_payment_method($payment_method);
1126
+	}
1127
+
1128
+
1129
+	/**
1130
+	 * Gets PMD_ID
1131
+	 *
1132
+	 * @return int
1133
+	 * @throws EE_Error
1134
+	 * @throws InvalidArgumentException
1135
+	 * @throws InvalidDataTypeException
1136
+	 * @throws InvalidInterfaceException
1137
+	 * @throws ReflectionException
1138
+	 */
1139
+	public function payment_method_ID()
1140
+	{
1141
+		return $this->get('PMD_ID');
1142
+	}
1143
+
1144
+
1145
+	/**
1146
+	 * Sets PMD_ID
1147
+	 *
1148
+	 * @param int $PMD_ID
1149
+	 * @throws EE_Error
1150
+	 * @throws InvalidArgumentException
1151
+	 * @throws InvalidDataTypeException
1152
+	 * @throws InvalidInterfaceException
1153
+	 * @throws ReflectionException
1154
+	 */
1155
+	public function set_payment_method_ID($PMD_ID)
1156
+	{
1157
+		$this->set('PMD_ID', $PMD_ID);
1158
+	}
1159
+
1160
+
1161
+	/**
1162
+	 * Gets the last-used payment method on this transaction
1163
+	 * (we COULD just use the last-made payment, but some payment methods, namely
1164
+	 * offline ones, dont' create payments)
1165
+	 *
1166
+	 * @return EE_Payment_Method
1167
+	 * @throws EE_Error
1168
+	 * @throws InvalidArgumentException
1169
+	 * @throws InvalidDataTypeException
1170
+	 * @throws InvalidInterfaceException
1171
+	 * @throws ReflectionException
1172
+	 */
1173
+	public function payment_method()
1174
+	{
1175
+		$pm = $this->get_first_related('Payment_Method');
1176
+		if ($pm instanceof EE_Payment_Method) {
1177
+			return $pm;
1178
+		}
1179
+		$last_payment = $this->last_payment();
1180
+		if ($last_payment instanceof EE_Payment && $last_payment->payment_method()) {
1181
+			return $last_payment->payment_method();
1182
+		}
1183
+		return null;
1184
+	}
1185
+
1186
+
1187
+	/**
1188
+	 * Gets the last payment made
1189
+	 *
1190
+	 * @return EE_Base_Class|EE_Payment
1191
+	 * @throws EE_Error
1192
+	 * @throws InvalidArgumentException
1193
+	 * @throws InvalidDataTypeException
1194
+	 * @throws InvalidInterfaceException
1195
+	 * @throws ReflectionException
1196
+	 */
1197
+	public function last_payment()
1198
+	{
1199
+		return $this->get_first_related('Payment', array('order_by' => array('PAY_ID' => 'desc')));
1200
+	}
1201
+
1202
+
1203
+	/**
1204
+	 * Gets all the line items which are unrelated to tickets on this transaction
1205
+	 *
1206
+	 * @return EE_Line_Item[]
1207
+	 * @throws EE_Error
1208
+	 * @throws InvalidArgumentException
1209
+	 * @throws InvalidDataTypeException
1210
+	 * @throws InvalidInterfaceException
1211
+	 * @throws ReflectionException
1212
+	 */
1213
+	public function non_ticket_line_items()
1214
+	{
1215
+		return EEM_Line_Item::instance()->get_all_non_ticket_line_items_for_transaction($this->ID());
1216
+	}
1217
+
1218
+
1219
+	/**
1220
+	 * possibly toggles TXN status
1221
+	 *
1222
+	 * @param  boolean $update whether to save the TXN
1223
+	 * @return bool whether the TXN was saved
1224
+	 * @throws EE_Error
1225
+	 * @throws InvalidArgumentException
1226
+	 * @throws InvalidDataTypeException
1227
+	 * @throws InvalidInterfaceException
1228
+	 * @throws ReflectionException
1229
+	 * @throws RuntimeException
1230
+	 */
1231
+	public function update_status_based_on_total_paid($update = true)
1232
+	{
1233
+		// set transaction status based on comparison of TXN_paid vs TXN_total
1234
+		if (EEH_Money::compare_floats($this->paid(), $this->total(), '>')) {
1235
+			$new_txn_status = EEM_Transaction::overpaid_status_code;
1236
+		} elseif (EEH_Money::compare_floats($this->paid(), $this->total())) {
1237
+			$new_txn_status = EEM_Transaction::complete_status_code;
1238
+		} elseif (EEH_Money::compare_floats($this->paid(), $this->total(), '<')) {
1239
+			$new_txn_status = EEM_Transaction::incomplete_status_code;
1240
+		} else {
1241
+			throw new RuntimeException(
1242
+				esc_html__('The total paid calculation for this transaction is inaccurate.', 'event_espresso')
1243
+			);
1244
+		}
1245
+		if ($new_txn_status !== $this->status_ID()) {
1246
+			$this->set_status($new_txn_status);
1247
+			if ($update) {
1248
+				return $this->save() ? true : false;
1249
+			}
1250
+		}
1251
+		return false;
1252
+	}
1253
+
1254
+
1255
+	/**
1256
+	 * Updates the transaction's status and total_paid based on all the payments
1257
+	 * that apply to it
1258
+	 *
1259
+	 * @deprecated
1260
+	 * @return array|bool
1261
+	 * @throws EE_Error
1262
+	 * @throws InvalidArgumentException
1263
+	 * @throws ReflectionException
1264
+	 * @throws InvalidDataTypeException
1265
+	 * @throws InvalidInterfaceException
1266
+	 */
1267
+	public function update_based_on_payments()
1268
+	{
1269
+		EE_Error::doing_it_wrong(
1270
+			__CLASS__ . '::' . __FUNCTION__,
1271
+			sprintf(
1272
+				esc_html__('This method is deprecated. Please use "%s" instead', 'event_espresso'),
1273
+				'EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()'
1274
+			),
1275
+			'4.6.0'
1276
+		);
1277
+		/** @type EE_Transaction_Processor $transaction_processor */
1278
+		$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
1279
+		return $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment($this);
1280
+	}
1281
+
1282
+
1283
+	/**
1284
+	 * @return string
1285
+	 */
1286
+	public function old_txn_status()
1287
+	{
1288
+		return $this->_old_txn_status;
1289
+	}
1290
+
1291
+
1292
+	/**
1293
+	 * @param string $old_txn_status
1294
+	 */
1295
+	public function set_old_txn_status($old_txn_status)
1296
+	{
1297
+		// only set the first time
1298
+		if ($this->_old_txn_status === null) {
1299
+			$this->_old_txn_status = $old_txn_status;
1300
+		}
1301
+	}
1302
+
1303
+
1304
+	/**
1305
+	 * reg_status_updated
1306
+	 *
1307
+	 * @return bool
1308
+	 * @throws EE_Error
1309
+	 * @throws InvalidArgumentException
1310
+	 * @throws InvalidDataTypeException
1311
+	 * @throws InvalidInterfaceException
1312
+	 * @throws ReflectionException
1313
+	 */
1314
+	public function txn_status_updated()
1315
+	{
1316
+		return $this->status_ID() !== $this->_old_txn_status && $this->_old_txn_status !== null;
1317
+	}
1318
+
1319
+
1320
+	/**
1321
+	 * _reg_steps_completed
1322
+	 * if $check_all is TRUE, then returns TRUE if ALL reg steps have been marked as completed,
1323
+	 * if a $reg_step_slug is provided, then this step will be skipped when testing for completion
1324
+	 * if $check_all is FALSE and a $reg_step_slug is provided, then ONLY that reg step will be tested for completion
1325
+	 *
1326
+	 * @param string $reg_step_slug
1327
+	 * @param bool   $check_all
1328
+	 * @return bool|int
1329
+	 * @throws EE_Error
1330
+	 * @throws InvalidArgumentException
1331
+	 * @throws InvalidDataTypeException
1332
+	 * @throws InvalidInterfaceException
1333
+	 * @throws ReflectionException
1334
+	 */
1335
+	private function _reg_steps_completed($reg_step_slug = '', $check_all = true)
1336
+	{
1337
+		$reg_steps = $this->reg_steps();
1338
+		if (! is_array($reg_steps) || empty($reg_steps)) {
1339
+			return false;
1340
+		}
1341
+		// loop thru reg steps array)
1342
+		foreach ($reg_steps as $slug => $reg_step_completed) {
1343
+			// if NOT checking ALL steps (only checking one step)
1344
+			if (! $check_all) {
1345
+				// and this is the one
1346
+				if ($slug === $reg_step_slug) {
1347
+					return $reg_step_completed;
1348
+				}
1349
+				// skip to next reg step in loop
1350
+				continue;
1351
+			}
1352
+			// $check_all must be true, else we would never have gotten to this point
1353
+			if ($slug === $reg_step_slug) {
1354
+				// if we reach this point, then we are testing either:
1355
+				// all_reg_steps_completed_except() or
1356
+				// all_reg_steps_completed_except_final_step(),
1357
+				// and since this is the reg step EXCEPTION being tested
1358
+				// we want to return true (yes true) if this reg step is NOT completed
1359
+				// ie: "is everything completed except the final step?"
1360
+				// "that is correct... the final step is not completed, but all others are."
1361
+				return $reg_step_completed !== true;
1362
+			}
1363
+			if ($reg_step_completed !== true) {
1364
+				// if any reg step is NOT completed, then ALL steps are not completed
1365
+				return false;
1366
+			}
1367
+		}
1368
+		return true;
1369
+	}
1370
+
1371
+
1372
+	/**
1373
+	 * all_reg_steps_completed
1374
+	 * returns:
1375
+	 *    true if ALL reg steps have been marked as completed
1376
+	 *        or false if any step is not completed
1377
+	 *
1378
+	 * @return bool
1379
+	 * @throws EE_Error
1380
+	 * @throws InvalidArgumentException
1381
+	 * @throws InvalidDataTypeException
1382
+	 * @throws InvalidInterfaceException
1383
+	 * @throws ReflectionException
1384
+	 */
1385
+	public function all_reg_steps_completed()
1386
+	{
1387
+		return $this->_reg_steps_completed();
1388
+	}
1389
+
1390
+
1391
+	/**
1392
+	 * all_reg_steps_completed_except
1393
+	 * returns:
1394
+	 *        true if ALL reg steps, except a particular step that you wish to skip over, have been marked as completed
1395
+	 *        or false if any other step is not completed
1396
+	 *        or false if ALL steps are completed including the exception you are testing !!!
1397
+	 *
1398
+	 * @param string $exception
1399
+	 * @return bool
1400
+	 * @throws EE_Error
1401
+	 * @throws InvalidArgumentException
1402
+	 * @throws InvalidDataTypeException
1403
+	 * @throws InvalidInterfaceException
1404
+	 * @throws ReflectionException
1405
+	 */
1406
+	public function all_reg_steps_completed_except($exception = '')
1407
+	{
1408
+		return $this->_reg_steps_completed($exception);
1409
+	}
1410
+
1411
+
1412
+	/**
1413
+	 * all_reg_steps_completed_except
1414
+	 * returns:
1415
+	 *        true if ALL reg steps, except the final step, have been marked as completed
1416
+	 *        or false if any step is not completed
1417
+	 *    or false if ALL steps are completed including the final step !!!
1418
+	 *
1419
+	 * @return bool
1420
+	 * @throws EE_Error
1421
+	 * @throws InvalidArgumentException
1422
+	 * @throws InvalidDataTypeException
1423
+	 * @throws InvalidInterfaceException
1424
+	 * @throws ReflectionException
1425
+	 */
1426
+	public function all_reg_steps_completed_except_final_step()
1427
+	{
1428
+		return $this->_reg_steps_completed('finalize_registration');
1429
+	}
1430
+
1431
+
1432
+	/**
1433
+	 * reg_step_completed
1434
+	 * returns:
1435
+	 *    true if a specific reg step has been marked as completed
1436
+	 *    a Unix timestamp if it has been initialized but not yet completed,
1437
+	 *    or false if it has not yet been initialized
1438
+	 *
1439
+	 * @param string $reg_step_slug
1440
+	 * @return bool|int
1441
+	 * @throws EE_Error
1442
+	 * @throws InvalidArgumentException
1443
+	 * @throws InvalidDataTypeException
1444
+	 * @throws InvalidInterfaceException
1445
+	 * @throws ReflectionException
1446
+	 */
1447
+	public function reg_step_completed($reg_step_slug)
1448
+	{
1449
+		return $this->_reg_steps_completed($reg_step_slug, false);
1450
+	}
1451
+
1452
+
1453
+	/**
1454
+	 * completed_final_reg_step
1455
+	 * returns:
1456
+	 *    true if the finalize_registration reg step has been marked as completed
1457
+	 *    a Unix timestamp if it has been initialized but not yet completed,
1458
+	 *    or false if it has not yet been initialized
1459
+	 *
1460
+	 * @return bool|int
1461
+	 * @throws EE_Error
1462
+	 * @throws InvalidArgumentException
1463
+	 * @throws InvalidDataTypeException
1464
+	 * @throws InvalidInterfaceException
1465
+	 * @throws ReflectionException
1466
+	 */
1467
+	public function final_reg_step_completed()
1468
+	{
1469
+		return $this->_reg_steps_completed('finalize_registration', false);
1470
+	}
1471
+
1472
+
1473
+	/**
1474
+	 * set_reg_step_initiated
1475
+	 * given a valid TXN_reg_step, this sets it's value to a unix timestamp
1476
+	 *
1477
+	 * @param string $reg_step_slug
1478
+	 * @return boolean
1479
+	 * @throws EE_Error
1480
+	 * @throws InvalidArgumentException
1481
+	 * @throws InvalidDataTypeException
1482
+	 * @throws InvalidInterfaceException
1483
+	 * @throws ReflectionException
1484
+	 */
1485
+	public function set_reg_step_initiated($reg_step_slug)
1486
+	{
1487
+		return $this->_set_reg_step_completed_status($reg_step_slug, time());
1488
+	}
1489
+
1490
+
1491
+	/**
1492
+	 * set_reg_step_completed
1493
+	 * given a valid TXN_reg_step, this sets the step as completed
1494
+	 *
1495
+	 * @param string $reg_step_slug
1496
+	 * @return boolean
1497
+	 * @throws EE_Error
1498
+	 * @throws InvalidArgumentException
1499
+	 * @throws InvalidDataTypeException
1500
+	 * @throws InvalidInterfaceException
1501
+	 * @throws ReflectionException
1502
+	 */
1503
+	public function set_reg_step_completed($reg_step_slug)
1504
+	{
1505
+		return $this->_set_reg_step_completed_status($reg_step_slug, true);
1506
+	}
1507
+
1508
+
1509
+	/**
1510
+	 * set_reg_step_completed
1511
+	 * given a valid TXN_reg_step slug, this sets the step as NOT completed
1512
+	 *
1513
+	 * @param string $reg_step_slug
1514
+	 * @return boolean
1515
+	 * @throws EE_Error
1516
+	 * @throws InvalidArgumentException
1517
+	 * @throws InvalidDataTypeException
1518
+	 * @throws InvalidInterfaceException
1519
+	 * @throws ReflectionException
1520
+	 */
1521
+	public function set_reg_step_not_completed($reg_step_slug)
1522
+	{
1523
+		return $this->_set_reg_step_completed_status($reg_step_slug, false);
1524
+	}
1525
+
1526
+
1527
+	/**
1528
+	 * set_reg_step_completed
1529
+	 * given a valid reg step slug, this sets the TXN_reg_step completed status which is either:
1530
+	 *
1531
+	 * @param  string      $reg_step_slug
1532
+	 * @param  boolean|int $status
1533
+	 * @return boolean
1534
+	 * @throws EE_Error
1535
+	 * @throws InvalidArgumentException
1536
+	 * @throws InvalidDataTypeException
1537
+	 * @throws InvalidInterfaceException
1538
+	 * @throws ReflectionException
1539
+	 */
1540
+	private function _set_reg_step_completed_status($reg_step_slug, $status)
1541
+	{
1542
+		// validate status
1543
+		$status = is_bool($status) || is_int($status) ? $status : false;
1544
+		// get reg steps array
1545
+		$txn_reg_steps = $this->reg_steps();
1546
+		// if reg step does NOT exist
1547
+		if (! isset($txn_reg_steps[ $reg_step_slug ])) {
1548
+			return false;
1549
+		}
1550
+		// if  we're trying to complete a step that is already completed
1551
+		if ($txn_reg_steps[ $reg_step_slug ] === true) {
1552
+			return true;
1553
+		}
1554
+		// if  we're trying to complete a step that hasn't even started
1555
+		if ($status === true && $txn_reg_steps[ $reg_step_slug ] === false) {
1556
+			return false;
1557
+		}
1558
+		// if current status value matches the incoming value (no change)
1559
+		// type casting as int means values should collapse to either 0, 1, or a timestamp like 1234567890
1560
+		if ((int) $txn_reg_steps[ $reg_step_slug ] === (int) $status) {
1561
+			// this will happen in cases where multiple AJAX requests occur during the same step
1562
+			return true;
1563
+		}
1564
+		// if we're trying to set a start time, but it has already been set...
1565
+		if (is_numeric($status) && is_numeric($txn_reg_steps[ $reg_step_slug ])) {
1566
+			// skip the update below, but don't return FALSE so that errors won't be displayed
1567
+			return true;
1568
+		}
1569
+		// update completed status
1570
+		$txn_reg_steps[ $reg_step_slug ] = $status;
1571
+		$this->set_reg_steps($txn_reg_steps);
1572
+		$this->save();
1573
+		return true;
1574
+	}
1575
+
1576
+
1577
+	/**
1578
+	 * remove_reg_step
1579
+	 * given a valid TXN_reg_step slug, this will remove (unset)
1580
+	 * the reg step from the TXN reg step array
1581
+	 *
1582
+	 * @param string $reg_step_slug
1583
+	 * @return void
1584
+	 * @throws EE_Error
1585
+	 * @throws InvalidArgumentException
1586
+	 * @throws InvalidDataTypeException
1587
+	 * @throws InvalidInterfaceException
1588
+	 * @throws ReflectionException
1589
+	 */
1590
+	public function remove_reg_step($reg_step_slug)
1591
+	{
1592
+		// get reg steps array
1593
+		$txn_reg_steps = $this->reg_steps();
1594
+		unset($txn_reg_steps[ $reg_step_slug ]);
1595
+		$this->set_reg_steps($txn_reg_steps);
1596
+	}
1597
+
1598
+
1599
+	/**
1600
+	 * toggle_failed_transaction_status
1601
+	 * upgrades a TXNs status from failed to abandoned,
1602
+	 * meaning that contact information has been captured for at least one registrant
1603
+	 *
1604
+	 * @param bool $save
1605
+	 * @return bool
1606
+	 * @throws EE_Error
1607
+	 * @throws InvalidArgumentException
1608
+	 * @throws InvalidDataTypeException
1609
+	 * @throws InvalidInterfaceException
1610
+	 * @throws ReflectionException
1611
+	 */
1612
+	public function toggle_failed_transaction_status($save = true)
1613
+	{
1614
+		// if TXN status is still set as "failed"...
1615
+		if ($this->status_ID() === EEM_Transaction::failed_status_code) {
1616
+			$this->set_status(EEM_Transaction::abandoned_status_code);
1617
+			if ($save) {
1618
+				$this->save();
1619
+			}
1620
+			return true;
1621
+		}
1622
+		return false;
1623
+	}
1624
+
1625
+
1626
+	/**
1627
+	 * toggle_abandoned_transaction_status
1628
+	 * upgrades a TXNs status from failed or abandoned to incomplete
1629
+	 *
1630
+	 * @return bool
1631
+	 * @throws EE_Error
1632
+	 * @throws InvalidArgumentException
1633
+	 * @throws InvalidDataTypeException
1634
+	 * @throws InvalidInterfaceException
1635
+	 * @throws ReflectionException
1636
+	 */
1637
+	public function toggle_abandoned_transaction_status()
1638
+	{
1639
+		// if TXN status has not been updated already due to a payment, and is still set as "failed" or "abandoned"...
1640
+		$txn_status = $this->status_ID();
1641
+		if (
1642
+			$txn_status === EEM_Transaction::failed_status_code
1643
+			|| $txn_status === EEM_Transaction::abandoned_status_code
1644
+		) {
1645
+			// if a contact record for the primary registrant has been created
1646
+			if (
1647
+				$this->primary_registration() instanceof EE_Registration
1648
+				&& $this->primary_registration()->attendee() instanceof EE_Attendee
1649
+			) {
1650
+				$this->set_status(EEM_Transaction::incomplete_status_code);
1651
+			} else {
1652
+				// no contact record? yer abandoned!
1653
+				$this->set_status(EEM_Transaction::abandoned_status_code);
1654
+			}
1655
+			return true;
1656
+		}
1657
+		return false;
1658
+	}
1659
+
1660
+
1661
+	/**
1662
+	 * checks if an Abandoned TXN has any related payments, and if so,
1663
+	 * updates the TXN status based on the amount paid
1664
+	 *
1665
+	 * @throws EE_Error
1666
+	 * @throws InvalidArgumentException
1667
+	 * @throws InvalidDataTypeException
1668
+	 * @throws InvalidInterfaceException
1669
+	 * @throws ReflectionException
1670
+	 * @throws RuntimeException
1671
+	 * @throws ReflectionException
1672
+	 */
1673
+	public function verify_abandoned_transaction_status()
1674
+	{
1675
+		if ($this->status_ID() !== EEM_Transaction::abandoned_status_code) {
1676
+			return;
1677
+		}
1678
+		$payments = $this->get_many_related('Payment');
1679
+		if (! empty($payments)) {
1680
+			foreach ($payments as $payment) {
1681
+				if ($payment instanceof EE_Payment) {
1682
+					// kk this TXN should NOT be abandoned
1683
+					$this->update_status_based_on_total_paid();
1684
+					if (! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) {
1685
+						EE_Error::add_attention(
1686
+							sprintf(
1687
+								esc_html__(
1688
+									'The status for Transaction #%1$d has been updated from "Abandoned" to "%2$s", because at least one payment has been made towards it. If the payment appears in the "Payment Details" table below, you may need to edit its status and/or other details as well.',
1689
+									'event_espresso'
1690
+								),
1691
+								$this->ID(),
1692
+								$this->pretty_status()
1693
+							)
1694
+						);
1695
+					}
1696
+					// get final reg step status
1697
+					$finalized = $this->final_reg_step_completed();
1698
+					// if the 'finalize_registration' step has been initiated (has a timestamp)
1699
+					// but has not yet been fully completed (TRUE)
1700
+					if (is_int($finalized) && $finalized !== false && $finalized !== true) {
1701
+						$this->set_reg_step_completed('finalize_registration');
1702
+						$this->save();
1703
+					}
1704
+				}
1705
+			}
1706
+		}
1707
+	}
1708
+
1709
+
1710
+	/**
1711
+	 * @since 4.10.4.p
1712
+	 * @throws EE_Error
1713
+	 * @throws InvalidArgumentException
1714
+	 * @throws InvalidDataTypeException
1715
+	 * @throws InvalidInterfaceException
1716
+	 * @throws ReflectionException
1717
+	 * @throws RuntimeException
1718
+	 */
1719
+	public function recalculateLineItems()
1720
+	{
1721
+		$total_line_item = $this->total_line_item(false);
1722
+		if ($total_line_item instanceof EE_Line_Item) {
1723
+			EEH_Line_Item::resetIsTaxableForTickets($total_line_item);
1724
+			return EEH_Line_Item::apply_taxes($total_line_item, true);
1725
+		}
1726
+		return false;
1727
+	}
1728
+
1729
+
1730
+	/**
1731
+	 * @param string $source function name that called this method
1732
+	 * @return boolean | int
1733
+	 */
1734
+	public function delete($source = 'unknown')
1735
+	{
1736
+		$current_user = wp_get_current_user();
1737
+		$this->add_extra_meta(
1738
+			EE_Transaction::EXTRA_META_KEY_TXN_DELETED,
1739
+			array(
1740
+				'deleted-by' => $current_user->ID ? $current_user->display_name : 'unauthed user',
1741
+				'timestamp'  => time(),
1742
+				'source'     => $source,
1743
+			)
1744
+		);
1745
+		return parent::delete();
1746
+	}
1747 1747
 }
Please login to merge, or discard this patch.
core/db_classes/EE_Registration.class.php 2 patches
Indentation   +2531 added lines, -2531 removed lines patch added patch discarded remove patch
@@ -17,2535 +17,2535 @@
 block discarded – undo
17 17
 class EE_Registration extends EE_Soft_Delete_Base_Class implements EEI_Registration, EEI_Admin_Links
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
-     * Used to reference when a registration has been checked out.
38
-     *
39
-     * @deprecated use \EE_Checkin::status_checked_out instead
40
-     * @type int
41
-     */
42
-    const checkin_status_out = 0;
43
-
44
-    /**
45
-     * extra meta key for tracking reg status os trashed registrations
46
-     *
47
-     * @type string
48
-     */
49
-    const PRE_TRASH_REG_STATUS_KEY = 'pre_trash_registration_status';
50
-
51
-    /**
52
-     * extra meta key for tracking if registration has reserved ticket
53
-     *
54
-     * @type string
55
-     */
56
-    const HAS_RESERVED_TICKET_KEY = 'has_reserved_ticket';
57
-
58
-    /**
59
-     * extra meta key for tracking when registrations are trashed and by who
60
-     *
61
-     * @type string
62
-     */
63
-    const EXTRA_META_KEY_REG_TRASHED = 'registration-trashed';
64
-
65
-    /**
66
-     * extra meta key for tracking when registrations are restored and by who
67
-     *
68
-     * @type string
69
-     */
70
-    const EXTRA_META_KEY_REG_RESTORED = 'registration-restored';
71
-
72
-
73
-    /**
74
-     * @param array  $props_n_values          incoming values
75
-     * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
76
-     *                                        used.)
77
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
78
-     *                                        date_format and the second value is the time format
79
-     * @return EE_Registration
80
-     * @throws EE_Error
81
-     * @throws InvalidArgumentException
82
-     * @throws InvalidDataTypeException
83
-     * @throws InvalidInterfaceException
84
-     * @throws ReflectionException
85
-     */
86
-    public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
87
-    {
88
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
89
-        return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
90
-    }
91
-
92
-
93
-    /**
94
-     * @param array  $props_n_values  incoming values from the database
95
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
96
-     *                                the website will be used.
97
-     * @return EE_Registration
98
-     * @throws EE_Error
99
-     * @throws InvalidArgumentException
100
-     * @throws InvalidDataTypeException
101
-     * @throws InvalidInterfaceException
102
-     * @throws ReflectionException
103
-     */
104
-    public static function new_instance_from_db($props_n_values = array(), $timezone = null)
105
-    {
106
-        return new self($props_n_values, true, $timezone);
107
-    }
108
-
109
-
110
-    /**
111
-     *        Set Event ID
112
-     *
113
-     * @param        int $EVT_ID Event ID
114
-     * @throws DomainException
115
-     * @throws EE_Error
116
-     * @throws EntityNotFoundException
117
-     * @throws InvalidArgumentException
118
-     * @throws InvalidDataTypeException
119
-     * @throws InvalidInterfaceException
120
-     * @throws ReflectionException
121
-     * @throws RuntimeException
122
-     * @throws UnexpectedEntityException
123
-     */
124
-    public function set_event($EVT_ID = 0)
125
-    {
126
-        $this->set('EVT_ID', $EVT_ID);
127
-    }
128
-
129
-
130
-    /**
131
-     * Overrides parent set() method so that all calls to set( 'REG_code', $REG_code ) OR set( 'STS_ID', $STS_ID ) can
132
-     * be routed to internal methods
133
-     *
134
-     * @param string $field_name
135
-     * @param mixed  $field_value
136
-     * @param bool   $use_default
137
-     * @throws DomainException
138
-     * @throws EE_Error
139
-     * @throws EntityNotFoundException
140
-     * @throws InvalidArgumentException
141
-     * @throws InvalidDataTypeException
142
-     * @throws InvalidInterfaceException
143
-     * @throws ReflectionException
144
-     * @throws RuntimeException
145
-     * @throws UnexpectedEntityException
146
-     */
147
-    public function set($field_name, $field_value, $use_default = false)
148
-    {
149
-        switch ($field_name) {
150
-            case 'REG_code':
151
-                if (! empty($field_value) && $this->reg_code() === null) {
152
-                    $this->set_reg_code($field_value, $use_default);
153
-                }
154
-                break;
155
-            case 'STS_ID':
156
-                $this->set_status($field_value, $use_default);
157
-                break;
158
-            default:
159
-                parent::set($field_name, $field_value, $use_default);
160
-        }
161
-    }
162
-
163
-
164
-    /**
165
-     * Set Status ID
166
-     * updates the registration status and ALSO...
167
-     * calls reserve_registration_space() if the reg status changes TO approved from any other reg status
168
-     * calls release_registration_space() if the reg status changes FROM approved to any other reg status
169
-     *
170
-     * @param string                $new_STS_ID
171
-     * @param boolean               $use_default
172
-     * @param ContextInterface|null $context
173
-     * @return bool
174
-     * @throws DomainException
175
-     * @throws EE_Error
176
-     * @throws EntityNotFoundException
177
-     * @throws InvalidArgumentException
178
-     * @throws InvalidDataTypeException
179
-     * @throws InvalidInterfaceException
180
-     * @throws ReflectionException
181
-     * @throws RuntimeException
182
-     * @throws UnexpectedEntityException
183
-     */
184
-    public function set_status($new_STS_ID = null, $use_default = false, ContextInterface $context = null)
185
-    {
186
-        // get current REG_Status
187
-        $old_STS_ID = $this->status_ID();
188
-        // if status has changed
189
-        if (
190
-            $old_STS_ID !== $new_STS_ID // and that status has actually changed
191
-            && ! empty($old_STS_ID) // and that old status is actually set
192
-            && ! empty($new_STS_ID) // as well as the new status
193
-            && $this->ID() // ensure registration is in the db
194
-        ) {
195
-            // update internal status first
196
-            parent::set('STS_ID', $new_STS_ID, $use_default);
197
-            // THEN handle other changes that occur when reg status changes
198
-            // TO approved
199
-            if ($new_STS_ID === EEM_Registration::status_id_approved) {
200
-                // reserve a space by incrementing ticket and datetime sold values
201
-                $this->reserveRegistrationSpace();
202
-                do_action('AHEE__EE_Registration__set_status__to_approved', $this, $old_STS_ID, $new_STS_ID, $context);
203
-                // OR FROM  approved
204
-            } elseif ($old_STS_ID === EEM_Registration::status_id_approved) {
205
-                // release a space by decrementing ticket and datetime sold values
206
-                $this->releaseRegistrationSpace();
207
-                do_action(
208
-                    'AHEE__EE_Registration__set_status__from_approved',
209
-                    $this,
210
-                    $old_STS_ID,
211
-                    $new_STS_ID,
212
-                    $context
213
-                );
214
-            }
215
-            // update status
216
-            parent::set('STS_ID', $new_STS_ID, $use_default);
217
-            $this->updateIfCanceledOrReinstated($new_STS_ID, $old_STS_ID, $context);
218
-            if ($this->statusChangeUpdatesTransaction($context)) {
219
-                $this->updateTransactionAfterStatusChange();
220
-            }
221
-            do_action('AHEE__EE_Registration__set_status__after_update', $this, $old_STS_ID, $new_STS_ID, $context);
222
-            return true;
223
-        }
224
-        // even though the old value matches the new value, it's still good to
225
-        // allow the parent set method to have a say
226
-        parent::set('STS_ID', $new_STS_ID, $use_default);
227
-        return true;
228
-    }
229
-
230
-
231
-    /**
232
-     * update REGs and TXN when cancelled or declined registrations involved
233
-     *
234
-     * @param string                $new_STS_ID
235
-     * @param string                $old_STS_ID
236
-     * @param ContextInterface|null $context
237
-     * @throws EE_Error
238
-     * @throws InvalidArgumentException
239
-     * @throws InvalidDataTypeException
240
-     * @throws InvalidInterfaceException
241
-     * @throws ReflectionException
242
-     * @throws RuntimeException
243
-     */
244
-    private function updateIfCanceledOrReinstated($new_STS_ID, $old_STS_ID, ContextInterface $context = null)
245
-    {
246
-        // these reg statuses should not be considered in any calculations involving monies owing
247
-        $closed_reg_statuses = EEM_Registration::closed_reg_statuses();
248
-        // true if registration has been cancelled or declined
249
-        $this->updateIfCanceled(
250
-            $closed_reg_statuses,
251
-            $new_STS_ID,
252
-            $old_STS_ID,
253
-            $context
254
-        );
255
-        $this->updateIfReinstated(
256
-            $closed_reg_statuses,
257
-            $new_STS_ID,
258
-            $old_STS_ID,
259
-            $context
260
-        );
261
-    }
262
-
263
-
264
-    /**
265
-     * update REGs and TXN when cancelled or declined registrations involved
266
-     *
267
-     * @param array                 $closed_reg_statuses
268
-     * @param string                $new_STS_ID
269
-     * @param string                $old_STS_ID
270
-     * @param ContextInterface|null $context
271
-     * @throws EE_Error
272
-     * @throws InvalidArgumentException
273
-     * @throws InvalidDataTypeException
274
-     * @throws InvalidInterfaceException
275
-     * @throws ReflectionException
276
-     * @throws RuntimeException
277
-     */
278
-    private function updateIfCanceled(
279
-        array $closed_reg_statuses,
280
-        $new_STS_ID,
281
-        $old_STS_ID,
282
-        ContextInterface $context = null
283
-    ) {
284
-        // true if registration has been cancelled or declined
285
-        if (
286
-            in_array($new_STS_ID, $closed_reg_statuses, true)
287
-            && ! in_array($old_STS_ID, $closed_reg_statuses, true)
288
-        ) {
289
-            /** @type EE_Registration_Processor $registration_processor */
290
-            $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
291
-            /** @type EE_Transaction_Processor $transaction_processor */
292
-            $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
293
-            // cancelled or declined registration
294
-            $registration_processor->update_registration_after_being_canceled_or_declined(
295
-                $this,
296
-                $closed_reg_statuses
297
-            );
298
-            $transaction_processor->update_transaction_after_canceled_or_declined_registration(
299
-                $this,
300
-                $closed_reg_statuses,
301
-                false
302
-            );
303
-            do_action(
304
-                'AHEE__EE_Registration__set_status__canceled_or_declined',
305
-                $this,
306
-                $old_STS_ID,
307
-                $new_STS_ID,
308
-                $context
309
-            );
310
-            return;
311
-        }
312
-    }
313
-
314
-
315
-    /**
316
-     * update REGs and TXN when cancelled or declined registrations involved
317
-     *
318
-     * @param array                 $closed_reg_statuses
319
-     * @param string                $new_STS_ID
320
-     * @param string                $old_STS_ID
321
-     * @param ContextInterface|null $context
322
-     * @throws EE_Error
323
-     * @throws InvalidArgumentException
324
-     * @throws InvalidDataTypeException
325
-     * @throws InvalidInterfaceException
326
-     * @throws ReflectionException
327
-     * @throws RuntimeException
328
-     */
329
-    private function updateIfReinstated(
330
-        array $closed_reg_statuses,
331
-        $new_STS_ID,
332
-        $old_STS_ID,
333
-        ContextInterface $context = null
334
-    ) {
335
-        // true if reinstating cancelled or declined registration
336
-        if (
337
-            in_array($old_STS_ID, $closed_reg_statuses, true)
338
-            && ! in_array($new_STS_ID, $closed_reg_statuses, true)
339
-        ) {
340
-            /** @type EE_Registration_Processor $registration_processor */
341
-            $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
342
-            /** @type EE_Transaction_Processor $transaction_processor */
343
-            $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
344
-            // reinstating cancelled or declined registration
345
-            $registration_processor->update_canceled_or_declined_registration_after_being_reinstated(
346
-                $this,
347
-                $closed_reg_statuses
348
-            );
349
-            $transaction_processor->update_transaction_after_reinstating_canceled_registration(
350
-                $this,
351
-                $closed_reg_statuses,
352
-                false
353
-            );
354
-            do_action(
355
-                'AHEE__EE_Registration__set_status__after_reinstated',
356
-                $this,
357
-                $old_STS_ID,
358
-                $new_STS_ID,
359
-                $context
360
-            );
361
-        }
362
-    }
363
-
364
-
365
-    /**
366
-     * @param ContextInterface|null $context
367
-     * @return bool
368
-     */
369
-    private function statusChangeUpdatesTransaction(ContextInterface $context = null)
370
-    {
371
-        $contexts_that_do_not_update_transaction = (array) apply_filters(
372
-            'AHEE__EE_Registration__statusChangeUpdatesTransaction__contexts_that_do_not_update_transaction',
373
-            array('spco_reg_step_attendee_information_process_registrations'),
374
-            $context,
375
-            $this
376
-        );
377
-        return ! (
378
-            $context instanceof ContextInterface
379
-            && in_array($context->slug(), $contexts_that_do_not_update_transaction, true)
380
-        );
381
-    }
382
-
383
-
384
-    /**
385
-     * @throws EE_Error
386
-     * @throws EntityNotFoundException
387
-     * @throws InvalidArgumentException
388
-     * @throws InvalidDataTypeException
389
-     * @throws InvalidInterfaceException
390
-     * @throws ReflectionException
391
-     * @throws RuntimeException
392
-     */
393
-    private function updateTransactionAfterStatusChange()
394
-    {
395
-        /** @type EE_Transaction_Payments $transaction_payments */
396
-        $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
397
-        $transaction_payments->recalculate_transaction_total($this->transaction(), false);
398
-        $this->transaction()->update_status_based_on_total_paid();
399
-    }
400
-
401
-
402
-    /**
403
-     * get Status ID
404
-     *
405
-     * @throws EE_Error
406
-     * @throws InvalidArgumentException
407
-     * @throws InvalidDataTypeException
408
-     * @throws InvalidInterfaceException
409
-     * @throws ReflectionException
410
-     */
411
-    public function status_ID()
412
-    {
413
-        return $this->get('STS_ID');
414
-    }
415
-
416
-
417
-    /**
418
-     * Gets the ticket this registration is for
419
-     *
420
-     * @param boolean $include_archived whether to include archived tickets or not.
421
-     * @return EE_Ticket|EE_Base_Class
422
-     * @throws EE_Error
423
-     * @throws InvalidArgumentException
424
-     * @throws InvalidDataTypeException
425
-     * @throws InvalidInterfaceException
426
-     * @throws ReflectionException
427
-     */
428
-    public function ticket($include_archived = true)
429
-    {
430
-        $query_params = array();
431
-        if ($include_archived) {
432
-            $query_params['default_where_conditions'] = 'none';
433
-        }
434
-        return $this->get_first_related('Ticket', $query_params);
435
-    }
436
-
437
-
438
-    /**
439
-     * Gets the event this registration is for
440
-     *
441
-     * @return EE_Event
442
-     * @throws EE_Error
443
-     * @throws EntityNotFoundException
444
-     * @throws InvalidArgumentException
445
-     * @throws InvalidDataTypeException
446
-     * @throws InvalidInterfaceException
447
-     * @throws ReflectionException
448
-     */
449
-    public function event()
450
-    {
451
-        $event = $this->get_first_related('Event');
452
-        if (! $event instanceof \EE_Event) {
453
-            throw new EntityNotFoundException('Event ID', $this->event_ID());
454
-        }
455
-        return $event;
456
-    }
457
-
458
-
459
-    /**
460
-     * Gets the "author" of the registration.  Note that for the purposes of registrations, the author will correspond
461
-     * with the author of the event this registration is for.
462
-     *
463
-     * @since 4.5.0
464
-     * @return int
465
-     * @throws EE_Error
466
-     * @throws EntityNotFoundException
467
-     * @throws InvalidArgumentException
468
-     * @throws InvalidDataTypeException
469
-     * @throws InvalidInterfaceException
470
-     * @throws ReflectionException
471
-     */
472
-    public function wp_user()
473
-    {
474
-        $event = $this->event();
475
-        if ($event instanceof EE_Event) {
476
-            return $event->wp_user();
477
-        }
478
-        return 0;
479
-    }
480
-
481
-
482
-    /**
483
-     * increments this registration's related ticket sold and corresponding datetime sold values
484
-     *
485
-     * @return void
486
-     * @throws DomainException
487
-     * @throws EE_Error
488
-     * @throws EntityNotFoundException
489
-     * @throws InvalidArgumentException
490
-     * @throws InvalidDataTypeException
491
-     * @throws InvalidInterfaceException
492
-     * @throws ReflectionException
493
-     * @throws UnexpectedEntityException
494
-     */
495
-    private function reserveRegistrationSpace()
496
-    {
497
-        // reserved ticket and datetime counts will be decremented as sold counts are incremented
498
-        // so stop tracking that this reg has a ticket reserved
499
-        $this->release_reserved_ticket(false, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
500
-        $ticket = $this->ticket();
501
-        $ticket->increaseSold();
502
-        // possibly set event status to sold out
503
-        $this->event()->perform_sold_out_status_check();
504
-    }
505
-
506
-
507
-    /**
508
-     * decrements (subtracts) this registration's related ticket sold and corresponding datetime sold values
509
-     *
510
-     * @return void
511
-     * @throws DomainException
512
-     * @throws EE_Error
513
-     * @throws EntityNotFoundException
514
-     * @throws InvalidArgumentException
515
-     * @throws InvalidDataTypeException
516
-     * @throws InvalidInterfaceException
517
-     * @throws ReflectionException
518
-     * @throws UnexpectedEntityException
519
-     */
520
-    private function releaseRegistrationSpace()
521
-    {
522
-        $ticket = $this->ticket();
523
-        $ticket->decreaseSold();
524
-        // possibly change event status from sold out back to previous status
525
-        $this->event()->perform_sold_out_status_check();
526
-    }
527
-
528
-
529
-    /**
530
-     * tracks this registration's ticket reservation in extra meta
531
-     * and can increment related ticket reserved and corresponding datetime reserved values
532
-     *
533
-     * @param bool   $update_ticket if true, will increment ticket and datetime reserved count
534
-     * @param string $source
535
-     * @return void
536
-     * @throws EE_Error
537
-     * @throws InvalidArgumentException
538
-     * @throws InvalidDataTypeException
539
-     * @throws InvalidInterfaceException
540
-     * @throws ReflectionException
541
-     */
542
-    public function reserve_ticket($update_ticket = false, $source = 'unknown')
543
-    {
544
-        // only reserve ticket if space is not currently reserved
545
-        if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) !== true) {
546
-            $reserved = $this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true);
547
-            if ($reserved && $update_ticket) {
548
-                $ticket = $this->ticket();
549
-                $ticket->increaseReserved(1, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
550
-                $this->update_extra_meta('reserve_ticket', "{$this->ticket_ID()} from {$source}");
551
-                $ticket->save();
552
-            }
553
-        }
554
-    }
555
-
556
-
557
-    /**
558
-     * stops tracking this registration's ticket reservation in extra meta
559
-     * decrements (subtracts) related ticket reserved and corresponding datetime reserved values
560
-     *
561
-     * @param bool   $update_ticket if true, will decrement ticket and datetime reserved count
562
-     * @param string $source
563
-     * @return void
564
-     * @throws EE_Error
565
-     * @throws InvalidArgumentException
566
-     * @throws InvalidDataTypeException
567
-     * @throws InvalidInterfaceException
568
-     * @throws ReflectionException
569
-     */
570
-    public function release_reserved_ticket($update_ticket = false, $source = 'unknown')
571
-    {
572
-        // only release ticket if space is currently reserved
573
-        if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) === true) {
574
-            $reserved = $this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, false);
575
-            if ($reserved && $update_ticket) {
576
-                $ticket = $this->ticket();
577
-                $ticket->decreaseReserved(1, true, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
578
-                $this->update_extra_meta('release_reserved_ticket', "{$this->ticket_ID()} from {$source}");
579
-            }
580
-        }
581
-    }
582
-
583
-
584
-    /**
585
-     * Set Attendee ID
586
-     *
587
-     * @param        int $ATT_ID Attendee ID
588
-     * @throws DomainException
589
-     * @throws EE_Error
590
-     * @throws EntityNotFoundException
591
-     * @throws InvalidArgumentException
592
-     * @throws InvalidDataTypeException
593
-     * @throws InvalidInterfaceException
594
-     * @throws ReflectionException
595
-     * @throws RuntimeException
596
-     * @throws UnexpectedEntityException
597
-     */
598
-    public function set_attendee_id($ATT_ID = 0)
599
-    {
600
-        $this->set('ATT_ID', $ATT_ID);
601
-    }
602
-
603
-
604
-    /**
605
-     *        Set Transaction ID
606
-     *
607
-     * @param        int $TXN_ID Transaction ID
608
-     * @throws DomainException
609
-     * @throws EE_Error
610
-     * @throws EntityNotFoundException
611
-     * @throws InvalidArgumentException
612
-     * @throws InvalidDataTypeException
613
-     * @throws InvalidInterfaceException
614
-     * @throws ReflectionException
615
-     * @throws RuntimeException
616
-     * @throws UnexpectedEntityException
617
-     */
618
-    public function set_transaction_id($TXN_ID = 0)
619
-    {
620
-        $this->set('TXN_ID', $TXN_ID);
621
-    }
622
-
623
-
624
-    /**
625
-     *        Set Session
626
-     *
627
-     * @param    string $REG_session PHP Session ID
628
-     * @throws DomainException
629
-     * @throws EE_Error
630
-     * @throws EntityNotFoundException
631
-     * @throws InvalidArgumentException
632
-     * @throws InvalidDataTypeException
633
-     * @throws InvalidInterfaceException
634
-     * @throws ReflectionException
635
-     * @throws RuntimeException
636
-     * @throws UnexpectedEntityException
637
-     */
638
-    public function set_session($REG_session = '')
639
-    {
640
-        $this->set('REG_session', $REG_session);
641
-    }
642
-
643
-
644
-    /**
645
-     *        Set Registration URL Link
646
-     *
647
-     * @param    string $REG_url_link Registration URL Link
648
-     * @throws DomainException
649
-     * @throws EE_Error
650
-     * @throws EntityNotFoundException
651
-     * @throws InvalidArgumentException
652
-     * @throws InvalidDataTypeException
653
-     * @throws InvalidInterfaceException
654
-     * @throws ReflectionException
655
-     * @throws RuntimeException
656
-     * @throws UnexpectedEntityException
657
-     */
658
-    public function set_reg_url_link($REG_url_link = '')
659
-    {
660
-        $this->set('REG_url_link', $REG_url_link);
661
-    }
662
-
663
-
664
-    /**
665
-     *        Set Attendee Counter
666
-     *
667
-     * @param        int $REG_count Primary Attendee
668
-     * @throws DomainException
669
-     * @throws EE_Error
670
-     * @throws EntityNotFoundException
671
-     * @throws InvalidArgumentException
672
-     * @throws InvalidDataTypeException
673
-     * @throws InvalidInterfaceException
674
-     * @throws ReflectionException
675
-     * @throws RuntimeException
676
-     * @throws UnexpectedEntityException
677
-     */
678
-    public function set_count($REG_count = 1)
679
-    {
680
-        $this->set('REG_count', $REG_count);
681
-    }
682
-
683
-
684
-    /**
685
-     *        Set Group Size
686
-     *
687
-     * @param        boolean $REG_group_size Group Registration
688
-     * @throws DomainException
689
-     * @throws EE_Error
690
-     * @throws EntityNotFoundException
691
-     * @throws InvalidArgumentException
692
-     * @throws InvalidDataTypeException
693
-     * @throws InvalidInterfaceException
694
-     * @throws ReflectionException
695
-     * @throws RuntimeException
696
-     * @throws UnexpectedEntityException
697
-     */
698
-    public function set_group_size($REG_group_size = false)
699
-    {
700
-        $this->set('REG_group_size', $REG_group_size);
701
-    }
702
-
703
-
704
-    /**
705
-     *    is_not_approved -  convenience method that returns TRUE if REG status ID ==
706
-     *    EEM_Registration::status_id_not_approved
707
-     *
708
-     * @return        boolean
709
-     * @throws EE_Error
710
-     * @throws InvalidArgumentException
711
-     * @throws InvalidDataTypeException
712
-     * @throws InvalidInterfaceException
713
-     * @throws ReflectionException
714
-     */
715
-    public function is_not_approved()
716
-    {
717
-        return $this->status_ID() === EEM_Registration::status_id_not_approved;
718
-    }
719
-
720
-
721
-    /**
722
-     *    is_pending_payment -  convenience method that returns TRUE if REG status ID ==
723
-     *    EEM_Registration::status_id_pending_payment
724
-     *
725
-     * @return        boolean
726
-     * @throws EE_Error
727
-     * @throws InvalidArgumentException
728
-     * @throws InvalidDataTypeException
729
-     * @throws InvalidInterfaceException
730
-     * @throws ReflectionException
731
-     */
732
-    public function is_pending_payment()
733
-    {
734
-        return $this->status_ID() === EEM_Registration::status_id_pending_payment;
735
-    }
736
-
737
-
738
-    /**
739
-     *    is_approved -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_approved
740
-     *
741
-     * @return        boolean
742
-     * @throws EE_Error
743
-     * @throws InvalidArgumentException
744
-     * @throws InvalidDataTypeException
745
-     * @throws InvalidInterfaceException
746
-     * @throws ReflectionException
747
-     */
748
-    public function is_approved()
749
-    {
750
-        return $this->status_ID() === EEM_Registration::status_id_approved;
751
-    }
752
-
753
-
754
-    /**
755
-     *    is_cancelled -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_cancelled
756
-     *
757
-     * @return        boolean
758
-     * @throws EE_Error
759
-     * @throws InvalidArgumentException
760
-     * @throws InvalidDataTypeException
761
-     * @throws InvalidInterfaceException
762
-     * @throws ReflectionException
763
-     */
764
-    public function is_cancelled()
765
-    {
766
-        return $this->status_ID() === EEM_Registration::status_id_cancelled;
767
-    }
768
-
769
-
770
-    /**
771
-     *    is_declined -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_declined
772
-     *
773
-     * @return        boolean
774
-     * @throws EE_Error
775
-     * @throws InvalidArgumentException
776
-     * @throws InvalidDataTypeException
777
-     * @throws InvalidInterfaceException
778
-     * @throws ReflectionException
779
-     */
780
-    public function is_declined()
781
-    {
782
-        return $this->status_ID() === EEM_Registration::status_id_declined;
783
-    }
784
-
785
-
786
-    /**
787
-     *    is_incomplete -  convenience method that returns TRUE if REG status ID ==
788
-     *    EEM_Registration::status_id_incomplete
789
-     *
790
-     * @return        boolean
791
-     * @throws EE_Error
792
-     * @throws InvalidArgumentException
793
-     * @throws InvalidDataTypeException
794
-     * @throws InvalidInterfaceException
795
-     * @throws ReflectionException
796
-     */
797
-    public function is_incomplete()
798
-    {
799
-        return $this->status_ID() === EEM_Registration::status_id_incomplete;
800
-    }
801
-
802
-
803
-    /**
804
-     *        Set Registration Date
805
-     *
806
-     * @param        mixed ( int or string ) $REG_date Registration Date - Unix timestamp or string representation of
807
-     *                                                 Date
808
-     * @throws DomainException
809
-     * @throws EE_Error
810
-     * @throws EntityNotFoundException
811
-     * @throws InvalidArgumentException
812
-     * @throws InvalidDataTypeException
813
-     * @throws InvalidInterfaceException
814
-     * @throws ReflectionException
815
-     * @throws RuntimeException
816
-     * @throws UnexpectedEntityException
817
-     */
818
-    public function set_reg_date($REG_date = false)
819
-    {
820
-        $this->set('REG_date', $REG_date);
821
-    }
822
-
823
-
824
-    /**
825
-     *    Set final price owing for this registration after all ticket/price modifications
826
-     *
827
-     * @param    float $REG_final_price
828
-     * @throws DomainException
829
-     * @throws EE_Error
830
-     * @throws EntityNotFoundException
831
-     * @throws InvalidArgumentException
832
-     * @throws InvalidDataTypeException
833
-     * @throws InvalidInterfaceException
834
-     * @throws ReflectionException
835
-     * @throws RuntimeException
836
-     * @throws UnexpectedEntityException
837
-     */
838
-    public function set_final_price($REG_final_price = 0.00)
839
-    {
840
-        $this->set('REG_final_price', $REG_final_price);
841
-    }
842
-
843
-
844
-    /**
845
-     *    Set amount paid towards this registration's final price
846
-     *
847
-     * @param    float $REG_paid
848
-     * @throws DomainException
849
-     * @throws EE_Error
850
-     * @throws EntityNotFoundException
851
-     * @throws InvalidArgumentException
852
-     * @throws InvalidDataTypeException
853
-     * @throws InvalidInterfaceException
854
-     * @throws ReflectionException
855
-     * @throws RuntimeException
856
-     * @throws UnexpectedEntityException
857
-     */
858
-    public function set_paid($REG_paid = 0.00)
859
-    {
860
-        $this->set('REG_paid', $REG_paid);
861
-    }
862
-
863
-
864
-    /**
865
-     *        Attendee Is Going
866
-     *
867
-     * @param        boolean $REG_att_is_going Attendee Is Going
868
-     * @throws DomainException
869
-     * @throws EE_Error
870
-     * @throws EntityNotFoundException
871
-     * @throws InvalidArgumentException
872
-     * @throws InvalidDataTypeException
873
-     * @throws InvalidInterfaceException
874
-     * @throws ReflectionException
875
-     * @throws RuntimeException
876
-     * @throws UnexpectedEntityException
877
-     */
878
-    public function set_att_is_going($REG_att_is_going = false)
879
-    {
880
-        $this->set('REG_att_is_going', $REG_att_is_going);
881
-    }
882
-
883
-
884
-    /**
885
-     * Gets the related attendee
886
-     *
887
-     * @return EE_Attendee|EE_Base_Class
888
-     * @throws EE_Error
889
-     * @throws InvalidArgumentException
890
-     * @throws InvalidDataTypeException
891
-     * @throws InvalidInterfaceException
892
-     * @throws ReflectionException
893
-     */
894
-    public function attendee()
895
-    {
896
-        return $this->get_first_related('Attendee');
897
-    }
898
-
899
-    /**
900
-     * Gets the name of the attendee.
901
-     * @since 4.10.12.p
902
-     * @param bool $apply_html_entities set to true if you want to use HTML entities.
903
-     * @return string
904
-     * @throws EE_Error
905
-     * @throws InvalidArgumentException
906
-     * @throws InvalidDataTypeException
907
-     * @throws InvalidInterfaceException
908
-     * @throws ReflectionException
909
-     */
910
-    public function attendeeName($apply_html_entities = false)
911
-    {
912
-        $attendee = $this->get_first_related('Attendee');
913
-        if ($attendee instanceof EE_Attendee) {
914
-            $attendee_name = $attendee->full_name($apply_html_entities);
915
-        } else {
916
-            $attendee_name = esc_html__('Unknown', 'event_espresso');
917
-        }
918
-        return $attendee_name;
919
-    }
920
-
921
-
922
-    /**
923
-     *        get Event ID
924
-     */
925
-    public function event_ID()
926
-    {
927
-        return $this->get('EVT_ID');
928
-    }
929
-
930
-
931
-    /**
932
-     *        get Event ID
933
-     */
934
-    public function event_name()
935
-    {
936
-        $event = $this->event_obj();
937
-        if ($event) {
938
-            return $event->name();
939
-        } else {
940
-            return null;
941
-        }
942
-    }
943
-
944
-
945
-    /**
946
-     * Fetches the event this registration is for
947
-     *
948
-     * @return EE_Base_Class|EE_Event
949
-     * @throws EE_Error
950
-     * @throws InvalidArgumentException
951
-     * @throws InvalidDataTypeException
952
-     * @throws InvalidInterfaceException
953
-     * @throws ReflectionException
954
-     */
955
-    public function event_obj()
956
-    {
957
-        return $this->get_first_related('Event');
958
-    }
959
-
960
-
961
-    /**
962
-     *        get Attendee ID
963
-     */
964
-    public function attendee_ID()
965
-    {
966
-        return $this->get('ATT_ID');
967
-    }
968
-
969
-
970
-    /**
971
-     *        get PHP Session ID
972
-     */
973
-    public function session_ID()
974
-    {
975
-        return $this->get('REG_session');
976
-    }
977
-
978
-
979
-    /**
980
-     * Gets the string which represents the URL trigger for the receipt template in the message template system.
981
-     *
982
-     * @param string $messenger 'pdf' or 'html'.  Default 'html'.
983
-     * @return string
984
-     * @throws DomainException
985
-     * @throws EE_Error
986
-     * @throws InvalidArgumentException
987
-     * @throws InvalidDataTypeException
988
-     * @throws InvalidInterfaceException
989
-     * @throws ReflectionException
990
-     */
991
-    public function receipt_url($messenger = 'html')
992
-    {
993
-
994
-        /**
995
-         * The below will be deprecated one version after this.  We check first if there is a custom receipt template
996
-         * already in use on old system.  If there is then we just return the standard url for it.
997
-         *
998
-         * @since 4.5.0
999
-         */
1000
-        $template_relative_path = 'modules/gateways/Invoice/lib/templates/receipt_body.template.php';
1001
-        $has_custom = EEH_Template::locate_template(
1002
-            $template_relative_path,
1003
-            array(),
1004
-            true,
1005
-            true,
1006
-            true
1007
-        );
1008
-
1009
-        if ($has_custom) {
1010
-            return add_query_arg(array('receipt' => 'true'), $this->invoice_url('launch'));
1011
-        }
1012
-        return apply_filters('FHEE__EE_Registration__receipt_url__receipt_url', '', $this, $messenger, 'receipt');
1013
-    }
1014
-
1015
-
1016
-    /**
1017
-     * Gets the string which represents the URL trigger for the invoice template in the message template system.
1018
-     *
1019
-     * @param string $messenger 'pdf' or 'html'.  Default 'html'.
1020
-     * @return string
1021
-     * @throws DomainException
1022
-     * @throws EE_Error
1023
-     * @throws InvalidArgumentException
1024
-     * @throws InvalidDataTypeException
1025
-     * @throws InvalidInterfaceException
1026
-     * @throws ReflectionException
1027
-     */
1028
-    public function invoice_url($messenger = 'html')
1029
-    {
1030
-        /**
1031
-         * The below will be deprecated one version after this.  We check first if there is a custom invoice template
1032
-         * already in use on old system.  If there is then we just return the standard url for it.
1033
-         *
1034
-         * @since 4.5.0
1035
-         */
1036
-        $template_relative_path = 'modules/gateways/Invoice/lib/templates/invoice_body.template.php';
1037
-        $has_custom = EEH_Template::locate_template(
1038
-            $template_relative_path,
1039
-            array(),
1040
-            true,
1041
-            true,
1042
-            true
1043
-        );
1044
-
1045
-        if ($has_custom) {
1046
-            if ($messenger == 'html') {
1047
-                return $this->invoice_url('launch');
1048
-            }
1049
-            $route = $messenger == 'download' || $messenger == 'pdf' ? 'download_invoice' : 'launch_invoice';
1050
-
1051
-            $query_args = array('ee' => $route, 'id' => $this->reg_url_link());
1052
-            if ($messenger == 'html') {
1053
-                $query_args['html'] = true;
1054
-            }
1055
-            return add_query_arg($query_args, get_permalink(EE_Registry::instance()->CFG->core->thank_you_page_id));
1056
-        }
1057
-        return apply_filters('FHEE__EE_Registration__invoice_url__invoice_url', '', $this, $messenger, 'invoice');
1058
-    }
1059
-
1060
-
1061
-    /**
1062
-     * get Registration URL Link
1063
-     *
1064
-     * @return string
1065
-     * @throws EE_Error
1066
-     * @throws InvalidArgumentException
1067
-     * @throws InvalidDataTypeException
1068
-     * @throws InvalidInterfaceException
1069
-     * @throws ReflectionException
1070
-     */
1071
-    public function reg_url_link()
1072
-    {
1073
-        return (string) $this->get('REG_url_link');
1074
-    }
1075
-
1076
-
1077
-    /**
1078
-     * Echoes out invoice_url()
1079
-     *
1080
-     * @param string $type 'download','launch', or 'html' (default is 'launch')
1081
-     * @return void
1082
-     * @throws DomainException
1083
-     * @throws EE_Error
1084
-     * @throws InvalidArgumentException
1085
-     * @throws InvalidDataTypeException
1086
-     * @throws InvalidInterfaceException
1087
-     * @throws ReflectionException
1088
-     */
1089
-    public function e_invoice_url($type = 'launch')
1090
-    {
1091
-        echo esc_url_raw($this->invoice_url($type));
1092
-    }
1093
-
1094
-
1095
-    /**
1096
-     * Echoes out payment_overview_url
1097
-     */
1098
-    public function e_payment_overview_url()
1099
-    {
1100
-        echo esc_url_raw($this->payment_overview_url());
1101
-    }
1102
-
1103
-
1104
-    /**
1105
-     * Gets the URL for the checkout payment options reg step
1106
-     * with this registration's REG_url_link added as a query parameter
1107
-     *
1108
-     * @param bool $clear_session Set to true when you want to clear the session on revisiting the
1109
-     *                            payment overview url.
1110
-     * @return string
1111
-     * @throws EE_Error
1112
-     * @throws InvalidArgumentException
1113
-     * @throws InvalidDataTypeException
1114
-     * @throws InvalidInterfaceException
1115
-     * @throws ReflectionException
1116
-     */
1117
-    public function payment_overview_url($clear_session = false)
1118
-    {
1119
-        return add_query_arg(
1120
-            (array) apply_filters(
1121
-                'FHEE__EE_Registration__payment_overview_url__query_args',
1122
-                array(
1123
-                    'e_reg_url_link' => $this->reg_url_link(),
1124
-                    'step'           => 'payment_options',
1125
-                    'revisit'        => true,
1126
-                    'clear_session'  => (bool) $clear_session,
1127
-                ),
1128
-                $this
1129
-            ),
1130
-            EE_Registry::instance()->CFG->core->reg_page_url()
1131
-        );
1132
-    }
1133
-
1134
-
1135
-    /**
1136
-     * Gets the URL for the checkout attendee information reg step
1137
-     * with this registration's REG_url_link added as a query parameter
1138
-     *
1139
-     * @return string
1140
-     * @throws EE_Error
1141
-     * @throws InvalidArgumentException
1142
-     * @throws InvalidDataTypeException
1143
-     * @throws InvalidInterfaceException
1144
-     * @throws ReflectionException
1145
-     */
1146
-    public function edit_attendee_information_url()
1147
-    {
1148
-        return add_query_arg(
1149
-            (array) apply_filters(
1150
-                'FHEE__EE_Registration__edit_attendee_information_url__query_args',
1151
-                array(
1152
-                    'e_reg_url_link' => $this->reg_url_link(),
1153
-                    'step'           => 'attendee_information',
1154
-                    'revisit'        => true,
1155
-                ),
1156
-                $this
1157
-            ),
1158
-            EE_Registry::instance()->CFG->core->reg_page_url()
1159
-        );
1160
-    }
1161
-
1162
-
1163
-    /**
1164
-     * Simply generates and returns the appropriate admin_url link to edit this registration
1165
-     *
1166
-     * @return string
1167
-     * @throws EE_Error
1168
-     * @throws InvalidArgumentException
1169
-     * @throws InvalidDataTypeException
1170
-     * @throws InvalidInterfaceException
1171
-     * @throws ReflectionException
1172
-     */
1173
-    public function get_admin_edit_url()
1174
-    {
1175
-        return EEH_URL::add_query_args_and_nonce(
1176
-            array(
1177
-                'page'    => 'espresso_registrations',
1178
-                'action'  => 'view_registration',
1179
-                '_REG_ID' => $this->ID(),
1180
-            ),
1181
-            admin_url('admin.php')
1182
-        );
1183
-    }
1184
-
1185
-
1186
-    /**
1187
-     * is_primary_registrant?
1188
-     *
1189
-     * @throws EE_Error
1190
-     * @throws InvalidArgumentException
1191
-     * @throws InvalidDataTypeException
1192
-     * @throws InvalidInterfaceException
1193
-     * @throws ReflectionException
1194
-     */
1195
-    public function is_primary_registrant()
1196
-    {
1197
-        return (int) $this->get('REG_count') === 1;
1198
-    }
1199
-
1200
-
1201
-    /**
1202
-     * This returns the primary registration object for this registration group (which may be this object).
1203
-     *
1204
-     * @return EE_Registration
1205
-     * @throws EE_Error
1206
-     * @throws InvalidArgumentException
1207
-     * @throws InvalidDataTypeException
1208
-     * @throws InvalidInterfaceException
1209
-     * @throws ReflectionException
1210
-     */
1211
-    public function get_primary_registration()
1212
-    {
1213
-        if ($this->is_primary_registrant()) {
1214
-            return $this;
1215
-        }
1216
-
1217
-        // k reg_count !== 1 so let's get the EE_Registration object matching this txn_id and reg_count == 1
1218
-        /** @var EE_Registration $primary_registrant */
1219
-        $primary_registrant = EEM_Registration::instance()->get_one(
1220
-            array(
1221
-                array(
1222
-                    'TXN_ID'    => $this->transaction_ID(),
1223
-                    'REG_count' => 1,
1224
-                ),
1225
-            )
1226
-        );
1227
-        return $primary_registrant;
1228
-    }
1229
-
1230
-
1231
-    /**
1232
-     * get  Attendee Number
1233
-     *
1234
-     * @throws EE_Error
1235
-     * @throws InvalidArgumentException
1236
-     * @throws InvalidDataTypeException
1237
-     * @throws InvalidInterfaceException
1238
-     * @throws ReflectionException
1239
-     */
1240
-    public function count()
1241
-    {
1242
-        return $this->get('REG_count');
1243
-    }
1244
-
1245
-
1246
-    /**
1247
-     * get Group Size
1248
-     *
1249
-     * @throws EE_Error
1250
-     * @throws InvalidArgumentException
1251
-     * @throws InvalidDataTypeException
1252
-     * @throws InvalidInterfaceException
1253
-     * @throws ReflectionException
1254
-     */
1255
-    public function group_size()
1256
-    {
1257
-        return $this->get('REG_group_size');
1258
-    }
1259
-
1260
-
1261
-    /**
1262
-     * get Registration Date
1263
-     *
1264
-     * @throws EE_Error
1265
-     * @throws InvalidArgumentException
1266
-     * @throws InvalidDataTypeException
1267
-     * @throws InvalidInterfaceException
1268
-     * @throws ReflectionException
1269
-     */
1270
-    public function date()
1271
-    {
1272
-        return $this->get('REG_date');
1273
-    }
1274
-
1275
-
1276
-    /**
1277
-     * gets a pretty date
1278
-     *
1279
-     * @param string $date_format
1280
-     * @param string $time_format
1281
-     * @return string
1282
-     * @throws EE_Error
1283
-     * @throws InvalidArgumentException
1284
-     * @throws InvalidDataTypeException
1285
-     * @throws InvalidInterfaceException
1286
-     * @throws ReflectionException
1287
-     */
1288
-    public function pretty_date($date_format = null, $time_format = null)
1289
-    {
1290
-        return $this->get_datetime('REG_date', $date_format, $time_format);
1291
-    }
1292
-
1293
-
1294
-    /**
1295
-     * final_price
1296
-     * the registration's share of the transaction total, so that the
1297
-     * sum of all the transaction's REG_final_prices equal the transaction's total
1298
-     *
1299
-     * @return float
1300
-     * @throws EE_Error
1301
-     * @throws InvalidArgumentException
1302
-     * @throws InvalidDataTypeException
1303
-     * @throws InvalidInterfaceException
1304
-     * @throws ReflectionException
1305
-     */
1306
-    public function final_price()
1307
-    {
1308
-        return $this->get('REG_final_price');
1309
-    }
1310
-
1311
-
1312
-    /**
1313
-     * pretty_final_price
1314
-     *  final price as formatted string, with correct decimal places and currency symbol
1315
-     *
1316
-     * @return string
1317
-     * @throws EE_Error
1318
-     * @throws InvalidArgumentException
1319
-     * @throws InvalidDataTypeException
1320
-     * @throws InvalidInterfaceException
1321
-     * @throws ReflectionException
1322
-     */
1323
-    public function pretty_final_price()
1324
-    {
1325
-        return $this->get_pretty('REG_final_price');
1326
-    }
1327
-
1328
-
1329
-    /**
1330
-     * get paid (yeah)
1331
-     *
1332
-     * @return float
1333
-     * @throws EE_Error
1334
-     * @throws InvalidArgumentException
1335
-     * @throws InvalidDataTypeException
1336
-     * @throws InvalidInterfaceException
1337
-     * @throws ReflectionException
1338
-     */
1339
-    public function paid()
1340
-    {
1341
-        return $this->get('REG_paid');
1342
-    }
1343
-
1344
-
1345
-    /**
1346
-     * pretty_paid
1347
-     *
1348
-     * @return float
1349
-     * @throws EE_Error
1350
-     * @throws InvalidArgumentException
1351
-     * @throws InvalidDataTypeException
1352
-     * @throws InvalidInterfaceException
1353
-     * @throws ReflectionException
1354
-     */
1355
-    public function pretty_paid()
1356
-    {
1357
-        return $this->get_pretty('REG_paid');
1358
-    }
1359
-
1360
-
1361
-    /**
1362
-     * owes_monies_and_can_pay
1363
-     * whether or not this registration has monies owing and it's' status allows payment
1364
-     *
1365
-     * @param array $requires_payment
1366
-     * @return bool
1367
-     * @throws EE_Error
1368
-     * @throws InvalidArgumentException
1369
-     * @throws InvalidDataTypeException
1370
-     * @throws InvalidInterfaceException
1371
-     * @throws ReflectionException
1372
-     */
1373
-    public function owes_monies_and_can_pay($requires_payment = array())
1374
-    {
1375
-        // these reg statuses require payment (if event is not free)
1376
-        $requires_payment = ! empty($requires_payment)
1377
-            ? $requires_payment
1378
-            : EEM_Registration::reg_statuses_that_allow_payment();
1379
-        if (
1380
-            $this->final_price() !== 0 &&
1381
-            $this->final_price() !== $this->paid() &&
1382
-            in_array($this->status_ID(), $requires_payment)
1383
-        ) {
1384
-            return true;
1385
-        }
1386
-        return false;
1387
-    }
1388
-
1389
-
1390
-    /**
1391
-     * Prints out the return value of $this->pretty_status()
1392
-     *
1393
-     * @param bool $show_icons
1394
-     * @return void
1395
-     * @throws EE_Error
1396
-     * @throws InvalidArgumentException
1397
-     * @throws InvalidDataTypeException
1398
-     * @throws InvalidInterfaceException
1399
-     * @throws ReflectionException
1400
-     */
1401
-    public function e_pretty_status($show_icons = false)
1402
-    {
1403
-        echo wp_kses($this->pretty_status($show_icons), AllowedTags::getAllowedTags());
1404
-    }
1405
-
1406
-
1407
-    /**
1408
-     * Returns a nice version of the status for displaying to customers
1409
-     *
1410
-     * @param bool $show_icons
1411
-     * @return string
1412
-     * @throws EE_Error
1413
-     * @throws InvalidArgumentException
1414
-     * @throws InvalidDataTypeException
1415
-     * @throws InvalidInterfaceException
1416
-     * @throws ReflectionException
1417
-     */
1418
-    public function pretty_status($show_icons = false)
1419
-    {
1420
-        $status = EEM_Status::instance()->localized_status(
1421
-            array($this->status_ID() => esc_html__('unknown', 'event_espresso')),
1422
-            false,
1423
-            'sentence'
1424
-        );
1425
-        $icon = '';
1426
-        switch ($this->status_ID()) {
1427
-            case EEM_Registration::status_id_approved:
1428
-                $icon = $show_icons
1429
-                    ? '<span class="dashicons dashicons-star-filled ee-icon-size-16 green-text"></span>'
1430
-                    : '';
1431
-                break;
1432
-            case EEM_Registration::status_id_pending_payment:
1433
-                $icon = $show_icons
1434
-                    ? '<span class="dashicons dashicons-star-half ee-icon-size-16 orange-text"></span>'
1435
-                    : '';
1436
-                break;
1437
-            case EEM_Registration::status_id_not_approved:
1438
-                $icon = $show_icons
1439
-                    ? '<span class="dashicons dashicons-marker ee-icon-size-16 orange-text"></span>'
1440
-                    : '';
1441
-                break;
1442
-            case EEM_Registration::status_id_cancelled:
1443
-                $icon = $show_icons
1444
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 lt-grey-text"></span>'
1445
-                    : '';
1446
-                break;
1447
-            case EEM_Registration::status_id_incomplete:
1448
-                $icon = $show_icons
1449
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 lt-orange-text"></span>'
1450
-                    : '';
1451
-                break;
1452
-            case EEM_Registration::status_id_declined:
1453
-                $icon = $show_icons
1454
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>'
1455
-                    : '';
1456
-                break;
1457
-            case EEM_Registration::status_id_wait_list:
1458
-                $icon = $show_icons
1459
-                    ? '<span class="dashicons dashicons-clipboard ee-icon-size-16 purple-text"></span>'
1460
-                    : '';
1461
-                break;
1462
-        }
1463
-        return $icon . $status[ $this->status_ID() ];
1464
-    }
1465
-
1466
-
1467
-    /**
1468
-     *        get Attendee Is Going
1469
-     */
1470
-    public function att_is_going()
1471
-    {
1472
-        return $this->get('REG_att_is_going');
1473
-    }
1474
-
1475
-
1476
-    /**
1477
-     * Gets related answers
1478
-     *
1479
-     * @param array $query_params @see
1480
-     *                            https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1481
-     * @return EE_Answer[]|EE_Base_Class[]
1482
-     * @throws EE_Error
1483
-     * @throws InvalidArgumentException
1484
-     * @throws InvalidDataTypeException
1485
-     * @throws InvalidInterfaceException
1486
-     * @throws ReflectionException
1487
-     */
1488
-    public function answers($query_params = null)
1489
-    {
1490
-        return $this->get_many_related('Answer', $query_params);
1491
-    }
1492
-
1493
-
1494
-    /**
1495
-     * Gets the registration's answer value to the specified question
1496
-     * (either the question's ID or a question object)
1497
-     *
1498
-     * @param EE_Question|int $question
1499
-     * @param bool            $pretty_value
1500
-     * @return array|string if pretty_value= true, the result will always be a string
1501
-     * (because the answer might be an array of answer values, so passing pretty_value=true
1502
-     * will convert it into some kind of string)
1503
-     * @throws EE_Error
1504
-     * @throws InvalidArgumentException
1505
-     * @throws InvalidDataTypeException
1506
-     * @throws InvalidInterfaceException
1507
-     */
1508
-    public function answer_value_to_question($question, $pretty_value = true)
1509
-    {
1510
-        $question_id = EEM_Question::instance()->ensure_is_ID($question);
1511
-        return EEM_Answer::instance()->get_answer_value_to_question($this, $question_id, $pretty_value);
1512
-    }
1513
-
1514
-
1515
-    /**
1516
-     * question_groups
1517
-     * returns an array of EE_Question_Group objects for this registration
1518
-     *
1519
-     * @return EE_Question_Group[]
1520
-     * @throws EE_Error
1521
-     * @throws InvalidArgumentException
1522
-     * @throws InvalidDataTypeException
1523
-     * @throws InvalidInterfaceException
1524
-     * @throws ReflectionException
1525
-     */
1526
-    public function question_groups()
1527
-    {
1528
-        return EEM_Event::instance()->get_question_groups_for_event($this->event_ID(), $this);
1529
-    }
1530
-
1531
-
1532
-    /**
1533
-     * count_question_groups
1534
-     * returns a count of the number of EE_Question_Group objects for this registration
1535
-     *
1536
-     * @return int
1537
-     * @throws EE_Error
1538
-     * @throws EntityNotFoundException
1539
-     * @throws InvalidArgumentException
1540
-     * @throws InvalidDataTypeException
1541
-     * @throws InvalidInterfaceException
1542
-     * @throws ReflectionException
1543
-     */
1544
-    public function count_question_groups()
1545
-    {
1546
-        return EEM_Event::instance()->count_related(
1547
-            $this->event_ID(),
1548
-            'Question_Group',
1549
-            [
1550
-                [
1551
-                    'Event_Question_Group.'
1552
-                    . EEM_Event_Question_Group::instance()->fieldNameForContext($this->is_primary_registrant()) => true,
1553
-                ]
1554
-            ]
1555
-        );
1556
-    }
1557
-
1558
-
1559
-    /**
1560
-     * Returns the registration date in the 'standard' string format
1561
-     * (function may be improved in the future to allow for different formats and timezones)
1562
-     *
1563
-     * @return string
1564
-     * @throws EE_Error
1565
-     * @throws InvalidArgumentException
1566
-     * @throws InvalidDataTypeException
1567
-     * @throws InvalidInterfaceException
1568
-     * @throws ReflectionException
1569
-     */
1570
-    public function reg_date()
1571
-    {
1572
-        return $this->get_datetime('REG_date');
1573
-    }
1574
-
1575
-
1576
-    /**
1577
-     * Gets the datetime-ticket for this registration (ie, it can be used to isolate
1578
-     * the ticket this registration purchased, or the datetime they have registered
1579
-     * to attend)
1580
-     *
1581
-     * @return EE_Base_Class|EE_Datetime_Ticket
1582
-     * @throws EE_Error
1583
-     * @throws InvalidArgumentException
1584
-     * @throws InvalidDataTypeException
1585
-     * @throws InvalidInterfaceException
1586
-     * @throws ReflectionException
1587
-     */
1588
-    public function datetime_ticket()
1589
-    {
1590
-        return $this->get_first_related('Datetime_Ticket');
1591
-    }
1592
-
1593
-
1594
-    /**
1595
-     * Sets the registration's datetime_ticket.
1596
-     *
1597
-     * @param EE_Datetime_Ticket $datetime_ticket
1598
-     * @return EE_Base_Class|EE_Datetime_Ticket
1599
-     * @throws EE_Error
1600
-     * @throws InvalidArgumentException
1601
-     * @throws InvalidDataTypeException
1602
-     * @throws InvalidInterfaceException
1603
-     * @throws ReflectionException
1604
-     */
1605
-    public function set_datetime_ticket($datetime_ticket)
1606
-    {
1607
-        return $this->_add_relation_to($datetime_ticket, 'Datetime_Ticket');
1608
-    }
1609
-
1610
-
1611
-    /**
1612
-     * Gets deleted
1613
-     *
1614
-     * @return bool
1615
-     * @throws EE_Error
1616
-     * @throws InvalidArgumentException
1617
-     * @throws InvalidDataTypeException
1618
-     * @throws InvalidInterfaceException
1619
-     * @throws ReflectionException
1620
-     */
1621
-    public function deleted()
1622
-    {
1623
-        return $this->get('REG_deleted');
1624
-    }
1625
-
1626
-
1627
-    /**
1628
-     * Sets deleted
1629
-     *
1630
-     * @param boolean $deleted
1631
-     * @return void
1632
-     * @throws DomainException
1633
-     * @throws EE_Error
1634
-     * @throws EntityNotFoundException
1635
-     * @throws InvalidArgumentException
1636
-     * @throws InvalidDataTypeException
1637
-     * @throws InvalidInterfaceException
1638
-     * @throws ReflectionException
1639
-     * @throws RuntimeException
1640
-     * @throws UnexpectedEntityException
1641
-     */
1642
-    public function set_deleted($deleted)
1643
-    {
1644
-        if ($deleted) {
1645
-            $this->delete(__METHOD__);
1646
-        } else {
1647
-            $this->restore(__METHOD__);
1648
-        }
1649
-    }
1650
-
1651
-
1652
-    /**
1653
-     * Get the status object of this object
1654
-     *
1655
-     * @return EE_Base_Class|EE_Status
1656
-     * @throws EE_Error
1657
-     * @throws InvalidArgumentException
1658
-     * @throws InvalidDataTypeException
1659
-     * @throws InvalidInterfaceException
1660
-     * @throws ReflectionException
1661
-     */
1662
-    public function status_obj()
1663
-    {
1664
-        return $this->get_first_related('Status');
1665
-    }
1666
-
1667
-
1668
-    /**
1669
-     * Returns the number of times this registration has checked into any of the datetimes
1670
-     * its available for
1671
-     *
1672
-     * @return int
1673
-     * @throws EE_Error
1674
-     * @throws InvalidArgumentException
1675
-     * @throws InvalidDataTypeException
1676
-     * @throws InvalidInterfaceException
1677
-     * @throws ReflectionException
1678
-     */
1679
-    public function count_checkins()
1680
-    {
1681
-        return $this->get_model()->count_related($this, 'Checkin');
1682
-    }
1683
-
1684
-
1685
-    /**
1686
-     * Returns the number of current Check-ins this registration is checked into for any of the datetimes the
1687
-     * registration is for.  Note, this is ONLY checked in (does not include checkedout)
1688
-     *
1689
-     * @return int
1690
-     * @throws EE_Error
1691
-     * @throws InvalidArgumentException
1692
-     * @throws InvalidDataTypeException
1693
-     * @throws InvalidInterfaceException
1694
-     * @throws ReflectionException
1695
-     */
1696
-    public function count_checkins_not_checkedout()
1697
-    {
1698
-        return $this->get_model()->count_related($this, 'Checkin', array(array('CHK_in' => 1)));
1699
-    }
1700
-
1701
-
1702
-    /**
1703
-     * The purpose of this method is simply to check whether this registration can checkin to the given datetime.
1704
-     *
1705
-     * @param int | EE_Datetime $DTT_OR_ID      The datetime the registration is being checked against
1706
-     * @param bool              $check_approved This is used to indicate whether the caller wants can_checkin to also
1707
-     *                                          consider registration status as well as datetime access.
1708
-     * @return bool
1709
-     * @throws EE_Error
1710
-     * @throws InvalidArgumentException
1711
-     * @throws InvalidDataTypeException
1712
-     * @throws InvalidInterfaceException
1713
-     * @throws ReflectionException
1714
-     */
1715
-    public function can_checkin($DTT_OR_ID, $check_approved = true)
1716
-    {
1717
-        $DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1718
-        // first check registration status
1719
-        if (! $DTT_ID || ($check_approved && ! $this->is_approved())) {
1720
-            return false;
1721
-        }
1722
-        // is there a datetime ticket that matches this dtt_ID?
1723
-        if (
1724
-            ! (EEM_Datetime_Ticket::instance()->exists(
1725
-                array(
1726
-                    array(
1727
-                        'TKT_ID' => $this->get('TKT_ID'),
1728
-                        'DTT_ID' => $DTT_ID,
1729
-                    ),
1730
-                )
1731
-            ))
1732
-        ) {
1733
-            return false;
1734
-        }
1735
-
1736
-        // final check is against TKT_uses
1737
-        return $this->verify_can_checkin_against_TKT_uses($DTT_ID);
1738
-    }
1739
-
1740
-
1741
-    /**
1742
-     * This method verifies whether the user can checkin for the given datetime considering the max uses value set on
1743
-     * the ticket. To do this,  a query is done to get the count of the datetime records already checked into.  If the
1744
-     * datetime given does not have a check-in record and checking in for that datetime will exceed the allowed uses,
1745
-     * then return false.  Otherwise return true.
1746
-     *
1747
-     * @param int | EE_Datetime $DTT_OR_ID The datetime the registration is being checked against
1748
-     * @return bool true means can checkin.  false means cannot checkin.
1749
-     * @throws EE_Error
1750
-     * @throws InvalidArgumentException
1751
-     * @throws InvalidDataTypeException
1752
-     * @throws InvalidInterfaceException
1753
-     * @throws ReflectionException
1754
-     */
1755
-    public function verify_can_checkin_against_TKT_uses($DTT_OR_ID)
1756
-    {
1757
-        $DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1758
-
1759
-        if (! $DTT_ID) {
1760
-            return false;
1761
-        }
1762
-
1763
-        $max_uses = $this->ticket() instanceof EE_Ticket ? $this->ticket()->uses() : EE_INF;
1764
-
1765
-        // if max uses is not set or equals infinity then return true cause its not a factor for whether user can
1766
-        // check-in or not.
1767
-        if (! $max_uses || $max_uses === EE_INF) {
1768
-            return true;
1769
-        }
1770
-
1771
-        // does this datetime have a checkin record?  If so, then the dtt count has already been verified so we can just
1772
-        // go ahead and toggle.
1773
-        if (EEM_Checkin::instance()->exists(array(array('REG_ID' => $this->ID(), 'DTT_ID' => $DTT_ID)))) {
1774
-            return true;
1775
-        }
1776
-
1777
-        // made it here so the last check is whether the number of checkins per unique datetime on this registration
1778
-        // disallows further check-ins.
1779
-        $count_unique_dtt_checkins = EEM_Checkin::instance()->count(
1780
-            array(
1781
-                array(
1782
-                    'REG_ID' => $this->ID(),
1783
-                    'CHK_in' => true,
1784
-                ),
1785
-            ),
1786
-            'DTT_ID',
1787
-            true
1788
-        );
1789
-        // checkins have already reached their max number of uses
1790
-        // so registrant can NOT checkin
1791
-        if ($count_unique_dtt_checkins >= $max_uses) {
1792
-            EE_Error::add_error(
1793
-                esc_html__(
1794
-                    'Check-in denied because number of datetime uses for the ticket has been reached or exceeded.',
1795
-                    'event_espresso'
1796
-                ),
1797
-                __FILE__,
1798
-                __FUNCTION__,
1799
-                __LINE__
1800
-            );
1801
-            return false;
1802
-        }
1803
-        return true;
1804
-    }
1805
-
1806
-
1807
-    /**
1808
-     * toggle Check-in status for this registration
1809
-     * Check-ins are toggled in the following order:
1810
-     * never checked in -> checked in
1811
-     * checked in -> checked out
1812
-     * checked out -> checked in
1813
-     *
1814
-     * @param  int $DTT_ID  include specific datetime to toggle Check-in for.
1815
-     *                      If not included or null, then it is assumed latest datetime is being toggled.
1816
-     * @param bool $verify  If true then can_checkin() is used to verify whether the person
1817
-     *                      can be checked in or not.  Otherwise this forces change in checkin status.
1818
-     * @return bool|int     the chk_in status toggled to OR false if nothing got changed.
1819
-     * @throws EE_Error
1820
-     * @throws InvalidArgumentException
1821
-     * @throws InvalidDataTypeException
1822
-     * @throws InvalidInterfaceException
1823
-     * @throws ReflectionException
1824
-     */
1825
-    public function toggle_checkin_status($DTT_ID = null, $verify = false)
1826
-    {
1827
-        if (empty($DTT_ID)) {
1828
-            $datetime = $this->get_latest_related_datetime();
1829
-            $DTT_ID = $datetime instanceof EE_Datetime ? $datetime->ID() : 0;
1830
-            // verify the registration can checkin for the given DTT_ID
1831
-        } elseif (! $this->can_checkin($DTT_ID, $verify)) {
1832
-            EE_Error::add_error(
1833
-                sprintf(
1834
-                    esc_html__(
1835
-                        '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',
1836
-                        'event_espresso'
1837
-                    ),
1838
-                    $this->ID(),
1839
-                    $DTT_ID
1840
-                ),
1841
-                __FILE__,
1842
-                __FUNCTION__,
1843
-                __LINE__
1844
-            );
1845
-            return false;
1846
-        }
1847
-        $status_paths = array(
1848
-            EE_Checkin::status_checked_never => EE_Checkin::status_checked_in,
1849
-            EE_Checkin::status_checked_in    => EE_Checkin::status_checked_out,
1850
-            EE_Checkin::status_checked_out   => EE_Checkin::status_checked_in,
1851
-        );
1852
-        // start by getting the current status so we know what status we'll be changing to.
1853
-        $cur_status = $this->check_in_status_for_datetime($DTT_ID);
1854
-        $status_to = $status_paths[ $cur_status ];
1855
-        // database only records true for checked IN or false for checked OUT
1856
-        // no record ( null ) means checked in NEVER, but we obviously don't save that
1857
-        $new_status = $status_to === EE_Checkin::status_checked_in;
1858
-        // add relation - note Check-ins are always creating new rows
1859
-        // because we are keeping track of Check-ins over time.
1860
-        // Eventually we'll probably want to show a list table
1861
-        // for the individual Check-ins so that they can be managed.
1862
-        $checkin = EE_Checkin::new_instance(
1863
-            array(
1864
-                'REG_ID' => $this->ID(),
1865
-                'DTT_ID' => $DTT_ID,
1866
-                'CHK_in' => $new_status,
1867
-            )
1868
-        );
1869
-        // if the record could not be saved then return false
1870
-        if ($checkin->save() === 0) {
1871
-            if (WP_DEBUG) {
1872
-                global $wpdb;
1873
-                $error = sprintf(
1874
-                    esc_html__(
1875
-                        'Registration check in update failed because of the following database error: %1$s%2$s',
1876
-                        'event_espresso'
1877
-                    ),
1878
-                    '<br />',
1879
-                    $wpdb->last_error
1880
-                );
1881
-            } else {
1882
-                $error = esc_html__(
1883
-                    'Registration check in update failed because of an unknown database error',
1884
-                    'event_espresso'
1885
-                );
1886
-            }
1887
-            EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
1888
-            return false;
1889
-        }
1890
-        // Fire a checked_in and checkout_out action.
1891
-        $checked_status = $status_to === EE_Checkin::status_checked_in ? 'checked_in' : 'checked_out';
1892
-        do_action("AHEE__EE_Registration__toggle_checkin_status__{$checked_status}", $this, $DTT_ID);
1893
-        return $status_to;
1894
-    }
1895
-
1896
-
1897
-    /**
1898
-     * Returns the latest datetime related to this registration (via the ticket attached to the registration).
1899
-     * "Latest" is defined by the `DTT_EVT_start` column.
1900
-     *
1901
-     * @return EE_Datetime|null
1902
-     * @throws EE_Error
1903
-     * @throws InvalidArgumentException
1904
-     * @throws InvalidDataTypeException
1905
-     * @throws InvalidInterfaceException
1906
-     * @throws ReflectionException
1907
-     */
1908
-    public function get_latest_related_datetime()
1909
-    {
1910
-        return EEM_Datetime::instance()->get_one(
1911
-            array(
1912
-                array(
1913
-                    'Ticket.Registration.REG_ID' => $this->ID(),
1914
-                ),
1915
-                'order_by' => array('DTT_EVT_start' => 'DESC'),
1916
-            )
1917
-        );
1918
-    }
1919
-
1920
-
1921
-    /**
1922
-     * Returns the earliest datetime related to this registration (via the ticket attached to the registration).
1923
-     * "Earliest" is defined by the `DTT_EVT_start` column.
1924
-     *
1925
-     * @return EE_Base_Class|EE_Soft_Delete_Base_Class|NULL
1926
-     * @throws EE_Error
1927
-     * @throws InvalidArgumentException
1928
-     * @throws InvalidDataTypeException
1929
-     * @throws InvalidInterfaceException
1930
-     * @throws ReflectionException
1931
-     */
1932
-    public function get_earliest_related_datetime()
1933
-    {
1934
-        return EEM_Datetime::instance()->get_one(
1935
-            array(
1936
-                array(
1937
-                    'Ticket.Registration.REG_ID' => $this->ID(),
1938
-                ),
1939
-                'order_by' => array('DTT_EVT_start' => 'ASC'),
1940
-            )
1941
-        );
1942
-    }
1943
-
1944
-
1945
-    /**
1946
-     * This method simply returns the check-in status for this registration and the given datetime.
1947
-     * If neither the datetime nor the checkin values are provided as arguments,
1948
-     * then this will return the LATEST check-in status for the registration across all datetimes it belongs to.
1949
-     *
1950
-     * @param  int       $DTT_ID  The ID of the datetime we're checking against
1951
-     *                            (if empty we'll get the primary datetime for
1952
-     *                            this registration (via event) and use it's ID);
1953
-     * @param EE_Checkin $checkin If present, we use the given checkin object rather than the dtt_id.
1954
-     * @return int                Integer representing Check-in status.
1955
-     * @throws EE_Error
1956
-     * @throws InvalidArgumentException
1957
-     * @throws InvalidDataTypeException
1958
-     * @throws InvalidInterfaceException
1959
-     * @throws ReflectionException
1960
-     */
1961
-    public function check_in_status_for_datetime($DTT_ID = 0, $checkin = null)
1962
-    {
1963
-        $checkin_query_params = array(
1964
-            'order_by' => array('CHK_timestamp' => 'DESC'),
1965
-        );
1966
-
1967
-        if ($DTT_ID > 0) {
1968
-            $checkin_query_params[0] = array('DTT_ID' => $DTT_ID);
1969
-        }
1970
-
1971
-        // get checkin object (if exists)
1972
-        $checkin = $checkin instanceof EE_Checkin
1973
-            ? $checkin
1974
-            : $this->get_first_related('Checkin', $checkin_query_params);
1975
-        if ($checkin instanceof EE_Checkin) {
1976
-            if ($checkin->get('CHK_in')) {
1977
-                return EE_Checkin::status_checked_in; // checked in
1978
-            }
1979
-            return EE_Checkin::status_checked_out; // had checked in but is now checked out.
1980
-        }
1981
-        return EE_Checkin::status_checked_never; // never been checked in
1982
-    }
1983
-
1984
-
1985
-    /**
1986
-     * This method returns a localized message for the toggled Check-in message.
1987
-     *
1988
-     * @param  int $DTT_ID include specific datetime to get the correct Check-in message.  If not included or null,
1989
-     *                     then it is assumed Check-in for primary datetime was toggled.
1990
-     * @param bool $error  This just flags that you want an error message returned. This is put in so that the error
1991
-     *                     message can be customized with the attendee name.
1992
-     * @return string internationalized message
1993
-     * @throws EE_Error
1994
-     * @throws InvalidArgumentException
1995
-     * @throws InvalidDataTypeException
1996
-     * @throws InvalidInterfaceException
1997
-     * @throws ReflectionException
1998
-     */
1999
-    public function get_checkin_msg($DTT_ID, $error = false)
2000
-    {
2001
-        // let's get the attendee first so we can include the name of the attendee
2002
-        $attendee = $this->get_first_related('Attendee');
2003
-        if ($attendee instanceof EE_Attendee) {
2004
-            if ($error) {
2005
-                return sprintf(
2006
-                    esc_html__("%s's check-in status was not changed.", "event_espresso"),
2007
-                    $attendee->full_name()
2008
-                );
2009
-            }
2010
-            $cur_status = $this->check_in_status_for_datetime($DTT_ID);
2011
-            // what is the status message going to be?
2012
-            switch ($cur_status) {
2013
-                case EE_Checkin::status_checked_never:
2014
-                    return sprintf(
2015
-                        esc_html__('%s has been removed from Check-in records', 'event_espresso'),
2016
-                        $attendee->full_name()
2017
-                    );
2018
-                    break;
2019
-                case EE_Checkin::status_checked_in:
2020
-                    return sprintf(esc_html__('%s has been checked in', 'event_espresso'), $attendee->full_name());
2021
-                    break;
2022
-                case EE_Checkin::status_checked_out:
2023
-                    return sprintf(esc_html__('%s has been checked out', 'event_espresso'), $attendee->full_name());
2024
-                    break;
2025
-            }
2026
-        }
2027
-        return esc_html__('The check-in status could not be determined.', 'event_espresso');
2028
-    }
2029
-
2030
-
2031
-    /**
2032
-     * Returns the related EE_Transaction to this registration
2033
-     *
2034
-     * @return EE_Transaction
2035
-     * @throws EE_Error
2036
-     * @throws EntityNotFoundException
2037
-     * @throws InvalidArgumentException
2038
-     * @throws InvalidDataTypeException
2039
-     * @throws InvalidInterfaceException
2040
-     * @throws ReflectionException
2041
-     */
2042
-    public function transaction()
2043
-    {
2044
-        $transaction = $this->get_first_related('Transaction');
2045
-        if (! $transaction instanceof \EE_Transaction) {
2046
-            throw new EntityNotFoundException('Transaction ID', $this->transaction_ID());
2047
-        }
2048
-        return $transaction;
2049
-    }
2050
-
2051
-
2052
-    /**
2053
-     * get Registration Code
2054
-     *
2055
-     * @return mixed
2056
-     * @throws EE_Error
2057
-     * @throws InvalidArgumentException
2058
-     * @throws InvalidDataTypeException
2059
-     * @throws InvalidInterfaceException
2060
-     * @throws ReflectionException
2061
-     */
2062
-    public function reg_code()
2063
-    {
2064
-        return $this->get('REG_code');
2065
-    }
2066
-
2067
-
2068
-    /**
2069
-     * @return mixed
2070
-     * @throws EE_Error
2071
-     * @throws InvalidArgumentException
2072
-     * @throws InvalidDataTypeException
2073
-     * @throws InvalidInterfaceException
2074
-     * @throws ReflectionException
2075
-     */
2076
-    public function transaction_ID()
2077
-    {
2078
-        return $this->get('TXN_ID');
2079
-    }
2080
-
2081
-
2082
-    /**
2083
-     * @return int
2084
-     * @throws EE_Error
2085
-     * @throws InvalidArgumentException
2086
-     * @throws InvalidDataTypeException
2087
-     * @throws InvalidInterfaceException
2088
-     * @throws ReflectionException
2089
-     */
2090
-    public function ticket_ID()
2091
-    {
2092
-        return $this->get('TKT_ID');
2093
-    }
2094
-
2095
-
2096
-    /**
2097
-     * Set Registration Code
2098
-     *
2099
-     * @param    string  $REG_code Registration Code
2100
-     * @param    boolean $use_default
2101
-     * @throws EE_Error
2102
-     * @throws InvalidArgumentException
2103
-     * @throws InvalidDataTypeException
2104
-     * @throws InvalidInterfaceException
2105
-     * @throws ReflectionException
2106
-     */
2107
-    public function set_reg_code($REG_code, $use_default = false)
2108
-    {
2109
-        if (empty($REG_code)) {
2110
-            EE_Error::add_error(
2111
-                esc_html__('REG_code can not be empty.', 'event_espresso'),
2112
-                __FILE__,
2113
-                __FUNCTION__,
2114
-                __LINE__
2115
-            );
2116
-            return;
2117
-        }
2118
-        if (! $this->reg_code()) {
2119
-            parent::set('REG_code', $REG_code, $use_default);
2120
-        } else {
2121
-            EE_Error::doing_it_wrong(
2122
-                __CLASS__ . '::' . __FUNCTION__,
2123
-                esc_html__('Can not change a registration REG_code once it has been set.', 'event_espresso'),
2124
-                '4.6.0'
2125
-            );
2126
-        }
2127
-    }
2128
-
2129
-
2130
-    /**
2131
-     * Returns all other registrations in the same group as this registrant who have the same ticket option.
2132
-     * Note, if you want to just get all registrations in the same transaction (group), use:
2133
-     *    $registration->transaction()->registrations();
2134
-     *
2135
-     * @since 4.5.0
2136
-     * @return EE_Registration[] or empty array if this isn't a group registration.
2137
-     * @throws EE_Error
2138
-     * @throws InvalidArgumentException
2139
-     * @throws InvalidDataTypeException
2140
-     * @throws InvalidInterfaceException
2141
-     * @throws ReflectionException
2142
-     */
2143
-    public function get_all_other_registrations_in_group()
2144
-    {
2145
-        if ($this->group_size() < 2) {
2146
-            return array();
2147
-        }
2148
-
2149
-        $query[0] = array(
2150
-            'TXN_ID' => $this->transaction_ID(),
2151
-            'REG_ID' => array('!=', $this->ID()),
2152
-            'TKT_ID' => $this->ticket_ID(),
2153
-        );
2154
-        /** @var EE_Registration[] $registrations */
2155
-        $registrations = $this->get_model()->get_all($query);
2156
-        return $registrations;
2157
-    }
2158
-
2159
-
2160
-    /**
2161
-     * Return the link to the admin details for the object.
2162
-     *
2163
-     * @return string
2164
-     * @throws EE_Error
2165
-     * @throws InvalidArgumentException
2166
-     * @throws InvalidDataTypeException
2167
-     * @throws InvalidInterfaceException
2168
-     * @throws ReflectionException
2169
-     */
2170
-    public function get_admin_details_link()
2171
-    {
2172
-        EE_Registry::instance()->load_helper('URL');
2173
-        return EEH_URL::add_query_args_and_nonce(
2174
-            array(
2175
-                'page'    => 'espresso_registrations',
2176
-                'action'  => 'view_registration',
2177
-                '_REG_ID' => $this->ID(),
2178
-            ),
2179
-            admin_url('admin.php')
2180
-        );
2181
-    }
2182
-
2183
-
2184
-    /**
2185
-     * Returns the link to the editor for the object.  Sometimes this is the same as the details.
2186
-     *
2187
-     * @return string
2188
-     * @throws EE_Error
2189
-     * @throws InvalidArgumentException
2190
-     * @throws InvalidDataTypeException
2191
-     * @throws InvalidInterfaceException
2192
-     * @throws ReflectionException
2193
-     */
2194
-    public function get_admin_edit_link()
2195
-    {
2196
-        return $this->get_admin_details_link();
2197
-    }
2198
-
2199
-
2200
-    /**
2201
-     * Returns the link to a settings page for the object.
2202
-     *
2203
-     * @return string
2204
-     * @throws EE_Error
2205
-     * @throws InvalidArgumentException
2206
-     * @throws InvalidDataTypeException
2207
-     * @throws InvalidInterfaceException
2208
-     * @throws ReflectionException
2209
-     */
2210
-    public function get_admin_settings_link()
2211
-    {
2212
-        return $this->get_admin_details_link();
2213
-    }
2214
-
2215
-
2216
-    /**
2217
-     * Returns the link to the "overview" for the object (typically the "list table" view).
2218
-     *
2219
-     * @return string
2220
-     * @throws EE_Error
2221
-     * @throws InvalidArgumentException
2222
-     * @throws InvalidDataTypeException
2223
-     * @throws InvalidInterfaceException
2224
-     * @throws ReflectionException
2225
-     */
2226
-    public function get_admin_overview_link()
2227
-    {
2228
-        EE_Registry::instance()->load_helper('URL');
2229
-        return EEH_URL::add_query_args_and_nonce(
2230
-            array(
2231
-                'page' => 'espresso_registrations',
2232
-            ),
2233
-            admin_url('admin.php')
2234
-        );
2235
-    }
2236
-
2237
-
2238
-    /**
2239
-     * @param array $query_params
2240
-     * @return EE_Base_Class[]|EE_Registration[]
2241
-     * @throws EE_Error
2242
-     * @throws InvalidArgumentException
2243
-     * @throws InvalidDataTypeException
2244
-     * @throws InvalidInterfaceException
2245
-     * @throws ReflectionException
2246
-     */
2247
-    public function payments($query_params = array())
2248
-    {
2249
-        return $this->get_many_related('Payment', $query_params);
2250
-    }
2251
-
2252
-
2253
-    /**
2254
-     * @param array $query_params
2255
-     * @return EE_Base_Class[]|EE_Registration_Payment[]
2256
-     * @throws EE_Error
2257
-     * @throws InvalidArgumentException
2258
-     * @throws InvalidDataTypeException
2259
-     * @throws InvalidInterfaceException
2260
-     * @throws ReflectionException
2261
-     */
2262
-    public function registration_payments($query_params = array())
2263
-    {
2264
-        return $this->get_many_related('Registration_Payment', $query_params);
2265
-    }
2266
-
2267
-
2268
-    /**
2269
-     * This grabs the payment method corresponding to the last payment made for the amount owing on the registration.
2270
-     * Note: if there are no payments on the registration there will be no payment method returned.
2271
-     *
2272
-     * @return EE_Payment|EE_Payment_Method|null
2273
-     * @throws EE_Error
2274
-     * @throws InvalidArgumentException
2275
-     * @throws InvalidDataTypeException
2276
-     * @throws InvalidInterfaceException
2277
-     */
2278
-    public function payment_method()
2279
-    {
2280
-        return EEM_Payment_Method::instance()->get_last_used_for_registration($this);
2281
-    }
2282
-
2283
-
2284
-    /**
2285
-     * @return \EE_Line_Item
2286
-     * @throws EE_Error
2287
-     * @throws EntityNotFoundException
2288
-     * @throws InvalidArgumentException
2289
-     * @throws InvalidDataTypeException
2290
-     * @throws InvalidInterfaceException
2291
-     * @throws ReflectionException
2292
-     */
2293
-    public function ticket_line_item()
2294
-    {
2295
-        $ticket = $this->ticket();
2296
-        $transaction = $this->transaction();
2297
-        $line_item = null;
2298
-        $ticket_line_items = \EEH_Line_Item::get_line_items_by_object_type_and_IDs(
2299
-            $transaction->total_line_item(),
2300
-            'Ticket',
2301
-            array($ticket->ID())
2302
-        );
2303
-        foreach ($ticket_line_items as $ticket_line_item) {
2304
-            if (
2305
-                $ticket_line_item instanceof \EE_Line_Item
2306
-                && $ticket_line_item->OBJ_type() === 'Ticket'
2307
-                && $ticket_line_item->OBJ_ID() === $ticket->ID()
2308
-            ) {
2309
-                $line_item = $ticket_line_item;
2310
-                break;
2311
-            }
2312
-        }
2313
-        if (! ($line_item instanceof \EE_Line_Item && $line_item->OBJ_type() === 'Ticket')) {
2314
-            throw new EntityNotFoundException('Line Item Ticket ID', $ticket->ID());
2315
-        }
2316
-        return $line_item;
2317
-    }
2318
-
2319
-
2320
-    /**
2321
-     * Soft Deletes this model object.
2322
-     *
2323
-     * @param string $source function name that called this method
2324
-     * @return boolean | int
2325
-     * @throws DomainException
2326
-     * @throws EE_Error
2327
-     * @throws EntityNotFoundException
2328
-     * @throws InvalidArgumentException
2329
-     * @throws InvalidDataTypeException
2330
-     * @throws InvalidInterfaceException
2331
-     * @throws ReflectionException
2332
-     * @throws RuntimeException
2333
-     * @throws UnexpectedEntityException
2334
-     */
2335
-    public function delete($source = 'unknown')
2336
-    {
2337
-        if ($this->update_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY, $this->status_ID()) === true) {
2338
-            $current_user = wp_get_current_user();
2339
-            $this->add_extra_meta(
2340
-                EE_Registration::EXTRA_META_KEY_REG_TRASHED,
2341
-                array(
2342
-                    'trashed-by' => $current_user->ID ? $current_user->display_name : 'unauthed user',
2343
-                    'timestamp'  => time(),
2344
-                    'source'     => $source,
2345
-                )
2346
-            );
2347
-            $this->set_status(EEM_Registration::status_id_cancelled);
2348
-        }
2349
-        return parent::delete();
2350
-    }
2351
-
2352
-
2353
-    /**
2354
-     * Restores whatever the previous status was on a registration before it was trashed (if possible)
2355
-     *
2356
-     * @param string $source function name that called this method
2357
-     * @return bool|int
2358
-     * @throws DomainException
2359
-     * @throws EE_Error
2360
-     * @throws EntityNotFoundException
2361
-     * @throws InvalidArgumentException
2362
-     * @throws InvalidDataTypeException
2363
-     * @throws InvalidInterfaceException
2364
-     * @throws ReflectionException
2365
-     * @throws RuntimeException
2366
-     * @throws UnexpectedEntityException
2367
-     */
2368
-    public function restore($source = 'unknown')
2369
-    {
2370
-        $previous_status = $this->get_extra_meta(
2371
-            EE_Registration::PRE_TRASH_REG_STATUS_KEY,
2372
-            true,
2373
-            EEM_Registration::status_id_cancelled
2374
-        );
2375
-        if ($previous_status) {
2376
-            $this->delete_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY);
2377
-            $this->set_status($previous_status);
2378
-        }
2379
-        $current_user = wp_get_current_user();
2380
-        $this->add_extra_meta(
2381
-            EE_Registration::EXTRA_META_KEY_REG_RESTORED,
2382
-            array(
2383
-                'restored-by' => $current_user->ID ? $current_user->display_name : 'unauthed user',
2384
-                'timestamp'   => time(),
2385
-                'source'      => $source,
2386
-            )
2387
-        );
2388
-        return parent::restore();
2389
-    }
2390
-
2391
-
2392
-    /**
2393
-     * possibly toggle Registration status based on comparison of REG_paid vs REG_final_price
2394
-     *
2395
-     * @param  boolean $trigger_set_status_logic EE_Registration::set_status() can trigger additional logic
2396
-     *                                           depending on whether the reg status changes to or from "Approved"
2397
-     * @return boolean whether the Registration status was updated
2398
-     * @throws DomainException
2399
-     * @throws EE_Error
2400
-     * @throws EntityNotFoundException
2401
-     * @throws InvalidArgumentException
2402
-     * @throws InvalidDataTypeException
2403
-     * @throws InvalidInterfaceException
2404
-     * @throws ReflectionException
2405
-     * @throws RuntimeException
2406
-     * @throws UnexpectedEntityException
2407
-     */
2408
-    public function updateStatusBasedOnTotalPaid($trigger_set_status_logic = true)
2409
-    {
2410
-        $paid = $this->paid();
2411
-        $price = $this->final_price();
2412
-        switch (true) {
2413
-            // overpaid or paid
2414
-            case EEH_Money::compare_floats($paid, $price, '>'):
2415
-            case EEH_Money::compare_floats($paid, $price):
2416
-                $new_status = EEM_Registration::status_id_approved;
2417
-                break;
2418
-            //  underpaid
2419
-            case EEH_Money::compare_floats($paid, $price, '<'):
2420
-                $new_status = EEM_Registration::status_id_pending_payment;
2421
-                break;
2422
-            // uhhh Houston...
2423
-            default:
2424
-                throw new RuntimeException(
2425
-                    esc_html__('The total paid calculation for this registration is inaccurate.', 'event_espresso')
2426
-                );
2427
-        }
2428
-        if ($new_status !== $this->status_ID()) {
2429
-            if ($trigger_set_status_logic) {
2430
-                return $this->set_status($new_status);
2431
-            }
2432
-            parent::set('STS_ID', $new_status);
2433
-            return true;
2434
-        }
2435
-        return false;
2436
-    }
2437
-
2438
-
2439
-    /*************************** DEPRECATED ***************************/
2440
-
2441
-
2442
-    /**
2443
-     * @deprecated
2444
-     * @since     4.7.0
2445
-     */
2446
-    public function price_paid()
2447
-    {
2448
-        EE_Error::doing_it_wrong(
2449
-            'EE_Registration::price_paid()',
2450
-            esc_html__(
2451
-                'This method is deprecated, please use EE_Registration::final_price() instead.',
2452
-                'event_espresso'
2453
-            ),
2454
-            '4.7.0'
2455
-        );
2456
-        return $this->final_price();
2457
-    }
2458
-
2459
-
2460
-    /**
2461
-     * @deprecated
2462
-     * @since     4.7.0
2463
-     * @param    float $REG_final_price
2464
-     * @throws EE_Error
2465
-     * @throws EntityNotFoundException
2466
-     * @throws InvalidArgumentException
2467
-     * @throws InvalidDataTypeException
2468
-     * @throws InvalidInterfaceException
2469
-     * @throws ReflectionException
2470
-     * @throws RuntimeException
2471
-     * @throws DomainException
2472
-     */
2473
-    public function set_price_paid($REG_final_price = 0.00)
2474
-    {
2475
-        EE_Error::doing_it_wrong(
2476
-            'EE_Registration::set_price_paid()',
2477
-            esc_html__(
2478
-                'This method is deprecated, please use EE_Registration::set_final_price() instead.',
2479
-                'event_espresso'
2480
-            ),
2481
-            '4.7.0'
2482
-        );
2483
-        $this->set_final_price($REG_final_price);
2484
-    }
2485
-
2486
-
2487
-    /**
2488
-     * @deprecated
2489
-     * @since 4.7.0
2490
-     * @return string
2491
-     * @throws EE_Error
2492
-     * @throws InvalidArgumentException
2493
-     * @throws InvalidDataTypeException
2494
-     * @throws InvalidInterfaceException
2495
-     * @throws ReflectionException
2496
-     */
2497
-    public function pretty_price_paid()
2498
-    {
2499
-        EE_Error::doing_it_wrong(
2500
-            'EE_Registration::pretty_price_paid()',
2501
-            esc_html__(
2502
-                'This method is deprecated, please use EE_Registration::pretty_final_price() instead.',
2503
-                'event_espresso'
2504
-            ),
2505
-            '4.7.0'
2506
-        );
2507
-        return $this->pretty_final_price();
2508
-    }
2509
-
2510
-
2511
-    /**
2512
-     * Gets the primary datetime related to this registration via the related Event to this registration
2513
-     *
2514
-     * @deprecated 4.9.17
2515
-     * @return EE_Datetime
2516
-     * @throws EE_Error
2517
-     * @throws EntityNotFoundException
2518
-     * @throws InvalidArgumentException
2519
-     * @throws InvalidDataTypeException
2520
-     * @throws InvalidInterfaceException
2521
-     * @throws ReflectionException
2522
-     */
2523
-    public function get_related_primary_datetime()
2524
-    {
2525
-        EE_Error::doing_it_wrong(
2526
-            __METHOD__,
2527
-            esc_html__(
2528
-                'Use EE_Registration::get_latest_related_datetime() or EE_Registration::get_earliest_related_datetime()',
2529
-                'event_espresso'
2530
-            ),
2531
-            '4.9.17',
2532
-            '5.0.0'
2533
-        );
2534
-        return $this->event()->primary_datetime();
2535
-    }
2536
-
2537
-    /**
2538
-     * Returns the contact's name (or "Unknown" if there is no contact.)
2539
-     * @since 4.10.12.p
2540
-     * @return string
2541
-     * @throws EE_Error
2542
-     * @throws InvalidArgumentException
2543
-     * @throws InvalidDataTypeException
2544
-     * @throws InvalidInterfaceException
2545
-     * @throws ReflectionException
2546
-     */
2547
-    public function name()
2548
-    {
2549
-        return $this->attendeeName();
2550
-    }
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
+	 * Used to reference when a registration has been checked out.
38
+	 *
39
+	 * @deprecated use \EE_Checkin::status_checked_out instead
40
+	 * @type int
41
+	 */
42
+	const checkin_status_out = 0;
43
+
44
+	/**
45
+	 * extra meta key for tracking reg status os trashed registrations
46
+	 *
47
+	 * @type string
48
+	 */
49
+	const PRE_TRASH_REG_STATUS_KEY = 'pre_trash_registration_status';
50
+
51
+	/**
52
+	 * extra meta key for tracking if registration has reserved ticket
53
+	 *
54
+	 * @type string
55
+	 */
56
+	const HAS_RESERVED_TICKET_KEY = 'has_reserved_ticket';
57
+
58
+	/**
59
+	 * extra meta key for tracking when registrations are trashed and by who
60
+	 *
61
+	 * @type string
62
+	 */
63
+	const EXTRA_META_KEY_REG_TRASHED = 'registration-trashed';
64
+
65
+	/**
66
+	 * extra meta key for tracking when registrations are restored and by who
67
+	 *
68
+	 * @type string
69
+	 */
70
+	const EXTRA_META_KEY_REG_RESTORED = 'registration-restored';
71
+
72
+
73
+	/**
74
+	 * @param array  $props_n_values          incoming values
75
+	 * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
76
+	 *                                        used.)
77
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
78
+	 *                                        date_format and the second value is the time format
79
+	 * @return EE_Registration
80
+	 * @throws EE_Error
81
+	 * @throws InvalidArgumentException
82
+	 * @throws InvalidDataTypeException
83
+	 * @throws InvalidInterfaceException
84
+	 * @throws ReflectionException
85
+	 */
86
+	public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
87
+	{
88
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
89
+		return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
90
+	}
91
+
92
+
93
+	/**
94
+	 * @param array  $props_n_values  incoming values from the database
95
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
96
+	 *                                the website will be used.
97
+	 * @return EE_Registration
98
+	 * @throws EE_Error
99
+	 * @throws InvalidArgumentException
100
+	 * @throws InvalidDataTypeException
101
+	 * @throws InvalidInterfaceException
102
+	 * @throws ReflectionException
103
+	 */
104
+	public static function new_instance_from_db($props_n_values = array(), $timezone = null)
105
+	{
106
+		return new self($props_n_values, true, $timezone);
107
+	}
108
+
109
+
110
+	/**
111
+	 *        Set Event ID
112
+	 *
113
+	 * @param        int $EVT_ID Event ID
114
+	 * @throws DomainException
115
+	 * @throws EE_Error
116
+	 * @throws EntityNotFoundException
117
+	 * @throws InvalidArgumentException
118
+	 * @throws InvalidDataTypeException
119
+	 * @throws InvalidInterfaceException
120
+	 * @throws ReflectionException
121
+	 * @throws RuntimeException
122
+	 * @throws UnexpectedEntityException
123
+	 */
124
+	public function set_event($EVT_ID = 0)
125
+	{
126
+		$this->set('EVT_ID', $EVT_ID);
127
+	}
128
+
129
+
130
+	/**
131
+	 * Overrides parent set() method so that all calls to set( 'REG_code', $REG_code ) OR set( 'STS_ID', $STS_ID ) can
132
+	 * be routed to internal methods
133
+	 *
134
+	 * @param string $field_name
135
+	 * @param mixed  $field_value
136
+	 * @param bool   $use_default
137
+	 * @throws DomainException
138
+	 * @throws EE_Error
139
+	 * @throws EntityNotFoundException
140
+	 * @throws InvalidArgumentException
141
+	 * @throws InvalidDataTypeException
142
+	 * @throws InvalidInterfaceException
143
+	 * @throws ReflectionException
144
+	 * @throws RuntimeException
145
+	 * @throws UnexpectedEntityException
146
+	 */
147
+	public function set($field_name, $field_value, $use_default = false)
148
+	{
149
+		switch ($field_name) {
150
+			case 'REG_code':
151
+				if (! empty($field_value) && $this->reg_code() === null) {
152
+					$this->set_reg_code($field_value, $use_default);
153
+				}
154
+				break;
155
+			case 'STS_ID':
156
+				$this->set_status($field_value, $use_default);
157
+				break;
158
+			default:
159
+				parent::set($field_name, $field_value, $use_default);
160
+		}
161
+	}
162
+
163
+
164
+	/**
165
+	 * Set Status ID
166
+	 * updates the registration status and ALSO...
167
+	 * calls reserve_registration_space() if the reg status changes TO approved from any other reg status
168
+	 * calls release_registration_space() if the reg status changes FROM approved to any other reg status
169
+	 *
170
+	 * @param string                $new_STS_ID
171
+	 * @param boolean               $use_default
172
+	 * @param ContextInterface|null $context
173
+	 * @return bool
174
+	 * @throws DomainException
175
+	 * @throws EE_Error
176
+	 * @throws EntityNotFoundException
177
+	 * @throws InvalidArgumentException
178
+	 * @throws InvalidDataTypeException
179
+	 * @throws InvalidInterfaceException
180
+	 * @throws ReflectionException
181
+	 * @throws RuntimeException
182
+	 * @throws UnexpectedEntityException
183
+	 */
184
+	public function set_status($new_STS_ID = null, $use_default = false, ContextInterface $context = null)
185
+	{
186
+		// get current REG_Status
187
+		$old_STS_ID = $this->status_ID();
188
+		// if status has changed
189
+		if (
190
+			$old_STS_ID !== $new_STS_ID // and that status has actually changed
191
+			&& ! empty($old_STS_ID) // and that old status is actually set
192
+			&& ! empty($new_STS_ID) // as well as the new status
193
+			&& $this->ID() // ensure registration is in the db
194
+		) {
195
+			// update internal status first
196
+			parent::set('STS_ID', $new_STS_ID, $use_default);
197
+			// THEN handle other changes that occur when reg status changes
198
+			// TO approved
199
+			if ($new_STS_ID === EEM_Registration::status_id_approved) {
200
+				// reserve a space by incrementing ticket and datetime sold values
201
+				$this->reserveRegistrationSpace();
202
+				do_action('AHEE__EE_Registration__set_status__to_approved', $this, $old_STS_ID, $new_STS_ID, $context);
203
+				// OR FROM  approved
204
+			} elseif ($old_STS_ID === EEM_Registration::status_id_approved) {
205
+				// release a space by decrementing ticket and datetime sold values
206
+				$this->releaseRegistrationSpace();
207
+				do_action(
208
+					'AHEE__EE_Registration__set_status__from_approved',
209
+					$this,
210
+					$old_STS_ID,
211
+					$new_STS_ID,
212
+					$context
213
+				);
214
+			}
215
+			// update status
216
+			parent::set('STS_ID', $new_STS_ID, $use_default);
217
+			$this->updateIfCanceledOrReinstated($new_STS_ID, $old_STS_ID, $context);
218
+			if ($this->statusChangeUpdatesTransaction($context)) {
219
+				$this->updateTransactionAfterStatusChange();
220
+			}
221
+			do_action('AHEE__EE_Registration__set_status__after_update', $this, $old_STS_ID, $new_STS_ID, $context);
222
+			return true;
223
+		}
224
+		// even though the old value matches the new value, it's still good to
225
+		// allow the parent set method to have a say
226
+		parent::set('STS_ID', $new_STS_ID, $use_default);
227
+		return true;
228
+	}
229
+
230
+
231
+	/**
232
+	 * update REGs and TXN when cancelled or declined registrations involved
233
+	 *
234
+	 * @param string                $new_STS_ID
235
+	 * @param string                $old_STS_ID
236
+	 * @param ContextInterface|null $context
237
+	 * @throws EE_Error
238
+	 * @throws InvalidArgumentException
239
+	 * @throws InvalidDataTypeException
240
+	 * @throws InvalidInterfaceException
241
+	 * @throws ReflectionException
242
+	 * @throws RuntimeException
243
+	 */
244
+	private function updateIfCanceledOrReinstated($new_STS_ID, $old_STS_ID, ContextInterface $context = null)
245
+	{
246
+		// these reg statuses should not be considered in any calculations involving monies owing
247
+		$closed_reg_statuses = EEM_Registration::closed_reg_statuses();
248
+		// true if registration has been cancelled or declined
249
+		$this->updateIfCanceled(
250
+			$closed_reg_statuses,
251
+			$new_STS_ID,
252
+			$old_STS_ID,
253
+			$context
254
+		);
255
+		$this->updateIfReinstated(
256
+			$closed_reg_statuses,
257
+			$new_STS_ID,
258
+			$old_STS_ID,
259
+			$context
260
+		);
261
+	}
262
+
263
+
264
+	/**
265
+	 * update REGs and TXN when cancelled or declined registrations involved
266
+	 *
267
+	 * @param array                 $closed_reg_statuses
268
+	 * @param string                $new_STS_ID
269
+	 * @param string                $old_STS_ID
270
+	 * @param ContextInterface|null $context
271
+	 * @throws EE_Error
272
+	 * @throws InvalidArgumentException
273
+	 * @throws InvalidDataTypeException
274
+	 * @throws InvalidInterfaceException
275
+	 * @throws ReflectionException
276
+	 * @throws RuntimeException
277
+	 */
278
+	private function updateIfCanceled(
279
+		array $closed_reg_statuses,
280
+		$new_STS_ID,
281
+		$old_STS_ID,
282
+		ContextInterface $context = null
283
+	) {
284
+		// true if registration has been cancelled or declined
285
+		if (
286
+			in_array($new_STS_ID, $closed_reg_statuses, true)
287
+			&& ! in_array($old_STS_ID, $closed_reg_statuses, true)
288
+		) {
289
+			/** @type EE_Registration_Processor $registration_processor */
290
+			$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
291
+			/** @type EE_Transaction_Processor $transaction_processor */
292
+			$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
293
+			// cancelled or declined registration
294
+			$registration_processor->update_registration_after_being_canceled_or_declined(
295
+				$this,
296
+				$closed_reg_statuses
297
+			);
298
+			$transaction_processor->update_transaction_after_canceled_or_declined_registration(
299
+				$this,
300
+				$closed_reg_statuses,
301
+				false
302
+			);
303
+			do_action(
304
+				'AHEE__EE_Registration__set_status__canceled_or_declined',
305
+				$this,
306
+				$old_STS_ID,
307
+				$new_STS_ID,
308
+				$context
309
+			);
310
+			return;
311
+		}
312
+	}
313
+
314
+
315
+	/**
316
+	 * update REGs and TXN when cancelled or declined registrations involved
317
+	 *
318
+	 * @param array                 $closed_reg_statuses
319
+	 * @param string                $new_STS_ID
320
+	 * @param string                $old_STS_ID
321
+	 * @param ContextInterface|null $context
322
+	 * @throws EE_Error
323
+	 * @throws InvalidArgumentException
324
+	 * @throws InvalidDataTypeException
325
+	 * @throws InvalidInterfaceException
326
+	 * @throws ReflectionException
327
+	 * @throws RuntimeException
328
+	 */
329
+	private function updateIfReinstated(
330
+		array $closed_reg_statuses,
331
+		$new_STS_ID,
332
+		$old_STS_ID,
333
+		ContextInterface $context = null
334
+	) {
335
+		// true if reinstating cancelled or declined registration
336
+		if (
337
+			in_array($old_STS_ID, $closed_reg_statuses, true)
338
+			&& ! in_array($new_STS_ID, $closed_reg_statuses, true)
339
+		) {
340
+			/** @type EE_Registration_Processor $registration_processor */
341
+			$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
342
+			/** @type EE_Transaction_Processor $transaction_processor */
343
+			$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
344
+			// reinstating cancelled or declined registration
345
+			$registration_processor->update_canceled_or_declined_registration_after_being_reinstated(
346
+				$this,
347
+				$closed_reg_statuses
348
+			);
349
+			$transaction_processor->update_transaction_after_reinstating_canceled_registration(
350
+				$this,
351
+				$closed_reg_statuses,
352
+				false
353
+			);
354
+			do_action(
355
+				'AHEE__EE_Registration__set_status__after_reinstated',
356
+				$this,
357
+				$old_STS_ID,
358
+				$new_STS_ID,
359
+				$context
360
+			);
361
+		}
362
+	}
363
+
364
+
365
+	/**
366
+	 * @param ContextInterface|null $context
367
+	 * @return bool
368
+	 */
369
+	private function statusChangeUpdatesTransaction(ContextInterface $context = null)
370
+	{
371
+		$contexts_that_do_not_update_transaction = (array) apply_filters(
372
+			'AHEE__EE_Registration__statusChangeUpdatesTransaction__contexts_that_do_not_update_transaction',
373
+			array('spco_reg_step_attendee_information_process_registrations'),
374
+			$context,
375
+			$this
376
+		);
377
+		return ! (
378
+			$context instanceof ContextInterface
379
+			&& in_array($context->slug(), $contexts_that_do_not_update_transaction, true)
380
+		);
381
+	}
382
+
383
+
384
+	/**
385
+	 * @throws EE_Error
386
+	 * @throws EntityNotFoundException
387
+	 * @throws InvalidArgumentException
388
+	 * @throws InvalidDataTypeException
389
+	 * @throws InvalidInterfaceException
390
+	 * @throws ReflectionException
391
+	 * @throws RuntimeException
392
+	 */
393
+	private function updateTransactionAfterStatusChange()
394
+	{
395
+		/** @type EE_Transaction_Payments $transaction_payments */
396
+		$transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
397
+		$transaction_payments->recalculate_transaction_total($this->transaction(), false);
398
+		$this->transaction()->update_status_based_on_total_paid();
399
+	}
400
+
401
+
402
+	/**
403
+	 * get Status ID
404
+	 *
405
+	 * @throws EE_Error
406
+	 * @throws InvalidArgumentException
407
+	 * @throws InvalidDataTypeException
408
+	 * @throws InvalidInterfaceException
409
+	 * @throws ReflectionException
410
+	 */
411
+	public function status_ID()
412
+	{
413
+		return $this->get('STS_ID');
414
+	}
415
+
416
+
417
+	/**
418
+	 * Gets the ticket this registration is for
419
+	 *
420
+	 * @param boolean $include_archived whether to include archived tickets or not.
421
+	 * @return EE_Ticket|EE_Base_Class
422
+	 * @throws EE_Error
423
+	 * @throws InvalidArgumentException
424
+	 * @throws InvalidDataTypeException
425
+	 * @throws InvalidInterfaceException
426
+	 * @throws ReflectionException
427
+	 */
428
+	public function ticket($include_archived = true)
429
+	{
430
+		$query_params = array();
431
+		if ($include_archived) {
432
+			$query_params['default_where_conditions'] = 'none';
433
+		}
434
+		return $this->get_first_related('Ticket', $query_params);
435
+	}
436
+
437
+
438
+	/**
439
+	 * Gets the event this registration is for
440
+	 *
441
+	 * @return EE_Event
442
+	 * @throws EE_Error
443
+	 * @throws EntityNotFoundException
444
+	 * @throws InvalidArgumentException
445
+	 * @throws InvalidDataTypeException
446
+	 * @throws InvalidInterfaceException
447
+	 * @throws ReflectionException
448
+	 */
449
+	public function event()
450
+	{
451
+		$event = $this->get_first_related('Event');
452
+		if (! $event instanceof \EE_Event) {
453
+			throw new EntityNotFoundException('Event ID', $this->event_ID());
454
+		}
455
+		return $event;
456
+	}
457
+
458
+
459
+	/**
460
+	 * Gets the "author" of the registration.  Note that for the purposes of registrations, the author will correspond
461
+	 * with the author of the event this registration is for.
462
+	 *
463
+	 * @since 4.5.0
464
+	 * @return int
465
+	 * @throws EE_Error
466
+	 * @throws EntityNotFoundException
467
+	 * @throws InvalidArgumentException
468
+	 * @throws InvalidDataTypeException
469
+	 * @throws InvalidInterfaceException
470
+	 * @throws ReflectionException
471
+	 */
472
+	public function wp_user()
473
+	{
474
+		$event = $this->event();
475
+		if ($event instanceof EE_Event) {
476
+			return $event->wp_user();
477
+		}
478
+		return 0;
479
+	}
480
+
481
+
482
+	/**
483
+	 * increments this registration's related ticket sold and corresponding datetime sold values
484
+	 *
485
+	 * @return void
486
+	 * @throws DomainException
487
+	 * @throws EE_Error
488
+	 * @throws EntityNotFoundException
489
+	 * @throws InvalidArgumentException
490
+	 * @throws InvalidDataTypeException
491
+	 * @throws InvalidInterfaceException
492
+	 * @throws ReflectionException
493
+	 * @throws UnexpectedEntityException
494
+	 */
495
+	private function reserveRegistrationSpace()
496
+	{
497
+		// reserved ticket and datetime counts will be decremented as sold counts are incremented
498
+		// so stop tracking that this reg has a ticket reserved
499
+		$this->release_reserved_ticket(false, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
500
+		$ticket = $this->ticket();
501
+		$ticket->increaseSold();
502
+		// possibly set event status to sold out
503
+		$this->event()->perform_sold_out_status_check();
504
+	}
505
+
506
+
507
+	/**
508
+	 * decrements (subtracts) this registration's related ticket sold and corresponding datetime sold values
509
+	 *
510
+	 * @return void
511
+	 * @throws DomainException
512
+	 * @throws EE_Error
513
+	 * @throws EntityNotFoundException
514
+	 * @throws InvalidArgumentException
515
+	 * @throws InvalidDataTypeException
516
+	 * @throws InvalidInterfaceException
517
+	 * @throws ReflectionException
518
+	 * @throws UnexpectedEntityException
519
+	 */
520
+	private function releaseRegistrationSpace()
521
+	{
522
+		$ticket = $this->ticket();
523
+		$ticket->decreaseSold();
524
+		// possibly change event status from sold out back to previous status
525
+		$this->event()->perform_sold_out_status_check();
526
+	}
527
+
528
+
529
+	/**
530
+	 * tracks this registration's ticket reservation in extra meta
531
+	 * and can increment related ticket reserved and corresponding datetime reserved values
532
+	 *
533
+	 * @param bool   $update_ticket if true, will increment ticket and datetime reserved count
534
+	 * @param string $source
535
+	 * @return void
536
+	 * @throws EE_Error
537
+	 * @throws InvalidArgumentException
538
+	 * @throws InvalidDataTypeException
539
+	 * @throws InvalidInterfaceException
540
+	 * @throws ReflectionException
541
+	 */
542
+	public function reserve_ticket($update_ticket = false, $source = 'unknown')
543
+	{
544
+		// only reserve ticket if space is not currently reserved
545
+		if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) !== true) {
546
+			$reserved = $this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true);
547
+			if ($reserved && $update_ticket) {
548
+				$ticket = $this->ticket();
549
+				$ticket->increaseReserved(1, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
550
+				$this->update_extra_meta('reserve_ticket', "{$this->ticket_ID()} from {$source}");
551
+				$ticket->save();
552
+			}
553
+		}
554
+	}
555
+
556
+
557
+	/**
558
+	 * stops tracking this registration's ticket reservation in extra meta
559
+	 * decrements (subtracts) related ticket reserved and corresponding datetime reserved values
560
+	 *
561
+	 * @param bool   $update_ticket if true, will decrement ticket and datetime reserved count
562
+	 * @param string $source
563
+	 * @return void
564
+	 * @throws EE_Error
565
+	 * @throws InvalidArgumentException
566
+	 * @throws InvalidDataTypeException
567
+	 * @throws InvalidInterfaceException
568
+	 * @throws ReflectionException
569
+	 */
570
+	public function release_reserved_ticket($update_ticket = false, $source = 'unknown')
571
+	{
572
+		// only release ticket if space is currently reserved
573
+		if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) === true) {
574
+			$reserved = $this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, false);
575
+			if ($reserved && $update_ticket) {
576
+				$ticket = $this->ticket();
577
+				$ticket->decreaseReserved(1, true, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
578
+				$this->update_extra_meta('release_reserved_ticket', "{$this->ticket_ID()} from {$source}");
579
+			}
580
+		}
581
+	}
582
+
583
+
584
+	/**
585
+	 * Set Attendee ID
586
+	 *
587
+	 * @param        int $ATT_ID Attendee ID
588
+	 * @throws DomainException
589
+	 * @throws EE_Error
590
+	 * @throws EntityNotFoundException
591
+	 * @throws InvalidArgumentException
592
+	 * @throws InvalidDataTypeException
593
+	 * @throws InvalidInterfaceException
594
+	 * @throws ReflectionException
595
+	 * @throws RuntimeException
596
+	 * @throws UnexpectedEntityException
597
+	 */
598
+	public function set_attendee_id($ATT_ID = 0)
599
+	{
600
+		$this->set('ATT_ID', $ATT_ID);
601
+	}
602
+
603
+
604
+	/**
605
+	 *        Set Transaction ID
606
+	 *
607
+	 * @param        int $TXN_ID Transaction ID
608
+	 * @throws DomainException
609
+	 * @throws EE_Error
610
+	 * @throws EntityNotFoundException
611
+	 * @throws InvalidArgumentException
612
+	 * @throws InvalidDataTypeException
613
+	 * @throws InvalidInterfaceException
614
+	 * @throws ReflectionException
615
+	 * @throws RuntimeException
616
+	 * @throws UnexpectedEntityException
617
+	 */
618
+	public function set_transaction_id($TXN_ID = 0)
619
+	{
620
+		$this->set('TXN_ID', $TXN_ID);
621
+	}
622
+
623
+
624
+	/**
625
+	 *        Set Session
626
+	 *
627
+	 * @param    string $REG_session PHP Session ID
628
+	 * @throws DomainException
629
+	 * @throws EE_Error
630
+	 * @throws EntityNotFoundException
631
+	 * @throws InvalidArgumentException
632
+	 * @throws InvalidDataTypeException
633
+	 * @throws InvalidInterfaceException
634
+	 * @throws ReflectionException
635
+	 * @throws RuntimeException
636
+	 * @throws UnexpectedEntityException
637
+	 */
638
+	public function set_session($REG_session = '')
639
+	{
640
+		$this->set('REG_session', $REG_session);
641
+	}
642
+
643
+
644
+	/**
645
+	 *        Set Registration URL Link
646
+	 *
647
+	 * @param    string $REG_url_link Registration URL Link
648
+	 * @throws DomainException
649
+	 * @throws EE_Error
650
+	 * @throws EntityNotFoundException
651
+	 * @throws InvalidArgumentException
652
+	 * @throws InvalidDataTypeException
653
+	 * @throws InvalidInterfaceException
654
+	 * @throws ReflectionException
655
+	 * @throws RuntimeException
656
+	 * @throws UnexpectedEntityException
657
+	 */
658
+	public function set_reg_url_link($REG_url_link = '')
659
+	{
660
+		$this->set('REG_url_link', $REG_url_link);
661
+	}
662
+
663
+
664
+	/**
665
+	 *        Set Attendee Counter
666
+	 *
667
+	 * @param        int $REG_count Primary Attendee
668
+	 * @throws DomainException
669
+	 * @throws EE_Error
670
+	 * @throws EntityNotFoundException
671
+	 * @throws InvalidArgumentException
672
+	 * @throws InvalidDataTypeException
673
+	 * @throws InvalidInterfaceException
674
+	 * @throws ReflectionException
675
+	 * @throws RuntimeException
676
+	 * @throws UnexpectedEntityException
677
+	 */
678
+	public function set_count($REG_count = 1)
679
+	{
680
+		$this->set('REG_count', $REG_count);
681
+	}
682
+
683
+
684
+	/**
685
+	 *        Set Group Size
686
+	 *
687
+	 * @param        boolean $REG_group_size Group Registration
688
+	 * @throws DomainException
689
+	 * @throws EE_Error
690
+	 * @throws EntityNotFoundException
691
+	 * @throws InvalidArgumentException
692
+	 * @throws InvalidDataTypeException
693
+	 * @throws InvalidInterfaceException
694
+	 * @throws ReflectionException
695
+	 * @throws RuntimeException
696
+	 * @throws UnexpectedEntityException
697
+	 */
698
+	public function set_group_size($REG_group_size = false)
699
+	{
700
+		$this->set('REG_group_size', $REG_group_size);
701
+	}
702
+
703
+
704
+	/**
705
+	 *    is_not_approved -  convenience method that returns TRUE if REG status ID ==
706
+	 *    EEM_Registration::status_id_not_approved
707
+	 *
708
+	 * @return        boolean
709
+	 * @throws EE_Error
710
+	 * @throws InvalidArgumentException
711
+	 * @throws InvalidDataTypeException
712
+	 * @throws InvalidInterfaceException
713
+	 * @throws ReflectionException
714
+	 */
715
+	public function is_not_approved()
716
+	{
717
+		return $this->status_ID() === EEM_Registration::status_id_not_approved;
718
+	}
719
+
720
+
721
+	/**
722
+	 *    is_pending_payment -  convenience method that returns TRUE if REG status ID ==
723
+	 *    EEM_Registration::status_id_pending_payment
724
+	 *
725
+	 * @return        boolean
726
+	 * @throws EE_Error
727
+	 * @throws InvalidArgumentException
728
+	 * @throws InvalidDataTypeException
729
+	 * @throws InvalidInterfaceException
730
+	 * @throws ReflectionException
731
+	 */
732
+	public function is_pending_payment()
733
+	{
734
+		return $this->status_ID() === EEM_Registration::status_id_pending_payment;
735
+	}
736
+
737
+
738
+	/**
739
+	 *    is_approved -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_approved
740
+	 *
741
+	 * @return        boolean
742
+	 * @throws EE_Error
743
+	 * @throws InvalidArgumentException
744
+	 * @throws InvalidDataTypeException
745
+	 * @throws InvalidInterfaceException
746
+	 * @throws ReflectionException
747
+	 */
748
+	public function is_approved()
749
+	{
750
+		return $this->status_ID() === EEM_Registration::status_id_approved;
751
+	}
752
+
753
+
754
+	/**
755
+	 *    is_cancelled -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_cancelled
756
+	 *
757
+	 * @return        boolean
758
+	 * @throws EE_Error
759
+	 * @throws InvalidArgumentException
760
+	 * @throws InvalidDataTypeException
761
+	 * @throws InvalidInterfaceException
762
+	 * @throws ReflectionException
763
+	 */
764
+	public function is_cancelled()
765
+	{
766
+		return $this->status_ID() === EEM_Registration::status_id_cancelled;
767
+	}
768
+
769
+
770
+	/**
771
+	 *    is_declined -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_declined
772
+	 *
773
+	 * @return        boolean
774
+	 * @throws EE_Error
775
+	 * @throws InvalidArgumentException
776
+	 * @throws InvalidDataTypeException
777
+	 * @throws InvalidInterfaceException
778
+	 * @throws ReflectionException
779
+	 */
780
+	public function is_declined()
781
+	{
782
+		return $this->status_ID() === EEM_Registration::status_id_declined;
783
+	}
784
+
785
+
786
+	/**
787
+	 *    is_incomplete -  convenience method that returns TRUE if REG status ID ==
788
+	 *    EEM_Registration::status_id_incomplete
789
+	 *
790
+	 * @return        boolean
791
+	 * @throws EE_Error
792
+	 * @throws InvalidArgumentException
793
+	 * @throws InvalidDataTypeException
794
+	 * @throws InvalidInterfaceException
795
+	 * @throws ReflectionException
796
+	 */
797
+	public function is_incomplete()
798
+	{
799
+		return $this->status_ID() === EEM_Registration::status_id_incomplete;
800
+	}
801
+
802
+
803
+	/**
804
+	 *        Set Registration Date
805
+	 *
806
+	 * @param        mixed ( int or string ) $REG_date Registration Date - Unix timestamp or string representation of
807
+	 *                                                 Date
808
+	 * @throws DomainException
809
+	 * @throws EE_Error
810
+	 * @throws EntityNotFoundException
811
+	 * @throws InvalidArgumentException
812
+	 * @throws InvalidDataTypeException
813
+	 * @throws InvalidInterfaceException
814
+	 * @throws ReflectionException
815
+	 * @throws RuntimeException
816
+	 * @throws UnexpectedEntityException
817
+	 */
818
+	public function set_reg_date($REG_date = false)
819
+	{
820
+		$this->set('REG_date', $REG_date);
821
+	}
822
+
823
+
824
+	/**
825
+	 *    Set final price owing for this registration after all ticket/price modifications
826
+	 *
827
+	 * @param    float $REG_final_price
828
+	 * @throws DomainException
829
+	 * @throws EE_Error
830
+	 * @throws EntityNotFoundException
831
+	 * @throws InvalidArgumentException
832
+	 * @throws InvalidDataTypeException
833
+	 * @throws InvalidInterfaceException
834
+	 * @throws ReflectionException
835
+	 * @throws RuntimeException
836
+	 * @throws UnexpectedEntityException
837
+	 */
838
+	public function set_final_price($REG_final_price = 0.00)
839
+	{
840
+		$this->set('REG_final_price', $REG_final_price);
841
+	}
842
+
843
+
844
+	/**
845
+	 *    Set amount paid towards this registration's final price
846
+	 *
847
+	 * @param    float $REG_paid
848
+	 * @throws DomainException
849
+	 * @throws EE_Error
850
+	 * @throws EntityNotFoundException
851
+	 * @throws InvalidArgumentException
852
+	 * @throws InvalidDataTypeException
853
+	 * @throws InvalidInterfaceException
854
+	 * @throws ReflectionException
855
+	 * @throws RuntimeException
856
+	 * @throws UnexpectedEntityException
857
+	 */
858
+	public function set_paid($REG_paid = 0.00)
859
+	{
860
+		$this->set('REG_paid', $REG_paid);
861
+	}
862
+
863
+
864
+	/**
865
+	 *        Attendee Is Going
866
+	 *
867
+	 * @param        boolean $REG_att_is_going Attendee Is Going
868
+	 * @throws DomainException
869
+	 * @throws EE_Error
870
+	 * @throws EntityNotFoundException
871
+	 * @throws InvalidArgumentException
872
+	 * @throws InvalidDataTypeException
873
+	 * @throws InvalidInterfaceException
874
+	 * @throws ReflectionException
875
+	 * @throws RuntimeException
876
+	 * @throws UnexpectedEntityException
877
+	 */
878
+	public function set_att_is_going($REG_att_is_going = false)
879
+	{
880
+		$this->set('REG_att_is_going', $REG_att_is_going);
881
+	}
882
+
883
+
884
+	/**
885
+	 * Gets the related attendee
886
+	 *
887
+	 * @return EE_Attendee|EE_Base_Class
888
+	 * @throws EE_Error
889
+	 * @throws InvalidArgumentException
890
+	 * @throws InvalidDataTypeException
891
+	 * @throws InvalidInterfaceException
892
+	 * @throws ReflectionException
893
+	 */
894
+	public function attendee()
895
+	{
896
+		return $this->get_first_related('Attendee');
897
+	}
898
+
899
+	/**
900
+	 * Gets the name of the attendee.
901
+	 * @since 4.10.12.p
902
+	 * @param bool $apply_html_entities set to true if you want to use HTML entities.
903
+	 * @return string
904
+	 * @throws EE_Error
905
+	 * @throws InvalidArgumentException
906
+	 * @throws InvalidDataTypeException
907
+	 * @throws InvalidInterfaceException
908
+	 * @throws ReflectionException
909
+	 */
910
+	public function attendeeName($apply_html_entities = false)
911
+	{
912
+		$attendee = $this->get_first_related('Attendee');
913
+		if ($attendee instanceof EE_Attendee) {
914
+			$attendee_name = $attendee->full_name($apply_html_entities);
915
+		} else {
916
+			$attendee_name = esc_html__('Unknown', 'event_espresso');
917
+		}
918
+		return $attendee_name;
919
+	}
920
+
921
+
922
+	/**
923
+	 *        get Event ID
924
+	 */
925
+	public function event_ID()
926
+	{
927
+		return $this->get('EVT_ID');
928
+	}
929
+
930
+
931
+	/**
932
+	 *        get Event ID
933
+	 */
934
+	public function event_name()
935
+	{
936
+		$event = $this->event_obj();
937
+		if ($event) {
938
+			return $event->name();
939
+		} else {
940
+			return null;
941
+		}
942
+	}
943
+
944
+
945
+	/**
946
+	 * Fetches the event this registration is for
947
+	 *
948
+	 * @return EE_Base_Class|EE_Event
949
+	 * @throws EE_Error
950
+	 * @throws InvalidArgumentException
951
+	 * @throws InvalidDataTypeException
952
+	 * @throws InvalidInterfaceException
953
+	 * @throws ReflectionException
954
+	 */
955
+	public function event_obj()
956
+	{
957
+		return $this->get_first_related('Event');
958
+	}
959
+
960
+
961
+	/**
962
+	 *        get Attendee ID
963
+	 */
964
+	public function attendee_ID()
965
+	{
966
+		return $this->get('ATT_ID');
967
+	}
968
+
969
+
970
+	/**
971
+	 *        get PHP Session ID
972
+	 */
973
+	public function session_ID()
974
+	{
975
+		return $this->get('REG_session');
976
+	}
977
+
978
+
979
+	/**
980
+	 * Gets the string which represents the URL trigger for the receipt template in the message template system.
981
+	 *
982
+	 * @param string $messenger 'pdf' or 'html'.  Default 'html'.
983
+	 * @return string
984
+	 * @throws DomainException
985
+	 * @throws EE_Error
986
+	 * @throws InvalidArgumentException
987
+	 * @throws InvalidDataTypeException
988
+	 * @throws InvalidInterfaceException
989
+	 * @throws ReflectionException
990
+	 */
991
+	public function receipt_url($messenger = 'html')
992
+	{
993
+
994
+		/**
995
+		 * The below will be deprecated one version after this.  We check first if there is a custom receipt template
996
+		 * already in use on old system.  If there is then we just return the standard url for it.
997
+		 *
998
+		 * @since 4.5.0
999
+		 */
1000
+		$template_relative_path = 'modules/gateways/Invoice/lib/templates/receipt_body.template.php';
1001
+		$has_custom = EEH_Template::locate_template(
1002
+			$template_relative_path,
1003
+			array(),
1004
+			true,
1005
+			true,
1006
+			true
1007
+		);
1008
+
1009
+		if ($has_custom) {
1010
+			return add_query_arg(array('receipt' => 'true'), $this->invoice_url('launch'));
1011
+		}
1012
+		return apply_filters('FHEE__EE_Registration__receipt_url__receipt_url', '', $this, $messenger, 'receipt');
1013
+	}
1014
+
1015
+
1016
+	/**
1017
+	 * Gets the string which represents the URL trigger for the invoice template in the message template system.
1018
+	 *
1019
+	 * @param string $messenger 'pdf' or 'html'.  Default 'html'.
1020
+	 * @return string
1021
+	 * @throws DomainException
1022
+	 * @throws EE_Error
1023
+	 * @throws InvalidArgumentException
1024
+	 * @throws InvalidDataTypeException
1025
+	 * @throws InvalidInterfaceException
1026
+	 * @throws ReflectionException
1027
+	 */
1028
+	public function invoice_url($messenger = 'html')
1029
+	{
1030
+		/**
1031
+		 * The below will be deprecated one version after this.  We check first if there is a custom invoice template
1032
+		 * already in use on old system.  If there is then we just return the standard url for it.
1033
+		 *
1034
+		 * @since 4.5.0
1035
+		 */
1036
+		$template_relative_path = 'modules/gateways/Invoice/lib/templates/invoice_body.template.php';
1037
+		$has_custom = EEH_Template::locate_template(
1038
+			$template_relative_path,
1039
+			array(),
1040
+			true,
1041
+			true,
1042
+			true
1043
+		);
1044
+
1045
+		if ($has_custom) {
1046
+			if ($messenger == 'html') {
1047
+				return $this->invoice_url('launch');
1048
+			}
1049
+			$route = $messenger == 'download' || $messenger == 'pdf' ? 'download_invoice' : 'launch_invoice';
1050
+
1051
+			$query_args = array('ee' => $route, 'id' => $this->reg_url_link());
1052
+			if ($messenger == 'html') {
1053
+				$query_args['html'] = true;
1054
+			}
1055
+			return add_query_arg($query_args, get_permalink(EE_Registry::instance()->CFG->core->thank_you_page_id));
1056
+		}
1057
+		return apply_filters('FHEE__EE_Registration__invoice_url__invoice_url', '', $this, $messenger, 'invoice');
1058
+	}
1059
+
1060
+
1061
+	/**
1062
+	 * get Registration URL Link
1063
+	 *
1064
+	 * @return string
1065
+	 * @throws EE_Error
1066
+	 * @throws InvalidArgumentException
1067
+	 * @throws InvalidDataTypeException
1068
+	 * @throws InvalidInterfaceException
1069
+	 * @throws ReflectionException
1070
+	 */
1071
+	public function reg_url_link()
1072
+	{
1073
+		return (string) $this->get('REG_url_link');
1074
+	}
1075
+
1076
+
1077
+	/**
1078
+	 * Echoes out invoice_url()
1079
+	 *
1080
+	 * @param string $type 'download','launch', or 'html' (default is 'launch')
1081
+	 * @return void
1082
+	 * @throws DomainException
1083
+	 * @throws EE_Error
1084
+	 * @throws InvalidArgumentException
1085
+	 * @throws InvalidDataTypeException
1086
+	 * @throws InvalidInterfaceException
1087
+	 * @throws ReflectionException
1088
+	 */
1089
+	public function e_invoice_url($type = 'launch')
1090
+	{
1091
+		echo esc_url_raw($this->invoice_url($type));
1092
+	}
1093
+
1094
+
1095
+	/**
1096
+	 * Echoes out payment_overview_url
1097
+	 */
1098
+	public function e_payment_overview_url()
1099
+	{
1100
+		echo esc_url_raw($this->payment_overview_url());
1101
+	}
1102
+
1103
+
1104
+	/**
1105
+	 * Gets the URL for the checkout payment options reg step
1106
+	 * with this registration's REG_url_link added as a query parameter
1107
+	 *
1108
+	 * @param bool $clear_session Set to true when you want to clear the session on revisiting the
1109
+	 *                            payment overview url.
1110
+	 * @return string
1111
+	 * @throws EE_Error
1112
+	 * @throws InvalidArgumentException
1113
+	 * @throws InvalidDataTypeException
1114
+	 * @throws InvalidInterfaceException
1115
+	 * @throws ReflectionException
1116
+	 */
1117
+	public function payment_overview_url($clear_session = false)
1118
+	{
1119
+		return add_query_arg(
1120
+			(array) apply_filters(
1121
+				'FHEE__EE_Registration__payment_overview_url__query_args',
1122
+				array(
1123
+					'e_reg_url_link' => $this->reg_url_link(),
1124
+					'step'           => 'payment_options',
1125
+					'revisit'        => true,
1126
+					'clear_session'  => (bool) $clear_session,
1127
+				),
1128
+				$this
1129
+			),
1130
+			EE_Registry::instance()->CFG->core->reg_page_url()
1131
+		);
1132
+	}
1133
+
1134
+
1135
+	/**
1136
+	 * Gets the URL for the checkout attendee information reg step
1137
+	 * with this registration's REG_url_link added as a query parameter
1138
+	 *
1139
+	 * @return string
1140
+	 * @throws EE_Error
1141
+	 * @throws InvalidArgumentException
1142
+	 * @throws InvalidDataTypeException
1143
+	 * @throws InvalidInterfaceException
1144
+	 * @throws ReflectionException
1145
+	 */
1146
+	public function edit_attendee_information_url()
1147
+	{
1148
+		return add_query_arg(
1149
+			(array) apply_filters(
1150
+				'FHEE__EE_Registration__edit_attendee_information_url__query_args',
1151
+				array(
1152
+					'e_reg_url_link' => $this->reg_url_link(),
1153
+					'step'           => 'attendee_information',
1154
+					'revisit'        => true,
1155
+				),
1156
+				$this
1157
+			),
1158
+			EE_Registry::instance()->CFG->core->reg_page_url()
1159
+		);
1160
+	}
1161
+
1162
+
1163
+	/**
1164
+	 * Simply generates and returns the appropriate admin_url link to edit this registration
1165
+	 *
1166
+	 * @return string
1167
+	 * @throws EE_Error
1168
+	 * @throws InvalidArgumentException
1169
+	 * @throws InvalidDataTypeException
1170
+	 * @throws InvalidInterfaceException
1171
+	 * @throws ReflectionException
1172
+	 */
1173
+	public function get_admin_edit_url()
1174
+	{
1175
+		return EEH_URL::add_query_args_and_nonce(
1176
+			array(
1177
+				'page'    => 'espresso_registrations',
1178
+				'action'  => 'view_registration',
1179
+				'_REG_ID' => $this->ID(),
1180
+			),
1181
+			admin_url('admin.php')
1182
+		);
1183
+	}
1184
+
1185
+
1186
+	/**
1187
+	 * is_primary_registrant?
1188
+	 *
1189
+	 * @throws EE_Error
1190
+	 * @throws InvalidArgumentException
1191
+	 * @throws InvalidDataTypeException
1192
+	 * @throws InvalidInterfaceException
1193
+	 * @throws ReflectionException
1194
+	 */
1195
+	public function is_primary_registrant()
1196
+	{
1197
+		return (int) $this->get('REG_count') === 1;
1198
+	}
1199
+
1200
+
1201
+	/**
1202
+	 * This returns the primary registration object for this registration group (which may be this object).
1203
+	 *
1204
+	 * @return EE_Registration
1205
+	 * @throws EE_Error
1206
+	 * @throws InvalidArgumentException
1207
+	 * @throws InvalidDataTypeException
1208
+	 * @throws InvalidInterfaceException
1209
+	 * @throws ReflectionException
1210
+	 */
1211
+	public function get_primary_registration()
1212
+	{
1213
+		if ($this->is_primary_registrant()) {
1214
+			return $this;
1215
+		}
1216
+
1217
+		// k reg_count !== 1 so let's get the EE_Registration object matching this txn_id and reg_count == 1
1218
+		/** @var EE_Registration $primary_registrant */
1219
+		$primary_registrant = EEM_Registration::instance()->get_one(
1220
+			array(
1221
+				array(
1222
+					'TXN_ID'    => $this->transaction_ID(),
1223
+					'REG_count' => 1,
1224
+				),
1225
+			)
1226
+		);
1227
+		return $primary_registrant;
1228
+	}
1229
+
1230
+
1231
+	/**
1232
+	 * get  Attendee Number
1233
+	 *
1234
+	 * @throws EE_Error
1235
+	 * @throws InvalidArgumentException
1236
+	 * @throws InvalidDataTypeException
1237
+	 * @throws InvalidInterfaceException
1238
+	 * @throws ReflectionException
1239
+	 */
1240
+	public function count()
1241
+	{
1242
+		return $this->get('REG_count');
1243
+	}
1244
+
1245
+
1246
+	/**
1247
+	 * get Group Size
1248
+	 *
1249
+	 * @throws EE_Error
1250
+	 * @throws InvalidArgumentException
1251
+	 * @throws InvalidDataTypeException
1252
+	 * @throws InvalidInterfaceException
1253
+	 * @throws ReflectionException
1254
+	 */
1255
+	public function group_size()
1256
+	{
1257
+		return $this->get('REG_group_size');
1258
+	}
1259
+
1260
+
1261
+	/**
1262
+	 * get Registration Date
1263
+	 *
1264
+	 * @throws EE_Error
1265
+	 * @throws InvalidArgumentException
1266
+	 * @throws InvalidDataTypeException
1267
+	 * @throws InvalidInterfaceException
1268
+	 * @throws ReflectionException
1269
+	 */
1270
+	public function date()
1271
+	{
1272
+		return $this->get('REG_date');
1273
+	}
1274
+
1275
+
1276
+	/**
1277
+	 * gets a pretty date
1278
+	 *
1279
+	 * @param string $date_format
1280
+	 * @param string $time_format
1281
+	 * @return string
1282
+	 * @throws EE_Error
1283
+	 * @throws InvalidArgumentException
1284
+	 * @throws InvalidDataTypeException
1285
+	 * @throws InvalidInterfaceException
1286
+	 * @throws ReflectionException
1287
+	 */
1288
+	public function pretty_date($date_format = null, $time_format = null)
1289
+	{
1290
+		return $this->get_datetime('REG_date', $date_format, $time_format);
1291
+	}
1292
+
1293
+
1294
+	/**
1295
+	 * final_price
1296
+	 * the registration's share of the transaction total, so that the
1297
+	 * sum of all the transaction's REG_final_prices equal the transaction's total
1298
+	 *
1299
+	 * @return float
1300
+	 * @throws EE_Error
1301
+	 * @throws InvalidArgumentException
1302
+	 * @throws InvalidDataTypeException
1303
+	 * @throws InvalidInterfaceException
1304
+	 * @throws ReflectionException
1305
+	 */
1306
+	public function final_price()
1307
+	{
1308
+		return $this->get('REG_final_price');
1309
+	}
1310
+
1311
+
1312
+	/**
1313
+	 * pretty_final_price
1314
+	 *  final price as formatted string, with correct decimal places and currency symbol
1315
+	 *
1316
+	 * @return string
1317
+	 * @throws EE_Error
1318
+	 * @throws InvalidArgumentException
1319
+	 * @throws InvalidDataTypeException
1320
+	 * @throws InvalidInterfaceException
1321
+	 * @throws ReflectionException
1322
+	 */
1323
+	public function pretty_final_price()
1324
+	{
1325
+		return $this->get_pretty('REG_final_price');
1326
+	}
1327
+
1328
+
1329
+	/**
1330
+	 * get paid (yeah)
1331
+	 *
1332
+	 * @return float
1333
+	 * @throws EE_Error
1334
+	 * @throws InvalidArgumentException
1335
+	 * @throws InvalidDataTypeException
1336
+	 * @throws InvalidInterfaceException
1337
+	 * @throws ReflectionException
1338
+	 */
1339
+	public function paid()
1340
+	{
1341
+		return $this->get('REG_paid');
1342
+	}
1343
+
1344
+
1345
+	/**
1346
+	 * pretty_paid
1347
+	 *
1348
+	 * @return float
1349
+	 * @throws EE_Error
1350
+	 * @throws InvalidArgumentException
1351
+	 * @throws InvalidDataTypeException
1352
+	 * @throws InvalidInterfaceException
1353
+	 * @throws ReflectionException
1354
+	 */
1355
+	public function pretty_paid()
1356
+	{
1357
+		return $this->get_pretty('REG_paid');
1358
+	}
1359
+
1360
+
1361
+	/**
1362
+	 * owes_monies_and_can_pay
1363
+	 * whether or not this registration has monies owing and it's' status allows payment
1364
+	 *
1365
+	 * @param array $requires_payment
1366
+	 * @return bool
1367
+	 * @throws EE_Error
1368
+	 * @throws InvalidArgumentException
1369
+	 * @throws InvalidDataTypeException
1370
+	 * @throws InvalidInterfaceException
1371
+	 * @throws ReflectionException
1372
+	 */
1373
+	public function owes_monies_and_can_pay($requires_payment = array())
1374
+	{
1375
+		// these reg statuses require payment (if event is not free)
1376
+		$requires_payment = ! empty($requires_payment)
1377
+			? $requires_payment
1378
+			: EEM_Registration::reg_statuses_that_allow_payment();
1379
+		if (
1380
+			$this->final_price() !== 0 &&
1381
+			$this->final_price() !== $this->paid() &&
1382
+			in_array($this->status_ID(), $requires_payment)
1383
+		) {
1384
+			return true;
1385
+		}
1386
+		return false;
1387
+	}
1388
+
1389
+
1390
+	/**
1391
+	 * Prints out the return value of $this->pretty_status()
1392
+	 *
1393
+	 * @param bool $show_icons
1394
+	 * @return void
1395
+	 * @throws EE_Error
1396
+	 * @throws InvalidArgumentException
1397
+	 * @throws InvalidDataTypeException
1398
+	 * @throws InvalidInterfaceException
1399
+	 * @throws ReflectionException
1400
+	 */
1401
+	public function e_pretty_status($show_icons = false)
1402
+	{
1403
+		echo wp_kses($this->pretty_status($show_icons), AllowedTags::getAllowedTags());
1404
+	}
1405
+
1406
+
1407
+	/**
1408
+	 * Returns a nice version of the status for displaying to customers
1409
+	 *
1410
+	 * @param bool $show_icons
1411
+	 * @return string
1412
+	 * @throws EE_Error
1413
+	 * @throws InvalidArgumentException
1414
+	 * @throws InvalidDataTypeException
1415
+	 * @throws InvalidInterfaceException
1416
+	 * @throws ReflectionException
1417
+	 */
1418
+	public function pretty_status($show_icons = false)
1419
+	{
1420
+		$status = EEM_Status::instance()->localized_status(
1421
+			array($this->status_ID() => esc_html__('unknown', 'event_espresso')),
1422
+			false,
1423
+			'sentence'
1424
+		);
1425
+		$icon = '';
1426
+		switch ($this->status_ID()) {
1427
+			case EEM_Registration::status_id_approved:
1428
+				$icon = $show_icons
1429
+					? '<span class="dashicons dashicons-star-filled ee-icon-size-16 green-text"></span>'
1430
+					: '';
1431
+				break;
1432
+			case EEM_Registration::status_id_pending_payment:
1433
+				$icon = $show_icons
1434
+					? '<span class="dashicons dashicons-star-half ee-icon-size-16 orange-text"></span>'
1435
+					: '';
1436
+				break;
1437
+			case EEM_Registration::status_id_not_approved:
1438
+				$icon = $show_icons
1439
+					? '<span class="dashicons dashicons-marker ee-icon-size-16 orange-text"></span>'
1440
+					: '';
1441
+				break;
1442
+			case EEM_Registration::status_id_cancelled:
1443
+				$icon = $show_icons
1444
+					? '<span class="dashicons dashicons-no ee-icon-size-16 lt-grey-text"></span>'
1445
+					: '';
1446
+				break;
1447
+			case EEM_Registration::status_id_incomplete:
1448
+				$icon = $show_icons
1449
+					? '<span class="dashicons dashicons-no ee-icon-size-16 lt-orange-text"></span>'
1450
+					: '';
1451
+				break;
1452
+			case EEM_Registration::status_id_declined:
1453
+				$icon = $show_icons
1454
+					? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>'
1455
+					: '';
1456
+				break;
1457
+			case EEM_Registration::status_id_wait_list:
1458
+				$icon = $show_icons
1459
+					? '<span class="dashicons dashicons-clipboard ee-icon-size-16 purple-text"></span>'
1460
+					: '';
1461
+				break;
1462
+		}
1463
+		return $icon . $status[ $this->status_ID() ];
1464
+	}
1465
+
1466
+
1467
+	/**
1468
+	 *        get Attendee Is Going
1469
+	 */
1470
+	public function att_is_going()
1471
+	{
1472
+		return $this->get('REG_att_is_going');
1473
+	}
1474
+
1475
+
1476
+	/**
1477
+	 * Gets related answers
1478
+	 *
1479
+	 * @param array $query_params @see
1480
+	 *                            https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1481
+	 * @return EE_Answer[]|EE_Base_Class[]
1482
+	 * @throws EE_Error
1483
+	 * @throws InvalidArgumentException
1484
+	 * @throws InvalidDataTypeException
1485
+	 * @throws InvalidInterfaceException
1486
+	 * @throws ReflectionException
1487
+	 */
1488
+	public function answers($query_params = null)
1489
+	{
1490
+		return $this->get_many_related('Answer', $query_params);
1491
+	}
1492
+
1493
+
1494
+	/**
1495
+	 * Gets the registration's answer value to the specified question
1496
+	 * (either the question's ID or a question object)
1497
+	 *
1498
+	 * @param EE_Question|int $question
1499
+	 * @param bool            $pretty_value
1500
+	 * @return array|string if pretty_value= true, the result will always be a string
1501
+	 * (because the answer might be an array of answer values, so passing pretty_value=true
1502
+	 * will convert it into some kind of string)
1503
+	 * @throws EE_Error
1504
+	 * @throws InvalidArgumentException
1505
+	 * @throws InvalidDataTypeException
1506
+	 * @throws InvalidInterfaceException
1507
+	 */
1508
+	public function answer_value_to_question($question, $pretty_value = true)
1509
+	{
1510
+		$question_id = EEM_Question::instance()->ensure_is_ID($question);
1511
+		return EEM_Answer::instance()->get_answer_value_to_question($this, $question_id, $pretty_value);
1512
+	}
1513
+
1514
+
1515
+	/**
1516
+	 * question_groups
1517
+	 * returns an array of EE_Question_Group objects for this registration
1518
+	 *
1519
+	 * @return EE_Question_Group[]
1520
+	 * @throws EE_Error
1521
+	 * @throws InvalidArgumentException
1522
+	 * @throws InvalidDataTypeException
1523
+	 * @throws InvalidInterfaceException
1524
+	 * @throws ReflectionException
1525
+	 */
1526
+	public function question_groups()
1527
+	{
1528
+		return EEM_Event::instance()->get_question_groups_for_event($this->event_ID(), $this);
1529
+	}
1530
+
1531
+
1532
+	/**
1533
+	 * count_question_groups
1534
+	 * returns a count of the number of EE_Question_Group objects for this registration
1535
+	 *
1536
+	 * @return int
1537
+	 * @throws EE_Error
1538
+	 * @throws EntityNotFoundException
1539
+	 * @throws InvalidArgumentException
1540
+	 * @throws InvalidDataTypeException
1541
+	 * @throws InvalidInterfaceException
1542
+	 * @throws ReflectionException
1543
+	 */
1544
+	public function count_question_groups()
1545
+	{
1546
+		return EEM_Event::instance()->count_related(
1547
+			$this->event_ID(),
1548
+			'Question_Group',
1549
+			[
1550
+				[
1551
+					'Event_Question_Group.'
1552
+					. EEM_Event_Question_Group::instance()->fieldNameForContext($this->is_primary_registrant()) => true,
1553
+				]
1554
+			]
1555
+		);
1556
+	}
1557
+
1558
+
1559
+	/**
1560
+	 * Returns the registration date in the 'standard' string format
1561
+	 * (function may be improved in the future to allow for different formats and timezones)
1562
+	 *
1563
+	 * @return string
1564
+	 * @throws EE_Error
1565
+	 * @throws InvalidArgumentException
1566
+	 * @throws InvalidDataTypeException
1567
+	 * @throws InvalidInterfaceException
1568
+	 * @throws ReflectionException
1569
+	 */
1570
+	public function reg_date()
1571
+	{
1572
+		return $this->get_datetime('REG_date');
1573
+	}
1574
+
1575
+
1576
+	/**
1577
+	 * Gets the datetime-ticket for this registration (ie, it can be used to isolate
1578
+	 * the ticket this registration purchased, or the datetime they have registered
1579
+	 * to attend)
1580
+	 *
1581
+	 * @return EE_Base_Class|EE_Datetime_Ticket
1582
+	 * @throws EE_Error
1583
+	 * @throws InvalidArgumentException
1584
+	 * @throws InvalidDataTypeException
1585
+	 * @throws InvalidInterfaceException
1586
+	 * @throws ReflectionException
1587
+	 */
1588
+	public function datetime_ticket()
1589
+	{
1590
+		return $this->get_first_related('Datetime_Ticket');
1591
+	}
1592
+
1593
+
1594
+	/**
1595
+	 * Sets the registration's datetime_ticket.
1596
+	 *
1597
+	 * @param EE_Datetime_Ticket $datetime_ticket
1598
+	 * @return EE_Base_Class|EE_Datetime_Ticket
1599
+	 * @throws EE_Error
1600
+	 * @throws InvalidArgumentException
1601
+	 * @throws InvalidDataTypeException
1602
+	 * @throws InvalidInterfaceException
1603
+	 * @throws ReflectionException
1604
+	 */
1605
+	public function set_datetime_ticket($datetime_ticket)
1606
+	{
1607
+		return $this->_add_relation_to($datetime_ticket, 'Datetime_Ticket');
1608
+	}
1609
+
1610
+
1611
+	/**
1612
+	 * Gets deleted
1613
+	 *
1614
+	 * @return bool
1615
+	 * @throws EE_Error
1616
+	 * @throws InvalidArgumentException
1617
+	 * @throws InvalidDataTypeException
1618
+	 * @throws InvalidInterfaceException
1619
+	 * @throws ReflectionException
1620
+	 */
1621
+	public function deleted()
1622
+	{
1623
+		return $this->get('REG_deleted');
1624
+	}
1625
+
1626
+
1627
+	/**
1628
+	 * Sets deleted
1629
+	 *
1630
+	 * @param boolean $deleted
1631
+	 * @return void
1632
+	 * @throws DomainException
1633
+	 * @throws EE_Error
1634
+	 * @throws EntityNotFoundException
1635
+	 * @throws InvalidArgumentException
1636
+	 * @throws InvalidDataTypeException
1637
+	 * @throws InvalidInterfaceException
1638
+	 * @throws ReflectionException
1639
+	 * @throws RuntimeException
1640
+	 * @throws UnexpectedEntityException
1641
+	 */
1642
+	public function set_deleted($deleted)
1643
+	{
1644
+		if ($deleted) {
1645
+			$this->delete(__METHOD__);
1646
+		} else {
1647
+			$this->restore(__METHOD__);
1648
+		}
1649
+	}
1650
+
1651
+
1652
+	/**
1653
+	 * Get the status object of this object
1654
+	 *
1655
+	 * @return EE_Base_Class|EE_Status
1656
+	 * @throws EE_Error
1657
+	 * @throws InvalidArgumentException
1658
+	 * @throws InvalidDataTypeException
1659
+	 * @throws InvalidInterfaceException
1660
+	 * @throws ReflectionException
1661
+	 */
1662
+	public function status_obj()
1663
+	{
1664
+		return $this->get_first_related('Status');
1665
+	}
1666
+
1667
+
1668
+	/**
1669
+	 * Returns the number of times this registration has checked into any of the datetimes
1670
+	 * its available for
1671
+	 *
1672
+	 * @return int
1673
+	 * @throws EE_Error
1674
+	 * @throws InvalidArgumentException
1675
+	 * @throws InvalidDataTypeException
1676
+	 * @throws InvalidInterfaceException
1677
+	 * @throws ReflectionException
1678
+	 */
1679
+	public function count_checkins()
1680
+	{
1681
+		return $this->get_model()->count_related($this, 'Checkin');
1682
+	}
1683
+
1684
+
1685
+	/**
1686
+	 * Returns the number of current Check-ins this registration is checked into for any of the datetimes the
1687
+	 * registration is for.  Note, this is ONLY checked in (does not include checkedout)
1688
+	 *
1689
+	 * @return int
1690
+	 * @throws EE_Error
1691
+	 * @throws InvalidArgumentException
1692
+	 * @throws InvalidDataTypeException
1693
+	 * @throws InvalidInterfaceException
1694
+	 * @throws ReflectionException
1695
+	 */
1696
+	public function count_checkins_not_checkedout()
1697
+	{
1698
+		return $this->get_model()->count_related($this, 'Checkin', array(array('CHK_in' => 1)));
1699
+	}
1700
+
1701
+
1702
+	/**
1703
+	 * The purpose of this method is simply to check whether this registration can checkin to the given datetime.
1704
+	 *
1705
+	 * @param int | EE_Datetime $DTT_OR_ID      The datetime the registration is being checked against
1706
+	 * @param bool              $check_approved This is used to indicate whether the caller wants can_checkin to also
1707
+	 *                                          consider registration status as well as datetime access.
1708
+	 * @return bool
1709
+	 * @throws EE_Error
1710
+	 * @throws InvalidArgumentException
1711
+	 * @throws InvalidDataTypeException
1712
+	 * @throws InvalidInterfaceException
1713
+	 * @throws ReflectionException
1714
+	 */
1715
+	public function can_checkin($DTT_OR_ID, $check_approved = true)
1716
+	{
1717
+		$DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1718
+		// first check registration status
1719
+		if (! $DTT_ID || ($check_approved && ! $this->is_approved())) {
1720
+			return false;
1721
+		}
1722
+		// is there a datetime ticket that matches this dtt_ID?
1723
+		if (
1724
+			! (EEM_Datetime_Ticket::instance()->exists(
1725
+				array(
1726
+					array(
1727
+						'TKT_ID' => $this->get('TKT_ID'),
1728
+						'DTT_ID' => $DTT_ID,
1729
+					),
1730
+				)
1731
+			))
1732
+		) {
1733
+			return false;
1734
+		}
1735
+
1736
+		// final check is against TKT_uses
1737
+		return $this->verify_can_checkin_against_TKT_uses($DTT_ID);
1738
+	}
1739
+
1740
+
1741
+	/**
1742
+	 * This method verifies whether the user can checkin for the given datetime considering the max uses value set on
1743
+	 * the ticket. To do this,  a query is done to get the count of the datetime records already checked into.  If the
1744
+	 * datetime given does not have a check-in record and checking in for that datetime will exceed the allowed uses,
1745
+	 * then return false.  Otherwise return true.
1746
+	 *
1747
+	 * @param int | EE_Datetime $DTT_OR_ID The datetime the registration is being checked against
1748
+	 * @return bool true means can checkin.  false means cannot checkin.
1749
+	 * @throws EE_Error
1750
+	 * @throws InvalidArgumentException
1751
+	 * @throws InvalidDataTypeException
1752
+	 * @throws InvalidInterfaceException
1753
+	 * @throws ReflectionException
1754
+	 */
1755
+	public function verify_can_checkin_against_TKT_uses($DTT_OR_ID)
1756
+	{
1757
+		$DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1758
+
1759
+		if (! $DTT_ID) {
1760
+			return false;
1761
+		}
1762
+
1763
+		$max_uses = $this->ticket() instanceof EE_Ticket ? $this->ticket()->uses() : EE_INF;
1764
+
1765
+		// if max uses is not set or equals infinity then return true cause its not a factor for whether user can
1766
+		// check-in or not.
1767
+		if (! $max_uses || $max_uses === EE_INF) {
1768
+			return true;
1769
+		}
1770
+
1771
+		// does this datetime have a checkin record?  If so, then the dtt count has already been verified so we can just
1772
+		// go ahead and toggle.
1773
+		if (EEM_Checkin::instance()->exists(array(array('REG_ID' => $this->ID(), 'DTT_ID' => $DTT_ID)))) {
1774
+			return true;
1775
+		}
1776
+
1777
+		// made it here so the last check is whether the number of checkins per unique datetime on this registration
1778
+		// disallows further check-ins.
1779
+		$count_unique_dtt_checkins = EEM_Checkin::instance()->count(
1780
+			array(
1781
+				array(
1782
+					'REG_ID' => $this->ID(),
1783
+					'CHK_in' => true,
1784
+				),
1785
+			),
1786
+			'DTT_ID',
1787
+			true
1788
+		);
1789
+		// checkins have already reached their max number of uses
1790
+		// so registrant can NOT checkin
1791
+		if ($count_unique_dtt_checkins >= $max_uses) {
1792
+			EE_Error::add_error(
1793
+				esc_html__(
1794
+					'Check-in denied because number of datetime uses for the ticket has been reached or exceeded.',
1795
+					'event_espresso'
1796
+				),
1797
+				__FILE__,
1798
+				__FUNCTION__,
1799
+				__LINE__
1800
+			);
1801
+			return false;
1802
+		}
1803
+		return true;
1804
+	}
1805
+
1806
+
1807
+	/**
1808
+	 * toggle Check-in status for this registration
1809
+	 * Check-ins are toggled in the following order:
1810
+	 * never checked in -> checked in
1811
+	 * checked in -> checked out
1812
+	 * checked out -> checked in
1813
+	 *
1814
+	 * @param  int $DTT_ID  include specific datetime to toggle Check-in for.
1815
+	 *                      If not included or null, then it is assumed latest datetime is being toggled.
1816
+	 * @param bool $verify  If true then can_checkin() is used to verify whether the person
1817
+	 *                      can be checked in or not.  Otherwise this forces change in checkin status.
1818
+	 * @return bool|int     the chk_in status toggled to OR false if nothing got changed.
1819
+	 * @throws EE_Error
1820
+	 * @throws InvalidArgumentException
1821
+	 * @throws InvalidDataTypeException
1822
+	 * @throws InvalidInterfaceException
1823
+	 * @throws ReflectionException
1824
+	 */
1825
+	public function toggle_checkin_status($DTT_ID = null, $verify = false)
1826
+	{
1827
+		if (empty($DTT_ID)) {
1828
+			$datetime = $this->get_latest_related_datetime();
1829
+			$DTT_ID = $datetime instanceof EE_Datetime ? $datetime->ID() : 0;
1830
+			// verify the registration can checkin for the given DTT_ID
1831
+		} elseif (! $this->can_checkin($DTT_ID, $verify)) {
1832
+			EE_Error::add_error(
1833
+				sprintf(
1834
+					esc_html__(
1835
+						'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',
1836
+						'event_espresso'
1837
+					),
1838
+					$this->ID(),
1839
+					$DTT_ID
1840
+				),
1841
+				__FILE__,
1842
+				__FUNCTION__,
1843
+				__LINE__
1844
+			);
1845
+			return false;
1846
+		}
1847
+		$status_paths = array(
1848
+			EE_Checkin::status_checked_never => EE_Checkin::status_checked_in,
1849
+			EE_Checkin::status_checked_in    => EE_Checkin::status_checked_out,
1850
+			EE_Checkin::status_checked_out   => EE_Checkin::status_checked_in,
1851
+		);
1852
+		// start by getting the current status so we know what status we'll be changing to.
1853
+		$cur_status = $this->check_in_status_for_datetime($DTT_ID);
1854
+		$status_to = $status_paths[ $cur_status ];
1855
+		// database only records true for checked IN or false for checked OUT
1856
+		// no record ( null ) means checked in NEVER, but we obviously don't save that
1857
+		$new_status = $status_to === EE_Checkin::status_checked_in;
1858
+		// add relation - note Check-ins are always creating new rows
1859
+		// because we are keeping track of Check-ins over time.
1860
+		// Eventually we'll probably want to show a list table
1861
+		// for the individual Check-ins so that they can be managed.
1862
+		$checkin = EE_Checkin::new_instance(
1863
+			array(
1864
+				'REG_ID' => $this->ID(),
1865
+				'DTT_ID' => $DTT_ID,
1866
+				'CHK_in' => $new_status,
1867
+			)
1868
+		);
1869
+		// if the record could not be saved then return false
1870
+		if ($checkin->save() === 0) {
1871
+			if (WP_DEBUG) {
1872
+				global $wpdb;
1873
+				$error = sprintf(
1874
+					esc_html__(
1875
+						'Registration check in update failed because of the following database error: %1$s%2$s',
1876
+						'event_espresso'
1877
+					),
1878
+					'<br />',
1879
+					$wpdb->last_error
1880
+				);
1881
+			} else {
1882
+				$error = esc_html__(
1883
+					'Registration check in update failed because of an unknown database error',
1884
+					'event_espresso'
1885
+				);
1886
+			}
1887
+			EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
1888
+			return false;
1889
+		}
1890
+		// Fire a checked_in and checkout_out action.
1891
+		$checked_status = $status_to === EE_Checkin::status_checked_in ? 'checked_in' : 'checked_out';
1892
+		do_action("AHEE__EE_Registration__toggle_checkin_status__{$checked_status}", $this, $DTT_ID);
1893
+		return $status_to;
1894
+	}
1895
+
1896
+
1897
+	/**
1898
+	 * Returns the latest datetime related to this registration (via the ticket attached to the registration).
1899
+	 * "Latest" is defined by the `DTT_EVT_start` column.
1900
+	 *
1901
+	 * @return EE_Datetime|null
1902
+	 * @throws EE_Error
1903
+	 * @throws InvalidArgumentException
1904
+	 * @throws InvalidDataTypeException
1905
+	 * @throws InvalidInterfaceException
1906
+	 * @throws ReflectionException
1907
+	 */
1908
+	public function get_latest_related_datetime()
1909
+	{
1910
+		return EEM_Datetime::instance()->get_one(
1911
+			array(
1912
+				array(
1913
+					'Ticket.Registration.REG_ID' => $this->ID(),
1914
+				),
1915
+				'order_by' => array('DTT_EVT_start' => 'DESC'),
1916
+			)
1917
+		);
1918
+	}
1919
+
1920
+
1921
+	/**
1922
+	 * Returns the earliest datetime related to this registration (via the ticket attached to the registration).
1923
+	 * "Earliest" is defined by the `DTT_EVT_start` column.
1924
+	 *
1925
+	 * @return EE_Base_Class|EE_Soft_Delete_Base_Class|NULL
1926
+	 * @throws EE_Error
1927
+	 * @throws InvalidArgumentException
1928
+	 * @throws InvalidDataTypeException
1929
+	 * @throws InvalidInterfaceException
1930
+	 * @throws ReflectionException
1931
+	 */
1932
+	public function get_earliest_related_datetime()
1933
+	{
1934
+		return EEM_Datetime::instance()->get_one(
1935
+			array(
1936
+				array(
1937
+					'Ticket.Registration.REG_ID' => $this->ID(),
1938
+				),
1939
+				'order_by' => array('DTT_EVT_start' => 'ASC'),
1940
+			)
1941
+		);
1942
+	}
1943
+
1944
+
1945
+	/**
1946
+	 * This method simply returns the check-in status for this registration and the given datetime.
1947
+	 * If neither the datetime nor the checkin values are provided as arguments,
1948
+	 * then this will return the LATEST check-in status for the registration across all datetimes it belongs to.
1949
+	 *
1950
+	 * @param  int       $DTT_ID  The ID of the datetime we're checking against
1951
+	 *                            (if empty we'll get the primary datetime for
1952
+	 *                            this registration (via event) and use it's ID);
1953
+	 * @param EE_Checkin $checkin If present, we use the given checkin object rather than the dtt_id.
1954
+	 * @return int                Integer representing Check-in status.
1955
+	 * @throws EE_Error
1956
+	 * @throws InvalidArgumentException
1957
+	 * @throws InvalidDataTypeException
1958
+	 * @throws InvalidInterfaceException
1959
+	 * @throws ReflectionException
1960
+	 */
1961
+	public function check_in_status_for_datetime($DTT_ID = 0, $checkin = null)
1962
+	{
1963
+		$checkin_query_params = array(
1964
+			'order_by' => array('CHK_timestamp' => 'DESC'),
1965
+		);
1966
+
1967
+		if ($DTT_ID > 0) {
1968
+			$checkin_query_params[0] = array('DTT_ID' => $DTT_ID);
1969
+		}
1970
+
1971
+		// get checkin object (if exists)
1972
+		$checkin = $checkin instanceof EE_Checkin
1973
+			? $checkin
1974
+			: $this->get_first_related('Checkin', $checkin_query_params);
1975
+		if ($checkin instanceof EE_Checkin) {
1976
+			if ($checkin->get('CHK_in')) {
1977
+				return EE_Checkin::status_checked_in; // checked in
1978
+			}
1979
+			return EE_Checkin::status_checked_out; // had checked in but is now checked out.
1980
+		}
1981
+		return EE_Checkin::status_checked_never; // never been checked in
1982
+	}
1983
+
1984
+
1985
+	/**
1986
+	 * This method returns a localized message for the toggled Check-in message.
1987
+	 *
1988
+	 * @param  int $DTT_ID include specific datetime to get the correct Check-in message.  If not included or null,
1989
+	 *                     then it is assumed Check-in for primary datetime was toggled.
1990
+	 * @param bool $error  This just flags that you want an error message returned. This is put in so that the error
1991
+	 *                     message can be customized with the attendee name.
1992
+	 * @return string internationalized message
1993
+	 * @throws EE_Error
1994
+	 * @throws InvalidArgumentException
1995
+	 * @throws InvalidDataTypeException
1996
+	 * @throws InvalidInterfaceException
1997
+	 * @throws ReflectionException
1998
+	 */
1999
+	public function get_checkin_msg($DTT_ID, $error = false)
2000
+	{
2001
+		// let's get the attendee first so we can include the name of the attendee
2002
+		$attendee = $this->get_first_related('Attendee');
2003
+		if ($attendee instanceof EE_Attendee) {
2004
+			if ($error) {
2005
+				return sprintf(
2006
+					esc_html__("%s's check-in status was not changed.", "event_espresso"),
2007
+					$attendee->full_name()
2008
+				);
2009
+			}
2010
+			$cur_status = $this->check_in_status_for_datetime($DTT_ID);
2011
+			// what is the status message going to be?
2012
+			switch ($cur_status) {
2013
+				case EE_Checkin::status_checked_never:
2014
+					return sprintf(
2015
+						esc_html__('%s has been removed from Check-in records', 'event_espresso'),
2016
+						$attendee->full_name()
2017
+					);
2018
+					break;
2019
+				case EE_Checkin::status_checked_in:
2020
+					return sprintf(esc_html__('%s has been checked in', 'event_espresso'), $attendee->full_name());
2021
+					break;
2022
+				case EE_Checkin::status_checked_out:
2023
+					return sprintf(esc_html__('%s has been checked out', 'event_espresso'), $attendee->full_name());
2024
+					break;
2025
+			}
2026
+		}
2027
+		return esc_html__('The check-in status could not be determined.', 'event_espresso');
2028
+	}
2029
+
2030
+
2031
+	/**
2032
+	 * Returns the related EE_Transaction to this registration
2033
+	 *
2034
+	 * @return EE_Transaction
2035
+	 * @throws EE_Error
2036
+	 * @throws EntityNotFoundException
2037
+	 * @throws InvalidArgumentException
2038
+	 * @throws InvalidDataTypeException
2039
+	 * @throws InvalidInterfaceException
2040
+	 * @throws ReflectionException
2041
+	 */
2042
+	public function transaction()
2043
+	{
2044
+		$transaction = $this->get_first_related('Transaction');
2045
+		if (! $transaction instanceof \EE_Transaction) {
2046
+			throw new EntityNotFoundException('Transaction ID', $this->transaction_ID());
2047
+		}
2048
+		return $transaction;
2049
+	}
2050
+
2051
+
2052
+	/**
2053
+	 * get Registration Code
2054
+	 *
2055
+	 * @return mixed
2056
+	 * @throws EE_Error
2057
+	 * @throws InvalidArgumentException
2058
+	 * @throws InvalidDataTypeException
2059
+	 * @throws InvalidInterfaceException
2060
+	 * @throws ReflectionException
2061
+	 */
2062
+	public function reg_code()
2063
+	{
2064
+		return $this->get('REG_code');
2065
+	}
2066
+
2067
+
2068
+	/**
2069
+	 * @return mixed
2070
+	 * @throws EE_Error
2071
+	 * @throws InvalidArgumentException
2072
+	 * @throws InvalidDataTypeException
2073
+	 * @throws InvalidInterfaceException
2074
+	 * @throws ReflectionException
2075
+	 */
2076
+	public function transaction_ID()
2077
+	{
2078
+		return $this->get('TXN_ID');
2079
+	}
2080
+
2081
+
2082
+	/**
2083
+	 * @return int
2084
+	 * @throws EE_Error
2085
+	 * @throws InvalidArgumentException
2086
+	 * @throws InvalidDataTypeException
2087
+	 * @throws InvalidInterfaceException
2088
+	 * @throws ReflectionException
2089
+	 */
2090
+	public function ticket_ID()
2091
+	{
2092
+		return $this->get('TKT_ID');
2093
+	}
2094
+
2095
+
2096
+	/**
2097
+	 * Set Registration Code
2098
+	 *
2099
+	 * @param    string  $REG_code Registration Code
2100
+	 * @param    boolean $use_default
2101
+	 * @throws EE_Error
2102
+	 * @throws InvalidArgumentException
2103
+	 * @throws InvalidDataTypeException
2104
+	 * @throws InvalidInterfaceException
2105
+	 * @throws ReflectionException
2106
+	 */
2107
+	public function set_reg_code($REG_code, $use_default = false)
2108
+	{
2109
+		if (empty($REG_code)) {
2110
+			EE_Error::add_error(
2111
+				esc_html__('REG_code can not be empty.', 'event_espresso'),
2112
+				__FILE__,
2113
+				__FUNCTION__,
2114
+				__LINE__
2115
+			);
2116
+			return;
2117
+		}
2118
+		if (! $this->reg_code()) {
2119
+			parent::set('REG_code', $REG_code, $use_default);
2120
+		} else {
2121
+			EE_Error::doing_it_wrong(
2122
+				__CLASS__ . '::' . __FUNCTION__,
2123
+				esc_html__('Can not change a registration REG_code once it has been set.', 'event_espresso'),
2124
+				'4.6.0'
2125
+			);
2126
+		}
2127
+	}
2128
+
2129
+
2130
+	/**
2131
+	 * Returns all other registrations in the same group as this registrant who have the same ticket option.
2132
+	 * Note, if you want to just get all registrations in the same transaction (group), use:
2133
+	 *    $registration->transaction()->registrations();
2134
+	 *
2135
+	 * @since 4.5.0
2136
+	 * @return EE_Registration[] or empty array if this isn't a group registration.
2137
+	 * @throws EE_Error
2138
+	 * @throws InvalidArgumentException
2139
+	 * @throws InvalidDataTypeException
2140
+	 * @throws InvalidInterfaceException
2141
+	 * @throws ReflectionException
2142
+	 */
2143
+	public function get_all_other_registrations_in_group()
2144
+	{
2145
+		if ($this->group_size() < 2) {
2146
+			return array();
2147
+		}
2148
+
2149
+		$query[0] = array(
2150
+			'TXN_ID' => $this->transaction_ID(),
2151
+			'REG_ID' => array('!=', $this->ID()),
2152
+			'TKT_ID' => $this->ticket_ID(),
2153
+		);
2154
+		/** @var EE_Registration[] $registrations */
2155
+		$registrations = $this->get_model()->get_all($query);
2156
+		return $registrations;
2157
+	}
2158
+
2159
+
2160
+	/**
2161
+	 * Return the link to the admin details for the object.
2162
+	 *
2163
+	 * @return string
2164
+	 * @throws EE_Error
2165
+	 * @throws InvalidArgumentException
2166
+	 * @throws InvalidDataTypeException
2167
+	 * @throws InvalidInterfaceException
2168
+	 * @throws ReflectionException
2169
+	 */
2170
+	public function get_admin_details_link()
2171
+	{
2172
+		EE_Registry::instance()->load_helper('URL');
2173
+		return EEH_URL::add_query_args_and_nonce(
2174
+			array(
2175
+				'page'    => 'espresso_registrations',
2176
+				'action'  => 'view_registration',
2177
+				'_REG_ID' => $this->ID(),
2178
+			),
2179
+			admin_url('admin.php')
2180
+		);
2181
+	}
2182
+
2183
+
2184
+	/**
2185
+	 * Returns the link to the editor for the object.  Sometimes this is the same as the details.
2186
+	 *
2187
+	 * @return string
2188
+	 * @throws EE_Error
2189
+	 * @throws InvalidArgumentException
2190
+	 * @throws InvalidDataTypeException
2191
+	 * @throws InvalidInterfaceException
2192
+	 * @throws ReflectionException
2193
+	 */
2194
+	public function get_admin_edit_link()
2195
+	{
2196
+		return $this->get_admin_details_link();
2197
+	}
2198
+
2199
+
2200
+	/**
2201
+	 * Returns the link to a settings page for the object.
2202
+	 *
2203
+	 * @return string
2204
+	 * @throws EE_Error
2205
+	 * @throws InvalidArgumentException
2206
+	 * @throws InvalidDataTypeException
2207
+	 * @throws InvalidInterfaceException
2208
+	 * @throws ReflectionException
2209
+	 */
2210
+	public function get_admin_settings_link()
2211
+	{
2212
+		return $this->get_admin_details_link();
2213
+	}
2214
+
2215
+
2216
+	/**
2217
+	 * Returns the link to the "overview" for the object (typically the "list table" view).
2218
+	 *
2219
+	 * @return string
2220
+	 * @throws EE_Error
2221
+	 * @throws InvalidArgumentException
2222
+	 * @throws InvalidDataTypeException
2223
+	 * @throws InvalidInterfaceException
2224
+	 * @throws ReflectionException
2225
+	 */
2226
+	public function get_admin_overview_link()
2227
+	{
2228
+		EE_Registry::instance()->load_helper('URL');
2229
+		return EEH_URL::add_query_args_and_nonce(
2230
+			array(
2231
+				'page' => 'espresso_registrations',
2232
+			),
2233
+			admin_url('admin.php')
2234
+		);
2235
+	}
2236
+
2237
+
2238
+	/**
2239
+	 * @param array $query_params
2240
+	 * @return EE_Base_Class[]|EE_Registration[]
2241
+	 * @throws EE_Error
2242
+	 * @throws InvalidArgumentException
2243
+	 * @throws InvalidDataTypeException
2244
+	 * @throws InvalidInterfaceException
2245
+	 * @throws ReflectionException
2246
+	 */
2247
+	public function payments($query_params = array())
2248
+	{
2249
+		return $this->get_many_related('Payment', $query_params);
2250
+	}
2251
+
2252
+
2253
+	/**
2254
+	 * @param array $query_params
2255
+	 * @return EE_Base_Class[]|EE_Registration_Payment[]
2256
+	 * @throws EE_Error
2257
+	 * @throws InvalidArgumentException
2258
+	 * @throws InvalidDataTypeException
2259
+	 * @throws InvalidInterfaceException
2260
+	 * @throws ReflectionException
2261
+	 */
2262
+	public function registration_payments($query_params = array())
2263
+	{
2264
+		return $this->get_many_related('Registration_Payment', $query_params);
2265
+	}
2266
+
2267
+
2268
+	/**
2269
+	 * This grabs the payment method corresponding to the last payment made for the amount owing on the registration.
2270
+	 * Note: if there are no payments on the registration there will be no payment method returned.
2271
+	 *
2272
+	 * @return EE_Payment|EE_Payment_Method|null
2273
+	 * @throws EE_Error
2274
+	 * @throws InvalidArgumentException
2275
+	 * @throws InvalidDataTypeException
2276
+	 * @throws InvalidInterfaceException
2277
+	 */
2278
+	public function payment_method()
2279
+	{
2280
+		return EEM_Payment_Method::instance()->get_last_used_for_registration($this);
2281
+	}
2282
+
2283
+
2284
+	/**
2285
+	 * @return \EE_Line_Item
2286
+	 * @throws EE_Error
2287
+	 * @throws EntityNotFoundException
2288
+	 * @throws InvalidArgumentException
2289
+	 * @throws InvalidDataTypeException
2290
+	 * @throws InvalidInterfaceException
2291
+	 * @throws ReflectionException
2292
+	 */
2293
+	public function ticket_line_item()
2294
+	{
2295
+		$ticket = $this->ticket();
2296
+		$transaction = $this->transaction();
2297
+		$line_item = null;
2298
+		$ticket_line_items = \EEH_Line_Item::get_line_items_by_object_type_and_IDs(
2299
+			$transaction->total_line_item(),
2300
+			'Ticket',
2301
+			array($ticket->ID())
2302
+		);
2303
+		foreach ($ticket_line_items as $ticket_line_item) {
2304
+			if (
2305
+				$ticket_line_item instanceof \EE_Line_Item
2306
+				&& $ticket_line_item->OBJ_type() === 'Ticket'
2307
+				&& $ticket_line_item->OBJ_ID() === $ticket->ID()
2308
+			) {
2309
+				$line_item = $ticket_line_item;
2310
+				break;
2311
+			}
2312
+		}
2313
+		if (! ($line_item instanceof \EE_Line_Item && $line_item->OBJ_type() === 'Ticket')) {
2314
+			throw new EntityNotFoundException('Line Item Ticket ID', $ticket->ID());
2315
+		}
2316
+		return $line_item;
2317
+	}
2318
+
2319
+
2320
+	/**
2321
+	 * Soft Deletes this model object.
2322
+	 *
2323
+	 * @param string $source function name that called this method
2324
+	 * @return boolean | int
2325
+	 * @throws DomainException
2326
+	 * @throws EE_Error
2327
+	 * @throws EntityNotFoundException
2328
+	 * @throws InvalidArgumentException
2329
+	 * @throws InvalidDataTypeException
2330
+	 * @throws InvalidInterfaceException
2331
+	 * @throws ReflectionException
2332
+	 * @throws RuntimeException
2333
+	 * @throws UnexpectedEntityException
2334
+	 */
2335
+	public function delete($source = 'unknown')
2336
+	{
2337
+		if ($this->update_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY, $this->status_ID()) === true) {
2338
+			$current_user = wp_get_current_user();
2339
+			$this->add_extra_meta(
2340
+				EE_Registration::EXTRA_META_KEY_REG_TRASHED,
2341
+				array(
2342
+					'trashed-by' => $current_user->ID ? $current_user->display_name : 'unauthed user',
2343
+					'timestamp'  => time(),
2344
+					'source'     => $source,
2345
+				)
2346
+			);
2347
+			$this->set_status(EEM_Registration::status_id_cancelled);
2348
+		}
2349
+		return parent::delete();
2350
+	}
2351
+
2352
+
2353
+	/**
2354
+	 * Restores whatever the previous status was on a registration before it was trashed (if possible)
2355
+	 *
2356
+	 * @param string $source function name that called this method
2357
+	 * @return bool|int
2358
+	 * @throws DomainException
2359
+	 * @throws EE_Error
2360
+	 * @throws EntityNotFoundException
2361
+	 * @throws InvalidArgumentException
2362
+	 * @throws InvalidDataTypeException
2363
+	 * @throws InvalidInterfaceException
2364
+	 * @throws ReflectionException
2365
+	 * @throws RuntimeException
2366
+	 * @throws UnexpectedEntityException
2367
+	 */
2368
+	public function restore($source = 'unknown')
2369
+	{
2370
+		$previous_status = $this->get_extra_meta(
2371
+			EE_Registration::PRE_TRASH_REG_STATUS_KEY,
2372
+			true,
2373
+			EEM_Registration::status_id_cancelled
2374
+		);
2375
+		if ($previous_status) {
2376
+			$this->delete_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY);
2377
+			$this->set_status($previous_status);
2378
+		}
2379
+		$current_user = wp_get_current_user();
2380
+		$this->add_extra_meta(
2381
+			EE_Registration::EXTRA_META_KEY_REG_RESTORED,
2382
+			array(
2383
+				'restored-by' => $current_user->ID ? $current_user->display_name : 'unauthed user',
2384
+				'timestamp'   => time(),
2385
+				'source'      => $source,
2386
+			)
2387
+		);
2388
+		return parent::restore();
2389
+	}
2390
+
2391
+
2392
+	/**
2393
+	 * possibly toggle Registration status based on comparison of REG_paid vs REG_final_price
2394
+	 *
2395
+	 * @param  boolean $trigger_set_status_logic EE_Registration::set_status() can trigger additional logic
2396
+	 *                                           depending on whether the reg status changes to or from "Approved"
2397
+	 * @return boolean whether the Registration status was updated
2398
+	 * @throws DomainException
2399
+	 * @throws EE_Error
2400
+	 * @throws EntityNotFoundException
2401
+	 * @throws InvalidArgumentException
2402
+	 * @throws InvalidDataTypeException
2403
+	 * @throws InvalidInterfaceException
2404
+	 * @throws ReflectionException
2405
+	 * @throws RuntimeException
2406
+	 * @throws UnexpectedEntityException
2407
+	 */
2408
+	public function updateStatusBasedOnTotalPaid($trigger_set_status_logic = true)
2409
+	{
2410
+		$paid = $this->paid();
2411
+		$price = $this->final_price();
2412
+		switch (true) {
2413
+			// overpaid or paid
2414
+			case EEH_Money::compare_floats($paid, $price, '>'):
2415
+			case EEH_Money::compare_floats($paid, $price):
2416
+				$new_status = EEM_Registration::status_id_approved;
2417
+				break;
2418
+			//  underpaid
2419
+			case EEH_Money::compare_floats($paid, $price, '<'):
2420
+				$new_status = EEM_Registration::status_id_pending_payment;
2421
+				break;
2422
+			// uhhh Houston...
2423
+			default:
2424
+				throw new RuntimeException(
2425
+					esc_html__('The total paid calculation for this registration is inaccurate.', 'event_espresso')
2426
+				);
2427
+		}
2428
+		if ($new_status !== $this->status_ID()) {
2429
+			if ($trigger_set_status_logic) {
2430
+				return $this->set_status($new_status);
2431
+			}
2432
+			parent::set('STS_ID', $new_status);
2433
+			return true;
2434
+		}
2435
+		return false;
2436
+	}
2437
+
2438
+
2439
+	/*************************** DEPRECATED ***************************/
2440
+
2441
+
2442
+	/**
2443
+	 * @deprecated
2444
+	 * @since     4.7.0
2445
+	 */
2446
+	public function price_paid()
2447
+	{
2448
+		EE_Error::doing_it_wrong(
2449
+			'EE_Registration::price_paid()',
2450
+			esc_html__(
2451
+				'This method is deprecated, please use EE_Registration::final_price() instead.',
2452
+				'event_espresso'
2453
+			),
2454
+			'4.7.0'
2455
+		);
2456
+		return $this->final_price();
2457
+	}
2458
+
2459
+
2460
+	/**
2461
+	 * @deprecated
2462
+	 * @since     4.7.0
2463
+	 * @param    float $REG_final_price
2464
+	 * @throws EE_Error
2465
+	 * @throws EntityNotFoundException
2466
+	 * @throws InvalidArgumentException
2467
+	 * @throws InvalidDataTypeException
2468
+	 * @throws InvalidInterfaceException
2469
+	 * @throws ReflectionException
2470
+	 * @throws RuntimeException
2471
+	 * @throws DomainException
2472
+	 */
2473
+	public function set_price_paid($REG_final_price = 0.00)
2474
+	{
2475
+		EE_Error::doing_it_wrong(
2476
+			'EE_Registration::set_price_paid()',
2477
+			esc_html__(
2478
+				'This method is deprecated, please use EE_Registration::set_final_price() instead.',
2479
+				'event_espresso'
2480
+			),
2481
+			'4.7.0'
2482
+		);
2483
+		$this->set_final_price($REG_final_price);
2484
+	}
2485
+
2486
+
2487
+	/**
2488
+	 * @deprecated
2489
+	 * @since 4.7.0
2490
+	 * @return string
2491
+	 * @throws EE_Error
2492
+	 * @throws InvalidArgumentException
2493
+	 * @throws InvalidDataTypeException
2494
+	 * @throws InvalidInterfaceException
2495
+	 * @throws ReflectionException
2496
+	 */
2497
+	public function pretty_price_paid()
2498
+	{
2499
+		EE_Error::doing_it_wrong(
2500
+			'EE_Registration::pretty_price_paid()',
2501
+			esc_html__(
2502
+				'This method is deprecated, please use EE_Registration::pretty_final_price() instead.',
2503
+				'event_espresso'
2504
+			),
2505
+			'4.7.0'
2506
+		);
2507
+		return $this->pretty_final_price();
2508
+	}
2509
+
2510
+
2511
+	/**
2512
+	 * Gets the primary datetime related to this registration via the related Event to this registration
2513
+	 *
2514
+	 * @deprecated 4.9.17
2515
+	 * @return EE_Datetime
2516
+	 * @throws EE_Error
2517
+	 * @throws EntityNotFoundException
2518
+	 * @throws InvalidArgumentException
2519
+	 * @throws InvalidDataTypeException
2520
+	 * @throws InvalidInterfaceException
2521
+	 * @throws ReflectionException
2522
+	 */
2523
+	public function get_related_primary_datetime()
2524
+	{
2525
+		EE_Error::doing_it_wrong(
2526
+			__METHOD__,
2527
+			esc_html__(
2528
+				'Use EE_Registration::get_latest_related_datetime() or EE_Registration::get_earliest_related_datetime()',
2529
+				'event_espresso'
2530
+			),
2531
+			'4.9.17',
2532
+			'5.0.0'
2533
+		);
2534
+		return $this->event()->primary_datetime();
2535
+	}
2536
+
2537
+	/**
2538
+	 * Returns the contact's name (or "Unknown" if there is no contact.)
2539
+	 * @since 4.10.12.p
2540
+	 * @return string
2541
+	 * @throws EE_Error
2542
+	 * @throws InvalidArgumentException
2543
+	 * @throws InvalidDataTypeException
2544
+	 * @throws InvalidInterfaceException
2545
+	 * @throws ReflectionException
2546
+	 */
2547
+	public function name()
2548
+	{
2549
+		return $this->attendeeName();
2550
+	}
2551 2551
 }
Please login to merge, or discard this patch.
Spacing   +15 added lines, -15 removed lines patch added patch discarded remove patch
@@ -148,7 +148,7 @@  discard block
 block discarded – undo
148 148
     {
149 149
         switch ($field_name) {
150 150
             case 'REG_code':
151
-                if (! empty($field_value) && $this->reg_code() === null) {
151
+                if ( ! empty($field_value) && $this->reg_code() === null) {
152 152
                     $this->set_reg_code($field_value, $use_default);
153 153
                 }
154 154
                 break;
@@ -449,7 +449,7 @@  discard block
 block discarded – undo
449 449
     public function event()
450 450
     {
451 451
         $event = $this->get_first_related('Event');
452
-        if (! $event instanceof \EE_Event) {
452
+        if ( ! $event instanceof \EE_Event) {
453 453
             throw new EntityNotFoundException('Event ID', $this->event_ID());
454 454
         }
455 455
         return $event;
@@ -496,7 +496,7 @@  discard block
 block discarded – undo
496 496
     {
497 497
         // reserved ticket and datetime counts will be decremented as sold counts are incremented
498 498
         // so stop tracking that this reg has a ticket reserved
499
-        $this->release_reserved_ticket(false, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
499
+        $this->release_reserved_ticket(false, "REG: {$this->ID()} (ln:".__LINE__.')');
500 500
         $ticket = $this->ticket();
501 501
         $ticket->increaseSold();
502 502
         // possibly set event status to sold out
@@ -546,7 +546,7 @@  discard block
 block discarded – undo
546 546
             $reserved = $this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true);
547 547
             if ($reserved && $update_ticket) {
548 548
                 $ticket = $this->ticket();
549
-                $ticket->increaseReserved(1, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
549
+                $ticket->increaseReserved(1, "REG: {$this->ID()} (ln:".__LINE__.')');
550 550
                 $this->update_extra_meta('reserve_ticket', "{$this->ticket_ID()} from {$source}");
551 551
                 $ticket->save();
552 552
             }
@@ -574,7 +574,7 @@  discard block
 block discarded – undo
574 574
             $reserved = $this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, false);
575 575
             if ($reserved && $update_ticket) {
576 576
                 $ticket = $this->ticket();
577
-                $ticket->decreaseReserved(1, true, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
577
+                $ticket->decreaseReserved(1, true, "REG: {$this->ID()} (ln:".__LINE__.')');
578 578
                 $this->update_extra_meta('release_reserved_ticket', "{$this->ticket_ID()} from {$source}");
579 579
             }
580 580
         }
@@ -1460,7 +1460,7 @@  discard block
 block discarded – undo
1460 1460
                     : '';
1461 1461
                 break;
1462 1462
         }
1463
-        return $icon . $status[ $this->status_ID() ];
1463
+        return $icon.$status[$this->status_ID()];
1464 1464
     }
1465 1465
 
1466 1466
 
@@ -1716,7 +1716,7 @@  discard block
 block discarded – undo
1716 1716
     {
1717 1717
         $DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1718 1718
         // first check registration status
1719
-        if (! $DTT_ID || ($check_approved && ! $this->is_approved())) {
1719
+        if ( ! $DTT_ID || ($check_approved && ! $this->is_approved())) {
1720 1720
             return false;
1721 1721
         }
1722 1722
         // is there a datetime ticket that matches this dtt_ID?
@@ -1756,7 +1756,7 @@  discard block
 block discarded – undo
1756 1756
     {
1757 1757
         $DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1758 1758
 
1759
-        if (! $DTT_ID) {
1759
+        if ( ! $DTT_ID) {
1760 1760
             return false;
1761 1761
         }
1762 1762
 
@@ -1764,7 +1764,7 @@  discard block
 block discarded – undo
1764 1764
 
1765 1765
         // if max uses is not set or equals infinity then return true cause its not a factor for whether user can
1766 1766
         // check-in or not.
1767
-        if (! $max_uses || $max_uses === EE_INF) {
1767
+        if ( ! $max_uses || $max_uses === EE_INF) {
1768 1768
             return true;
1769 1769
         }
1770 1770
 
@@ -1828,7 +1828,7 @@  discard block
 block discarded – undo
1828 1828
             $datetime = $this->get_latest_related_datetime();
1829 1829
             $DTT_ID = $datetime instanceof EE_Datetime ? $datetime->ID() : 0;
1830 1830
             // verify the registration can checkin for the given DTT_ID
1831
-        } elseif (! $this->can_checkin($DTT_ID, $verify)) {
1831
+        } elseif ( ! $this->can_checkin($DTT_ID, $verify)) {
1832 1832
             EE_Error::add_error(
1833 1833
                 sprintf(
1834 1834
                     esc_html__(
@@ -1851,7 +1851,7 @@  discard block
 block discarded – undo
1851 1851
         );
1852 1852
         // start by getting the current status so we know what status we'll be changing to.
1853 1853
         $cur_status = $this->check_in_status_for_datetime($DTT_ID);
1854
-        $status_to = $status_paths[ $cur_status ];
1854
+        $status_to = $status_paths[$cur_status];
1855 1855
         // database only records true for checked IN or false for checked OUT
1856 1856
         // no record ( null ) means checked in NEVER, but we obviously don't save that
1857 1857
         $new_status = $status_to === EE_Checkin::status_checked_in;
@@ -2042,7 +2042,7 @@  discard block
 block discarded – undo
2042 2042
     public function transaction()
2043 2043
     {
2044 2044
         $transaction = $this->get_first_related('Transaction');
2045
-        if (! $transaction instanceof \EE_Transaction) {
2045
+        if ( ! $transaction instanceof \EE_Transaction) {
2046 2046
             throw new EntityNotFoundException('Transaction ID', $this->transaction_ID());
2047 2047
         }
2048 2048
         return $transaction;
@@ -2115,11 +2115,11 @@  discard block
 block discarded – undo
2115 2115
             );
2116 2116
             return;
2117 2117
         }
2118
-        if (! $this->reg_code()) {
2118
+        if ( ! $this->reg_code()) {
2119 2119
             parent::set('REG_code', $REG_code, $use_default);
2120 2120
         } else {
2121 2121
             EE_Error::doing_it_wrong(
2122
-                __CLASS__ . '::' . __FUNCTION__,
2122
+                __CLASS__.'::'.__FUNCTION__,
2123 2123
                 esc_html__('Can not change a registration REG_code once it has been set.', 'event_espresso'),
2124 2124
                 '4.6.0'
2125 2125
             );
@@ -2310,7 +2310,7 @@  discard block
 block discarded – undo
2310 2310
                 break;
2311 2311
             }
2312 2312
         }
2313
-        if (! ($line_item instanceof \EE_Line_Item && $line_item->OBJ_type() === 'Ticket')) {
2313
+        if ( ! ($line_item instanceof \EE_Line_Item && $line_item->OBJ_type() === 'Ticket')) {
2314 2314
             throw new EntityNotFoundException('Line Item Ticket ID', $ticket->ID());
2315 2315
         }
2316 2316
         return $line_item;
Please login to merge, or discard this patch.
admin_pages/registrations/Registrations_Admin_Page.core.php 1 patch
Indentation   +3686 added lines, -3686 removed lines patch added patch discarded remove patch
@@ -22,2225 +22,2225 @@  discard block
 block discarded – undo
22 22
 class Registrations_Admin_Page extends EE_Admin_Page_CPT
23 23
 {
24 24
 
25
-    /**
26
-     * @var EE_Registration
27
-     */
28
-    private $_registration;
29
-
30
-    /**
31
-     * @var EE_Event
32
-     */
33
-    private $_reg_event;
34
-
35
-    /**
36
-     * @var EE_Session
37
-     */
38
-    private $_session;
39
-
40
-    /**
41
-     * @var array
42
-     */
43
-    private static $_reg_status;
44
-
45
-    /**
46
-     * Form for displaying the custom questions for this registration.
47
-     * This gets used a few times throughout the request so its best to cache it
48
-     *
49
-     * @var EE_Registration_Custom_Questions_Form
50
-     */
51
-    protected $_reg_custom_questions_form = null;
52
-
53
-    /**
54
-     * @var EEM_Registration $registration_model
55
-     */
56
-    private $registration_model;
57
-
58
-    /**
59
-     * @var EEM_Attendee $attendee_model
60
-     */
61
-    private $attendee_model;
62
-
63
-    /**
64
-     * @var EEM_Event $event_model
65
-     */
66
-    private $event_model;
67
-
68
-    /**
69
-     * @var EEM_Status $status_model
70
-     */
71
-    private $status_model;
72
-
73
-
74
-    /**
75
-     * @param bool $routing
76
-     * @throws EE_Error
77
-     * @throws InvalidArgumentException
78
-     * @throws InvalidDataTypeException
79
-     * @throws InvalidInterfaceException
80
-     * @throws ReflectionException
81
-     */
82
-    public function __construct($routing = true)
83
-    {
84
-        parent::__construct($routing);
85
-        add_action('wp_loaded', [$this, 'wp_loaded']);
86
-    }
87
-
88
-
89
-    /**
90
-     * @return EEM_Registration
91
-     * @throws InvalidArgumentException
92
-     * @throws InvalidDataTypeException
93
-     * @throws InvalidInterfaceException
94
-     * @since 4.10.2.p
95
-     */
96
-    protected function getRegistrationModel()
97
-    {
98
-        if (! $this->registration_model instanceof EEM_Registration) {
99
-            $this->registration_model = $this->getLoader()->getShared('EEM_Registration');
100
-        }
101
-        return $this->registration_model;
102
-    }
103
-
104
-
105
-    /**
106
-     * @return EEM_Attendee
107
-     * @throws InvalidArgumentException
108
-     * @throws InvalidDataTypeException
109
-     * @throws InvalidInterfaceException
110
-     * @since 4.10.2.p
111
-     */
112
-    protected function getAttendeeModel()
113
-    {
114
-        if (! $this->attendee_model instanceof EEM_Attendee) {
115
-            $this->attendee_model = $this->getLoader()->getShared('EEM_Attendee');
116
-        }
117
-        return $this->attendee_model;
118
-    }
119
-
120
-
121
-    /**
122
-     * @return EEM_Event
123
-     * @throws InvalidArgumentException
124
-     * @throws InvalidDataTypeException
125
-     * @throws InvalidInterfaceException
126
-     * @since 4.10.2.p
127
-     */
128
-    protected function getEventModel()
129
-    {
130
-        if (! $this->event_model instanceof EEM_Event) {
131
-            $this->event_model = $this->getLoader()->getShared('EEM_Event');
132
-        }
133
-        return $this->event_model;
134
-    }
135
-
136
-
137
-    /**
138
-     * @return EEM_Status
139
-     * @throws InvalidArgumentException
140
-     * @throws InvalidDataTypeException
141
-     * @throws InvalidInterfaceException
142
-     * @since 4.10.2.p
143
-     */
144
-    protected function getStatusModel()
145
-    {
146
-        if (! $this->status_model instanceof EEM_Status) {
147
-            $this->status_model = $this->getLoader()->getShared('EEM_Status');
148
-        }
149
-        return $this->status_model;
150
-    }
151
-
152
-
153
-    public function wp_loaded()
154
-    {
155
-        // when adding a new registration...
156
-        $action = $this->request->getRequestParam('action');
157
-        if ($action === 'new_registration') {
158
-            EE_System::do_not_cache();
159
-            if ($this->request->getRequestParam('processing_registration', 0, 'int') !== 1) {
160
-                // and it's NOT the attendee information reg step
161
-                // force cookie expiration by setting time to last week
162
-                setcookie('ee_registration_added', 0, time() - WEEK_IN_SECONDS, '/');
163
-                // and update the global
164
-                $_COOKIE['ee_registration_added'] = 0;
165
-            }
166
-        }
167
-    }
168
-
169
-
170
-    protected function _init_page_props()
171
-    {
172
-        $this->page_slug        = REG_PG_SLUG;
173
-        $this->_admin_base_url  = REG_ADMIN_URL;
174
-        $this->_admin_base_path = REG_ADMIN;
175
-        $this->page_label       = esc_html__('Registrations', 'event_espresso');
176
-        $this->_cpt_routes      = [
177
-            'add_new_attendee' => 'espresso_attendees',
178
-            'edit_attendee'    => 'espresso_attendees',
179
-            'insert_attendee'  => 'espresso_attendees',
180
-            'update_attendee'  => 'espresso_attendees',
181
-        ];
182
-        $this->_cpt_model_names = [
183
-            'add_new_attendee' => 'EEM_Attendee',
184
-            'edit_attendee'    => 'EEM_Attendee',
185
-        ];
186
-        $this->_cpt_edit_routes = [
187
-            'espresso_attendees' => 'edit_attendee',
188
-        ];
189
-        $this->_pagenow_map     = [
190
-            'add_new_attendee' => 'post-new.php',
191
-            'edit_attendee'    => 'post.php',
192
-            'trash'            => 'post.php',
193
-        ];
194
-        add_action('edit_form_after_title', [$this, 'after_title_form_fields'], 10);
195
-        // add filters so that the comment urls don't take users to a confusing 404 page
196
-        add_filter('get_comment_link', [$this, 'clear_comment_link'], 10, 2);
197
-    }
198
-
199
-
200
-    /**
201
-     * @param string     $link    The comment permalink with '#comment-$id' appended.
202
-     * @param WP_Comment $comment The current comment object.
203
-     * @return string
204
-     */
205
-    public function clear_comment_link($link, WP_Comment $comment)
206
-    {
207
-        // gotta make sure this only happens on this route
208
-        $post_type = get_post_type($comment->comment_post_ID);
209
-        if ($post_type === 'espresso_attendees') {
210
-            return '#commentsdiv';
211
-        }
212
-        return $link;
213
-    }
214
-
215
-
216
-    protected function _ajax_hooks()
217
-    {
218
-        // todo: all hooks for registrations ajax goes in here
219
-        add_action('wp_ajax_toggle_checkin_status', [$this, 'toggle_checkin_status']);
220
-    }
221
-
222
-
223
-    protected function _define_page_props()
224
-    {
225
-        $this->_admin_page_title = $this->page_label;
226
-        $this->_labels           = [
227
-            'buttons'                      => [
228
-                'add-registrant'      => esc_html__('Add New Registration', 'event_espresso'),
229
-                'add-attendee'        => esc_html__('Add Contact', 'event_espresso'),
230
-                'edit'                => esc_html__('Edit Contact', 'event_espresso'),
231
-                'csv_reg_report'      => esc_html__('Registrations CSV Report', 'event_espresso'),
232
-                'contact_list_report' => esc_html__('Contact List Report', 'event_espresso'),
233
-                'contact_list_export' => esc_html__('Export Data', 'event_espresso'),
234
-            ],
235
-            'publishbox'                   => [
236
-                'add_new_attendee' => esc_html__('Add Contact Record', 'event_espresso'),
237
-                'edit_attendee'    => esc_html__('Update Contact Record', 'event_espresso'),
238
-            ],
239
-            'hide_add_button_on_cpt_route' => [
240
-                'edit_attendee' => true,
241
-            ],
242
-        ];
243
-    }
244
-
245
-
246
-    /**
247
-     * grab url requests and route them
248
-     *
249
-     * @return void
250
-     * @throws EE_Error
251
-     */
252
-    public function _set_page_routes()
253
-    {
254
-        $this->_get_registration_status_array();
255
-        $REG_ID             = $this->request->getRequestParam('_REG_ID', 0, 'int');
256
-        $REG_ID             = $this->request->getRequestParam('reg_status_change_form[REG_ID]', $REG_ID, 'int');
257
-        $ATT_ID             = $this->request->getRequestParam('ATT_ID', 0, 'int');
258
-        $ATT_ID             = $this->request->getRequestParam('post', $ATT_ID, 'int');
259
-        $this->_page_routes = [
260
-            'default'                             => [
261
-                'func'       => [$this, '_registrations_overview_list_table'],
262
-                'capability' => 'ee_read_registrations',
263
-            ],
264
-            'view_registration'                   => [
265
-                'func'       => '_registration_details',
266
-                'capability' => 'ee_read_registration',
267
-                'obj_id'     => $REG_ID,
268
-            ],
269
-            'edit_registration'                   => [
270
-                'func'               => '_update_attendee_registration_form',
271
-                'noheader'           => true,
272
-                'headers_sent_route' => 'view_registration',
273
-                'capability'         => 'ee_edit_registration',
274
-                'obj_id'             => $REG_ID,
275
-                '_REG_ID'            => $REG_ID,
276
-            ],
277
-            'trash_registrations'                 => [
278
-                'func'       => '_trash_or_restore_registrations',
279
-                'args'       => ['trash' => true],
280
-                'noheader'   => true,
281
-                'capability' => 'ee_delete_registrations',
282
-            ],
283
-            'restore_registrations'               => [
284
-                'func'       => '_trash_or_restore_registrations',
285
-                'args'       => ['trash' => false],
286
-                'noheader'   => true,
287
-                'capability' => 'ee_delete_registrations',
288
-            ],
289
-            'delete_registrations'                => [
290
-                'func'       => '_delete_registrations',
291
-                'noheader'   => true,
292
-                'capability' => 'ee_delete_registrations',
293
-            ],
294
-            'new_registration'                    => [
295
-                'func'       => 'new_registration',
296
-                'capability' => 'ee_edit_registrations',
297
-            ],
298
-            'process_reg_step'                    => [
299
-                'func'       => 'process_reg_step',
300
-                'noheader'   => true,
301
-                'capability' => 'ee_edit_registrations',
302
-            ],
303
-            'redirect_to_txn'                     => [
304
-                'func'       => 'redirect_to_txn',
305
-                'noheader'   => true,
306
-                'capability' => 'ee_edit_registrations',
307
-            ],
308
-            'change_reg_status'                   => [
309
-                'func'       => '_change_reg_status',
310
-                'noheader'   => true,
311
-                'capability' => 'ee_edit_registration',
312
-                'obj_id'     => $REG_ID,
313
-            ],
314
-            'approve_registration'                => [
315
-                'func'       => 'approve_registration',
316
-                'noheader'   => true,
317
-                'capability' => 'ee_edit_registration',
318
-                'obj_id'     => $REG_ID,
319
-            ],
320
-            'approve_and_notify_registration'     => [
321
-                'func'       => 'approve_registration',
322
-                'noheader'   => true,
323
-                'args'       => [true],
324
-                'capability' => 'ee_edit_registration',
325
-                'obj_id'     => $REG_ID,
326
-            ],
327
-            'approve_registrations'               => [
328
-                'func'       => 'bulk_action_on_registrations',
329
-                'noheader'   => true,
330
-                'capability' => 'ee_edit_registrations',
331
-                'args'       => ['approve'],
332
-            ],
333
-            'approve_and_notify_registrations'    => [
334
-                'func'       => 'bulk_action_on_registrations',
335
-                'noheader'   => true,
336
-                'capability' => 'ee_edit_registrations',
337
-                'args'       => ['approve', true],
338
-            ],
339
-            'decline_registration'                => [
340
-                'func'       => 'decline_registration',
341
-                'noheader'   => true,
342
-                'capability' => 'ee_edit_registration',
343
-                'obj_id'     => $REG_ID,
344
-            ],
345
-            'decline_and_notify_registration'     => [
346
-                'func'       => 'decline_registration',
347
-                'noheader'   => true,
348
-                'args'       => [true],
349
-                'capability' => 'ee_edit_registration',
350
-                'obj_id'     => $REG_ID,
351
-            ],
352
-            'decline_registrations'               => [
353
-                'func'       => 'bulk_action_on_registrations',
354
-                'noheader'   => true,
355
-                'capability' => 'ee_edit_registrations',
356
-                'args'       => ['decline'],
357
-            ],
358
-            'decline_and_notify_registrations'    => [
359
-                'func'       => 'bulk_action_on_registrations',
360
-                'noheader'   => true,
361
-                'capability' => 'ee_edit_registrations',
362
-                'args'       => ['decline', true],
363
-            ],
364
-            'pending_registration'                => [
365
-                'func'       => 'pending_registration',
366
-                'noheader'   => true,
367
-                'capability' => 'ee_edit_registration',
368
-                'obj_id'     => $REG_ID,
369
-            ],
370
-            'pending_and_notify_registration'     => [
371
-                'func'       => 'pending_registration',
372
-                'noheader'   => true,
373
-                'args'       => [true],
374
-                'capability' => 'ee_edit_registration',
375
-                'obj_id'     => $REG_ID,
376
-            ],
377
-            'pending_registrations'               => [
378
-                'func'       => 'bulk_action_on_registrations',
379
-                'noheader'   => true,
380
-                'capability' => 'ee_edit_registrations',
381
-                'args'       => ['pending'],
382
-            ],
383
-            'pending_and_notify_registrations'    => [
384
-                'func'       => 'bulk_action_on_registrations',
385
-                'noheader'   => true,
386
-                'capability' => 'ee_edit_registrations',
387
-                'args'       => ['pending', true],
388
-            ],
389
-            'no_approve_registration'             => [
390
-                'func'       => 'not_approve_registration',
391
-                'noheader'   => true,
392
-                'capability' => 'ee_edit_registration',
393
-                'obj_id'     => $REG_ID,
394
-            ],
395
-            'no_approve_and_notify_registration'  => [
396
-                'func'       => 'not_approve_registration',
397
-                'noheader'   => true,
398
-                'args'       => [true],
399
-                'capability' => 'ee_edit_registration',
400
-                'obj_id'     => $REG_ID,
401
-            ],
402
-            'no_approve_registrations'            => [
403
-                'func'       => 'bulk_action_on_registrations',
404
-                'noheader'   => true,
405
-                'capability' => 'ee_edit_registrations',
406
-                'args'       => ['not_approve'],
407
-            ],
408
-            'no_approve_and_notify_registrations' => [
409
-                'func'       => 'bulk_action_on_registrations',
410
-                'noheader'   => true,
411
-                'capability' => 'ee_edit_registrations',
412
-                'args'       => ['not_approve', true],
413
-            ],
414
-            'cancel_registration'                 => [
415
-                'func'       => 'cancel_registration',
416
-                'noheader'   => true,
417
-                'capability' => 'ee_edit_registration',
418
-                'obj_id'     => $REG_ID,
419
-            ],
420
-            'cancel_and_notify_registration'      => [
421
-                'func'       => 'cancel_registration',
422
-                'noheader'   => true,
423
-                'args'       => [true],
424
-                'capability' => 'ee_edit_registration',
425
-                'obj_id'     => $REG_ID,
426
-            ],
427
-            'cancel_registrations'                => [
428
-                'func'       => 'bulk_action_on_registrations',
429
-                'noheader'   => true,
430
-                'capability' => 'ee_edit_registrations',
431
-                'args'       => ['cancel'],
432
-            ],
433
-            'cancel_and_notify_registrations'     => [
434
-                'func'       => 'bulk_action_on_registrations',
435
-                'noheader'   => true,
436
-                'capability' => 'ee_edit_registrations',
437
-                'args'       => ['cancel', true],
438
-            ],
439
-            'wait_list_registration'              => [
440
-                'func'       => 'wait_list_registration',
441
-                'noheader'   => true,
442
-                'capability' => 'ee_edit_registration',
443
-                'obj_id'     => $REG_ID,
444
-            ],
445
-            'wait_list_and_notify_registration'   => [
446
-                'func'       => 'wait_list_registration',
447
-                'noheader'   => true,
448
-                'args'       => [true],
449
-                'capability' => 'ee_edit_registration',
450
-                'obj_id'     => $REG_ID,
451
-            ],
452
-            'contact_list'                        => [
453
-                'func'       => '_attendee_contact_list_table',
454
-                'capability' => 'ee_read_contacts',
455
-            ],
456
-            'add_new_attendee'                    => [
457
-                'func' => '_create_new_cpt_item',
458
-                'args' => [
459
-                    'new_attendee' => true,
460
-                    'capability'   => 'ee_edit_contacts',
461
-                ],
462
-            ],
463
-            'edit_attendee'                       => [
464
-                'func'       => '_edit_cpt_item',
465
-                'capability' => 'ee_edit_contacts',
466
-                'obj_id'     => $ATT_ID,
467
-            ],
468
-            'duplicate_attendee'                  => [
469
-                'func'       => '_duplicate_attendee',
470
-                'noheader'   => true,
471
-                'capability' => 'ee_edit_contacts',
472
-                'obj_id'     => $ATT_ID,
473
-            ],
474
-            'insert_attendee'                     => [
475
-                'func'       => '_insert_or_update_attendee',
476
-                'args'       => [
477
-                    'new_attendee' => true,
478
-                ],
479
-                'noheader'   => true,
480
-                'capability' => 'ee_edit_contacts',
481
-            ],
482
-            'update_attendee'                     => [
483
-                'func'       => '_insert_or_update_attendee',
484
-                'args'       => [
485
-                    'new_attendee' => false,
486
-                ],
487
-                'noheader'   => true,
488
-                'capability' => 'ee_edit_contacts',
489
-                'obj_id'     => $ATT_ID,
490
-            ],
491
-            'trash_attendees'                     => [
492
-                'func'       => '_trash_or_restore_attendees',
493
-                'args'       => [
494
-                    'trash' => 'true',
495
-                ],
496
-                'noheader'   => true,
497
-                'capability' => 'ee_delete_contacts',
498
-            ],
499
-            'trash_attendee'                      => [
500
-                'func'       => '_trash_or_restore_attendees',
501
-                'args'       => [
502
-                    'trash' => true,
503
-                ],
504
-                'noheader'   => true,
505
-                'capability' => 'ee_delete_contacts',
506
-                'obj_id'     => $ATT_ID,
507
-            ],
508
-            'restore_attendees'                   => [
509
-                'func'       => '_trash_or_restore_attendees',
510
-                'args'       => [
511
-                    'trash' => false,
512
-                ],
513
-                'noheader'   => true,
514
-                'capability' => 'ee_delete_contacts',
515
-                'obj_id'     => $ATT_ID,
516
-            ],
517
-            'resend_registration'                 => [
518
-                'func'       => '_resend_registration',
519
-                'noheader'   => true,
520
-                'capability' => 'ee_send_message',
521
-            ],
522
-            'registrations_report'                => [
523
-                'func'       => [$this, '_registrations_report'],
524
-                'noheader'   => true,
525
-                'capability' => 'ee_read_registrations',
526
-            ],
527
-            'contact_list_export'                 => [
528
-                'func'       => '_contact_list_export',
529
-                'noheader'   => true,
530
-                'capability' => 'export',
531
-            ],
532
-            'contact_list_report'                 => [
533
-                'func'       => '_contact_list_report',
534
-                'noheader'   => true,
535
-                'capability' => 'ee_read_contacts',
536
-            ],
537
-        ];
538
-    }
539
-
540
-
541
-    protected function _set_page_config()
542
-    {
543
-        $REG_ID             = $this->request->getRequestParam('_REG_ID', 0, 'int');
544
-        $ATT_ID             = $this->request->getRequestParam('ATT_ID', 0, 'int');
545
-        $this->_page_config = [
546
-            'default'           => [
547
-                'nav'           => [
548
-                    'label' => esc_html__('Overview', 'event_espresso'),
549
-                    'order' => 5,
550
-                ],
551
-                'help_tabs'     => [
552
-                    'registrations_overview_help_tab'                       => [
553
-                        'title'    => esc_html__('Registrations Overview', 'event_espresso'),
554
-                        'filename' => 'registrations_overview',
555
-                    ],
556
-                    'registrations_overview_table_column_headings_help_tab' => [
557
-                        'title'    => esc_html__('Registrations Table Column Headings', 'event_espresso'),
558
-                        'filename' => 'registrations_overview_table_column_headings',
559
-                    ],
560
-                    'registrations_overview_filters_help_tab'               => [
561
-                        'title'    => esc_html__('Registration Filters', 'event_espresso'),
562
-                        'filename' => 'registrations_overview_filters',
563
-                    ],
564
-                    'registrations_overview_views_help_tab'                 => [
565
-                        'title'    => esc_html__('Registration Views', 'event_espresso'),
566
-                        'filename' => 'registrations_overview_views',
567
-                    ],
568
-                    'registrations_regoverview_other_help_tab'              => [
569
-                        'title'    => esc_html__('Registrations Other', 'event_espresso'),
570
-                        'filename' => 'registrations_overview_other',
571
-                    ],
572
-                ],
573
-                'qtips'         => ['Registration_List_Table_Tips'],
574
-                'list_table'    => 'EE_Registrations_List_Table',
575
-                'require_nonce' => false,
576
-            ],
577
-            'view_registration' => [
578
-                'nav'           => [
579
-                    'label'      => esc_html__('REG Details', 'event_espresso'),
580
-                    'order'      => 15,
581
-                    'url'        => $REG_ID
582
-                        ? add_query_arg(['_REG_ID' => $REG_ID], $this->_current_page_view_url)
583
-                        : $this->_admin_base_url,
584
-                    'persistent' => false,
585
-                ],
586
-                'help_tabs'     => [
587
-                    'registrations_details_help_tab'                    => [
588
-                        'title'    => esc_html__('Registration Details', 'event_espresso'),
589
-                        'filename' => 'registrations_details',
590
-                    ],
591
-                    'registrations_details_table_help_tab'              => [
592
-                        'title'    => esc_html__('Registration Details Table', 'event_espresso'),
593
-                        'filename' => 'registrations_details_table',
594
-                    ],
595
-                    'registrations_details_form_answers_help_tab'       => [
596
-                        'title'    => esc_html__('Registration Form Answers', 'event_espresso'),
597
-                        'filename' => 'registrations_details_form_answers',
598
-                    ],
599
-                    'registrations_details_registrant_details_help_tab' => [
600
-                        'title'    => esc_html__('Contact Details', 'event_espresso'),
601
-                        'filename' => 'registrations_details_registrant_details',
602
-                    ],
603
-                ],
604
-                'metaboxes'     => array_merge(
605
-                    $this->_default_espresso_metaboxes,
606
-                    ['_registration_details_metaboxes']
607
-                ),
608
-                'require_nonce' => false,
609
-            ],
610
-            'new_registration'  => [
611
-                'nav'           => [
612
-                    'label'      => esc_html__('Add New Registration', 'event_espresso'),
613
-                    'url'        => '#',
614
-                    'order'      => 15,
615
-                    'persistent' => false,
616
-                ],
617
-                'metaboxes'     => $this->_default_espresso_metaboxes,
618
-                'labels'        => [
619
-                    'publishbox' => esc_html__('Save Registration', 'event_espresso'),
620
-                ],
621
-                'require_nonce' => false,
622
-            ],
623
-            'add_new_attendee'  => [
624
-                'nav'           => [
625
-                    'label'      => esc_html__('Add Contact', 'event_espresso'),
626
-                    'order'      => 15,
627
-                    'persistent' => false,
628
-                ],
629
-                'metaboxes'     => array_merge(
630
-                    $this->_default_espresso_metaboxes,
631
-                    ['_publish_post_box', 'attendee_editor_metaboxes']
632
-                ),
633
-                'require_nonce' => false,
634
-            ],
635
-            'edit_attendee'     => [
636
-                'nav'           => [
637
-                    'label'      => esc_html__('Edit Contact', 'event_espresso'),
638
-                    'order'      => 15,
639
-                    'persistent' => false,
640
-                    'url'        => $ATT_ID
641
-                        ? add_query_arg(['ATT_ID' => $ATT_ID], $this->_current_page_view_url)
642
-                        : $this->_admin_base_url,
643
-                ],
644
-                'metaboxes'     => ['attendee_editor_metaboxes'],
645
-                'require_nonce' => false,
646
-            ],
647
-            'contact_list'      => [
648
-                'nav'           => [
649
-                    'label' => esc_html__('Contact List', 'event_espresso'),
650
-                    'order' => 20,
651
-                ],
652
-                'list_table'    => 'EE_Attendee_Contact_List_Table',
653
-                'help_tabs'     => [
654
-                    'registrations_contact_list_help_tab'                       => [
655
-                        'title'    => esc_html__('Registrations Contact List', 'event_espresso'),
656
-                        'filename' => 'registrations_contact_list',
657
-                    ],
658
-                    'registrations_contact-list_table_column_headings_help_tab' => [
659
-                        'title'    => esc_html__('Contact List Table Column Headings', 'event_espresso'),
660
-                        'filename' => 'registrations_contact_list_table_column_headings',
661
-                    ],
662
-                    'registrations_contact_list_views_help_tab'                 => [
663
-                        'title'    => esc_html__('Contact List Views', 'event_espresso'),
664
-                        'filename' => 'registrations_contact_list_views',
665
-                    ],
666
-                    'registrations_contact_list_other_help_tab'                 => [
667
-                        'title'    => esc_html__('Contact List Other', 'event_espresso'),
668
-                        'filename' => 'registrations_contact_list_other',
669
-                    ],
670
-                ],
671
-                'metaboxes'     => [],
672
-                'require_nonce' => false,
673
-            ],
674
-            // override default cpt routes
675
-            'create_new'        => '',
676
-            'edit'              => '',
677
-        ];
678
-    }
679
-
680
-
681
-    /**
682
-     * The below methods aren't used by this class currently
683
-     */
684
-    protected function _add_screen_options()
685
-    {
686
-    }
687
-
688
-
689
-    protected function _add_feature_pointers()
690
-    {
691
-    }
692
-
693
-
694
-    public function admin_init()
695
-    {
696
-        EE_Registry::$i18n_js_strings['update_att_qstns'] = esc_html__(
697
-            'click "Update Registration Questions" to save your changes',
698
-            'event_espresso'
699
-        );
700
-    }
701
-
702
-
703
-    public function admin_notices()
704
-    {
705
-    }
706
-
707
-
708
-    public function admin_footer_scripts()
709
-    {
710
-    }
711
-
712
-
713
-    /**
714
-     * get list of registration statuses
715
-     *
716
-     * @return void
717
-     * @throws EE_Error
718
-     */
719
-    private function _get_registration_status_array()
720
-    {
721
-        self::$_reg_status = EEM_Registration::reg_status_array([], true);
722
-    }
723
-
724
-
725
-    /**
726
-     * @throws InvalidArgumentException
727
-     * @throws InvalidDataTypeException
728
-     * @throws InvalidInterfaceException
729
-     * @since 4.10.2.p
730
-     */
731
-    protected function _add_screen_options_default()
732
-    {
733
-        $this->_per_page_screen_option();
734
-    }
735
-
736
-
737
-    /**
738
-     * @throws InvalidArgumentException
739
-     * @throws InvalidDataTypeException
740
-     * @throws InvalidInterfaceException
741
-     * @since 4.10.2.p
742
-     */
743
-    protected function _add_screen_options_contact_list()
744
-    {
745
-        $page_title              = $this->_admin_page_title;
746
-        $this->_admin_page_title = esc_html__('Contacts', 'event_espresso');
747
-        $this->_per_page_screen_option();
748
-        $this->_admin_page_title = $page_title;
749
-    }
750
-
751
-
752
-    public function load_scripts_styles()
753
-    {
754
-        // style
755
-        wp_register_style(
756
-            'espresso_reg',
757
-            REG_ASSETS_URL . 'espresso_registrations_admin.css',
758
-            ['ee-admin-css'],
759
-            EVENT_ESPRESSO_VERSION
760
-        );
761
-        wp_enqueue_style('espresso_reg');
762
-        // script
763
-        wp_register_script(
764
-            'espresso_reg',
765
-            REG_ASSETS_URL . 'espresso_registrations_admin.js',
766
-            ['jquery-ui-datepicker', 'jquery-ui-draggable', 'ee_admin_js'],
767
-            EVENT_ESPRESSO_VERSION,
768
-            true
769
-        );
770
-        wp_enqueue_script('espresso_reg');
771
-    }
772
-
773
-
774
-    /**
775
-     * @throws EE_Error
776
-     * @throws InvalidArgumentException
777
-     * @throws InvalidDataTypeException
778
-     * @throws InvalidInterfaceException
779
-     * @throws ReflectionException
780
-     * @since 4.10.2.p
781
-     */
782
-    public function load_scripts_styles_edit_attendee()
783
-    {
784
-        // stuff to only show up on our attendee edit details page.
785
-        $attendee_details_translations = [
786
-            'att_publish_text' => sprintf(
787
-            /* translators: The date and time */
788
-                wp_strip_all_tags(__('Created on: %s', 'event_espresso')),
789
-                '<b>' . $this->_cpt_model_obj->get_datetime('ATT_created') . '</b>'
790
-            ),
791
-        ];
792
-        wp_localize_script('espresso_reg', 'ATTENDEE_DETAILS', $attendee_details_translations);
793
-        wp_enqueue_script('jquery-validate');
794
-    }
795
-
796
-
797
-    /**
798
-     * @throws EE_Error
799
-     * @throws InvalidArgumentException
800
-     * @throws InvalidDataTypeException
801
-     * @throws InvalidInterfaceException
802
-     * @throws ReflectionException
803
-     * @since 4.10.2.p
804
-     */
805
-    public function load_scripts_styles_view_registration()
806
-    {
807
-        // styles
808
-        wp_enqueue_style('espresso-ui-theme');
809
-        // scripts
810
-        $this->_get_reg_custom_questions_form($this->_registration->ID());
811
-        $this->_reg_custom_questions_form->wp_enqueue_scripts();
812
-    }
813
-
814
-
815
-    public function load_scripts_styles_contact_list()
816
-    {
817
-        wp_dequeue_style('espresso_reg');
818
-        wp_register_style(
819
-            'espresso_att',
820
-            REG_ASSETS_URL . 'espresso_attendees_admin.css',
821
-            ['ee-admin-css'],
822
-            EVENT_ESPRESSO_VERSION
823
-        );
824
-        wp_enqueue_style('espresso_att');
825
-    }
826
-
827
-
828
-    public function load_scripts_styles_new_registration()
829
-    {
830
-        wp_register_script(
831
-            'ee-spco-for-admin',
832
-            REG_ASSETS_URL . 'spco_for_admin.js',
833
-            ['underscore', 'jquery'],
834
-            EVENT_ESPRESSO_VERSION,
835
-            true
836
-        );
837
-        wp_enqueue_script('ee-spco-for-admin');
838
-        add_filter('FHEE__EED_Ticket_Selector__load_tckt_slctr_assets', '__return_true');
839
-        EE_Form_Section_Proper::wp_enqueue_scripts();
840
-        EED_Ticket_Selector::load_tckt_slctr_assets();
841
-        EE_Datepicker_Input::enqueue_styles_and_scripts();
842
-    }
843
-
844
-
845
-    public function AHEE__EE_Admin_Page__route_admin_request_resend_registration()
846
-    {
847
-        add_filter('FHEE_load_EE_messages', '__return_true');
848
-    }
849
-
850
-
851
-    public function AHEE__EE_Admin_Page__route_admin_request_approve_registration()
852
-    {
853
-        add_filter('FHEE_load_EE_messages', '__return_true');
854
-    }
855
-
856
-
857
-    /**
858
-     * @throws EE_Error
859
-     * @throws InvalidArgumentException
860
-     * @throws InvalidDataTypeException
861
-     * @throws InvalidInterfaceException
862
-     * @throws ReflectionException
863
-     * @since 4.10.2.p
864
-     */
865
-    protected function _set_list_table_views_default()
866
-    {
867
-        // for notification related bulk actions we need to make sure only active messengers have an option.
868
-        EED_Messages::set_autoloaders();
869
-        /** @type EE_Message_Resource_Manager $message_resource_manager */
870
-        $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
871
-        $active_mts               = $message_resource_manager->list_of_active_message_types();
872
-        // key= bulk_action_slug, value= message type.
873
-        $match_array = [
874
-            'approve_registrations'    => 'registration',
875
-            'decline_registrations'    => 'declined_registration',
876
-            'pending_registrations'    => 'pending_approval',
877
-            'no_approve_registrations' => 'not_approved_registration',
878
-            'cancel_registrations'     => 'cancelled_registration',
879
-        ];
880
-        $can_send    = EE_Registry::instance()->CAP->current_user_can(
881
-            'ee_send_message',
882
-            'batch_send_messages'
883
-        );
884
-        /** setup reg status bulk actions **/
885
-        $def_reg_status_actions['approve_registrations'] = esc_html__('Approve Registrations', 'event_espresso');
886
-        if ($can_send && in_array($match_array['approve_registrations'], $active_mts, true)) {
887
-            $def_reg_status_actions['approve_and_notify_registrations'] = esc_html__(
888
-                'Approve and Notify Registrations',
889
-                'event_espresso'
890
-            );
891
-        }
892
-        $def_reg_status_actions['decline_registrations'] = esc_html__('Decline Registrations', 'event_espresso');
893
-        if ($can_send && in_array($match_array['decline_registrations'], $active_mts, true)) {
894
-            $def_reg_status_actions['decline_and_notify_registrations'] = esc_html__(
895
-                'Decline and Notify Registrations',
896
-                'event_espresso'
897
-            );
898
-        }
899
-        $def_reg_status_actions['pending_registrations'] = esc_html__(
900
-            'Set Registrations to Pending Payment',
901
-            'event_espresso'
902
-        );
903
-        if ($can_send && in_array($match_array['pending_registrations'], $active_mts, true)) {
904
-            $def_reg_status_actions['pending_and_notify_registrations'] = esc_html__(
905
-                'Set Registrations to Pending Payment and Notify',
906
-                'event_espresso'
907
-            );
908
-        }
909
-        $def_reg_status_actions['no_approve_registrations'] = esc_html__(
910
-            'Set Registrations to Not Approved',
911
-            'event_espresso'
912
-        );
913
-        if ($can_send && in_array($match_array['no_approve_registrations'], $active_mts, true)) {
914
-            $def_reg_status_actions['no_approve_and_notify_registrations'] = esc_html__(
915
-                'Set Registrations to Not Approved and Notify',
916
-                'event_espresso'
917
-            );
918
-        }
919
-        $def_reg_status_actions['cancel_registrations'] = esc_html__('Cancel Registrations', 'event_espresso');
920
-        if ($can_send && in_array($match_array['cancel_registrations'], $active_mts, true)) {
921
-            $def_reg_status_actions['cancel_and_notify_registrations'] = esc_html__(
922
-                'Cancel Registrations and Notify',
923
-                'event_espresso'
924
-            );
925
-        }
926
-        $def_reg_status_actions = apply_filters(
927
-            'FHEE__Registrations_Admin_Page___set_list_table_views_default__def_reg_status_actions_array',
928
-            $def_reg_status_actions,
929
-            $active_mts,
930
-            $can_send
931
-        );
932
-
933
-        $this->_views = [
934
-            'all'   => [
935
-                'slug'        => 'all',
936
-                'label'       => esc_html__('View All Registrations', 'event_espresso'),
937
-                'count'       => 0,
938
-                'bulk_action' => array_merge(
939
-                    $def_reg_status_actions,
940
-                    [
941
-                        'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
942
-                    ]
943
-                ),
944
-            ],
945
-            'month' => [
946
-                'slug'        => 'month',
947
-                'label'       => esc_html__('This Month', 'event_espresso'),
948
-                'count'       => 0,
949
-                'bulk_action' => array_merge(
950
-                    $def_reg_status_actions,
951
-                    [
952
-                        'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
953
-                    ]
954
-                ),
955
-            ],
956
-            'today' => [
957
-                'slug'        => 'today',
958
-                'label'       => sprintf(
959
-                    esc_html__('Today - %s', 'event_espresso'),
960
-                    date('M d, Y', current_time('timestamp'))
961
-                ),
962
-                'count'       => 0,
963
-                'bulk_action' => array_merge(
964
-                    $def_reg_status_actions,
965
-                    [
966
-                        'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
967
-                    ]
968
-                ),
969
-            ],
970
-        ];
971
-        if (
972
-            EE_Registry::instance()->CAP->current_user_can(
973
-                'ee_delete_registrations',
974
-                'espresso_registrations_delete_registration'
975
-            )
976
-        ) {
977
-            $this->_views['incomplete'] = [
978
-                'slug'        => 'incomplete',
979
-                'label'       => esc_html__('Incomplete', 'event_espresso'),
980
-                'count'       => 0,
981
-                'bulk_action' => [
982
-                    'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
983
-                ],
984
-            ];
985
-            $this->_views['trash']      = [
986
-                'slug'        => 'trash',
987
-                'label'       => esc_html__('Trash', 'event_espresso'),
988
-                'count'       => 0,
989
-                'bulk_action' => [
990
-                    'restore_registrations' => esc_html__('Restore Registrations', 'event_espresso'),
991
-                    'delete_registrations'  => esc_html__('Delete Registrations Permanently', 'event_espresso'),
992
-                ],
993
-            ];
994
-        }
995
-    }
996
-
997
-
998
-    protected function _set_list_table_views_contact_list()
999
-    {
1000
-        $this->_views = [
1001
-            'in_use' => [
1002
-                'slug'        => 'in_use',
1003
-                'label'       => esc_html__('In Use', 'event_espresso'),
1004
-                'count'       => 0,
1005
-                'bulk_action' => [
1006
-                    'trash_attendees' => esc_html__('Move to Trash', 'event_espresso'),
1007
-                ],
1008
-            ],
1009
-        ];
1010
-        if (
1011
-            EE_Registry::instance()->CAP->current_user_can(
1012
-                'ee_delete_contacts',
1013
-                'espresso_registrations_trash_attendees'
1014
-            )
1015
-        ) {
1016
-            $this->_views['trash'] = [
1017
-                'slug'        => 'trash',
1018
-                'label'       => esc_html__('Trash', 'event_espresso'),
1019
-                'count'       => 0,
1020
-                'bulk_action' => [
1021
-                    'restore_attendees' => esc_html__('Restore from Trash', 'event_espresso'),
1022
-                ],
1023
-            ];
1024
-        }
1025
-    }
1026
-
1027
-
1028
-    /**
1029
-     * @return array
1030
-     * @throws EE_Error
1031
-     */
1032
-    protected function _registration_legend_items()
1033
-    {
1034
-        $fc_items = [
1035
-            'star-icon'        => [
1036
-                'class' => 'dashicons dashicons-star-filled lt-blue-icon ee-icon-size-8',
1037
-                'desc'  => esc_html__('This is the Primary Registrant', 'event_espresso'),
1038
-            ],
1039
-            'view_details'     => [
1040
-                'class' => 'dashicons dashicons-clipboard',
1041
-                'desc'  => esc_html__('View Registration Details', 'event_espresso'),
1042
-            ],
1043
-            'edit_attendee'    => [
1044
-                'class' => 'ee-icon ee-icon-user-edit ee-icon-size-16',
1045
-                'desc'  => esc_html__('Edit Contact Details', 'event_espresso'),
1046
-            ],
1047
-            'view_transaction' => [
1048
-                'class' => 'dashicons dashicons-cart',
1049
-                'desc'  => esc_html__('View Transaction Details', 'event_espresso'),
1050
-            ],
1051
-            'view_invoice'     => [
1052
-                'class' => 'dashicons dashicons-media-spreadsheet',
1053
-                'desc'  => esc_html__('View Transaction Invoice', 'event_espresso'),
1054
-            ],
1055
-        ];
1056
-        if (
1057
-            EE_Registry::instance()->CAP->current_user_can(
1058
-                'ee_send_message',
1059
-                'espresso_registrations_resend_registration'
1060
-            )
1061
-        ) {
1062
-            $fc_items['resend_registration'] = [
1063
-                'class' => 'dashicons dashicons-email-alt',
1064
-                'desc'  => esc_html__('Resend Registration Details', 'event_espresso'),
1065
-            ];
1066
-        } else {
1067
-            $fc_items['blank'] = ['class' => 'blank', 'desc' => ''];
1068
-        }
1069
-        if (
1070
-            EE_Registry::instance()->CAP->current_user_can(
1071
-                'ee_read_global_messages',
1072
-                'view_filtered_messages'
1073
-            )
1074
-        ) {
1075
-            $related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
1076
-            if (is_array($related_for_icon) && isset($related_for_icon['css_class'], $related_for_icon['label'])) {
1077
-                $fc_items['view_related_messages'] = [
1078
-                    'class' => $related_for_icon['css_class'],
1079
-                    'desc'  => $related_for_icon['label'],
1080
-                ];
1081
-            }
1082
-        }
1083
-        $sc_items = [
1084
-            'approved_status'   => [
1085
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_approved,
1086
-                'desc'  => EEH_Template::pretty_status(
1087
-                    EEM_Registration::status_id_approved,
1088
-                    false,
1089
-                    'sentence'
1090
-                ),
1091
-            ],
1092
-            'pending_status'    => [
1093
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_pending_payment,
1094
-                'desc'  => EEH_Template::pretty_status(
1095
-                    EEM_Registration::status_id_pending_payment,
1096
-                    false,
1097
-                    'sentence'
1098
-                ),
1099
-            ],
1100
-            'wait_list'         => [
1101
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_wait_list,
1102
-                'desc'  => EEH_Template::pretty_status(
1103
-                    EEM_Registration::status_id_wait_list,
1104
-                    false,
1105
-                    'sentence'
1106
-                ),
1107
-            ],
1108
-            'incomplete_status' => [
1109
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_incomplete,
1110
-                'desc'  => EEH_Template::pretty_status(
1111
-                    EEM_Registration::status_id_incomplete,
1112
-                    false,
1113
-                    'sentence'
1114
-                ),
1115
-            ],
1116
-            'not_approved'      => [
1117
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_not_approved,
1118
-                'desc'  => EEH_Template::pretty_status(
1119
-                    EEM_Registration::status_id_not_approved,
1120
-                    false,
1121
-                    'sentence'
1122
-                ),
1123
-            ],
1124
-            'declined_status'   => [
1125
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_declined,
1126
-                'desc'  => EEH_Template::pretty_status(
1127
-                    EEM_Registration::status_id_declined,
1128
-                    false,
1129
-                    'sentence'
1130
-                ),
1131
-            ],
1132
-            'cancelled_status'  => [
1133
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_cancelled,
1134
-                'desc'  => EEH_Template::pretty_status(
1135
-                    EEM_Registration::status_id_cancelled,
1136
-                    false,
1137
-                    'sentence'
1138
-                ),
1139
-            ],
1140
-        ];
1141
-        return array_merge($fc_items, $sc_items);
1142
-    }
1143
-
1144
-
1145
-
1146
-    /***************************************        REGISTRATION OVERVIEW        **************************************/
1147
-
1148
-
1149
-    /**
1150
-     * @throws DomainException
1151
-     * @throws EE_Error
1152
-     * @throws InvalidArgumentException
1153
-     * @throws InvalidDataTypeException
1154
-     * @throws InvalidInterfaceException
1155
-     */
1156
-    protected function _registrations_overview_list_table()
1157
-    {
1158
-        $this->appendAddNewRegistrationButtonToPageTitle();
1159
-        $header_text                  = '';
1160
-        $admin_page_header_decorators = [
1161
-            'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\AttendeeFilterHeader',
1162
-            'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\EventFilterHeader',
1163
-            'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\DateFilterHeader',
1164
-            'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\TicketFilterHeader',
1165
-        ];
1166
-        foreach ($admin_page_header_decorators as $admin_page_header_decorator) {
1167
-            $filter_header_decorator = $this->getLoader()->getNew($admin_page_header_decorator);
1168
-            $header_text             = $filter_header_decorator->getHeaderText($header_text);
1169
-        }
1170
-        $this->_template_args['admin_page_header'] = $header_text;
1171
-        $this->_template_args['after_list_table']  = $this->_display_legend($this->_registration_legend_items());
1172
-        $this->display_admin_list_table_page_with_no_sidebar();
1173
-    }
1174
-
1175
-
1176
-    /**
1177
-     * @throws EE_Error
1178
-     * @throws InvalidArgumentException
1179
-     * @throws InvalidDataTypeException
1180
-     * @throws InvalidInterfaceException
1181
-     */
1182
-    private function appendAddNewRegistrationButtonToPageTitle()
1183
-    {
1184
-        $EVT_ID = $this->request->getRequestParam('event_id', 0, 'int');
1185
-        if (
1186
-            $EVT_ID
1187
-            && EE_Registry::instance()->CAP->current_user_can(
1188
-                'ee_edit_registrations',
1189
-                'espresso_registrations_new_registration',
1190
-                $EVT_ID
1191
-            )
1192
-        ) {
1193
-            $this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
1194
-                'new_registration',
1195
-                'add-registrant',
1196
-                ['event_id' => $EVT_ID],
1197
-                'add-new-h2'
1198
-            );
1199
-        }
1200
-    }
1201
-
1202
-
1203
-    /**
1204
-     * This sets the _registration property for the registration details screen
1205
-     *
1206
-     * @return void
1207
-     * @throws EE_Error
1208
-     * @throws InvalidArgumentException
1209
-     * @throws InvalidDataTypeException
1210
-     * @throws InvalidInterfaceException
1211
-     */
1212
-    private function _set_registration_object()
1213
-    {
1214
-        // get out if we've already set the object
1215
-        if ($this->_registration instanceof EE_Registration) {
1216
-            return;
1217
-        }
1218
-        $REG_ID = $this->request->getRequestParam('_REG_ID', 0, 'int');
1219
-        if ($this->_registration = $this->getRegistrationModel()->get_one_by_ID($REG_ID)) {
1220
-            return;
1221
-        }
1222
-        $error_msg = sprintf(
1223
-            esc_html__(
1224
-                'An error occurred and the details for Registration ID #%s could not be retrieved.',
1225
-                'event_espresso'
1226
-            ),
1227
-            $REG_ID
1228
-        );
1229
-        EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
1230
-        $this->_registration = null;
1231
-    }
1232
-
1233
-
1234
-    /**
1235
-     * Used to retrieve registrations for the list table.
1236
-     *
1237
-     * @param int  $per_page
1238
-     * @param bool $count
1239
-     * @param bool $this_month
1240
-     * @param bool $today
1241
-     * @return EE_Registration[]|int
1242
-     * @throws EE_Error
1243
-     * @throws InvalidArgumentException
1244
-     * @throws InvalidDataTypeException
1245
-     * @throws InvalidInterfaceException
1246
-     */
1247
-    public function get_registrations(
1248
-        $per_page = 10,
1249
-        $count = false,
1250
-        $this_month = false,
1251
-        $today = false
1252
-    ) {
1253
-        if ($this_month) {
1254
-            $this->request->setRequestParam('status', 'month');
1255
-        }
1256
-        if ($today) {
1257
-            $this->request->setRequestParam('status', 'today');
1258
-        }
1259
-        $query_params = $this->_get_registration_query_parameters([], $per_page, $count);
1260
-        /**
1261
-         * Override the default groupby added by EEM_Base so that sorts with multiple order bys work as expected
1262
-         *
1263
-         * @link https://events.codebasehq.com/projects/event-espresso/tickets/10093
1264
-         * @see  https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1265
-         *                      or if you have the development copy of EE you can view this at the path:
1266
-         *                      /docs/G--Model-System/model-query-params.md
1267
-         */
1268
-        $query_params['group_by'] = '';
1269
-
1270
-        return $count
1271
-            ? $this->getRegistrationModel()->count($query_params)
1272
-            /** @type EE_Registration[] */
1273
-            : $this->getRegistrationModel()->get_all($query_params);
1274
-    }
1275
-
1276
-
1277
-    /**
1278
-     * Retrieves the query parameters to be used by the Registration model for getting registrations.
1279
-     * Note: this listens to values on the request for some of the query parameters.
1280
-     *
1281
-     * @param array $request
1282
-     * @param int   $per_page
1283
-     * @param bool  $count
1284
-     * @return array
1285
-     * @throws EE_Error
1286
-     * @throws InvalidArgumentException
1287
-     * @throws InvalidDataTypeException
1288
-     * @throws InvalidInterfaceException
1289
-     */
1290
-    protected function _get_registration_query_parameters(
1291
-        $request = [],
1292
-        $per_page = 10,
1293
-        $count = false
1294
-    ) {
1295
-        /** @var EventEspresso\core\domain\services\admin\registrations\list_table\QueryBuilder $list_table_query_builder */
1296
-        $list_table_query_builder = $this->getLoader()->getNew(
1297
-            'EventEspresso\core\domain\services\admin\registrations\list_table\QueryBuilder',
1298
-            [null, null, $request]
1299
-        );
1300
-        return $list_table_query_builder->getQueryParams($per_page, $count);
1301
-    }
1302
-
1303
-
1304
-    public function get_registration_status_array()
1305
-    {
1306
-        return self::$_reg_status;
1307
-    }
1308
-
1309
-
1310
-
1311
-
1312
-    /***************************************        REGISTRATION DETAILS        ***************************************/
1313
-    /**
1314
-     * generates HTML for the View Registration Details Admin page
1315
-     *
1316
-     * @return void
1317
-     * @throws DomainException
1318
-     * @throws EE_Error
1319
-     * @throws InvalidArgumentException
1320
-     * @throws InvalidDataTypeException
1321
-     * @throws InvalidInterfaceException
1322
-     * @throws EntityNotFoundException
1323
-     * @throws ReflectionException
1324
-     */
1325
-    protected function _registration_details()
1326
-    {
1327
-        $this->_template_args = [];
1328
-        $this->_set_registration_object();
1329
-        if (is_object($this->_registration)) {
1330
-            $transaction                                   = $this->_registration->transaction()
1331
-                ? $this->_registration->transaction()
1332
-                : EE_Transaction::new_instance();
1333
-            $this->_session                                = $transaction->session_data();
1334
-            $event_id                                      = $this->_registration->event_ID();
1335
-            $this->_template_args['reg_nmbr']['value']     = $this->_registration->ID();
1336
-            $this->_template_args['reg_nmbr']['label']     = esc_html__('Registration Number', 'event_espresso');
1337
-            $this->_template_args['reg_datetime']['value'] = $this->_registration->get_i18n_datetime('REG_date');
1338
-            $this->_template_args['reg_datetime']['label'] = esc_html__('Date', 'event_espresso');
1339
-            $this->_template_args['grand_total']           = $transaction->total();
1340
-            $this->_template_args['currency_sign']         = EE_Registry::instance()->CFG->currency->sign;
1341
-            // link back to overview
1342
-            $this->_template_args['reg_overview_url']            = REG_ADMIN_URL;
1343
-            $this->_template_args['registration']                = $this->_registration;
1344
-            $this->_template_args['filtered_registrations_link'] = EE_Admin_Page::add_query_args_and_nonce(
1345
-                [
1346
-                    'action'   => 'default',
1347
-                    'event_id' => $event_id,
1348
-                ],
1349
-                REG_ADMIN_URL
1350
-            );
1351
-            $this->_template_args['filtered_transactions_link']  = EE_Admin_Page::add_query_args_and_nonce(
1352
-                [
1353
-                    'action' => 'default',
1354
-                    'EVT_ID' => $event_id,
1355
-                    'page'   => 'espresso_transactions',
1356
-                ],
1357
-                admin_url('admin.php')
1358
-            );
1359
-            $this->_template_args['event_link']                  = EE_Admin_Page::add_query_args_and_nonce(
1360
-                [
1361
-                    'page'   => 'espresso_events',
1362
-                    'action' => 'edit',
1363
-                    'post'   => $event_id,
1364
-                ],
1365
-                admin_url('admin.php')
1366
-            );
1367
-            // next and previous links
1368
-            $next_reg                                      = $this->_registration->next(
1369
-                null,
1370
-                [],
1371
-                'REG_ID'
1372
-            );
1373
-            $this->_template_args['next_registration']     = $next_reg
1374
-                ? $this->_next_link(
1375
-                    EE_Admin_Page::add_query_args_and_nonce(
1376
-                        [
1377
-                            'action'  => 'view_registration',
1378
-                            '_REG_ID' => $next_reg['REG_ID'],
1379
-                        ],
1380
-                        REG_ADMIN_URL
1381
-                    ),
1382
-                    'dashicons dashicons-arrow-right ee-icon-size-22'
1383
-                )
1384
-                : '';
1385
-            $previous_reg                                  = $this->_registration->previous(
1386
-                null,
1387
-                [],
1388
-                'REG_ID'
1389
-            );
1390
-            $this->_template_args['previous_registration'] = $previous_reg
1391
-                ? $this->_previous_link(
1392
-                    EE_Admin_Page::add_query_args_and_nonce(
1393
-                        [
1394
-                            'action'  => 'view_registration',
1395
-                            '_REG_ID' => $previous_reg['REG_ID'],
1396
-                        ],
1397
-                        REG_ADMIN_URL
1398
-                    ),
1399
-                    'dashicons dashicons-arrow-left ee-icon-size-22'
1400
-                )
1401
-                : '';
1402
-            // grab header
1403
-            $template_path                             = REG_TEMPLATE_PATH . 'reg_admin_details_header.template.php';
1404
-            $this->_template_args['REG_ID']            = $this->_registration->ID();
1405
-            $this->_template_args['admin_page_header'] = EEH_Template::display_template(
1406
-                $template_path,
1407
-                $this->_template_args,
1408
-                true
1409
-            );
1410
-        } else {
1411
-            $this->_template_args['admin_page_header'] = '';
1412
-            $this->_display_espresso_notices();
1413
-        }
1414
-        // the details template wrapper
1415
-        $this->display_admin_page_with_sidebar();
1416
-    }
1417
-
1418
-
1419
-    /**
1420
-     * @throws EE_Error
1421
-     * @throws InvalidArgumentException
1422
-     * @throws InvalidDataTypeException
1423
-     * @throws InvalidInterfaceException
1424
-     * @throws ReflectionException
1425
-     * @since 4.10.2.p
1426
-     */
1427
-    protected function _registration_details_metaboxes()
1428
-    {
1429
-        do_action('AHEE__Registrations_Admin_Page___registration_details_metabox__start', $this);
1430
-        $this->_set_registration_object();
1431
-        $attendee = $this->_registration instanceof EE_Registration ? $this->_registration->attendee() : null;
1432
-        add_meta_box(
1433
-            'edit-reg-status-mbox',
1434
-            esc_html__('Registration Status', 'event_espresso'),
1435
-            [$this, 'set_reg_status_buttons_metabox'],
1436
-            $this->_wp_page_slug,
1437
-            'normal',
1438
-            'high'
1439
-        );
1440
-        add_meta_box(
1441
-            'edit-reg-details-mbox',
1442
-            esc_html__('Registration Details', 'event_espresso'),
1443
-            [$this, '_reg_details_meta_box'],
1444
-            $this->_wp_page_slug,
1445
-            'normal',
1446
-            'high'
1447
-        );
1448
-        if (
1449
-            $attendee instanceof EE_Attendee
1450
-            && EE_Registry::instance()->CAP->current_user_can(
1451
-                'ee_read_registration',
1452
-                'edit-reg-questions-mbox',
1453
-                $this->_registration->ID()
1454
-            )
1455
-        ) {
1456
-            add_meta_box(
1457
-                'edit-reg-questions-mbox',
1458
-                esc_html__('Registration Form Answers', 'event_espresso'),
1459
-                [$this, '_reg_questions_meta_box'],
1460
-                $this->_wp_page_slug,
1461
-                'normal',
1462
-                'high'
1463
-            );
1464
-        }
1465
-        add_meta_box(
1466
-            'edit-reg-registrant-mbox',
1467
-            esc_html__('Contact Details', 'event_espresso'),
1468
-            [$this, '_reg_registrant_side_meta_box'],
1469
-            $this->_wp_page_slug,
1470
-            'side',
1471
-            'high'
1472
-        );
1473
-        if ($this->_registration->group_size() > 1) {
1474
-            add_meta_box(
1475
-                'edit-reg-attendees-mbox',
1476
-                esc_html__('Other Registrations in this Transaction', 'event_espresso'),
1477
-                [$this, '_reg_attendees_meta_box'],
1478
-                $this->_wp_page_slug,
1479
-                'normal',
1480
-                'high'
1481
-            );
1482
-        }
1483
-    }
1484
-
1485
-
1486
-    /**
1487
-     * set_reg_status_buttons_metabox
1488
-     *
1489
-     * @return void
1490
-     * @throws EE_Error
1491
-     * @throws EntityNotFoundException
1492
-     * @throws InvalidArgumentException
1493
-     * @throws InvalidDataTypeException
1494
-     * @throws InvalidInterfaceException
1495
-     * @throws ReflectionException
1496
-     */
1497
-    public function set_reg_status_buttons_metabox()
1498
-    {
1499
-        $this->_set_registration_object();
1500
-        $change_reg_status_form = $this->_generate_reg_status_change_form();
1501
-        $output                 = $change_reg_status_form->form_open(
1502
-            self::add_query_args_and_nonce(
1503
-                [
1504
-                    'action' => 'change_reg_status',
1505
-                ],
1506
-                REG_ADMIN_URL
1507
-            )
1508
-        );
1509
-        $output                 .= $change_reg_status_form->get_html();
1510
-        $output                 .= $change_reg_status_form->form_close();
1511
-        echo wp_kses($output, AllowedTags::getWithFormTags());
1512
-    }
1513
-
1514
-
1515
-    /**
1516
-     * @return EE_Form_Section_Proper
1517
-     * @throws EE_Error
1518
-     * @throws InvalidArgumentException
1519
-     * @throws InvalidDataTypeException
1520
-     * @throws InvalidInterfaceException
1521
-     * @throws EntityNotFoundException
1522
-     * @throws ReflectionException
1523
-     */
1524
-    protected function _generate_reg_status_change_form()
1525
-    {
1526
-        $reg_status_change_form_array = [
1527
-            'name'            => 'reg_status_change_form',
1528
-            'html_id'         => 'reg-status-change-form',
1529
-            'layout_strategy' => new EE_Admin_Two_Column_Layout(),
1530
-            'subsections'     => [
1531
-                'return'         => new EE_Hidden_Input(
1532
-                    [
1533
-                        'name'    => 'return',
1534
-                        'default' => 'view_registration',
1535
-                    ]
1536
-                ),
1537
-                'REG_ID'         => new EE_Hidden_Input(
1538
-                    [
1539
-                        'name'    => 'REG_ID',
1540
-                        'default' => $this->_registration->ID(),
1541
-                    ]
1542
-                ),
1543
-                'current_status' => new EE_Form_Section_HTML(
1544
-                    EEH_HTML::table(
1545
-                        EEH_HTML::tr(
1546
-                            EEH_HTML::th(
1547
-                                EEH_HTML::label(
1548
-                                    EEH_HTML::strong(
1549
-                                        esc_html__('Current Registration Status', 'event_espresso')
1550
-                                    )
1551
-                                )
1552
-                            )
1553
-                            . EEH_HTML::td(
1554
-                                EEH_HTML::strong(
1555
-                                    $this->_registration->pretty_status(),
1556
-                                    '',
1557
-                                    'status-' . $this->_registration->status_ID(),
1558
-                                    'line-height: 1em; font-size: 1.5em; font-weight: bold;'
1559
-                                )
1560
-                            )
1561
-                        )
1562
-                    )
1563
-                ),
1564
-            ],
1565
-        ];
1566
-        if (
1567
-            EE_Registry::instance()->CAP->current_user_can(
1568
-                'ee_edit_registration',
1569
-                'toggle_registration_status',
1570
-                $this->_registration->ID()
1571
-            )
1572
-        ) {
1573
-            $reg_status_change_form_array['subsections']['reg_status']         = new EE_Select_Input(
1574
-                $this->_get_reg_statuses(),
1575
-                [
1576
-                    'html_label_text' => esc_html__('Change Registration Status to', 'event_espresso'),
1577
-                    'default'         => $this->_registration->status_ID(),
1578
-                ]
1579
-            );
1580
-            $reg_status_change_form_array['subsections']['send_notifications'] = new EE_Yes_No_Input(
1581
-                [
1582
-                    'html_label_text' => esc_html__('Send Related Messages', 'event_espresso'),
1583
-                    'default'         => false,
1584
-                    'html_help_text'  => esc_html__(
1585
-                        'If set to "Yes", then the related messages will be sent to the registrant.',
1586
-                        'event_espresso'
1587
-                    ),
1588
-                ]
1589
-            );
1590
-            $reg_status_change_form_array['subsections']['submit']             = new EE_Submit_Input(
1591
-                [
1592
-                    'html_class'      => 'button-primary',
1593
-                    'html_label_text' => '&nbsp;',
1594
-                    'default'         => esc_html__('Update Registration Status', 'event_espresso'),
1595
-                ]
1596
-            );
1597
-        }
1598
-        return new EE_Form_Section_Proper($reg_status_change_form_array);
1599
-    }
1600
-
1601
-
1602
-    /**
1603
-     * Returns an array of all the buttons for the various statuses and switch status actions
1604
-     *
1605
-     * @return array
1606
-     * @throws EE_Error
1607
-     * @throws InvalidArgumentException
1608
-     * @throws InvalidDataTypeException
1609
-     * @throws InvalidInterfaceException
1610
-     * @throws EntityNotFoundException
1611
-     */
1612
-    protected function _get_reg_statuses()
1613
-    {
1614
-        $reg_status_array = $this->getRegistrationModel()->reg_status_array();
1615
-        unset($reg_status_array[ EEM_Registration::status_id_incomplete ]);
1616
-        // get current reg status
1617
-        $current_status = $this->_registration->status_ID();
1618
-        // is registration for free event? This will determine whether to display the pending payment option
1619
-        if (
1620
-            $current_status !== EEM_Registration::status_id_pending_payment
1621
-            && EEH_Money::compare_floats($this->_registration->ticket()->price(), 0.00)
1622
-        ) {
1623
-            unset($reg_status_array[ EEM_Registration::status_id_pending_payment ]);
1624
-        }
1625
-        return $this->getStatusModel()->localized_status($reg_status_array, false, 'sentence');
1626
-    }
1627
-
1628
-
1629
-    /**
1630
-     * This method is used when using _REG_ID from request which may or may not be an array of reg_ids.
1631
-     *
1632
-     * @param bool $status REG status given for changing registrations to.
1633
-     * @param bool $notify Whether to send messages notifications or not.
1634
-     * @return array (array with reg_id(s) updated and whether update was successful.
1635
-     * @throws DomainException
1636
-     * @throws EE_Error
1637
-     * @throws EntityNotFoundException
1638
-     * @throws InvalidArgumentException
1639
-     * @throws InvalidDataTypeException
1640
-     * @throws InvalidInterfaceException
1641
-     * @throws ReflectionException
1642
-     * @throws RuntimeException
1643
-     */
1644
-    protected function _set_registration_status_from_request($status = false, $notify = false)
1645
-    {
1646
-        $REG_IDs = $this->request->requestParamIsSet('reg_status_change_form')
1647
-            ? $this->request->getRequestParam('reg_status_change_form[REG_ID]', [], 'int', true)
1648
-            : $this->request->getRequestParam('_REG_ID', [], 'int', true);
1649
-
1650
-        // sanitize $REG_IDs
1651
-        $REG_IDs = array_map('absint', $REG_IDs);
1652
-        // and remove empty entries
1653
-        $REG_IDs = array_filter($REG_IDs);
1654
-
1655
-        $result = $this->_set_registration_status($REG_IDs, $status, $notify);
1656
-
1657
-        /**
1658
-         * Set and filter $_req_data['_REG_ID'] for any potential future messages notifications.
1659
-         * Currently this value is used downstream by the _process_resend_registration method.
1660
-         *
1661
-         * @param int|array                $registration_ids The registration ids that have had their status changed successfully.
1662
-         * @param bool                     $status           The status registrations were changed to.
1663
-         * @param bool                     $success          If the status was changed successfully for all registrations.
1664
-         * @param Registrations_Admin_Page $admin_page_object
1665
-         */
1666
-        $REG_ID = apply_filters(
1667
-            'FHEE__Registrations_Admin_Page___set_registration_status_from_request__REG_IDs',
1668
-            $result['REG_ID'],
1669
-            $status,
1670
-            $result['success'],
1671
-            $this
1672
-        );
1673
-        $this->request->setRequestParam('_REG_ID', $REG_ID);
1674
-
1675
-        // notify?
1676
-        if (
1677
-            $notify
1678
-            && $result['success']
1679
-            && ! empty($REG_ID)
1680
-            && EE_Registry::instance()->CAP->current_user_can(
1681
-                'ee_send_message',
1682
-                'espresso_registrations_resend_registration'
1683
-            )
1684
-        ) {
1685
-            $this->_process_resend_registration();
1686
-        }
1687
-        return $result;
1688
-    }
1689
-
1690
-
1691
-    /**
1692
-     * Set the registration status for the given reg_id (which may or may not be an array, it gets typecast to an
1693
-     * array). Note, this method does NOT take care of possible notifications.  That is required by calling code.
1694
-     *
1695
-     * @param array  $REG_IDs
1696
-     * @param string $status
1697
-     * @param bool   $notify Used to indicate whether notification was requested or not.  This determines the context
1698
-     *                       slug sent with setting the registration status.
1699
-     * @return array (an array with 'success' key representing whether status change was successful, and 'REG_ID' as
1700
-     * @throws EE_Error
1701
-     * @throws InvalidArgumentException
1702
-     * @throws InvalidDataTypeException
1703
-     * @throws InvalidInterfaceException
1704
-     * @throws ReflectionException
1705
-     * @throws RuntimeException
1706
-     * @throws EntityNotFoundException
1707
-     * @throws DomainException
1708
-     */
1709
-    protected function _set_registration_status($REG_IDs = [], $status = '', $notify = false)
1710
-    {
1711
-        $success = false;
1712
-        // typecast $REG_IDs
1713
-        $REG_IDs = (array) $REG_IDs;
1714
-        if (! empty($REG_IDs)) {
1715
-            $success = true;
1716
-            // set default status if none is passed
1717
-            $status         = $status ?: EEM_Registration::status_id_pending_payment;
1718
-            $status_context = $notify
1719
-                ? Domain::CONTEXT_REGISTRATION_STATUS_CHANGE_REGISTRATION_ADMIN_NOTIFY
1720
-                : Domain::CONTEXT_REGISTRATION_STATUS_CHANGE_REGISTRATION_ADMIN;
1721
-            // loop through REG_ID's and change status
1722
-            foreach ($REG_IDs as $REG_ID) {
1723
-                $registration = $this->getRegistrationModel()->get_one_by_ID($REG_ID);
1724
-                if ($registration instanceof EE_Registration) {
1725
-                    $registration->set_status(
1726
-                        $status,
1727
-                        false,
1728
-                        new Context(
1729
-                            $status_context,
1730
-                            esc_html__(
1731
-                                'Manually triggered status change on a Registration Admin Page route.',
1732
-                                'event_espresso'
1733
-                            )
1734
-                        )
1735
-                    );
1736
-                    $result = $registration->save();
1737
-                    // verifying explicit fails because update *may* just return 0 for 0 rows affected
1738
-                    $success = $result !== false ? $success : false;
1739
-                }
1740
-            }
1741
-        }
1742
-
1743
-        // return $success and processed registrations
1744
-        return ['REG_ID' => $REG_IDs, 'success' => $success];
1745
-    }
1746
-
1747
-
1748
-    /**
1749
-     * Common logic for setting up success message and redirecting to appropriate route
1750
-     *
1751
-     * @param string $STS_ID status id for the registration changed to
1752
-     * @param bool   $notify indicates whether the _set_registration_status_from_request does notifications or not.
1753
-     * @return void
1754
-     * @throws DomainException
1755
-     * @throws EE_Error
1756
-     * @throws EntityNotFoundException
1757
-     * @throws InvalidArgumentException
1758
-     * @throws InvalidDataTypeException
1759
-     * @throws InvalidInterfaceException
1760
-     * @throws ReflectionException
1761
-     * @throws RuntimeException
1762
-     */
1763
-    protected function _reg_status_change_return($STS_ID, $notify = false)
1764
-    {
1765
-        $result  = ! empty($STS_ID) ? $this->_set_registration_status_from_request($STS_ID, $notify)
1766
-            : ['success' => false];
1767
-        $success = isset($result['success']) && $result['success'];
1768
-        // setup success message
1769
-        if ($success) {
1770
-            if (is_array($result['REG_ID']) && count($result['REG_ID']) === 1) {
1771
-                $msg = sprintf(
1772
-                    esc_html__('Registration status has been set to %s', 'event_espresso'),
1773
-                    EEH_Template::pretty_status($STS_ID, false, 'lower')
1774
-                );
1775
-            } else {
1776
-                $msg = sprintf(
1777
-                    esc_html__('Registrations have been set to %s.', 'event_espresso'),
1778
-                    EEH_Template::pretty_status($STS_ID, false, 'lower')
1779
-                );
1780
-            }
1781
-            EE_Error::add_success($msg);
1782
-        } else {
1783
-            EE_Error::add_error(
1784
-                esc_html__(
1785
-                    'Something went wrong, and the status was not changed',
1786
-                    'event_espresso'
1787
-                ),
1788
-                __FILE__,
1789
-                __LINE__,
1790
-                __FUNCTION__
1791
-            );
1792
-        }
1793
-        $return = $this->request->getRequestParam('return');
1794
-        $route  = $return === 'view_registration'
1795
-            ? ['action' => 'view_registration', '_REG_ID' => reset($result['REG_ID'])]
1796
-            : ['action' => 'default'];
1797
-        $route  = $this->mergeExistingRequestParamsWithRedirectArgs($route);
1798
-        $this->_redirect_after_action($success, '', '', $route, true);
1799
-    }
1800
-
1801
-
1802
-    /**
1803
-     * incoming reg status change from reg details page.
1804
-     *
1805
-     * @return void
1806
-     * @throws EE_Error
1807
-     * @throws EntityNotFoundException
1808
-     * @throws InvalidArgumentException
1809
-     * @throws InvalidDataTypeException
1810
-     * @throws InvalidInterfaceException
1811
-     * @throws ReflectionException
1812
-     * @throws RuntimeException
1813
-     * @throws DomainException
1814
-     */
1815
-    protected function _change_reg_status()
1816
-    {
1817
-        $this->request->setRequestParam('return', 'view_registration');
1818
-        // set notify based on whether the send notifications toggle is set or not
1819
-        $notify     = $this->request->getRequestParam('reg_status_change_form[send_notifications]', false, 'bool');
1820
-        $reg_status = $this->request->getRequestParam('reg_status_change_form[reg_status]', '');
1821
-        $this->request->setRequestParam('reg_status_change_form[reg_status]', $reg_status);
1822
-        switch ($reg_status) {
1823
-            case EEM_Registration::status_id_approved:
1824
-            case EEH_Template::pretty_status(EEM_Registration::status_id_approved, false, 'sentence'):
1825
-                $this->approve_registration($notify);
1826
-                break;
1827
-            case EEM_Registration::status_id_pending_payment:
1828
-            case EEH_Template::pretty_status(EEM_Registration::status_id_pending_payment, false, 'sentence'):
1829
-                $this->pending_registration($notify);
1830
-                break;
1831
-            case EEM_Registration::status_id_not_approved:
1832
-            case EEH_Template::pretty_status(EEM_Registration::status_id_not_approved, false, 'sentence'):
1833
-                $this->not_approve_registration($notify);
1834
-                break;
1835
-            case EEM_Registration::status_id_declined:
1836
-            case EEH_Template::pretty_status(EEM_Registration::status_id_declined, false, 'sentence'):
1837
-                $this->decline_registration($notify);
1838
-                break;
1839
-            case EEM_Registration::status_id_cancelled:
1840
-            case EEH_Template::pretty_status(EEM_Registration::status_id_cancelled, false, 'sentence'):
1841
-                $this->cancel_registration($notify);
1842
-                break;
1843
-            case EEM_Registration::status_id_wait_list:
1844
-            case EEH_Template::pretty_status(EEM_Registration::status_id_wait_list, false, 'sentence'):
1845
-                $this->wait_list_registration($notify);
1846
-                break;
1847
-            case EEM_Registration::status_id_incomplete:
1848
-            default:
1849
-                $this->request->unSetRequestParam('return');
1850
-                $this->_reg_status_change_return('');
1851
-                break;
1852
-        }
1853
-    }
1854
-
1855
-
1856
-    /**
1857
-     * Callback for bulk action routes.
1858
-     * Note: although we could just register the singular route callbacks for each bulk action route as well, this
1859
-     * method was chosen so there is one central place all the registration status bulk actions are going through.
1860
-     * Potentially, this provides an easier place to locate logic that is specific to these bulk actions (as opposed to
1861
-     * when an action is happening on just a single registration).
1862
-     *
1863
-     * @param      $action
1864
-     * @param bool $notify
1865
-     */
1866
-    protected function bulk_action_on_registrations($action, $notify = false)
1867
-    {
1868
-        do_action(
1869
-            'AHEE__Registrations_Admin_Page__bulk_action_on_registrations__before_execution',
1870
-            $this,
1871
-            $action,
1872
-            $notify
1873
-        );
1874
-        $method = $action . '_registration';
1875
-        if (method_exists($this, $method)) {
1876
-            $this->$method($notify);
1877
-        }
1878
-    }
1879
-
1880
-
1881
-    /**
1882
-     * approve_registration
1883
-     *
1884
-     * @param bool $notify whether or not to notify the registrant about their approval.
1885
-     * @return void
1886
-     * @throws EE_Error
1887
-     * @throws EntityNotFoundException
1888
-     * @throws InvalidArgumentException
1889
-     * @throws InvalidDataTypeException
1890
-     * @throws InvalidInterfaceException
1891
-     * @throws ReflectionException
1892
-     * @throws RuntimeException
1893
-     * @throws DomainException
1894
-     */
1895
-    protected function approve_registration($notify = false)
1896
-    {
1897
-        $this->_reg_status_change_return(EEM_Registration::status_id_approved, $notify);
1898
-    }
1899
-
1900
-
1901
-    /**
1902
-     * decline_registration
1903
-     *
1904
-     * @param bool $notify whether or not to notify the registrant about their status change.
1905
-     * @return void
1906
-     * @throws EE_Error
1907
-     * @throws EntityNotFoundException
1908
-     * @throws InvalidArgumentException
1909
-     * @throws InvalidDataTypeException
1910
-     * @throws InvalidInterfaceException
1911
-     * @throws ReflectionException
1912
-     * @throws RuntimeException
1913
-     * @throws DomainException
1914
-     */
1915
-    protected function decline_registration($notify = false)
1916
-    {
1917
-        $this->_reg_status_change_return(EEM_Registration::status_id_declined, $notify);
1918
-    }
1919
-
1920
-
1921
-    /**
1922
-     * cancel_registration
1923
-     *
1924
-     * @param bool $notify whether or not to notify the registrant about their status change.
1925
-     * @return void
1926
-     * @throws EE_Error
1927
-     * @throws EntityNotFoundException
1928
-     * @throws InvalidArgumentException
1929
-     * @throws InvalidDataTypeException
1930
-     * @throws InvalidInterfaceException
1931
-     * @throws ReflectionException
1932
-     * @throws RuntimeException
1933
-     * @throws DomainException
1934
-     */
1935
-    protected function cancel_registration($notify = false)
1936
-    {
1937
-        $this->_reg_status_change_return(EEM_Registration::status_id_cancelled, $notify);
1938
-    }
1939
-
1940
-
1941
-    /**
1942
-     * not_approve_registration
1943
-     *
1944
-     * @param bool $notify whether or not to notify the registrant about their status change.
1945
-     * @return void
1946
-     * @throws EE_Error
1947
-     * @throws EntityNotFoundException
1948
-     * @throws InvalidArgumentException
1949
-     * @throws InvalidDataTypeException
1950
-     * @throws InvalidInterfaceException
1951
-     * @throws ReflectionException
1952
-     * @throws RuntimeException
1953
-     * @throws DomainException
1954
-     */
1955
-    protected function not_approve_registration($notify = false)
1956
-    {
1957
-        $this->_reg_status_change_return(EEM_Registration::status_id_not_approved, $notify);
1958
-    }
1959
-
1960
-
1961
-    /**
1962
-     * decline_registration
1963
-     *
1964
-     * @param bool $notify whether or not to notify the registrant about their status change.
1965
-     * @return void
1966
-     * @throws EE_Error
1967
-     * @throws EntityNotFoundException
1968
-     * @throws InvalidArgumentException
1969
-     * @throws InvalidDataTypeException
1970
-     * @throws InvalidInterfaceException
1971
-     * @throws ReflectionException
1972
-     * @throws RuntimeException
1973
-     * @throws DomainException
1974
-     */
1975
-    protected function pending_registration($notify = false)
1976
-    {
1977
-        $this->_reg_status_change_return(EEM_Registration::status_id_pending_payment, $notify);
1978
-    }
1979
-
1980
-
1981
-    /**
1982
-     * waitlist_registration
1983
-     *
1984
-     * @param bool $notify whether or not to notify the registrant about their status change.
1985
-     * @return void
1986
-     * @throws EE_Error
1987
-     * @throws EntityNotFoundException
1988
-     * @throws InvalidArgumentException
1989
-     * @throws InvalidDataTypeException
1990
-     * @throws InvalidInterfaceException
1991
-     * @throws ReflectionException
1992
-     * @throws RuntimeException
1993
-     * @throws DomainException
1994
-     */
1995
-    protected function wait_list_registration($notify = false)
1996
-    {
1997
-        $this->_reg_status_change_return(EEM_Registration::status_id_wait_list, $notify);
1998
-    }
1999
-
2000
-
2001
-    /**
2002
-     * generates HTML for the Registration main meta box
2003
-     *
2004
-     * @return void
2005
-     * @throws DomainException
2006
-     * @throws EE_Error
2007
-     * @throws InvalidArgumentException
2008
-     * @throws InvalidDataTypeException
2009
-     * @throws InvalidInterfaceException
2010
-     * @throws ReflectionException
2011
-     * @throws EntityNotFoundException
2012
-     */
2013
-    public function _reg_details_meta_box()
2014
-    {
2015
-        EEH_Autoloader::register_line_item_display_autoloaders();
2016
-        EEH_Autoloader::register_line_item_filter_autoloaders();
2017
-        EE_Registry::instance()->load_helper('Line_Item');
2018
-        $transaction    = $this->_registration->transaction() ? $this->_registration->transaction()
2019
-            : EE_Transaction::new_instance();
2020
-        $this->_session = $transaction->session_data();
2021
-        $filters        = new EE_Line_Item_Filter_Collection();
2022
-        $filters->add(new EE_Single_Registration_Line_Item_Filter($this->_registration));
2023
-        $filters->add(new EE_Non_Zero_Line_Item_Filter());
2024
-        $line_item_filter_processor              = new EE_Line_Item_Filter_Processor(
2025
-            $filters,
2026
-            $transaction->total_line_item()
2027
-        );
2028
-        $filtered_line_item_tree                 = $line_item_filter_processor->process();
2029
-        $line_item_display                       = new EE_Line_Item_Display(
2030
-            'reg_admin_table',
2031
-            'EE_Admin_Table_Registration_Line_Item_Display_Strategy'
2032
-        );
2033
-        $this->_template_args['line_item_table'] = $line_item_display->display_line_item(
2034
-            $filtered_line_item_tree,
2035
-            ['EE_Registration' => $this->_registration]
2036
-        );
2037
-        $attendee                                = $this->_registration->attendee();
2038
-        if (
2039
-            EE_Registry::instance()->CAP->current_user_can(
2040
-                'ee_read_transaction',
2041
-                'espresso_transactions_view_transaction'
2042
-            )
2043
-        ) {
2044
-            $this->_template_args['view_transaction_button'] = EEH_Template::get_button_or_link(
2045
-                EE_Admin_Page::add_query_args_and_nonce(
2046
-                    [
2047
-                        'action' => 'view_transaction',
2048
-                        'TXN_ID' => $transaction->ID(),
2049
-                    ],
2050
-                    TXN_ADMIN_URL
2051
-                ),
2052
-                esc_html__(' View Transaction', 'event_espresso'),
2053
-                'button secondary-button right',
2054
-                'dashicons dashicons-cart'
2055
-            );
2056
-        } else {
2057
-            $this->_template_args['view_transaction_button'] = '';
2058
-        }
2059
-        if (
2060
-            $attendee instanceof EE_Attendee
2061
-            && EE_Registry::instance()->CAP->current_user_can(
2062
-                'ee_send_message',
2063
-                'espresso_registrations_resend_registration'
2064
-            )
2065
-        ) {
2066
-            $this->_template_args['resend_registration_button'] = EEH_Template::get_button_or_link(
2067
-                EE_Admin_Page::add_query_args_and_nonce(
2068
-                    [
2069
-                        'action'      => 'resend_registration',
2070
-                        '_REG_ID'     => $this->_registration->ID(),
2071
-                        'redirect_to' => 'view_registration',
2072
-                    ],
2073
-                    REG_ADMIN_URL
2074
-                ),
2075
-                esc_html__(' Resend Registration', 'event_espresso'),
2076
-                'button secondary-button right',
2077
-                'dashicons dashicons-email-alt'
2078
-            );
2079
-        } else {
2080
-            $this->_template_args['resend_registration_button'] = '';
2081
-        }
2082
-        $this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
2083
-        $payment                               = $transaction->get_first_related('Payment');
2084
-        $payment                               = ! $payment instanceof EE_Payment
2085
-            ? EE_Payment::new_instance()
2086
-            : $payment;
2087
-        $payment_method                        = $payment->get_first_related('Payment_Method');
2088
-        $payment_method                        = ! $payment_method instanceof EE_Payment_Method
2089
-            ? EE_Payment_Method::new_instance()
2090
-            : $payment_method;
2091
-        $reg_details                           = [
2092
-            'payment_method'       => $payment_method->name(),
2093
-            'response_msg'         => $payment->gateway_response(),
2094
-            'registration_id'      => $this->_registration->get('REG_code'),
2095
-            'registration_session' => $this->_registration->session_ID(),
2096
-            'ip_address'           => isset($this->_session['ip_address']) ? $this->_session['ip_address'] : '',
2097
-            'user_agent'           => isset($this->_session['user_agent']) ? $this->_session['user_agent'] : '',
2098
-        ];
2099
-        if (isset($reg_details['registration_id'])) {
2100
-            $this->_template_args['reg_details']['registration_id']['value'] = $reg_details['registration_id'];
2101
-            $this->_template_args['reg_details']['registration_id']['label'] = esc_html__(
2102
-                'Registration ID',
2103
-                'event_espresso'
2104
-            );
2105
-            $this->_template_args['reg_details']['registration_id']['class'] = 'regular-text';
2106
-        }
2107
-        if (isset($reg_details['payment_method'])) {
2108
-            $this->_template_args['reg_details']['payment_method']['value'] = $reg_details['payment_method'];
2109
-            $this->_template_args['reg_details']['payment_method']['label'] = esc_html__(
2110
-                'Most Recent Payment Method',
2111
-                'event_espresso'
2112
-            );
2113
-            $this->_template_args['reg_details']['payment_method']['class'] = 'regular-text';
2114
-            $this->_template_args['reg_details']['response_msg']['value']   = $reg_details['response_msg'];
2115
-            $this->_template_args['reg_details']['response_msg']['label']   = esc_html__(
2116
-                'Payment method response',
2117
-                'event_espresso'
2118
-            );
2119
-            $this->_template_args['reg_details']['response_msg']['class']   = 'regular-text';
2120
-        }
2121
-        $this->_template_args['reg_details']['registration_session']['value'] = $reg_details['registration_session'];
2122
-        $this->_template_args['reg_details']['registration_session']['label'] = esc_html__(
2123
-            'Registration Session',
2124
-            'event_espresso'
2125
-        );
2126
-        $this->_template_args['reg_details']['registration_session']['class'] = 'regular-text';
2127
-        $this->_template_args['reg_details']['ip_address']['value']           = $reg_details['ip_address'];
2128
-        $this->_template_args['reg_details']['ip_address']['label']           = esc_html__(
2129
-            'Registration placed from IP',
2130
-            'event_espresso'
2131
-        );
2132
-        $this->_template_args['reg_details']['ip_address']['class']           = 'regular-text';
2133
-        $this->_template_args['reg_details']['user_agent']['value']           = $reg_details['user_agent'];
2134
-        $this->_template_args['reg_details']['user_agent']['label']           = esc_html__(
2135
-            'Registrant User Agent',
2136
-            'event_espresso'
2137
-        );
2138
-        $this->_template_args['reg_details']['user_agent']['class']           = 'large-text';
2139
-        $this->_template_args['event_link']                                   = EE_Admin_Page::add_query_args_and_nonce(
2140
-            [
2141
-                'action'   => 'default',
2142
-                'event_id' => $this->_registration->event_ID(),
2143
-            ],
2144
-            REG_ADMIN_URL
2145
-        );
2146
-        $this->_template_args['REG_ID']                                       = $this->_registration->ID();
2147
-        $this->_template_args['event_id']                                     = $this->_registration->event_ID();
2148
-        $template_path                                                        =
2149
-            REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_details.template.php';
2150
-        EEH_Template::display_template($template_path, $this->_template_args); // already escaped
2151
-    }
2152
-
2153
-
2154
-    /**
2155
-     * generates HTML for the Registration Questions meta box.
2156
-     * If pre-4.8.32.rc.000 hooks are used, uses old methods (with its filters),
2157
-     * otherwise uses new forms system
2158
-     *
2159
-     * @return void
2160
-     * @throws DomainException
2161
-     * @throws EE_Error
2162
-     * @throws InvalidArgumentException
2163
-     * @throws InvalidDataTypeException
2164
-     * @throws InvalidInterfaceException
2165
-     * @throws ReflectionException
2166
-     */
2167
-    public function _reg_questions_meta_box()
2168
-    {
2169
-        // allow someone to override this method entirely
2170
-        if (
2171
-            apply_filters(
2172
-                'FHEE__Registrations_Admin_Page___reg_questions_meta_box__do_default',
2173
-                true,
2174
-                $this,
2175
-                $this->_registration
2176
-            )
2177
-        ) {
2178
-            $form                                              = $this->_get_reg_custom_questions_form(
2179
-                $this->_registration->ID()
2180
-            );
2181
-            $this->_template_args['att_questions']             = count($form->subforms()) > 0
2182
-                ? $form->get_html_and_js()
2183
-                : '';
2184
-            $this->_template_args['reg_questions_form_action'] = 'edit_registration';
2185
-            $this->_template_args['REG_ID']                    = $this->_registration->ID();
2186
-            $template_path                                     =
2187
-                REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_questions.template.php';
2188
-            EEH_Template::display_template($template_path, $this->_template_args);
2189
-        }
2190
-    }
2191
-
2192
-
2193
-    /**
2194
-     * form_before_question_group
2195
-     *
2196
-     * @param string $output
2197
-     * @return        string
2198
-     * @deprecated    as of 4.8.32.rc.000
2199
-     */
2200
-    public function form_before_question_group($output)
2201
-    {
2202
-        EE_Error::doing_it_wrong(
2203
-            __CLASS__ . '::' . __FUNCTION__,
2204
-            esc_html__(
2205
-                'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2206
-                'event_espresso'
2207
-            ),
2208
-            '4.8.32.rc.000'
2209
-        );
2210
-        return '
25
+	/**
26
+	 * @var EE_Registration
27
+	 */
28
+	private $_registration;
29
+
30
+	/**
31
+	 * @var EE_Event
32
+	 */
33
+	private $_reg_event;
34
+
35
+	/**
36
+	 * @var EE_Session
37
+	 */
38
+	private $_session;
39
+
40
+	/**
41
+	 * @var array
42
+	 */
43
+	private static $_reg_status;
44
+
45
+	/**
46
+	 * Form for displaying the custom questions for this registration.
47
+	 * This gets used a few times throughout the request so its best to cache it
48
+	 *
49
+	 * @var EE_Registration_Custom_Questions_Form
50
+	 */
51
+	protected $_reg_custom_questions_form = null;
52
+
53
+	/**
54
+	 * @var EEM_Registration $registration_model
55
+	 */
56
+	private $registration_model;
57
+
58
+	/**
59
+	 * @var EEM_Attendee $attendee_model
60
+	 */
61
+	private $attendee_model;
62
+
63
+	/**
64
+	 * @var EEM_Event $event_model
65
+	 */
66
+	private $event_model;
67
+
68
+	/**
69
+	 * @var EEM_Status $status_model
70
+	 */
71
+	private $status_model;
72
+
73
+
74
+	/**
75
+	 * @param bool $routing
76
+	 * @throws EE_Error
77
+	 * @throws InvalidArgumentException
78
+	 * @throws InvalidDataTypeException
79
+	 * @throws InvalidInterfaceException
80
+	 * @throws ReflectionException
81
+	 */
82
+	public function __construct($routing = true)
83
+	{
84
+		parent::__construct($routing);
85
+		add_action('wp_loaded', [$this, 'wp_loaded']);
86
+	}
87
+
88
+
89
+	/**
90
+	 * @return EEM_Registration
91
+	 * @throws InvalidArgumentException
92
+	 * @throws InvalidDataTypeException
93
+	 * @throws InvalidInterfaceException
94
+	 * @since 4.10.2.p
95
+	 */
96
+	protected function getRegistrationModel()
97
+	{
98
+		if (! $this->registration_model instanceof EEM_Registration) {
99
+			$this->registration_model = $this->getLoader()->getShared('EEM_Registration');
100
+		}
101
+		return $this->registration_model;
102
+	}
103
+
104
+
105
+	/**
106
+	 * @return EEM_Attendee
107
+	 * @throws InvalidArgumentException
108
+	 * @throws InvalidDataTypeException
109
+	 * @throws InvalidInterfaceException
110
+	 * @since 4.10.2.p
111
+	 */
112
+	protected function getAttendeeModel()
113
+	{
114
+		if (! $this->attendee_model instanceof EEM_Attendee) {
115
+			$this->attendee_model = $this->getLoader()->getShared('EEM_Attendee');
116
+		}
117
+		return $this->attendee_model;
118
+	}
119
+
120
+
121
+	/**
122
+	 * @return EEM_Event
123
+	 * @throws InvalidArgumentException
124
+	 * @throws InvalidDataTypeException
125
+	 * @throws InvalidInterfaceException
126
+	 * @since 4.10.2.p
127
+	 */
128
+	protected function getEventModel()
129
+	{
130
+		if (! $this->event_model instanceof EEM_Event) {
131
+			$this->event_model = $this->getLoader()->getShared('EEM_Event');
132
+		}
133
+		return $this->event_model;
134
+	}
135
+
136
+
137
+	/**
138
+	 * @return EEM_Status
139
+	 * @throws InvalidArgumentException
140
+	 * @throws InvalidDataTypeException
141
+	 * @throws InvalidInterfaceException
142
+	 * @since 4.10.2.p
143
+	 */
144
+	protected function getStatusModel()
145
+	{
146
+		if (! $this->status_model instanceof EEM_Status) {
147
+			$this->status_model = $this->getLoader()->getShared('EEM_Status');
148
+		}
149
+		return $this->status_model;
150
+	}
151
+
152
+
153
+	public function wp_loaded()
154
+	{
155
+		// when adding a new registration...
156
+		$action = $this->request->getRequestParam('action');
157
+		if ($action === 'new_registration') {
158
+			EE_System::do_not_cache();
159
+			if ($this->request->getRequestParam('processing_registration', 0, 'int') !== 1) {
160
+				// and it's NOT the attendee information reg step
161
+				// force cookie expiration by setting time to last week
162
+				setcookie('ee_registration_added', 0, time() - WEEK_IN_SECONDS, '/');
163
+				// and update the global
164
+				$_COOKIE['ee_registration_added'] = 0;
165
+			}
166
+		}
167
+	}
168
+
169
+
170
+	protected function _init_page_props()
171
+	{
172
+		$this->page_slug        = REG_PG_SLUG;
173
+		$this->_admin_base_url  = REG_ADMIN_URL;
174
+		$this->_admin_base_path = REG_ADMIN;
175
+		$this->page_label       = esc_html__('Registrations', 'event_espresso');
176
+		$this->_cpt_routes      = [
177
+			'add_new_attendee' => 'espresso_attendees',
178
+			'edit_attendee'    => 'espresso_attendees',
179
+			'insert_attendee'  => 'espresso_attendees',
180
+			'update_attendee'  => 'espresso_attendees',
181
+		];
182
+		$this->_cpt_model_names = [
183
+			'add_new_attendee' => 'EEM_Attendee',
184
+			'edit_attendee'    => 'EEM_Attendee',
185
+		];
186
+		$this->_cpt_edit_routes = [
187
+			'espresso_attendees' => 'edit_attendee',
188
+		];
189
+		$this->_pagenow_map     = [
190
+			'add_new_attendee' => 'post-new.php',
191
+			'edit_attendee'    => 'post.php',
192
+			'trash'            => 'post.php',
193
+		];
194
+		add_action('edit_form_after_title', [$this, 'after_title_form_fields'], 10);
195
+		// add filters so that the comment urls don't take users to a confusing 404 page
196
+		add_filter('get_comment_link', [$this, 'clear_comment_link'], 10, 2);
197
+	}
198
+
199
+
200
+	/**
201
+	 * @param string     $link    The comment permalink with '#comment-$id' appended.
202
+	 * @param WP_Comment $comment The current comment object.
203
+	 * @return string
204
+	 */
205
+	public function clear_comment_link($link, WP_Comment $comment)
206
+	{
207
+		// gotta make sure this only happens on this route
208
+		$post_type = get_post_type($comment->comment_post_ID);
209
+		if ($post_type === 'espresso_attendees') {
210
+			return '#commentsdiv';
211
+		}
212
+		return $link;
213
+	}
214
+
215
+
216
+	protected function _ajax_hooks()
217
+	{
218
+		// todo: all hooks for registrations ajax goes in here
219
+		add_action('wp_ajax_toggle_checkin_status', [$this, 'toggle_checkin_status']);
220
+	}
221
+
222
+
223
+	protected function _define_page_props()
224
+	{
225
+		$this->_admin_page_title = $this->page_label;
226
+		$this->_labels           = [
227
+			'buttons'                      => [
228
+				'add-registrant'      => esc_html__('Add New Registration', 'event_espresso'),
229
+				'add-attendee'        => esc_html__('Add Contact', 'event_espresso'),
230
+				'edit'                => esc_html__('Edit Contact', 'event_espresso'),
231
+				'csv_reg_report'      => esc_html__('Registrations CSV Report', 'event_espresso'),
232
+				'contact_list_report' => esc_html__('Contact List Report', 'event_espresso'),
233
+				'contact_list_export' => esc_html__('Export Data', 'event_espresso'),
234
+			],
235
+			'publishbox'                   => [
236
+				'add_new_attendee' => esc_html__('Add Contact Record', 'event_espresso'),
237
+				'edit_attendee'    => esc_html__('Update Contact Record', 'event_espresso'),
238
+			],
239
+			'hide_add_button_on_cpt_route' => [
240
+				'edit_attendee' => true,
241
+			],
242
+		];
243
+	}
244
+
245
+
246
+	/**
247
+	 * grab url requests and route them
248
+	 *
249
+	 * @return void
250
+	 * @throws EE_Error
251
+	 */
252
+	public function _set_page_routes()
253
+	{
254
+		$this->_get_registration_status_array();
255
+		$REG_ID             = $this->request->getRequestParam('_REG_ID', 0, 'int');
256
+		$REG_ID             = $this->request->getRequestParam('reg_status_change_form[REG_ID]', $REG_ID, 'int');
257
+		$ATT_ID             = $this->request->getRequestParam('ATT_ID', 0, 'int');
258
+		$ATT_ID             = $this->request->getRequestParam('post', $ATT_ID, 'int');
259
+		$this->_page_routes = [
260
+			'default'                             => [
261
+				'func'       => [$this, '_registrations_overview_list_table'],
262
+				'capability' => 'ee_read_registrations',
263
+			],
264
+			'view_registration'                   => [
265
+				'func'       => '_registration_details',
266
+				'capability' => 'ee_read_registration',
267
+				'obj_id'     => $REG_ID,
268
+			],
269
+			'edit_registration'                   => [
270
+				'func'               => '_update_attendee_registration_form',
271
+				'noheader'           => true,
272
+				'headers_sent_route' => 'view_registration',
273
+				'capability'         => 'ee_edit_registration',
274
+				'obj_id'             => $REG_ID,
275
+				'_REG_ID'            => $REG_ID,
276
+			],
277
+			'trash_registrations'                 => [
278
+				'func'       => '_trash_or_restore_registrations',
279
+				'args'       => ['trash' => true],
280
+				'noheader'   => true,
281
+				'capability' => 'ee_delete_registrations',
282
+			],
283
+			'restore_registrations'               => [
284
+				'func'       => '_trash_or_restore_registrations',
285
+				'args'       => ['trash' => false],
286
+				'noheader'   => true,
287
+				'capability' => 'ee_delete_registrations',
288
+			],
289
+			'delete_registrations'                => [
290
+				'func'       => '_delete_registrations',
291
+				'noheader'   => true,
292
+				'capability' => 'ee_delete_registrations',
293
+			],
294
+			'new_registration'                    => [
295
+				'func'       => 'new_registration',
296
+				'capability' => 'ee_edit_registrations',
297
+			],
298
+			'process_reg_step'                    => [
299
+				'func'       => 'process_reg_step',
300
+				'noheader'   => true,
301
+				'capability' => 'ee_edit_registrations',
302
+			],
303
+			'redirect_to_txn'                     => [
304
+				'func'       => 'redirect_to_txn',
305
+				'noheader'   => true,
306
+				'capability' => 'ee_edit_registrations',
307
+			],
308
+			'change_reg_status'                   => [
309
+				'func'       => '_change_reg_status',
310
+				'noheader'   => true,
311
+				'capability' => 'ee_edit_registration',
312
+				'obj_id'     => $REG_ID,
313
+			],
314
+			'approve_registration'                => [
315
+				'func'       => 'approve_registration',
316
+				'noheader'   => true,
317
+				'capability' => 'ee_edit_registration',
318
+				'obj_id'     => $REG_ID,
319
+			],
320
+			'approve_and_notify_registration'     => [
321
+				'func'       => 'approve_registration',
322
+				'noheader'   => true,
323
+				'args'       => [true],
324
+				'capability' => 'ee_edit_registration',
325
+				'obj_id'     => $REG_ID,
326
+			],
327
+			'approve_registrations'               => [
328
+				'func'       => 'bulk_action_on_registrations',
329
+				'noheader'   => true,
330
+				'capability' => 'ee_edit_registrations',
331
+				'args'       => ['approve'],
332
+			],
333
+			'approve_and_notify_registrations'    => [
334
+				'func'       => 'bulk_action_on_registrations',
335
+				'noheader'   => true,
336
+				'capability' => 'ee_edit_registrations',
337
+				'args'       => ['approve', true],
338
+			],
339
+			'decline_registration'                => [
340
+				'func'       => 'decline_registration',
341
+				'noheader'   => true,
342
+				'capability' => 'ee_edit_registration',
343
+				'obj_id'     => $REG_ID,
344
+			],
345
+			'decline_and_notify_registration'     => [
346
+				'func'       => 'decline_registration',
347
+				'noheader'   => true,
348
+				'args'       => [true],
349
+				'capability' => 'ee_edit_registration',
350
+				'obj_id'     => $REG_ID,
351
+			],
352
+			'decline_registrations'               => [
353
+				'func'       => 'bulk_action_on_registrations',
354
+				'noheader'   => true,
355
+				'capability' => 'ee_edit_registrations',
356
+				'args'       => ['decline'],
357
+			],
358
+			'decline_and_notify_registrations'    => [
359
+				'func'       => 'bulk_action_on_registrations',
360
+				'noheader'   => true,
361
+				'capability' => 'ee_edit_registrations',
362
+				'args'       => ['decline', true],
363
+			],
364
+			'pending_registration'                => [
365
+				'func'       => 'pending_registration',
366
+				'noheader'   => true,
367
+				'capability' => 'ee_edit_registration',
368
+				'obj_id'     => $REG_ID,
369
+			],
370
+			'pending_and_notify_registration'     => [
371
+				'func'       => 'pending_registration',
372
+				'noheader'   => true,
373
+				'args'       => [true],
374
+				'capability' => 'ee_edit_registration',
375
+				'obj_id'     => $REG_ID,
376
+			],
377
+			'pending_registrations'               => [
378
+				'func'       => 'bulk_action_on_registrations',
379
+				'noheader'   => true,
380
+				'capability' => 'ee_edit_registrations',
381
+				'args'       => ['pending'],
382
+			],
383
+			'pending_and_notify_registrations'    => [
384
+				'func'       => 'bulk_action_on_registrations',
385
+				'noheader'   => true,
386
+				'capability' => 'ee_edit_registrations',
387
+				'args'       => ['pending', true],
388
+			],
389
+			'no_approve_registration'             => [
390
+				'func'       => 'not_approve_registration',
391
+				'noheader'   => true,
392
+				'capability' => 'ee_edit_registration',
393
+				'obj_id'     => $REG_ID,
394
+			],
395
+			'no_approve_and_notify_registration'  => [
396
+				'func'       => 'not_approve_registration',
397
+				'noheader'   => true,
398
+				'args'       => [true],
399
+				'capability' => 'ee_edit_registration',
400
+				'obj_id'     => $REG_ID,
401
+			],
402
+			'no_approve_registrations'            => [
403
+				'func'       => 'bulk_action_on_registrations',
404
+				'noheader'   => true,
405
+				'capability' => 'ee_edit_registrations',
406
+				'args'       => ['not_approve'],
407
+			],
408
+			'no_approve_and_notify_registrations' => [
409
+				'func'       => 'bulk_action_on_registrations',
410
+				'noheader'   => true,
411
+				'capability' => 'ee_edit_registrations',
412
+				'args'       => ['not_approve', true],
413
+			],
414
+			'cancel_registration'                 => [
415
+				'func'       => 'cancel_registration',
416
+				'noheader'   => true,
417
+				'capability' => 'ee_edit_registration',
418
+				'obj_id'     => $REG_ID,
419
+			],
420
+			'cancel_and_notify_registration'      => [
421
+				'func'       => 'cancel_registration',
422
+				'noheader'   => true,
423
+				'args'       => [true],
424
+				'capability' => 'ee_edit_registration',
425
+				'obj_id'     => $REG_ID,
426
+			],
427
+			'cancel_registrations'                => [
428
+				'func'       => 'bulk_action_on_registrations',
429
+				'noheader'   => true,
430
+				'capability' => 'ee_edit_registrations',
431
+				'args'       => ['cancel'],
432
+			],
433
+			'cancel_and_notify_registrations'     => [
434
+				'func'       => 'bulk_action_on_registrations',
435
+				'noheader'   => true,
436
+				'capability' => 'ee_edit_registrations',
437
+				'args'       => ['cancel', true],
438
+			],
439
+			'wait_list_registration'              => [
440
+				'func'       => 'wait_list_registration',
441
+				'noheader'   => true,
442
+				'capability' => 'ee_edit_registration',
443
+				'obj_id'     => $REG_ID,
444
+			],
445
+			'wait_list_and_notify_registration'   => [
446
+				'func'       => 'wait_list_registration',
447
+				'noheader'   => true,
448
+				'args'       => [true],
449
+				'capability' => 'ee_edit_registration',
450
+				'obj_id'     => $REG_ID,
451
+			],
452
+			'contact_list'                        => [
453
+				'func'       => '_attendee_contact_list_table',
454
+				'capability' => 'ee_read_contacts',
455
+			],
456
+			'add_new_attendee'                    => [
457
+				'func' => '_create_new_cpt_item',
458
+				'args' => [
459
+					'new_attendee' => true,
460
+					'capability'   => 'ee_edit_contacts',
461
+				],
462
+			],
463
+			'edit_attendee'                       => [
464
+				'func'       => '_edit_cpt_item',
465
+				'capability' => 'ee_edit_contacts',
466
+				'obj_id'     => $ATT_ID,
467
+			],
468
+			'duplicate_attendee'                  => [
469
+				'func'       => '_duplicate_attendee',
470
+				'noheader'   => true,
471
+				'capability' => 'ee_edit_contacts',
472
+				'obj_id'     => $ATT_ID,
473
+			],
474
+			'insert_attendee'                     => [
475
+				'func'       => '_insert_or_update_attendee',
476
+				'args'       => [
477
+					'new_attendee' => true,
478
+				],
479
+				'noheader'   => true,
480
+				'capability' => 'ee_edit_contacts',
481
+			],
482
+			'update_attendee'                     => [
483
+				'func'       => '_insert_or_update_attendee',
484
+				'args'       => [
485
+					'new_attendee' => false,
486
+				],
487
+				'noheader'   => true,
488
+				'capability' => 'ee_edit_contacts',
489
+				'obj_id'     => $ATT_ID,
490
+			],
491
+			'trash_attendees'                     => [
492
+				'func'       => '_trash_or_restore_attendees',
493
+				'args'       => [
494
+					'trash' => 'true',
495
+				],
496
+				'noheader'   => true,
497
+				'capability' => 'ee_delete_contacts',
498
+			],
499
+			'trash_attendee'                      => [
500
+				'func'       => '_trash_or_restore_attendees',
501
+				'args'       => [
502
+					'trash' => true,
503
+				],
504
+				'noheader'   => true,
505
+				'capability' => 'ee_delete_contacts',
506
+				'obj_id'     => $ATT_ID,
507
+			],
508
+			'restore_attendees'                   => [
509
+				'func'       => '_trash_or_restore_attendees',
510
+				'args'       => [
511
+					'trash' => false,
512
+				],
513
+				'noheader'   => true,
514
+				'capability' => 'ee_delete_contacts',
515
+				'obj_id'     => $ATT_ID,
516
+			],
517
+			'resend_registration'                 => [
518
+				'func'       => '_resend_registration',
519
+				'noheader'   => true,
520
+				'capability' => 'ee_send_message',
521
+			],
522
+			'registrations_report'                => [
523
+				'func'       => [$this, '_registrations_report'],
524
+				'noheader'   => true,
525
+				'capability' => 'ee_read_registrations',
526
+			],
527
+			'contact_list_export'                 => [
528
+				'func'       => '_contact_list_export',
529
+				'noheader'   => true,
530
+				'capability' => 'export',
531
+			],
532
+			'contact_list_report'                 => [
533
+				'func'       => '_contact_list_report',
534
+				'noheader'   => true,
535
+				'capability' => 'ee_read_contacts',
536
+			],
537
+		];
538
+	}
539
+
540
+
541
+	protected function _set_page_config()
542
+	{
543
+		$REG_ID             = $this->request->getRequestParam('_REG_ID', 0, 'int');
544
+		$ATT_ID             = $this->request->getRequestParam('ATT_ID', 0, 'int');
545
+		$this->_page_config = [
546
+			'default'           => [
547
+				'nav'           => [
548
+					'label' => esc_html__('Overview', 'event_espresso'),
549
+					'order' => 5,
550
+				],
551
+				'help_tabs'     => [
552
+					'registrations_overview_help_tab'                       => [
553
+						'title'    => esc_html__('Registrations Overview', 'event_espresso'),
554
+						'filename' => 'registrations_overview',
555
+					],
556
+					'registrations_overview_table_column_headings_help_tab' => [
557
+						'title'    => esc_html__('Registrations Table Column Headings', 'event_espresso'),
558
+						'filename' => 'registrations_overview_table_column_headings',
559
+					],
560
+					'registrations_overview_filters_help_tab'               => [
561
+						'title'    => esc_html__('Registration Filters', 'event_espresso'),
562
+						'filename' => 'registrations_overview_filters',
563
+					],
564
+					'registrations_overview_views_help_tab'                 => [
565
+						'title'    => esc_html__('Registration Views', 'event_espresso'),
566
+						'filename' => 'registrations_overview_views',
567
+					],
568
+					'registrations_regoverview_other_help_tab'              => [
569
+						'title'    => esc_html__('Registrations Other', 'event_espresso'),
570
+						'filename' => 'registrations_overview_other',
571
+					],
572
+				],
573
+				'qtips'         => ['Registration_List_Table_Tips'],
574
+				'list_table'    => 'EE_Registrations_List_Table',
575
+				'require_nonce' => false,
576
+			],
577
+			'view_registration' => [
578
+				'nav'           => [
579
+					'label'      => esc_html__('REG Details', 'event_espresso'),
580
+					'order'      => 15,
581
+					'url'        => $REG_ID
582
+						? add_query_arg(['_REG_ID' => $REG_ID], $this->_current_page_view_url)
583
+						: $this->_admin_base_url,
584
+					'persistent' => false,
585
+				],
586
+				'help_tabs'     => [
587
+					'registrations_details_help_tab'                    => [
588
+						'title'    => esc_html__('Registration Details', 'event_espresso'),
589
+						'filename' => 'registrations_details',
590
+					],
591
+					'registrations_details_table_help_tab'              => [
592
+						'title'    => esc_html__('Registration Details Table', 'event_espresso'),
593
+						'filename' => 'registrations_details_table',
594
+					],
595
+					'registrations_details_form_answers_help_tab'       => [
596
+						'title'    => esc_html__('Registration Form Answers', 'event_espresso'),
597
+						'filename' => 'registrations_details_form_answers',
598
+					],
599
+					'registrations_details_registrant_details_help_tab' => [
600
+						'title'    => esc_html__('Contact Details', 'event_espresso'),
601
+						'filename' => 'registrations_details_registrant_details',
602
+					],
603
+				],
604
+				'metaboxes'     => array_merge(
605
+					$this->_default_espresso_metaboxes,
606
+					['_registration_details_metaboxes']
607
+				),
608
+				'require_nonce' => false,
609
+			],
610
+			'new_registration'  => [
611
+				'nav'           => [
612
+					'label'      => esc_html__('Add New Registration', 'event_espresso'),
613
+					'url'        => '#',
614
+					'order'      => 15,
615
+					'persistent' => false,
616
+				],
617
+				'metaboxes'     => $this->_default_espresso_metaboxes,
618
+				'labels'        => [
619
+					'publishbox' => esc_html__('Save Registration', 'event_espresso'),
620
+				],
621
+				'require_nonce' => false,
622
+			],
623
+			'add_new_attendee'  => [
624
+				'nav'           => [
625
+					'label'      => esc_html__('Add Contact', 'event_espresso'),
626
+					'order'      => 15,
627
+					'persistent' => false,
628
+				],
629
+				'metaboxes'     => array_merge(
630
+					$this->_default_espresso_metaboxes,
631
+					['_publish_post_box', 'attendee_editor_metaboxes']
632
+				),
633
+				'require_nonce' => false,
634
+			],
635
+			'edit_attendee'     => [
636
+				'nav'           => [
637
+					'label'      => esc_html__('Edit Contact', 'event_espresso'),
638
+					'order'      => 15,
639
+					'persistent' => false,
640
+					'url'        => $ATT_ID
641
+						? add_query_arg(['ATT_ID' => $ATT_ID], $this->_current_page_view_url)
642
+						: $this->_admin_base_url,
643
+				],
644
+				'metaboxes'     => ['attendee_editor_metaboxes'],
645
+				'require_nonce' => false,
646
+			],
647
+			'contact_list'      => [
648
+				'nav'           => [
649
+					'label' => esc_html__('Contact List', 'event_espresso'),
650
+					'order' => 20,
651
+				],
652
+				'list_table'    => 'EE_Attendee_Contact_List_Table',
653
+				'help_tabs'     => [
654
+					'registrations_contact_list_help_tab'                       => [
655
+						'title'    => esc_html__('Registrations Contact List', 'event_espresso'),
656
+						'filename' => 'registrations_contact_list',
657
+					],
658
+					'registrations_contact-list_table_column_headings_help_tab' => [
659
+						'title'    => esc_html__('Contact List Table Column Headings', 'event_espresso'),
660
+						'filename' => 'registrations_contact_list_table_column_headings',
661
+					],
662
+					'registrations_contact_list_views_help_tab'                 => [
663
+						'title'    => esc_html__('Contact List Views', 'event_espresso'),
664
+						'filename' => 'registrations_contact_list_views',
665
+					],
666
+					'registrations_contact_list_other_help_tab'                 => [
667
+						'title'    => esc_html__('Contact List Other', 'event_espresso'),
668
+						'filename' => 'registrations_contact_list_other',
669
+					],
670
+				],
671
+				'metaboxes'     => [],
672
+				'require_nonce' => false,
673
+			],
674
+			// override default cpt routes
675
+			'create_new'        => '',
676
+			'edit'              => '',
677
+		];
678
+	}
679
+
680
+
681
+	/**
682
+	 * The below methods aren't used by this class currently
683
+	 */
684
+	protected function _add_screen_options()
685
+	{
686
+	}
687
+
688
+
689
+	protected function _add_feature_pointers()
690
+	{
691
+	}
692
+
693
+
694
+	public function admin_init()
695
+	{
696
+		EE_Registry::$i18n_js_strings['update_att_qstns'] = esc_html__(
697
+			'click "Update Registration Questions" to save your changes',
698
+			'event_espresso'
699
+		);
700
+	}
701
+
702
+
703
+	public function admin_notices()
704
+	{
705
+	}
706
+
707
+
708
+	public function admin_footer_scripts()
709
+	{
710
+	}
711
+
712
+
713
+	/**
714
+	 * get list of registration statuses
715
+	 *
716
+	 * @return void
717
+	 * @throws EE_Error
718
+	 */
719
+	private function _get_registration_status_array()
720
+	{
721
+		self::$_reg_status = EEM_Registration::reg_status_array([], true);
722
+	}
723
+
724
+
725
+	/**
726
+	 * @throws InvalidArgumentException
727
+	 * @throws InvalidDataTypeException
728
+	 * @throws InvalidInterfaceException
729
+	 * @since 4.10.2.p
730
+	 */
731
+	protected function _add_screen_options_default()
732
+	{
733
+		$this->_per_page_screen_option();
734
+	}
735
+
736
+
737
+	/**
738
+	 * @throws InvalidArgumentException
739
+	 * @throws InvalidDataTypeException
740
+	 * @throws InvalidInterfaceException
741
+	 * @since 4.10.2.p
742
+	 */
743
+	protected function _add_screen_options_contact_list()
744
+	{
745
+		$page_title              = $this->_admin_page_title;
746
+		$this->_admin_page_title = esc_html__('Contacts', 'event_espresso');
747
+		$this->_per_page_screen_option();
748
+		$this->_admin_page_title = $page_title;
749
+	}
750
+
751
+
752
+	public function load_scripts_styles()
753
+	{
754
+		// style
755
+		wp_register_style(
756
+			'espresso_reg',
757
+			REG_ASSETS_URL . 'espresso_registrations_admin.css',
758
+			['ee-admin-css'],
759
+			EVENT_ESPRESSO_VERSION
760
+		);
761
+		wp_enqueue_style('espresso_reg');
762
+		// script
763
+		wp_register_script(
764
+			'espresso_reg',
765
+			REG_ASSETS_URL . 'espresso_registrations_admin.js',
766
+			['jquery-ui-datepicker', 'jquery-ui-draggable', 'ee_admin_js'],
767
+			EVENT_ESPRESSO_VERSION,
768
+			true
769
+		);
770
+		wp_enqueue_script('espresso_reg');
771
+	}
772
+
773
+
774
+	/**
775
+	 * @throws EE_Error
776
+	 * @throws InvalidArgumentException
777
+	 * @throws InvalidDataTypeException
778
+	 * @throws InvalidInterfaceException
779
+	 * @throws ReflectionException
780
+	 * @since 4.10.2.p
781
+	 */
782
+	public function load_scripts_styles_edit_attendee()
783
+	{
784
+		// stuff to only show up on our attendee edit details page.
785
+		$attendee_details_translations = [
786
+			'att_publish_text' => sprintf(
787
+			/* translators: The date and time */
788
+				wp_strip_all_tags(__('Created on: %s', 'event_espresso')),
789
+				'<b>' . $this->_cpt_model_obj->get_datetime('ATT_created') . '</b>'
790
+			),
791
+		];
792
+		wp_localize_script('espresso_reg', 'ATTENDEE_DETAILS', $attendee_details_translations);
793
+		wp_enqueue_script('jquery-validate');
794
+	}
795
+
796
+
797
+	/**
798
+	 * @throws EE_Error
799
+	 * @throws InvalidArgumentException
800
+	 * @throws InvalidDataTypeException
801
+	 * @throws InvalidInterfaceException
802
+	 * @throws ReflectionException
803
+	 * @since 4.10.2.p
804
+	 */
805
+	public function load_scripts_styles_view_registration()
806
+	{
807
+		// styles
808
+		wp_enqueue_style('espresso-ui-theme');
809
+		// scripts
810
+		$this->_get_reg_custom_questions_form($this->_registration->ID());
811
+		$this->_reg_custom_questions_form->wp_enqueue_scripts();
812
+	}
813
+
814
+
815
+	public function load_scripts_styles_contact_list()
816
+	{
817
+		wp_dequeue_style('espresso_reg');
818
+		wp_register_style(
819
+			'espresso_att',
820
+			REG_ASSETS_URL . 'espresso_attendees_admin.css',
821
+			['ee-admin-css'],
822
+			EVENT_ESPRESSO_VERSION
823
+		);
824
+		wp_enqueue_style('espresso_att');
825
+	}
826
+
827
+
828
+	public function load_scripts_styles_new_registration()
829
+	{
830
+		wp_register_script(
831
+			'ee-spco-for-admin',
832
+			REG_ASSETS_URL . 'spco_for_admin.js',
833
+			['underscore', 'jquery'],
834
+			EVENT_ESPRESSO_VERSION,
835
+			true
836
+		);
837
+		wp_enqueue_script('ee-spco-for-admin');
838
+		add_filter('FHEE__EED_Ticket_Selector__load_tckt_slctr_assets', '__return_true');
839
+		EE_Form_Section_Proper::wp_enqueue_scripts();
840
+		EED_Ticket_Selector::load_tckt_slctr_assets();
841
+		EE_Datepicker_Input::enqueue_styles_and_scripts();
842
+	}
843
+
844
+
845
+	public function AHEE__EE_Admin_Page__route_admin_request_resend_registration()
846
+	{
847
+		add_filter('FHEE_load_EE_messages', '__return_true');
848
+	}
849
+
850
+
851
+	public function AHEE__EE_Admin_Page__route_admin_request_approve_registration()
852
+	{
853
+		add_filter('FHEE_load_EE_messages', '__return_true');
854
+	}
855
+
856
+
857
+	/**
858
+	 * @throws EE_Error
859
+	 * @throws InvalidArgumentException
860
+	 * @throws InvalidDataTypeException
861
+	 * @throws InvalidInterfaceException
862
+	 * @throws ReflectionException
863
+	 * @since 4.10.2.p
864
+	 */
865
+	protected function _set_list_table_views_default()
866
+	{
867
+		// for notification related bulk actions we need to make sure only active messengers have an option.
868
+		EED_Messages::set_autoloaders();
869
+		/** @type EE_Message_Resource_Manager $message_resource_manager */
870
+		$message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
871
+		$active_mts               = $message_resource_manager->list_of_active_message_types();
872
+		// key= bulk_action_slug, value= message type.
873
+		$match_array = [
874
+			'approve_registrations'    => 'registration',
875
+			'decline_registrations'    => 'declined_registration',
876
+			'pending_registrations'    => 'pending_approval',
877
+			'no_approve_registrations' => 'not_approved_registration',
878
+			'cancel_registrations'     => 'cancelled_registration',
879
+		];
880
+		$can_send    = EE_Registry::instance()->CAP->current_user_can(
881
+			'ee_send_message',
882
+			'batch_send_messages'
883
+		);
884
+		/** setup reg status bulk actions **/
885
+		$def_reg_status_actions['approve_registrations'] = esc_html__('Approve Registrations', 'event_espresso');
886
+		if ($can_send && in_array($match_array['approve_registrations'], $active_mts, true)) {
887
+			$def_reg_status_actions['approve_and_notify_registrations'] = esc_html__(
888
+				'Approve and Notify Registrations',
889
+				'event_espresso'
890
+			);
891
+		}
892
+		$def_reg_status_actions['decline_registrations'] = esc_html__('Decline Registrations', 'event_espresso');
893
+		if ($can_send && in_array($match_array['decline_registrations'], $active_mts, true)) {
894
+			$def_reg_status_actions['decline_and_notify_registrations'] = esc_html__(
895
+				'Decline and Notify Registrations',
896
+				'event_espresso'
897
+			);
898
+		}
899
+		$def_reg_status_actions['pending_registrations'] = esc_html__(
900
+			'Set Registrations to Pending Payment',
901
+			'event_espresso'
902
+		);
903
+		if ($can_send && in_array($match_array['pending_registrations'], $active_mts, true)) {
904
+			$def_reg_status_actions['pending_and_notify_registrations'] = esc_html__(
905
+				'Set Registrations to Pending Payment and Notify',
906
+				'event_espresso'
907
+			);
908
+		}
909
+		$def_reg_status_actions['no_approve_registrations'] = esc_html__(
910
+			'Set Registrations to Not Approved',
911
+			'event_espresso'
912
+		);
913
+		if ($can_send && in_array($match_array['no_approve_registrations'], $active_mts, true)) {
914
+			$def_reg_status_actions['no_approve_and_notify_registrations'] = esc_html__(
915
+				'Set Registrations to Not Approved and Notify',
916
+				'event_espresso'
917
+			);
918
+		}
919
+		$def_reg_status_actions['cancel_registrations'] = esc_html__('Cancel Registrations', 'event_espresso');
920
+		if ($can_send && in_array($match_array['cancel_registrations'], $active_mts, true)) {
921
+			$def_reg_status_actions['cancel_and_notify_registrations'] = esc_html__(
922
+				'Cancel Registrations and Notify',
923
+				'event_espresso'
924
+			);
925
+		}
926
+		$def_reg_status_actions = apply_filters(
927
+			'FHEE__Registrations_Admin_Page___set_list_table_views_default__def_reg_status_actions_array',
928
+			$def_reg_status_actions,
929
+			$active_mts,
930
+			$can_send
931
+		);
932
+
933
+		$this->_views = [
934
+			'all'   => [
935
+				'slug'        => 'all',
936
+				'label'       => esc_html__('View All Registrations', 'event_espresso'),
937
+				'count'       => 0,
938
+				'bulk_action' => array_merge(
939
+					$def_reg_status_actions,
940
+					[
941
+						'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
942
+					]
943
+				),
944
+			],
945
+			'month' => [
946
+				'slug'        => 'month',
947
+				'label'       => esc_html__('This Month', 'event_espresso'),
948
+				'count'       => 0,
949
+				'bulk_action' => array_merge(
950
+					$def_reg_status_actions,
951
+					[
952
+						'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
953
+					]
954
+				),
955
+			],
956
+			'today' => [
957
+				'slug'        => 'today',
958
+				'label'       => sprintf(
959
+					esc_html__('Today - %s', 'event_espresso'),
960
+					date('M d, Y', current_time('timestamp'))
961
+				),
962
+				'count'       => 0,
963
+				'bulk_action' => array_merge(
964
+					$def_reg_status_actions,
965
+					[
966
+						'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
967
+					]
968
+				),
969
+			],
970
+		];
971
+		if (
972
+			EE_Registry::instance()->CAP->current_user_can(
973
+				'ee_delete_registrations',
974
+				'espresso_registrations_delete_registration'
975
+			)
976
+		) {
977
+			$this->_views['incomplete'] = [
978
+				'slug'        => 'incomplete',
979
+				'label'       => esc_html__('Incomplete', 'event_espresso'),
980
+				'count'       => 0,
981
+				'bulk_action' => [
982
+					'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
983
+				],
984
+			];
985
+			$this->_views['trash']      = [
986
+				'slug'        => 'trash',
987
+				'label'       => esc_html__('Trash', 'event_espresso'),
988
+				'count'       => 0,
989
+				'bulk_action' => [
990
+					'restore_registrations' => esc_html__('Restore Registrations', 'event_espresso'),
991
+					'delete_registrations'  => esc_html__('Delete Registrations Permanently', 'event_espresso'),
992
+				],
993
+			];
994
+		}
995
+	}
996
+
997
+
998
+	protected function _set_list_table_views_contact_list()
999
+	{
1000
+		$this->_views = [
1001
+			'in_use' => [
1002
+				'slug'        => 'in_use',
1003
+				'label'       => esc_html__('In Use', 'event_espresso'),
1004
+				'count'       => 0,
1005
+				'bulk_action' => [
1006
+					'trash_attendees' => esc_html__('Move to Trash', 'event_espresso'),
1007
+				],
1008
+			],
1009
+		];
1010
+		if (
1011
+			EE_Registry::instance()->CAP->current_user_can(
1012
+				'ee_delete_contacts',
1013
+				'espresso_registrations_trash_attendees'
1014
+			)
1015
+		) {
1016
+			$this->_views['trash'] = [
1017
+				'slug'        => 'trash',
1018
+				'label'       => esc_html__('Trash', 'event_espresso'),
1019
+				'count'       => 0,
1020
+				'bulk_action' => [
1021
+					'restore_attendees' => esc_html__('Restore from Trash', 'event_espresso'),
1022
+				],
1023
+			];
1024
+		}
1025
+	}
1026
+
1027
+
1028
+	/**
1029
+	 * @return array
1030
+	 * @throws EE_Error
1031
+	 */
1032
+	protected function _registration_legend_items()
1033
+	{
1034
+		$fc_items = [
1035
+			'star-icon'        => [
1036
+				'class' => 'dashicons dashicons-star-filled lt-blue-icon ee-icon-size-8',
1037
+				'desc'  => esc_html__('This is the Primary Registrant', 'event_espresso'),
1038
+			],
1039
+			'view_details'     => [
1040
+				'class' => 'dashicons dashicons-clipboard',
1041
+				'desc'  => esc_html__('View Registration Details', 'event_espresso'),
1042
+			],
1043
+			'edit_attendee'    => [
1044
+				'class' => 'ee-icon ee-icon-user-edit ee-icon-size-16',
1045
+				'desc'  => esc_html__('Edit Contact Details', 'event_espresso'),
1046
+			],
1047
+			'view_transaction' => [
1048
+				'class' => 'dashicons dashicons-cart',
1049
+				'desc'  => esc_html__('View Transaction Details', 'event_espresso'),
1050
+			],
1051
+			'view_invoice'     => [
1052
+				'class' => 'dashicons dashicons-media-spreadsheet',
1053
+				'desc'  => esc_html__('View Transaction Invoice', 'event_espresso'),
1054
+			],
1055
+		];
1056
+		if (
1057
+			EE_Registry::instance()->CAP->current_user_can(
1058
+				'ee_send_message',
1059
+				'espresso_registrations_resend_registration'
1060
+			)
1061
+		) {
1062
+			$fc_items['resend_registration'] = [
1063
+				'class' => 'dashicons dashicons-email-alt',
1064
+				'desc'  => esc_html__('Resend Registration Details', 'event_espresso'),
1065
+			];
1066
+		} else {
1067
+			$fc_items['blank'] = ['class' => 'blank', 'desc' => ''];
1068
+		}
1069
+		if (
1070
+			EE_Registry::instance()->CAP->current_user_can(
1071
+				'ee_read_global_messages',
1072
+				'view_filtered_messages'
1073
+			)
1074
+		) {
1075
+			$related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
1076
+			if (is_array($related_for_icon) && isset($related_for_icon['css_class'], $related_for_icon['label'])) {
1077
+				$fc_items['view_related_messages'] = [
1078
+					'class' => $related_for_icon['css_class'],
1079
+					'desc'  => $related_for_icon['label'],
1080
+				];
1081
+			}
1082
+		}
1083
+		$sc_items = [
1084
+			'approved_status'   => [
1085
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_approved,
1086
+				'desc'  => EEH_Template::pretty_status(
1087
+					EEM_Registration::status_id_approved,
1088
+					false,
1089
+					'sentence'
1090
+				),
1091
+			],
1092
+			'pending_status'    => [
1093
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_pending_payment,
1094
+				'desc'  => EEH_Template::pretty_status(
1095
+					EEM_Registration::status_id_pending_payment,
1096
+					false,
1097
+					'sentence'
1098
+				),
1099
+			],
1100
+			'wait_list'         => [
1101
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_wait_list,
1102
+				'desc'  => EEH_Template::pretty_status(
1103
+					EEM_Registration::status_id_wait_list,
1104
+					false,
1105
+					'sentence'
1106
+				),
1107
+			],
1108
+			'incomplete_status' => [
1109
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_incomplete,
1110
+				'desc'  => EEH_Template::pretty_status(
1111
+					EEM_Registration::status_id_incomplete,
1112
+					false,
1113
+					'sentence'
1114
+				),
1115
+			],
1116
+			'not_approved'      => [
1117
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_not_approved,
1118
+				'desc'  => EEH_Template::pretty_status(
1119
+					EEM_Registration::status_id_not_approved,
1120
+					false,
1121
+					'sentence'
1122
+				),
1123
+			],
1124
+			'declined_status'   => [
1125
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_declined,
1126
+				'desc'  => EEH_Template::pretty_status(
1127
+					EEM_Registration::status_id_declined,
1128
+					false,
1129
+					'sentence'
1130
+				),
1131
+			],
1132
+			'cancelled_status'  => [
1133
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_cancelled,
1134
+				'desc'  => EEH_Template::pretty_status(
1135
+					EEM_Registration::status_id_cancelled,
1136
+					false,
1137
+					'sentence'
1138
+				),
1139
+			],
1140
+		];
1141
+		return array_merge($fc_items, $sc_items);
1142
+	}
1143
+
1144
+
1145
+
1146
+	/***************************************        REGISTRATION OVERVIEW        **************************************/
1147
+
1148
+
1149
+	/**
1150
+	 * @throws DomainException
1151
+	 * @throws EE_Error
1152
+	 * @throws InvalidArgumentException
1153
+	 * @throws InvalidDataTypeException
1154
+	 * @throws InvalidInterfaceException
1155
+	 */
1156
+	protected function _registrations_overview_list_table()
1157
+	{
1158
+		$this->appendAddNewRegistrationButtonToPageTitle();
1159
+		$header_text                  = '';
1160
+		$admin_page_header_decorators = [
1161
+			'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\AttendeeFilterHeader',
1162
+			'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\EventFilterHeader',
1163
+			'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\DateFilterHeader',
1164
+			'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\TicketFilterHeader',
1165
+		];
1166
+		foreach ($admin_page_header_decorators as $admin_page_header_decorator) {
1167
+			$filter_header_decorator = $this->getLoader()->getNew($admin_page_header_decorator);
1168
+			$header_text             = $filter_header_decorator->getHeaderText($header_text);
1169
+		}
1170
+		$this->_template_args['admin_page_header'] = $header_text;
1171
+		$this->_template_args['after_list_table']  = $this->_display_legend($this->_registration_legend_items());
1172
+		$this->display_admin_list_table_page_with_no_sidebar();
1173
+	}
1174
+
1175
+
1176
+	/**
1177
+	 * @throws EE_Error
1178
+	 * @throws InvalidArgumentException
1179
+	 * @throws InvalidDataTypeException
1180
+	 * @throws InvalidInterfaceException
1181
+	 */
1182
+	private function appendAddNewRegistrationButtonToPageTitle()
1183
+	{
1184
+		$EVT_ID = $this->request->getRequestParam('event_id', 0, 'int');
1185
+		if (
1186
+			$EVT_ID
1187
+			&& EE_Registry::instance()->CAP->current_user_can(
1188
+				'ee_edit_registrations',
1189
+				'espresso_registrations_new_registration',
1190
+				$EVT_ID
1191
+			)
1192
+		) {
1193
+			$this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
1194
+				'new_registration',
1195
+				'add-registrant',
1196
+				['event_id' => $EVT_ID],
1197
+				'add-new-h2'
1198
+			);
1199
+		}
1200
+	}
1201
+
1202
+
1203
+	/**
1204
+	 * This sets the _registration property for the registration details screen
1205
+	 *
1206
+	 * @return void
1207
+	 * @throws EE_Error
1208
+	 * @throws InvalidArgumentException
1209
+	 * @throws InvalidDataTypeException
1210
+	 * @throws InvalidInterfaceException
1211
+	 */
1212
+	private function _set_registration_object()
1213
+	{
1214
+		// get out if we've already set the object
1215
+		if ($this->_registration instanceof EE_Registration) {
1216
+			return;
1217
+		}
1218
+		$REG_ID = $this->request->getRequestParam('_REG_ID', 0, 'int');
1219
+		if ($this->_registration = $this->getRegistrationModel()->get_one_by_ID($REG_ID)) {
1220
+			return;
1221
+		}
1222
+		$error_msg = sprintf(
1223
+			esc_html__(
1224
+				'An error occurred and the details for Registration ID #%s could not be retrieved.',
1225
+				'event_espresso'
1226
+			),
1227
+			$REG_ID
1228
+		);
1229
+		EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
1230
+		$this->_registration = null;
1231
+	}
1232
+
1233
+
1234
+	/**
1235
+	 * Used to retrieve registrations for the list table.
1236
+	 *
1237
+	 * @param int  $per_page
1238
+	 * @param bool $count
1239
+	 * @param bool $this_month
1240
+	 * @param bool $today
1241
+	 * @return EE_Registration[]|int
1242
+	 * @throws EE_Error
1243
+	 * @throws InvalidArgumentException
1244
+	 * @throws InvalidDataTypeException
1245
+	 * @throws InvalidInterfaceException
1246
+	 */
1247
+	public function get_registrations(
1248
+		$per_page = 10,
1249
+		$count = false,
1250
+		$this_month = false,
1251
+		$today = false
1252
+	) {
1253
+		if ($this_month) {
1254
+			$this->request->setRequestParam('status', 'month');
1255
+		}
1256
+		if ($today) {
1257
+			$this->request->setRequestParam('status', 'today');
1258
+		}
1259
+		$query_params = $this->_get_registration_query_parameters([], $per_page, $count);
1260
+		/**
1261
+		 * Override the default groupby added by EEM_Base so that sorts with multiple order bys work as expected
1262
+		 *
1263
+		 * @link https://events.codebasehq.com/projects/event-espresso/tickets/10093
1264
+		 * @see  https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1265
+		 *                      or if you have the development copy of EE you can view this at the path:
1266
+		 *                      /docs/G--Model-System/model-query-params.md
1267
+		 */
1268
+		$query_params['group_by'] = '';
1269
+
1270
+		return $count
1271
+			? $this->getRegistrationModel()->count($query_params)
1272
+			/** @type EE_Registration[] */
1273
+			: $this->getRegistrationModel()->get_all($query_params);
1274
+	}
1275
+
1276
+
1277
+	/**
1278
+	 * Retrieves the query parameters to be used by the Registration model for getting registrations.
1279
+	 * Note: this listens to values on the request for some of the query parameters.
1280
+	 *
1281
+	 * @param array $request
1282
+	 * @param int   $per_page
1283
+	 * @param bool  $count
1284
+	 * @return array
1285
+	 * @throws EE_Error
1286
+	 * @throws InvalidArgumentException
1287
+	 * @throws InvalidDataTypeException
1288
+	 * @throws InvalidInterfaceException
1289
+	 */
1290
+	protected function _get_registration_query_parameters(
1291
+		$request = [],
1292
+		$per_page = 10,
1293
+		$count = false
1294
+	) {
1295
+		/** @var EventEspresso\core\domain\services\admin\registrations\list_table\QueryBuilder $list_table_query_builder */
1296
+		$list_table_query_builder = $this->getLoader()->getNew(
1297
+			'EventEspresso\core\domain\services\admin\registrations\list_table\QueryBuilder',
1298
+			[null, null, $request]
1299
+		);
1300
+		return $list_table_query_builder->getQueryParams($per_page, $count);
1301
+	}
1302
+
1303
+
1304
+	public function get_registration_status_array()
1305
+	{
1306
+		return self::$_reg_status;
1307
+	}
1308
+
1309
+
1310
+
1311
+
1312
+	/***************************************        REGISTRATION DETAILS        ***************************************/
1313
+	/**
1314
+	 * generates HTML for the View Registration Details Admin page
1315
+	 *
1316
+	 * @return void
1317
+	 * @throws DomainException
1318
+	 * @throws EE_Error
1319
+	 * @throws InvalidArgumentException
1320
+	 * @throws InvalidDataTypeException
1321
+	 * @throws InvalidInterfaceException
1322
+	 * @throws EntityNotFoundException
1323
+	 * @throws ReflectionException
1324
+	 */
1325
+	protected function _registration_details()
1326
+	{
1327
+		$this->_template_args = [];
1328
+		$this->_set_registration_object();
1329
+		if (is_object($this->_registration)) {
1330
+			$transaction                                   = $this->_registration->transaction()
1331
+				? $this->_registration->transaction()
1332
+				: EE_Transaction::new_instance();
1333
+			$this->_session                                = $transaction->session_data();
1334
+			$event_id                                      = $this->_registration->event_ID();
1335
+			$this->_template_args['reg_nmbr']['value']     = $this->_registration->ID();
1336
+			$this->_template_args['reg_nmbr']['label']     = esc_html__('Registration Number', 'event_espresso');
1337
+			$this->_template_args['reg_datetime']['value'] = $this->_registration->get_i18n_datetime('REG_date');
1338
+			$this->_template_args['reg_datetime']['label'] = esc_html__('Date', 'event_espresso');
1339
+			$this->_template_args['grand_total']           = $transaction->total();
1340
+			$this->_template_args['currency_sign']         = EE_Registry::instance()->CFG->currency->sign;
1341
+			// link back to overview
1342
+			$this->_template_args['reg_overview_url']            = REG_ADMIN_URL;
1343
+			$this->_template_args['registration']                = $this->_registration;
1344
+			$this->_template_args['filtered_registrations_link'] = EE_Admin_Page::add_query_args_and_nonce(
1345
+				[
1346
+					'action'   => 'default',
1347
+					'event_id' => $event_id,
1348
+				],
1349
+				REG_ADMIN_URL
1350
+			);
1351
+			$this->_template_args['filtered_transactions_link']  = EE_Admin_Page::add_query_args_and_nonce(
1352
+				[
1353
+					'action' => 'default',
1354
+					'EVT_ID' => $event_id,
1355
+					'page'   => 'espresso_transactions',
1356
+				],
1357
+				admin_url('admin.php')
1358
+			);
1359
+			$this->_template_args['event_link']                  = EE_Admin_Page::add_query_args_and_nonce(
1360
+				[
1361
+					'page'   => 'espresso_events',
1362
+					'action' => 'edit',
1363
+					'post'   => $event_id,
1364
+				],
1365
+				admin_url('admin.php')
1366
+			);
1367
+			// next and previous links
1368
+			$next_reg                                      = $this->_registration->next(
1369
+				null,
1370
+				[],
1371
+				'REG_ID'
1372
+			);
1373
+			$this->_template_args['next_registration']     = $next_reg
1374
+				? $this->_next_link(
1375
+					EE_Admin_Page::add_query_args_and_nonce(
1376
+						[
1377
+							'action'  => 'view_registration',
1378
+							'_REG_ID' => $next_reg['REG_ID'],
1379
+						],
1380
+						REG_ADMIN_URL
1381
+					),
1382
+					'dashicons dashicons-arrow-right ee-icon-size-22'
1383
+				)
1384
+				: '';
1385
+			$previous_reg                                  = $this->_registration->previous(
1386
+				null,
1387
+				[],
1388
+				'REG_ID'
1389
+			);
1390
+			$this->_template_args['previous_registration'] = $previous_reg
1391
+				? $this->_previous_link(
1392
+					EE_Admin_Page::add_query_args_and_nonce(
1393
+						[
1394
+							'action'  => 'view_registration',
1395
+							'_REG_ID' => $previous_reg['REG_ID'],
1396
+						],
1397
+						REG_ADMIN_URL
1398
+					),
1399
+					'dashicons dashicons-arrow-left ee-icon-size-22'
1400
+				)
1401
+				: '';
1402
+			// grab header
1403
+			$template_path                             = REG_TEMPLATE_PATH . 'reg_admin_details_header.template.php';
1404
+			$this->_template_args['REG_ID']            = $this->_registration->ID();
1405
+			$this->_template_args['admin_page_header'] = EEH_Template::display_template(
1406
+				$template_path,
1407
+				$this->_template_args,
1408
+				true
1409
+			);
1410
+		} else {
1411
+			$this->_template_args['admin_page_header'] = '';
1412
+			$this->_display_espresso_notices();
1413
+		}
1414
+		// the details template wrapper
1415
+		$this->display_admin_page_with_sidebar();
1416
+	}
1417
+
1418
+
1419
+	/**
1420
+	 * @throws EE_Error
1421
+	 * @throws InvalidArgumentException
1422
+	 * @throws InvalidDataTypeException
1423
+	 * @throws InvalidInterfaceException
1424
+	 * @throws ReflectionException
1425
+	 * @since 4.10.2.p
1426
+	 */
1427
+	protected function _registration_details_metaboxes()
1428
+	{
1429
+		do_action('AHEE__Registrations_Admin_Page___registration_details_metabox__start', $this);
1430
+		$this->_set_registration_object();
1431
+		$attendee = $this->_registration instanceof EE_Registration ? $this->_registration->attendee() : null;
1432
+		add_meta_box(
1433
+			'edit-reg-status-mbox',
1434
+			esc_html__('Registration Status', 'event_espresso'),
1435
+			[$this, 'set_reg_status_buttons_metabox'],
1436
+			$this->_wp_page_slug,
1437
+			'normal',
1438
+			'high'
1439
+		);
1440
+		add_meta_box(
1441
+			'edit-reg-details-mbox',
1442
+			esc_html__('Registration Details', 'event_espresso'),
1443
+			[$this, '_reg_details_meta_box'],
1444
+			$this->_wp_page_slug,
1445
+			'normal',
1446
+			'high'
1447
+		);
1448
+		if (
1449
+			$attendee instanceof EE_Attendee
1450
+			&& EE_Registry::instance()->CAP->current_user_can(
1451
+				'ee_read_registration',
1452
+				'edit-reg-questions-mbox',
1453
+				$this->_registration->ID()
1454
+			)
1455
+		) {
1456
+			add_meta_box(
1457
+				'edit-reg-questions-mbox',
1458
+				esc_html__('Registration Form Answers', 'event_espresso'),
1459
+				[$this, '_reg_questions_meta_box'],
1460
+				$this->_wp_page_slug,
1461
+				'normal',
1462
+				'high'
1463
+			);
1464
+		}
1465
+		add_meta_box(
1466
+			'edit-reg-registrant-mbox',
1467
+			esc_html__('Contact Details', 'event_espresso'),
1468
+			[$this, '_reg_registrant_side_meta_box'],
1469
+			$this->_wp_page_slug,
1470
+			'side',
1471
+			'high'
1472
+		);
1473
+		if ($this->_registration->group_size() > 1) {
1474
+			add_meta_box(
1475
+				'edit-reg-attendees-mbox',
1476
+				esc_html__('Other Registrations in this Transaction', 'event_espresso'),
1477
+				[$this, '_reg_attendees_meta_box'],
1478
+				$this->_wp_page_slug,
1479
+				'normal',
1480
+				'high'
1481
+			);
1482
+		}
1483
+	}
1484
+
1485
+
1486
+	/**
1487
+	 * set_reg_status_buttons_metabox
1488
+	 *
1489
+	 * @return void
1490
+	 * @throws EE_Error
1491
+	 * @throws EntityNotFoundException
1492
+	 * @throws InvalidArgumentException
1493
+	 * @throws InvalidDataTypeException
1494
+	 * @throws InvalidInterfaceException
1495
+	 * @throws ReflectionException
1496
+	 */
1497
+	public function set_reg_status_buttons_metabox()
1498
+	{
1499
+		$this->_set_registration_object();
1500
+		$change_reg_status_form = $this->_generate_reg_status_change_form();
1501
+		$output                 = $change_reg_status_form->form_open(
1502
+			self::add_query_args_and_nonce(
1503
+				[
1504
+					'action' => 'change_reg_status',
1505
+				],
1506
+				REG_ADMIN_URL
1507
+			)
1508
+		);
1509
+		$output                 .= $change_reg_status_form->get_html();
1510
+		$output                 .= $change_reg_status_form->form_close();
1511
+		echo wp_kses($output, AllowedTags::getWithFormTags());
1512
+	}
1513
+
1514
+
1515
+	/**
1516
+	 * @return EE_Form_Section_Proper
1517
+	 * @throws EE_Error
1518
+	 * @throws InvalidArgumentException
1519
+	 * @throws InvalidDataTypeException
1520
+	 * @throws InvalidInterfaceException
1521
+	 * @throws EntityNotFoundException
1522
+	 * @throws ReflectionException
1523
+	 */
1524
+	protected function _generate_reg_status_change_form()
1525
+	{
1526
+		$reg_status_change_form_array = [
1527
+			'name'            => 'reg_status_change_form',
1528
+			'html_id'         => 'reg-status-change-form',
1529
+			'layout_strategy' => new EE_Admin_Two_Column_Layout(),
1530
+			'subsections'     => [
1531
+				'return'         => new EE_Hidden_Input(
1532
+					[
1533
+						'name'    => 'return',
1534
+						'default' => 'view_registration',
1535
+					]
1536
+				),
1537
+				'REG_ID'         => new EE_Hidden_Input(
1538
+					[
1539
+						'name'    => 'REG_ID',
1540
+						'default' => $this->_registration->ID(),
1541
+					]
1542
+				),
1543
+				'current_status' => new EE_Form_Section_HTML(
1544
+					EEH_HTML::table(
1545
+						EEH_HTML::tr(
1546
+							EEH_HTML::th(
1547
+								EEH_HTML::label(
1548
+									EEH_HTML::strong(
1549
+										esc_html__('Current Registration Status', 'event_espresso')
1550
+									)
1551
+								)
1552
+							)
1553
+							. EEH_HTML::td(
1554
+								EEH_HTML::strong(
1555
+									$this->_registration->pretty_status(),
1556
+									'',
1557
+									'status-' . $this->_registration->status_ID(),
1558
+									'line-height: 1em; font-size: 1.5em; font-weight: bold;'
1559
+								)
1560
+							)
1561
+						)
1562
+					)
1563
+				),
1564
+			],
1565
+		];
1566
+		if (
1567
+			EE_Registry::instance()->CAP->current_user_can(
1568
+				'ee_edit_registration',
1569
+				'toggle_registration_status',
1570
+				$this->_registration->ID()
1571
+			)
1572
+		) {
1573
+			$reg_status_change_form_array['subsections']['reg_status']         = new EE_Select_Input(
1574
+				$this->_get_reg_statuses(),
1575
+				[
1576
+					'html_label_text' => esc_html__('Change Registration Status to', 'event_espresso'),
1577
+					'default'         => $this->_registration->status_ID(),
1578
+				]
1579
+			);
1580
+			$reg_status_change_form_array['subsections']['send_notifications'] = new EE_Yes_No_Input(
1581
+				[
1582
+					'html_label_text' => esc_html__('Send Related Messages', 'event_espresso'),
1583
+					'default'         => false,
1584
+					'html_help_text'  => esc_html__(
1585
+						'If set to "Yes", then the related messages will be sent to the registrant.',
1586
+						'event_espresso'
1587
+					),
1588
+				]
1589
+			);
1590
+			$reg_status_change_form_array['subsections']['submit']             = new EE_Submit_Input(
1591
+				[
1592
+					'html_class'      => 'button-primary',
1593
+					'html_label_text' => '&nbsp;',
1594
+					'default'         => esc_html__('Update Registration Status', 'event_espresso'),
1595
+				]
1596
+			);
1597
+		}
1598
+		return new EE_Form_Section_Proper($reg_status_change_form_array);
1599
+	}
1600
+
1601
+
1602
+	/**
1603
+	 * Returns an array of all the buttons for the various statuses and switch status actions
1604
+	 *
1605
+	 * @return array
1606
+	 * @throws EE_Error
1607
+	 * @throws InvalidArgumentException
1608
+	 * @throws InvalidDataTypeException
1609
+	 * @throws InvalidInterfaceException
1610
+	 * @throws EntityNotFoundException
1611
+	 */
1612
+	protected function _get_reg_statuses()
1613
+	{
1614
+		$reg_status_array = $this->getRegistrationModel()->reg_status_array();
1615
+		unset($reg_status_array[ EEM_Registration::status_id_incomplete ]);
1616
+		// get current reg status
1617
+		$current_status = $this->_registration->status_ID();
1618
+		// is registration for free event? This will determine whether to display the pending payment option
1619
+		if (
1620
+			$current_status !== EEM_Registration::status_id_pending_payment
1621
+			&& EEH_Money::compare_floats($this->_registration->ticket()->price(), 0.00)
1622
+		) {
1623
+			unset($reg_status_array[ EEM_Registration::status_id_pending_payment ]);
1624
+		}
1625
+		return $this->getStatusModel()->localized_status($reg_status_array, false, 'sentence');
1626
+	}
1627
+
1628
+
1629
+	/**
1630
+	 * This method is used when using _REG_ID from request which may or may not be an array of reg_ids.
1631
+	 *
1632
+	 * @param bool $status REG status given for changing registrations to.
1633
+	 * @param bool $notify Whether to send messages notifications or not.
1634
+	 * @return array (array with reg_id(s) updated and whether update was successful.
1635
+	 * @throws DomainException
1636
+	 * @throws EE_Error
1637
+	 * @throws EntityNotFoundException
1638
+	 * @throws InvalidArgumentException
1639
+	 * @throws InvalidDataTypeException
1640
+	 * @throws InvalidInterfaceException
1641
+	 * @throws ReflectionException
1642
+	 * @throws RuntimeException
1643
+	 */
1644
+	protected function _set_registration_status_from_request($status = false, $notify = false)
1645
+	{
1646
+		$REG_IDs = $this->request->requestParamIsSet('reg_status_change_form')
1647
+			? $this->request->getRequestParam('reg_status_change_form[REG_ID]', [], 'int', true)
1648
+			: $this->request->getRequestParam('_REG_ID', [], 'int', true);
1649
+
1650
+		// sanitize $REG_IDs
1651
+		$REG_IDs = array_map('absint', $REG_IDs);
1652
+		// and remove empty entries
1653
+		$REG_IDs = array_filter($REG_IDs);
1654
+
1655
+		$result = $this->_set_registration_status($REG_IDs, $status, $notify);
1656
+
1657
+		/**
1658
+		 * Set and filter $_req_data['_REG_ID'] for any potential future messages notifications.
1659
+		 * Currently this value is used downstream by the _process_resend_registration method.
1660
+		 *
1661
+		 * @param int|array                $registration_ids The registration ids that have had their status changed successfully.
1662
+		 * @param bool                     $status           The status registrations were changed to.
1663
+		 * @param bool                     $success          If the status was changed successfully for all registrations.
1664
+		 * @param Registrations_Admin_Page $admin_page_object
1665
+		 */
1666
+		$REG_ID = apply_filters(
1667
+			'FHEE__Registrations_Admin_Page___set_registration_status_from_request__REG_IDs',
1668
+			$result['REG_ID'],
1669
+			$status,
1670
+			$result['success'],
1671
+			$this
1672
+		);
1673
+		$this->request->setRequestParam('_REG_ID', $REG_ID);
1674
+
1675
+		// notify?
1676
+		if (
1677
+			$notify
1678
+			&& $result['success']
1679
+			&& ! empty($REG_ID)
1680
+			&& EE_Registry::instance()->CAP->current_user_can(
1681
+				'ee_send_message',
1682
+				'espresso_registrations_resend_registration'
1683
+			)
1684
+		) {
1685
+			$this->_process_resend_registration();
1686
+		}
1687
+		return $result;
1688
+	}
1689
+
1690
+
1691
+	/**
1692
+	 * Set the registration status for the given reg_id (which may or may not be an array, it gets typecast to an
1693
+	 * array). Note, this method does NOT take care of possible notifications.  That is required by calling code.
1694
+	 *
1695
+	 * @param array  $REG_IDs
1696
+	 * @param string $status
1697
+	 * @param bool   $notify Used to indicate whether notification was requested or not.  This determines the context
1698
+	 *                       slug sent with setting the registration status.
1699
+	 * @return array (an array with 'success' key representing whether status change was successful, and 'REG_ID' as
1700
+	 * @throws EE_Error
1701
+	 * @throws InvalidArgumentException
1702
+	 * @throws InvalidDataTypeException
1703
+	 * @throws InvalidInterfaceException
1704
+	 * @throws ReflectionException
1705
+	 * @throws RuntimeException
1706
+	 * @throws EntityNotFoundException
1707
+	 * @throws DomainException
1708
+	 */
1709
+	protected function _set_registration_status($REG_IDs = [], $status = '', $notify = false)
1710
+	{
1711
+		$success = false;
1712
+		// typecast $REG_IDs
1713
+		$REG_IDs = (array) $REG_IDs;
1714
+		if (! empty($REG_IDs)) {
1715
+			$success = true;
1716
+			// set default status if none is passed
1717
+			$status         = $status ?: EEM_Registration::status_id_pending_payment;
1718
+			$status_context = $notify
1719
+				? Domain::CONTEXT_REGISTRATION_STATUS_CHANGE_REGISTRATION_ADMIN_NOTIFY
1720
+				: Domain::CONTEXT_REGISTRATION_STATUS_CHANGE_REGISTRATION_ADMIN;
1721
+			// loop through REG_ID's and change status
1722
+			foreach ($REG_IDs as $REG_ID) {
1723
+				$registration = $this->getRegistrationModel()->get_one_by_ID($REG_ID);
1724
+				if ($registration instanceof EE_Registration) {
1725
+					$registration->set_status(
1726
+						$status,
1727
+						false,
1728
+						new Context(
1729
+							$status_context,
1730
+							esc_html__(
1731
+								'Manually triggered status change on a Registration Admin Page route.',
1732
+								'event_espresso'
1733
+							)
1734
+						)
1735
+					);
1736
+					$result = $registration->save();
1737
+					// verifying explicit fails because update *may* just return 0 for 0 rows affected
1738
+					$success = $result !== false ? $success : false;
1739
+				}
1740
+			}
1741
+		}
1742
+
1743
+		// return $success and processed registrations
1744
+		return ['REG_ID' => $REG_IDs, 'success' => $success];
1745
+	}
1746
+
1747
+
1748
+	/**
1749
+	 * Common logic for setting up success message and redirecting to appropriate route
1750
+	 *
1751
+	 * @param string $STS_ID status id for the registration changed to
1752
+	 * @param bool   $notify indicates whether the _set_registration_status_from_request does notifications or not.
1753
+	 * @return void
1754
+	 * @throws DomainException
1755
+	 * @throws EE_Error
1756
+	 * @throws EntityNotFoundException
1757
+	 * @throws InvalidArgumentException
1758
+	 * @throws InvalidDataTypeException
1759
+	 * @throws InvalidInterfaceException
1760
+	 * @throws ReflectionException
1761
+	 * @throws RuntimeException
1762
+	 */
1763
+	protected function _reg_status_change_return($STS_ID, $notify = false)
1764
+	{
1765
+		$result  = ! empty($STS_ID) ? $this->_set_registration_status_from_request($STS_ID, $notify)
1766
+			: ['success' => false];
1767
+		$success = isset($result['success']) && $result['success'];
1768
+		// setup success message
1769
+		if ($success) {
1770
+			if (is_array($result['REG_ID']) && count($result['REG_ID']) === 1) {
1771
+				$msg = sprintf(
1772
+					esc_html__('Registration status has been set to %s', 'event_espresso'),
1773
+					EEH_Template::pretty_status($STS_ID, false, 'lower')
1774
+				);
1775
+			} else {
1776
+				$msg = sprintf(
1777
+					esc_html__('Registrations have been set to %s.', 'event_espresso'),
1778
+					EEH_Template::pretty_status($STS_ID, false, 'lower')
1779
+				);
1780
+			}
1781
+			EE_Error::add_success($msg);
1782
+		} else {
1783
+			EE_Error::add_error(
1784
+				esc_html__(
1785
+					'Something went wrong, and the status was not changed',
1786
+					'event_espresso'
1787
+				),
1788
+				__FILE__,
1789
+				__LINE__,
1790
+				__FUNCTION__
1791
+			);
1792
+		}
1793
+		$return = $this->request->getRequestParam('return');
1794
+		$route  = $return === 'view_registration'
1795
+			? ['action' => 'view_registration', '_REG_ID' => reset($result['REG_ID'])]
1796
+			: ['action' => 'default'];
1797
+		$route  = $this->mergeExistingRequestParamsWithRedirectArgs($route);
1798
+		$this->_redirect_after_action($success, '', '', $route, true);
1799
+	}
1800
+
1801
+
1802
+	/**
1803
+	 * incoming reg status change from reg details page.
1804
+	 *
1805
+	 * @return void
1806
+	 * @throws EE_Error
1807
+	 * @throws EntityNotFoundException
1808
+	 * @throws InvalidArgumentException
1809
+	 * @throws InvalidDataTypeException
1810
+	 * @throws InvalidInterfaceException
1811
+	 * @throws ReflectionException
1812
+	 * @throws RuntimeException
1813
+	 * @throws DomainException
1814
+	 */
1815
+	protected function _change_reg_status()
1816
+	{
1817
+		$this->request->setRequestParam('return', 'view_registration');
1818
+		// set notify based on whether the send notifications toggle is set or not
1819
+		$notify     = $this->request->getRequestParam('reg_status_change_form[send_notifications]', false, 'bool');
1820
+		$reg_status = $this->request->getRequestParam('reg_status_change_form[reg_status]', '');
1821
+		$this->request->setRequestParam('reg_status_change_form[reg_status]', $reg_status);
1822
+		switch ($reg_status) {
1823
+			case EEM_Registration::status_id_approved:
1824
+			case EEH_Template::pretty_status(EEM_Registration::status_id_approved, false, 'sentence'):
1825
+				$this->approve_registration($notify);
1826
+				break;
1827
+			case EEM_Registration::status_id_pending_payment:
1828
+			case EEH_Template::pretty_status(EEM_Registration::status_id_pending_payment, false, 'sentence'):
1829
+				$this->pending_registration($notify);
1830
+				break;
1831
+			case EEM_Registration::status_id_not_approved:
1832
+			case EEH_Template::pretty_status(EEM_Registration::status_id_not_approved, false, 'sentence'):
1833
+				$this->not_approve_registration($notify);
1834
+				break;
1835
+			case EEM_Registration::status_id_declined:
1836
+			case EEH_Template::pretty_status(EEM_Registration::status_id_declined, false, 'sentence'):
1837
+				$this->decline_registration($notify);
1838
+				break;
1839
+			case EEM_Registration::status_id_cancelled:
1840
+			case EEH_Template::pretty_status(EEM_Registration::status_id_cancelled, false, 'sentence'):
1841
+				$this->cancel_registration($notify);
1842
+				break;
1843
+			case EEM_Registration::status_id_wait_list:
1844
+			case EEH_Template::pretty_status(EEM_Registration::status_id_wait_list, false, 'sentence'):
1845
+				$this->wait_list_registration($notify);
1846
+				break;
1847
+			case EEM_Registration::status_id_incomplete:
1848
+			default:
1849
+				$this->request->unSetRequestParam('return');
1850
+				$this->_reg_status_change_return('');
1851
+				break;
1852
+		}
1853
+	}
1854
+
1855
+
1856
+	/**
1857
+	 * Callback for bulk action routes.
1858
+	 * Note: although we could just register the singular route callbacks for each bulk action route as well, this
1859
+	 * method was chosen so there is one central place all the registration status bulk actions are going through.
1860
+	 * Potentially, this provides an easier place to locate logic that is specific to these bulk actions (as opposed to
1861
+	 * when an action is happening on just a single registration).
1862
+	 *
1863
+	 * @param      $action
1864
+	 * @param bool $notify
1865
+	 */
1866
+	protected function bulk_action_on_registrations($action, $notify = false)
1867
+	{
1868
+		do_action(
1869
+			'AHEE__Registrations_Admin_Page__bulk_action_on_registrations__before_execution',
1870
+			$this,
1871
+			$action,
1872
+			$notify
1873
+		);
1874
+		$method = $action . '_registration';
1875
+		if (method_exists($this, $method)) {
1876
+			$this->$method($notify);
1877
+		}
1878
+	}
1879
+
1880
+
1881
+	/**
1882
+	 * approve_registration
1883
+	 *
1884
+	 * @param bool $notify whether or not to notify the registrant about their approval.
1885
+	 * @return void
1886
+	 * @throws EE_Error
1887
+	 * @throws EntityNotFoundException
1888
+	 * @throws InvalidArgumentException
1889
+	 * @throws InvalidDataTypeException
1890
+	 * @throws InvalidInterfaceException
1891
+	 * @throws ReflectionException
1892
+	 * @throws RuntimeException
1893
+	 * @throws DomainException
1894
+	 */
1895
+	protected function approve_registration($notify = false)
1896
+	{
1897
+		$this->_reg_status_change_return(EEM_Registration::status_id_approved, $notify);
1898
+	}
1899
+
1900
+
1901
+	/**
1902
+	 * decline_registration
1903
+	 *
1904
+	 * @param bool $notify whether or not to notify the registrant about their status change.
1905
+	 * @return void
1906
+	 * @throws EE_Error
1907
+	 * @throws EntityNotFoundException
1908
+	 * @throws InvalidArgumentException
1909
+	 * @throws InvalidDataTypeException
1910
+	 * @throws InvalidInterfaceException
1911
+	 * @throws ReflectionException
1912
+	 * @throws RuntimeException
1913
+	 * @throws DomainException
1914
+	 */
1915
+	protected function decline_registration($notify = false)
1916
+	{
1917
+		$this->_reg_status_change_return(EEM_Registration::status_id_declined, $notify);
1918
+	}
1919
+
1920
+
1921
+	/**
1922
+	 * cancel_registration
1923
+	 *
1924
+	 * @param bool $notify whether or not to notify the registrant about their status change.
1925
+	 * @return void
1926
+	 * @throws EE_Error
1927
+	 * @throws EntityNotFoundException
1928
+	 * @throws InvalidArgumentException
1929
+	 * @throws InvalidDataTypeException
1930
+	 * @throws InvalidInterfaceException
1931
+	 * @throws ReflectionException
1932
+	 * @throws RuntimeException
1933
+	 * @throws DomainException
1934
+	 */
1935
+	protected function cancel_registration($notify = false)
1936
+	{
1937
+		$this->_reg_status_change_return(EEM_Registration::status_id_cancelled, $notify);
1938
+	}
1939
+
1940
+
1941
+	/**
1942
+	 * not_approve_registration
1943
+	 *
1944
+	 * @param bool $notify whether or not to notify the registrant about their status change.
1945
+	 * @return void
1946
+	 * @throws EE_Error
1947
+	 * @throws EntityNotFoundException
1948
+	 * @throws InvalidArgumentException
1949
+	 * @throws InvalidDataTypeException
1950
+	 * @throws InvalidInterfaceException
1951
+	 * @throws ReflectionException
1952
+	 * @throws RuntimeException
1953
+	 * @throws DomainException
1954
+	 */
1955
+	protected function not_approve_registration($notify = false)
1956
+	{
1957
+		$this->_reg_status_change_return(EEM_Registration::status_id_not_approved, $notify);
1958
+	}
1959
+
1960
+
1961
+	/**
1962
+	 * decline_registration
1963
+	 *
1964
+	 * @param bool $notify whether or not to notify the registrant about their status change.
1965
+	 * @return void
1966
+	 * @throws EE_Error
1967
+	 * @throws EntityNotFoundException
1968
+	 * @throws InvalidArgumentException
1969
+	 * @throws InvalidDataTypeException
1970
+	 * @throws InvalidInterfaceException
1971
+	 * @throws ReflectionException
1972
+	 * @throws RuntimeException
1973
+	 * @throws DomainException
1974
+	 */
1975
+	protected function pending_registration($notify = false)
1976
+	{
1977
+		$this->_reg_status_change_return(EEM_Registration::status_id_pending_payment, $notify);
1978
+	}
1979
+
1980
+
1981
+	/**
1982
+	 * waitlist_registration
1983
+	 *
1984
+	 * @param bool $notify whether or not to notify the registrant about their status change.
1985
+	 * @return void
1986
+	 * @throws EE_Error
1987
+	 * @throws EntityNotFoundException
1988
+	 * @throws InvalidArgumentException
1989
+	 * @throws InvalidDataTypeException
1990
+	 * @throws InvalidInterfaceException
1991
+	 * @throws ReflectionException
1992
+	 * @throws RuntimeException
1993
+	 * @throws DomainException
1994
+	 */
1995
+	protected function wait_list_registration($notify = false)
1996
+	{
1997
+		$this->_reg_status_change_return(EEM_Registration::status_id_wait_list, $notify);
1998
+	}
1999
+
2000
+
2001
+	/**
2002
+	 * generates HTML for the Registration main meta box
2003
+	 *
2004
+	 * @return void
2005
+	 * @throws DomainException
2006
+	 * @throws EE_Error
2007
+	 * @throws InvalidArgumentException
2008
+	 * @throws InvalidDataTypeException
2009
+	 * @throws InvalidInterfaceException
2010
+	 * @throws ReflectionException
2011
+	 * @throws EntityNotFoundException
2012
+	 */
2013
+	public function _reg_details_meta_box()
2014
+	{
2015
+		EEH_Autoloader::register_line_item_display_autoloaders();
2016
+		EEH_Autoloader::register_line_item_filter_autoloaders();
2017
+		EE_Registry::instance()->load_helper('Line_Item');
2018
+		$transaction    = $this->_registration->transaction() ? $this->_registration->transaction()
2019
+			: EE_Transaction::new_instance();
2020
+		$this->_session = $transaction->session_data();
2021
+		$filters        = new EE_Line_Item_Filter_Collection();
2022
+		$filters->add(new EE_Single_Registration_Line_Item_Filter($this->_registration));
2023
+		$filters->add(new EE_Non_Zero_Line_Item_Filter());
2024
+		$line_item_filter_processor              = new EE_Line_Item_Filter_Processor(
2025
+			$filters,
2026
+			$transaction->total_line_item()
2027
+		);
2028
+		$filtered_line_item_tree                 = $line_item_filter_processor->process();
2029
+		$line_item_display                       = new EE_Line_Item_Display(
2030
+			'reg_admin_table',
2031
+			'EE_Admin_Table_Registration_Line_Item_Display_Strategy'
2032
+		);
2033
+		$this->_template_args['line_item_table'] = $line_item_display->display_line_item(
2034
+			$filtered_line_item_tree,
2035
+			['EE_Registration' => $this->_registration]
2036
+		);
2037
+		$attendee                                = $this->_registration->attendee();
2038
+		if (
2039
+			EE_Registry::instance()->CAP->current_user_can(
2040
+				'ee_read_transaction',
2041
+				'espresso_transactions_view_transaction'
2042
+			)
2043
+		) {
2044
+			$this->_template_args['view_transaction_button'] = EEH_Template::get_button_or_link(
2045
+				EE_Admin_Page::add_query_args_and_nonce(
2046
+					[
2047
+						'action' => 'view_transaction',
2048
+						'TXN_ID' => $transaction->ID(),
2049
+					],
2050
+					TXN_ADMIN_URL
2051
+				),
2052
+				esc_html__(' View Transaction', 'event_espresso'),
2053
+				'button secondary-button right',
2054
+				'dashicons dashicons-cart'
2055
+			);
2056
+		} else {
2057
+			$this->_template_args['view_transaction_button'] = '';
2058
+		}
2059
+		if (
2060
+			$attendee instanceof EE_Attendee
2061
+			&& EE_Registry::instance()->CAP->current_user_can(
2062
+				'ee_send_message',
2063
+				'espresso_registrations_resend_registration'
2064
+			)
2065
+		) {
2066
+			$this->_template_args['resend_registration_button'] = EEH_Template::get_button_or_link(
2067
+				EE_Admin_Page::add_query_args_and_nonce(
2068
+					[
2069
+						'action'      => 'resend_registration',
2070
+						'_REG_ID'     => $this->_registration->ID(),
2071
+						'redirect_to' => 'view_registration',
2072
+					],
2073
+					REG_ADMIN_URL
2074
+				),
2075
+				esc_html__(' Resend Registration', 'event_espresso'),
2076
+				'button secondary-button right',
2077
+				'dashicons dashicons-email-alt'
2078
+			);
2079
+		} else {
2080
+			$this->_template_args['resend_registration_button'] = '';
2081
+		}
2082
+		$this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
2083
+		$payment                               = $transaction->get_first_related('Payment');
2084
+		$payment                               = ! $payment instanceof EE_Payment
2085
+			? EE_Payment::new_instance()
2086
+			: $payment;
2087
+		$payment_method                        = $payment->get_first_related('Payment_Method');
2088
+		$payment_method                        = ! $payment_method instanceof EE_Payment_Method
2089
+			? EE_Payment_Method::new_instance()
2090
+			: $payment_method;
2091
+		$reg_details                           = [
2092
+			'payment_method'       => $payment_method->name(),
2093
+			'response_msg'         => $payment->gateway_response(),
2094
+			'registration_id'      => $this->_registration->get('REG_code'),
2095
+			'registration_session' => $this->_registration->session_ID(),
2096
+			'ip_address'           => isset($this->_session['ip_address']) ? $this->_session['ip_address'] : '',
2097
+			'user_agent'           => isset($this->_session['user_agent']) ? $this->_session['user_agent'] : '',
2098
+		];
2099
+		if (isset($reg_details['registration_id'])) {
2100
+			$this->_template_args['reg_details']['registration_id']['value'] = $reg_details['registration_id'];
2101
+			$this->_template_args['reg_details']['registration_id']['label'] = esc_html__(
2102
+				'Registration ID',
2103
+				'event_espresso'
2104
+			);
2105
+			$this->_template_args['reg_details']['registration_id']['class'] = 'regular-text';
2106
+		}
2107
+		if (isset($reg_details['payment_method'])) {
2108
+			$this->_template_args['reg_details']['payment_method']['value'] = $reg_details['payment_method'];
2109
+			$this->_template_args['reg_details']['payment_method']['label'] = esc_html__(
2110
+				'Most Recent Payment Method',
2111
+				'event_espresso'
2112
+			);
2113
+			$this->_template_args['reg_details']['payment_method']['class'] = 'regular-text';
2114
+			$this->_template_args['reg_details']['response_msg']['value']   = $reg_details['response_msg'];
2115
+			$this->_template_args['reg_details']['response_msg']['label']   = esc_html__(
2116
+				'Payment method response',
2117
+				'event_espresso'
2118
+			);
2119
+			$this->_template_args['reg_details']['response_msg']['class']   = 'regular-text';
2120
+		}
2121
+		$this->_template_args['reg_details']['registration_session']['value'] = $reg_details['registration_session'];
2122
+		$this->_template_args['reg_details']['registration_session']['label'] = esc_html__(
2123
+			'Registration Session',
2124
+			'event_espresso'
2125
+		);
2126
+		$this->_template_args['reg_details']['registration_session']['class'] = 'regular-text';
2127
+		$this->_template_args['reg_details']['ip_address']['value']           = $reg_details['ip_address'];
2128
+		$this->_template_args['reg_details']['ip_address']['label']           = esc_html__(
2129
+			'Registration placed from IP',
2130
+			'event_espresso'
2131
+		);
2132
+		$this->_template_args['reg_details']['ip_address']['class']           = 'regular-text';
2133
+		$this->_template_args['reg_details']['user_agent']['value']           = $reg_details['user_agent'];
2134
+		$this->_template_args['reg_details']['user_agent']['label']           = esc_html__(
2135
+			'Registrant User Agent',
2136
+			'event_espresso'
2137
+		);
2138
+		$this->_template_args['reg_details']['user_agent']['class']           = 'large-text';
2139
+		$this->_template_args['event_link']                                   = EE_Admin_Page::add_query_args_and_nonce(
2140
+			[
2141
+				'action'   => 'default',
2142
+				'event_id' => $this->_registration->event_ID(),
2143
+			],
2144
+			REG_ADMIN_URL
2145
+		);
2146
+		$this->_template_args['REG_ID']                                       = $this->_registration->ID();
2147
+		$this->_template_args['event_id']                                     = $this->_registration->event_ID();
2148
+		$template_path                                                        =
2149
+			REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_details.template.php';
2150
+		EEH_Template::display_template($template_path, $this->_template_args); // already escaped
2151
+	}
2152
+
2153
+
2154
+	/**
2155
+	 * generates HTML for the Registration Questions meta box.
2156
+	 * If pre-4.8.32.rc.000 hooks are used, uses old methods (with its filters),
2157
+	 * otherwise uses new forms system
2158
+	 *
2159
+	 * @return void
2160
+	 * @throws DomainException
2161
+	 * @throws EE_Error
2162
+	 * @throws InvalidArgumentException
2163
+	 * @throws InvalidDataTypeException
2164
+	 * @throws InvalidInterfaceException
2165
+	 * @throws ReflectionException
2166
+	 */
2167
+	public function _reg_questions_meta_box()
2168
+	{
2169
+		// allow someone to override this method entirely
2170
+		if (
2171
+			apply_filters(
2172
+				'FHEE__Registrations_Admin_Page___reg_questions_meta_box__do_default',
2173
+				true,
2174
+				$this,
2175
+				$this->_registration
2176
+			)
2177
+		) {
2178
+			$form                                              = $this->_get_reg_custom_questions_form(
2179
+				$this->_registration->ID()
2180
+			);
2181
+			$this->_template_args['att_questions']             = count($form->subforms()) > 0
2182
+				? $form->get_html_and_js()
2183
+				: '';
2184
+			$this->_template_args['reg_questions_form_action'] = 'edit_registration';
2185
+			$this->_template_args['REG_ID']                    = $this->_registration->ID();
2186
+			$template_path                                     =
2187
+				REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_questions.template.php';
2188
+			EEH_Template::display_template($template_path, $this->_template_args);
2189
+		}
2190
+	}
2191
+
2192
+
2193
+	/**
2194
+	 * form_before_question_group
2195
+	 *
2196
+	 * @param string $output
2197
+	 * @return        string
2198
+	 * @deprecated    as of 4.8.32.rc.000
2199
+	 */
2200
+	public function form_before_question_group($output)
2201
+	{
2202
+		EE_Error::doing_it_wrong(
2203
+			__CLASS__ . '::' . __FUNCTION__,
2204
+			esc_html__(
2205
+				'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2206
+				'event_espresso'
2207
+			),
2208
+			'4.8.32.rc.000'
2209
+		);
2210
+		return '
2211 2211
 	<table class="form-table ee-width-100">
2212 2212
 		<tbody>
2213 2213
 			';
2214
-    }
2215
-
2216
-
2217
-    /**
2218
-     * form_after_question_group
2219
-     *
2220
-     * @param string $output
2221
-     * @return        string
2222
-     * @deprecated    as of 4.8.32.rc.000
2223
-     */
2224
-    public function form_after_question_group($output)
2225
-    {
2226
-        EE_Error::doing_it_wrong(
2227
-            __CLASS__ . '::' . __FUNCTION__,
2228
-            esc_html__(
2229
-                'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2230
-                'event_espresso'
2231
-            ),
2232
-            '4.8.32.rc.000'
2233
-        );
2234
-        return '
2214
+	}
2215
+
2216
+
2217
+	/**
2218
+	 * form_after_question_group
2219
+	 *
2220
+	 * @param string $output
2221
+	 * @return        string
2222
+	 * @deprecated    as of 4.8.32.rc.000
2223
+	 */
2224
+	public function form_after_question_group($output)
2225
+	{
2226
+		EE_Error::doing_it_wrong(
2227
+			__CLASS__ . '::' . __FUNCTION__,
2228
+			esc_html__(
2229
+				'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2230
+				'event_espresso'
2231
+			),
2232
+			'4.8.32.rc.000'
2233
+		);
2234
+		return '
2235 2235
 			<tr class="hide-if-no-js">
2236 2236
 				<th> </th>
2237 2237
 				<td class="reg-admin-edit-attendee-question-td">
2238 2238
 					<a class="reg-admin-edit-attendee-question-lnk" href="#" title="'
2239
-               . esc_attr__('click to edit question', 'event_espresso')
2240
-               . '">
2239
+			   . esc_attr__('click to edit question', 'event_espresso')
2240
+			   . '">
2241 2241
 						<span class="reg-admin-edit-question-group-spn lt-grey-txt">'
2242
-               . esc_html__('edit the above question group', 'event_espresso')
2243
-               . '</span>
2242
+			   . esc_html__('edit the above question group', 'event_espresso')
2243
+			   . '</span>
2244 2244
 						<div class="dashicons dashicons-edit"></div>
2245 2245
 					</a>
2246 2246
 				</td>
@@ -2248,641 +2248,641 @@  discard block
 block discarded – undo
2248 2248
 		</tbody>
2249 2249
 	</table>
2250 2250
 ';
2251
-    }
2252
-
2253
-
2254
-    /**
2255
-     * form_form_field_label_wrap
2256
-     *
2257
-     * @param string $label
2258
-     * @return        string
2259
-     * @deprecated    as of 4.8.32.rc.000
2260
-     */
2261
-    public function form_form_field_label_wrap($label)
2262
-    {
2263
-        EE_Error::doing_it_wrong(
2264
-            __CLASS__ . '::' . __FUNCTION__,
2265
-            esc_html__(
2266
-                'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2267
-                'event_espresso'
2268
-            ),
2269
-            '4.8.32.rc.000'
2270
-        );
2271
-        return '
2251
+	}
2252
+
2253
+
2254
+	/**
2255
+	 * form_form_field_label_wrap
2256
+	 *
2257
+	 * @param string $label
2258
+	 * @return        string
2259
+	 * @deprecated    as of 4.8.32.rc.000
2260
+	 */
2261
+	public function form_form_field_label_wrap($label)
2262
+	{
2263
+		EE_Error::doing_it_wrong(
2264
+			__CLASS__ . '::' . __FUNCTION__,
2265
+			esc_html__(
2266
+				'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2267
+				'event_espresso'
2268
+			),
2269
+			'4.8.32.rc.000'
2270
+		);
2271
+		return '
2272 2272
 			<tr>
2273 2273
 				<th>
2274 2274
 					' . $label . '
2275 2275
 				</th>';
2276
-    }
2277
-
2278
-
2279
-    /**
2280
-     * form_form_field_input__wrap
2281
-     *
2282
-     * @param string $input
2283
-     * @return        string
2284
-     * @deprecated    as of 4.8.32.rc.000
2285
-     */
2286
-    public function form_form_field_input__wrap($input)
2287
-    {
2288
-        EE_Error::doing_it_wrong(
2289
-            __CLASS__ . '::' . __FUNCTION__,
2290
-            esc_html__(
2291
-                'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2292
-                'event_espresso'
2293
-            ),
2294
-            '4.8.32.rc.000'
2295
-        );
2296
-        return '
2276
+	}
2277
+
2278
+
2279
+	/**
2280
+	 * form_form_field_input__wrap
2281
+	 *
2282
+	 * @param string $input
2283
+	 * @return        string
2284
+	 * @deprecated    as of 4.8.32.rc.000
2285
+	 */
2286
+	public function form_form_field_input__wrap($input)
2287
+	{
2288
+		EE_Error::doing_it_wrong(
2289
+			__CLASS__ . '::' . __FUNCTION__,
2290
+			esc_html__(
2291
+				'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2292
+				'event_espresso'
2293
+			),
2294
+			'4.8.32.rc.000'
2295
+		);
2296
+		return '
2297 2297
 				<td class="reg-admin-attendee-questions-input-td disabled-input">
2298 2298
 					' . $input . '
2299 2299
 				</td>
2300 2300
 			</tr>';
2301
-    }
2302
-
2303
-
2304
-    /**
2305
-     * Updates the registration's custom questions according to the form info, if the form is submitted.
2306
-     * If it's not a post, the "view_registrations" route will be called next on the SAME request
2307
-     * to display the page
2308
-     *
2309
-     * @return void
2310
-     * @throws EE_Error
2311
-     * @throws InvalidArgumentException
2312
-     * @throws InvalidDataTypeException
2313
-     * @throws InvalidInterfaceException
2314
-     * @throws ReflectionException
2315
-     */
2316
-    protected function _update_attendee_registration_form()
2317
-    {
2318
-        do_action('AHEE__Registrations_Admin_Page___update_attendee_registration_form__start', $this);
2319
-        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
2320
-            $REG_ID  = $this->request->getRequestParam('_REG_ID', 0, 'int');
2321
-            $success = $this->_save_reg_custom_questions_form($REG_ID);
2322
-            if ($success) {
2323
-                $what  = esc_html__('Registration Form', 'event_espresso');
2324
-                $route = $REG_ID
2325
-                    ? ['action' => 'view_registration', '_REG_ID' => $REG_ID]
2326
-                    : ['action' => 'default'];
2327
-                $this->_redirect_after_action(true, $what, esc_html__('updated', 'event_espresso'), $route);
2328
-            }
2329
-        }
2330
-    }
2331
-
2332
-
2333
-    /**
2334
-     * Gets the form for saving registrations custom questions (if done
2335
-     * previously retrieves the cached form object, which may have validation errors in it)
2336
-     *
2337
-     * @param int $REG_ID
2338
-     * @return EE_Registration_Custom_Questions_Form
2339
-     * @throws EE_Error
2340
-     * @throws InvalidArgumentException
2341
-     * @throws InvalidDataTypeException
2342
-     * @throws InvalidInterfaceException
2343
-     * @throws ReflectionException
2344
-     */
2345
-    protected function _get_reg_custom_questions_form($REG_ID)
2346
-    {
2347
-        if (! $this->_reg_custom_questions_form) {
2348
-            require_once(REG_ADMIN . 'form_sections/EE_Registration_Custom_Questions_Form.form.php');
2349
-            $this->_reg_custom_questions_form = new EE_Registration_Custom_Questions_Form(
2350
-                $this->getRegistrationModel()->get_one_by_ID($REG_ID)
2351
-            );
2352
-            $this->_reg_custom_questions_form->_construct_finalize(null, null);
2353
-        }
2354
-        return $this->_reg_custom_questions_form;
2355
-    }
2356
-
2357
-
2358
-    /**
2359
-     * Saves
2360
-     *
2361
-     * @param bool $REG_ID
2362
-     * @return bool
2363
-     * @throws EE_Error
2364
-     * @throws InvalidArgumentException
2365
-     * @throws InvalidDataTypeException
2366
-     * @throws InvalidInterfaceException
2367
-     * @throws ReflectionException
2368
-     */
2369
-    private function _save_reg_custom_questions_form($REG_ID = 0)
2370
-    {
2371
-        if (! $REG_ID) {
2372
-            EE_Error::add_error(
2373
-                esc_html__(
2374
-                    'An error occurred. No registration ID was received.',
2375
-                    'event_espresso'
2376
-                ),
2377
-                __FILE__,
2378
-                __FUNCTION__,
2379
-                __LINE__
2380
-            );
2381
-        }
2382
-        $form = $this->_get_reg_custom_questions_form($REG_ID);
2383
-        $form->receive_form_submission($this->request->requestParams());
2384
-        $success = false;
2385
-        if ($form->is_valid()) {
2386
-            foreach ($form->subforms() as $question_group_form) {
2387
-                foreach ($question_group_form->inputs() as $question_id => $input) {
2388
-                    $where_conditions    = [
2389
-                        'QST_ID' => $question_id,
2390
-                        'REG_ID' => $REG_ID,
2391
-                    ];
2392
-                    $possibly_new_values = [
2393
-                        'ANS_value' => $input->normalized_value(),
2394
-                    ];
2395
-                    $answer              = EEM_Answer::instance()->get_one([$where_conditions]);
2396
-                    if ($answer instanceof EE_Answer) {
2397
-                        $success = $answer->save($possibly_new_values);
2398
-                    } else {
2399
-                        // insert it then
2400
-                        $cols_n_vals = array_merge($where_conditions, $possibly_new_values);
2401
-                        $answer      = EE_Answer::new_instance($cols_n_vals);
2402
-                        $success     = $answer->save();
2403
-                    }
2404
-                }
2405
-            }
2406
-        } else {
2407
-            EE_Error::add_error($form->get_validation_error_string(), __FILE__, __FUNCTION__, __LINE__);
2408
-        }
2409
-        return $success;
2410
-    }
2411
-
2412
-
2413
-    /**
2414
-     * generates HTML for the Registration main meta box
2415
-     *
2416
-     * @return void
2417
-     * @throws DomainException
2418
-     * @throws EE_Error
2419
-     * @throws InvalidArgumentException
2420
-     * @throws InvalidDataTypeException
2421
-     * @throws InvalidInterfaceException
2422
-     * @throws ReflectionException
2423
-     */
2424
-    public function _reg_attendees_meta_box()
2425
-    {
2426
-        $REG = $this->getRegistrationModel();
2427
-        // get all other registrations on this transaction, and cache
2428
-        // the attendees for them so we don't have to run another query using force_join
2429
-        $registrations                           = $REG->get_all(
2430
-            [
2431
-                [
2432
-                    'TXN_ID' => $this->_registration->transaction_ID(),
2433
-                    'REG_ID' => ['!=', $this->_registration->ID()],
2434
-                ],
2435
-                'force_join'               => ['Attendee'],
2436
-                'default_where_conditions' => 'other_models_only',
2437
-            ]
2438
-        );
2439
-        $this->_template_args['attendees']       = [];
2440
-        $this->_template_args['attendee_notice'] = '';
2441
-        if (
2442
-            empty($registrations)
2443
-            || (is_array($registrations)
2444
-                && ! EEH_Array::get_one_item_from_array($registrations))
2445
-        ) {
2446
-            EE_Error::add_error(
2447
-                esc_html__(
2448
-                    'There are no records attached to this registration. Something may have gone wrong with the registration',
2449
-                    'event_espresso'
2450
-                ),
2451
-                __FILE__,
2452
-                __FUNCTION__,
2453
-                __LINE__
2454
-            );
2455
-            $this->_template_args['attendee_notice'] = EE_Error::get_notices();
2456
-        } else {
2457
-            $att_nmbr = 1;
2458
-            foreach ($registrations as $registration) {
2459
-                /* @var $registration EE_Registration */
2460
-                $attendee                                                      = $registration->attendee()
2461
-                    ? $registration->attendee()
2462
-                    : $this->getAttendeeModel()->create_default_object();
2463
-                $this->_template_args['attendees'][ $att_nmbr ]['STS_ID']      = $registration->status_ID();
2464
-                $this->_template_args['attendees'][ $att_nmbr ]['fname']       = $attendee->fname();
2465
-                $this->_template_args['attendees'][ $att_nmbr ]['lname']       = $attendee->lname();
2466
-                $this->_template_args['attendees'][ $att_nmbr ]['email']       = $attendee->email();
2467
-                $this->_template_args['attendees'][ $att_nmbr ]['final_price'] = $registration->final_price();
2468
-                $this->_template_args['attendees'][ $att_nmbr ]['address']     = implode(
2469
-                    ', ',
2470
-                    $attendee->full_address_as_array()
2471
-                );
2472
-                $this->_template_args['attendees'][ $att_nmbr ]['att_link']    = self::add_query_args_and_nonce(
2473
-                    [
2474
-                        'action' => 'edit_attendee',
2475
-                        'post'   => $attendee->ID(),
2476
-                    ],
2477
-                    REG_ADMIN_URL
2478
-                );
2479
-                $this->_template_args['attendees'][ $att_nmbr ]['event_name']  =
2480
-                    $registration->event_obj() instanceof EE_Event
2481
-                        ? $registration->event_obj()->name()
2482
-                        : '';
2483
-                $att_nmbr++;
2484
-            }
2485
-            $this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
2486
-        }
2487
-        $template_path = REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_attendees.template.php';
2488
-        EEH_Template::display_template($template_path, $this->_template_args);
2489
-    }
2490
-
2491
-
2492
-    /**
2493
-     * generates HTML for the Edit Registration side meta box
2494
-     *
2495
-     * @return void
2496
-     * @throws DomainException
2497
-     * @throws EE_Error
2498
-     * @throws InvalidArgumentException
2499
-     * @throws InvalidDataTypeException
2500
-     * @throws InvalidInterfaceException
2501
-     * @throws ReflectionException
2502
-     */
2503
-    public function _reg_registrant_side_meta_box()
2504
-    {
2505
-        /*@var $attendee EE_Attendee */
2506
-        $att_check = $this->_registration->attendee();
2507
-        $attendee  = $att_check instanceof EE_Attendee
2508
-            ? $att_check
2509
-            : $this->getAttendeeModel()->create_default_object();
2510
-        // now let's determine if this is not the primary registration.  If it isn't then we set the
2511
-        // primary_registration object for reference BUT ONLY if the Attendee object loaded is not the same as the
2512
-        // primary registration object (that way we know if we need to show create button or not)
2513
-        if (! $this->_registration->is_primary_registrant()) {
2514
-            $primary_registration = $this->_registration->get_primary_registration();
2515
-            $primary_attendee     = $primary_registration instanceof EE_Registration ? $primary_registration->attendee()
2516
-                : null;
2517
-            if (! $primary_attendee instanceof EE_Attendee || $attendee->ID() !== $primary_attendee->ID()) {
2518
-                // in here?  This means the displayed registration is not the primary registrant but ALREADY HAS its own
2519
-                // custom attendee object so let's not worry about the primary reg.
2520
-                $primary_registration = null;
2521
-            }
2522
-        } else {
2523
-            $primary_registration = null;
2524
-        }
2525
-        $this->_template_args['ATT_ID']            = $attendee->ID();
2526
-        $this->_template_args['fname']             = $attendee->fname();
2527
-        $this->_template_args['lname']             = $attendee->lname();
2528
-        $this->_template_args['email']             = $attendee->email();
2529
-        $this->_template_args['phone']             = $attendee->phone();
2530
-        $this->_template_args['formatted_address'] = EEH_Address::format($attendee);
2531
-        // edit link
2532
-        $this->_template_args['att_edit_link']  = EE_Admin_Page::add_query_args_and_nonce(
2533
-            [
2534
-                'action' => 'edit_attendee',
2535
-                'post'   => $attendee->ID(),
2536
-            ],
2537
-            REG_ADMIN_URL
2538
-        );
2539
-        $this->_template_args['att_edit_label'] = esc_html__('View/Edit Contact', 'event_espresso');
2540
-        // create link
2541
-        $this->_template_args['create_link']  = $primary_registration instanceof EE_Registration
2542
-            ? EE_Admin_Page::add_query_args_and_nonce(
2543
-                [
2544
-                    'action'  => 'duplicate_attendee',
2545
-                    '_REG_ID' => $this->_registration->ID(),
2546
-                ],
2547
-                REG_ADMIN_URL
2548
-            ) : '';
2549
-        $this->_template_args['create_label'] = esc_html__('Create Contact', 'event_espresso');
2550
-        $this->_template_args['att_check']    = $att_check;
2551
-        $template_path                        =
2552
-            REG_TEMPLATE_PATH . 'reg_admin_details_side_meta_box_registrant.template.php';
2553
-        EEH_Template::display_template($template_path, $this->_template_args);
2554
-    }
2555
-
2556
-
2557
-    /**
2558
-     * trash or restore registrations
2559
-     *
2560
-     * @param boolean $trash whether to archive or restore
2561
-     * @return void
2562
-     * @throws DomainException
2563
-     * @throws EE_Error
2564
-     * @throws EntityNotFoundException
2565
-     * @throws InvalidArgumentException
2566
-     * @throws InvalidDataTypeException
2567
-     * @throws InvalidInterfaceException
2568
-     * @throws ReflectionException
2569
-     * @throws RuntimeException
2570
-     * @throws UnexpectedEntityException
2571
-     */
2572
-    protected function _trash_or_restore_registrations($trash = true)
2573
-    {
2574
-        // if empty _REG_ID then get out because there's nothing to do
2575
-        $REG_IDs = $this->request->getRequestParam('_REG_ID', [], 'int', true);
2576
-        if (empty($REG_IDs)) {
2577
-            EE_Error::add_error(
2578
-                sprintf(
2579
-                    esc_html__(
2580
-                        'In order to %1$s registrations you must select which ones you wish to %1$s by clicking the checkboxes.',
2581
-                        'event_espresso'
2582
-                    ),
2583
-                    $trash ? 'trash' : 'restore'
2584
-                ),
2585
-                __FILE__,
2586
-                __LINE__,
2587
-                __FUNCTION__
2588
-            );
2589
-            $this->_redirect_after_action(false, '', '', [], true);
2590
-        }
2591
-        $success        = 0;
2592
-        $overwrite_msgs = false;
2593
-        // Checkboxes
2594
-        $reg_count = count($REG_IDs);
2595
-        // cycle thru checkboxes
2596
-        foreach ($REG_IDs as $REG_ID) {
2597
-            /** @var EE_Registration $REG */
2598
-            $REG      = $this->getRegistrationModel()->get_one_by_ID($REG_ID);
2599
-            $payments = $REG->registration_payments();
2600
-            if (! empty($payments)) {
2601
-                $name           = $REG->attendee() instanceof EE_Attendee
2602
-                    ? $REG->attendee()->full_name()
2603
-                    : esc_html__('Unknown Attendee', 'event_espresso');
2604
-                $overwrite_msgs = true;
2605
-                EE_Error::add_error(
2606
-                    sprintf(
2607
-                        esc_html__(
2608
-                            'The registration for %s could not be trashed because it has payments attached to the related transaction.  If you wish to trash this registration you must first delete the payments on the related transaction.',
2609
-                            'event_espresso'
2610
-                        ),
2611
-                        $name
2612
-                    ),
2613
-                    __FILE__,
2614
-                    __FUNCTION__,
2615
-                    __LINE__
2616
-                );
2617
-                // can't trash this registration because it has payments.
2618
-                continue;
2619
-            }
2620
-            $updated = $trash ? $REG->delete(__METHOD__) : $REG->restore(__METHOD__);
2621
-            if ($updated) {
2622
-                $success++;
2623
-            }
2624
-        }
2625
-        $this->_redirect_after_action(
2626
-            $success === $reg_count, // were ALL registrations affected?
2627
-            $success > 1
2628
-                ? esc_html__('Registrations', 'event_espresso')
2629
-                : esc_html__('Registration', 'event_espresso'),
2630
-            $trash
2631
-                ? esc_html__('moved to the trash', 'event_espresso')
2632
-                : esc_html__('restored', 'event_espresso'),
2633
-            $this->mergeExistingRequestParamsWithRedirectArgs(['action' => 'default']),
2634
-            $overwrite_msgs
2635
-        );
2636
-    }
2637
-
2638
-
2639
-    /**
2640
-     * This is used to permanently delete registrations.  Note, this will handle not only deleting permanently the
2641
-     * registration but also.
2642
-     * 1. Removing relations to EE_Attendee
2643
-     * 2. Deleting permanently the related transaction, but ONLY if all related registrations to the transaction are
2644
-     * ALSO trashed.
2645
-     * 3. Deleting permanently any related Line items but only if the above conditions are met.
2646
-     * 4. Removing relationships between all tickets and the related registrations
2647
-     * 5. Deleting permanently any related Answers (and the answers for other related registrations that were deleted.)
2648
-     * 6. Deleting permanently any related Checkins.
2649
-     *
2650
-     * @return void
2651
-     * @throws EE_Error
2652
-     * @throws InvalidArgumentException
2653
-     * @throws InvalidDataTypeException
2654
-     * @throws InvalidInterfaceException
2655
-     * @throws ReflectionException
2656
-     */
2657
-    protected function _delete_registrations()
2658
-    {
2659
-        $REG_MDL = $this->getRegistrationModel();
2660
-        $success = 0;
2661
-        // Checkboxes
2662
-        $REG_IDs = $this->request->getRequestParam('_REG_ID', [], 'int', true);
2663
-
2664
-        if (! empty($REG_IDs)) {
2665
-            // if array has more than one element than success message should be plural
2666
-            $success = count($REG_IDs) > 1 ? 2 : 1;
2667
-            // cycle thru checkboxes
2668
-            foreach ($REG_IDs as $REG_ID) {
2669
-                $REG = $REG_MDL->get_one_by_ID($REG_ID);
2670
-                if (! $REG instanceof EE_Registration) {
2671
-                    continue;
2672
-                }
2673
-                $deleted = $this->_delete_registration($REG);
2674
-                if (! $deleted) {
2675
-                    $success = 0;
2676
-                }
2677
-            }
2678
-        }
2679
-
2680
-        $what        = $success > 1
2681
-            ? esc_html__('Registrations', 'event_espresso')
2682
-            : esc_html__('Registration', 'event_espresso');
2683
-        $action_desc = esc_html__('permanently deleted.', 'event_espresso');
2684
-        $this->_redirect_after_action(
2685
-            $success,
2686
-            $what,
2687
-            $action_desc,
2688
-            $this->mergeExistingRequestParamsWithRedirectArgs(['action' => 'default']),
2689
-            true
2690
-        );
2691
-    }
2692
-
2693
-
2694
-    /**
2695
-     * handles the permanent deletion of a registration.  See comments with _delete_registrations() for details on what
2696
-     * models get affected.
2697
-     *
2698
-     * @param EE_Registration $REG registration to be deleted permanently
2699
-     * @return bool true = successful deletion, false = fail.
2700
-     * @throws EE_Error
2701
-     * @throws InvalidArgumentException
2702
-     * @throws InvalidDataTypeException
2703
-     * @throws InvalidInterfaceException
2704
-     * @throws ReflectionException
2705
-     */
2706
-    protected function _delete_registration(EE_Registration $REG)
2707
-    {
2708
-        // first we start with the transaction... ultimately, we WILL not delete permanently if there are any related
2709
-        // registrations on the transaction that are NOT trashed.
2710
-        $TXN = $REG->get_first_related('Transaction');
2711
-        if (! $TXN instanceof EE_Transaction) {
2712
-            EE_Error::add_error(
2713
-                sprintf(
2714
-                    esc_html__(
2715
-                        'Unable to permanently delete registration %d because its related transaction has already been deleted. If you can restore the related transaction to the database then this registration can be deleted.',
2716
-                        'event_espresso'
2717
-                    ),
2718
-                    $REG->id()
2719
-                ),
2720
-                __FILE__,
2721
-                __FUNCTION__,
2722
-                __LINE__
2723
-            );
2724
-            return false;
2725
-        }
2726
-        $REGS        = $TXN->get_many_related('Registration');
2727
-        $all_trashed = true;
2728
-        foreach ($REGS as $registration) {
2729
-            if (! $registration->get('REG_deleted')) {
2730
-                $all_trashed = false;
2731
-            }
2732
-        }
2733
-        if (! $all_trashed) {
2734
-            EE_Error::add_error(
2735
-                esc_html__(
2736
-                    'Unable to permanently delete this registration. Before this registration can be permanently deleted, all registrations made in the same transaction must be trashed as well.  These registrations will be permanently deleted in the same action.',
2737
-                    'event_espresso'
2738
-                ),
2739
-                __FILE__,
2740
-                __FUNCTION__,
2741
-                __LINE__
2742
-            );
2743
-            return false;
2744
-        }
2745
-        // k made it here so that means we can delete all the related transactions and their answers (but let's do them
2746
-        // separately from THIS one).
2747
-        foreach ($REGS as $registration) {
2748
-            // delete related answers
2749
-            $registration->delete_related_permanently('Answer');
2750
-            // remove relationship to EE_Attendee (but we ALWAYS leave the contact record intact)
2751
-            $attendee = $registration->get_first_related('Attendee');
2752
-            if ($attendee instanceof EE_Attendee) {
2753
-                $registration->_remove_relation_to($attendee, 'Attendee');
2754
-            }
2755
-            // now remove relationships to tickets on this registration.
2756
-            $registration->_remove_relations('Ticket');
2757
-            // now delete permanently the checkins related to this registration.
2758
-            $registration->delete_related_permanently('Checkin');
2759
-            if ($registration->ID() === $REG->ID()) {
2760
-                continue;
2761
-            } //we don't want to delete permanently the existing registration just yet.
2762
-            // remove relation to transaction for these registrations if NOT the existing registrations
2763
-            $registration->_remove_relations('Transaction');
2764
-            // delete permanently any related messages.
2765
-            $registration->delete_related_permanently('Message');
2766
-            // now delete this registration permanently
2767
-            $registration->delete_permanently();
2768
-        }
2769
-        // now all related registrations on the transaction are handled.  So let's just handle this registration itself
2770
-        // (the transaction and line items should be all that's left).
2771
-        // delete the line items related to the transaction for this registration.
2772
-        $TXN->delete_related_permanently('Line_Item');
2773
-        // we need to remove all the relationships on the transaction
2774
-        $TXN->delete_related_permanently('Payment');
2775
-        $TXN->delete_related_permanently('Extra_Meta');
2776
-        $TXN->delete_related_permanently('Message');
2777
-        // now we can delete this REG permanently (and the transaction of course)
2778
-        $REG->delete_related_permanently('Transaction');
2779
-        return $REG->delete_permanently();
2780
-    }
2781
-
2782
-
2783
-    /**
2784
-     *    generates HTML for the Register New Attendee Admin page
2785
-     *
2786
-     * @throws DomainException
2787
-     * @throws EE_Error
2788
-     * @throws InvalidArgumentException
2789
-     * @throws InvalidDataTypeException
2790
-     * @throws InvalidInterfaceException
2791
-     * @throws ReflectionException
2792
-     */
2793
-    public function new_registration()
2794
-    {
2795
-        if (! $this->_set_reg_event()) {
2796
-            throw new EE_Error(
2797
-                esc_html__(
2798
-                    'Unable to continue with registering because there is no Event ID in the request',
2799
-                    'event_espresso'
2800
-                )
2801
-            );
2802
-        }
2803
-        /** @var CurrentPage $current_page */
2804
-        $current_page = $this->loader->getShared(CurrentPage::class);
2805
-        $current_page->setEspressoPage(true);
2806
-        // gotta start with a clean slate if we're not coming here via ajax
2807
-        if (
2808
-            ! $this->request->isAjax()
2809
-            && (
2810
-                ! $this->request->requestParamIsSet('processing_registration')
2811
-                || $this->request->requestParamIsSet('step_error')
2812
-            )
2813
-        ) {
2814
-            EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
2815
-        }
2816
-        $this->_template_args['event_name'] = '';
2817
-        // event name
2818
-        if ($this->_reg_event) {
2819
-            $this->_template_args['event_name'] = $this->_reg_event->name();
2820
-            $edit_event_url                     = self::add_query_args_and_nonce(
2821
-                [
2822
-                    'action' => 'edit',
2823
-                    'post'   => $this->_reg_event->ID(),
2824
-                ],
2825
-                EVENTS_ADMIN_URL
2826
-            );
2827
-            $edit_event_lnk                     = '<a href="'
2828
-                                                  . $edit_event_url
2829
-                                                  . '" title="'
2830
-                                                  . esc_attr__('Edit ', 'event_espresso')
2831
-                                                  . $this->_reg_event->name()
2832
-                                                  . '">'
2833
-                                                  . esc_html__('Edit Event', 'event_espresso')
2834
-                                                  . '</a>';
2835
-            $this->_template_args['event_name'] .= ' <span class="admin-page-header-edit-lnk not-bold">'
2836
-                                                   . $edit_event_lnk
2837
-                                                   . '</span>';
2838
-        }
2839
-        $this->_template_args['step_content'] = $this->_get_registration_step_content();
2840
-        if ($this->request->isAjax()) {
2841
-            $this->_return_json();
2842
-        }
2843
-        // grab header
2844
-        $template_path                              =
2845
-            REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee.template.php';
2846
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
2847
-            $template_path,
2848
-            $this->_template_args,
2849
-            true
2850
-        );
2851
-        // $this->_set_publish_post_box_vars( NULL, FALSE, FALSE, NULL, FALSE );
2852
-        // the details template wrapper
2853
-        $this->display_admin_page_with_sidebar();
2854
-    }
2855
-
2856
-
2857
-    /**
2858
-     * This returns the content for a registration step
2859
-     *
2860
-     * @return string html
2861
-     * @throws DomainException
2862
-     * @throws EE_Error
2863
-     * @throws InvalidArgumentException
2864
-     * @throws InvalidDataTypeException
2865
-     * @throws InvalidInterfaceException
2866
-     * @throws ReflectionException
2867
-     */
2868
-    protected function _get_registration_step_content()
2869
-    {
2870
-        if (isset($_COOKIE['ee_registration_added']) && $_COOKIE['ee_registration_added']) {
2871
-            $warning_msg = sprintf(
2872
-                esc_html__(
2873
-                    '%2$sWARNING!!!%3$s%1$sPlease do not use the back button to return to this page for the purpose of adding another registration.%1$sThis can result in lost and/or corrupted data.%1$sIf you wish to add another registration, then please click the%1$s%7$s"Add Another New Registration to Event"%8$s button%1$son the Transaction details page, after you are redirected.%1$s%1$s%4$s redirecting in %5$s seconds %6$s',
2874
-                    'event_espresso'
2875
-                ),
2876
-                '<br />',
2877
-                '<h3 class="important-notice">',
2878
-                '</h3>',
2879
-                '<div class="float-right">',
2880
-                '<span id="redirect_timer" class="important-notice">30</span>',
2881
-                '</div>',
2882
-                '<b>',
2883
-                '</b>'
2884
-            );
2885
-            return '
2301
+	}
2302
+
2303
+
2304
+	/**
2305
+	 * Updates the registration's custom questions according to the form info, if the form is submitted.
2306
+	 * If it's not a post, the "view_registrations" route will be called next on the SAME request
2307
+	 * to display the page
2308
+	 *
2309
+	 * @return void
2310
+	 * @throws EE_Error
2311
+	 * @throws InvalidArgumentException
2312
+	 * @throws InvalidDataTypeException
2313
+	 * @throws InvalidInterfaceException
2314
+	 * @throws ReflectionException
2315
+	 */
2316
+	protected function _update_attendee_registration_form()
2317
+	{
2318
+		do_action('AHEE__Registrations_Admin_Page___update_attendee_registration_form__start', $this);
2319
+		if ($_SERVER['REQUEST_METHOD'] === 'POST') {
2320
+			$REG_ID  = $this->request->getRequestParam('_REG_ID', 0, 'int');
2321
+			$success = $this->_save_reg_custom_questions_form($REG_ID);
2322
+			if ($success) {
2323
+				$what  = esc_html__('Registration Form', 'event_espresso');
2324
+				$route = $REG_ID
2325
+					? ['action' => 'view_registration', '_REG_ID' => $REG_ID]
2326
+					: ['action' => 'default'];
2327
+				$this->_redirect_after_action(true, $what, esc_html__('updated', 'event_espresso'), $route);
2328
+			}
2329
+		}
2330
+	}
2331
+
2332
+
2333
+	/**
2334
+	 * Gets the form for saving registrations custom questions (if done
2335
+	 * previously retrieves the cached form object, which may have validation errors in it)
2336
+	 *
2337
+	 * @param int $REG_ID
2338
+	 * @return EE_Registration_Custom_Questions_Form
2339
+	 * @throws EE_Error
2340
+	 * @throws InvalidArgumentException
2341
+	 * @throws InvalidDataTypeException
2342
+	 * @throws InvalidInterfaceException
2343
+	 * @throws ReflectionException
2344
+	 */
2345
+	protected function _get_reg_custom_questions_form($REG_ID)
2346
+	{
2347
+		if (! $this->_reg_custom_questions_form) {
2348
+			require_once(REG_ADMIN . 'form_sections/EE_Registration_Custom_Questions_Form.form.php');
2349
+			$this->_reg_custom_questions_form = new EE_Registration_Custom_Questions_Form(
2350
+				$this->getRegistrationModel()->get_one_by_ID($REG_ID)
2351
+			);
2352
+			$this->_reg_custom_questions_form->_construct_finalize(null, null);
2353
+		}
2354
+		return $this->_reg_custom_questions_form;
2355
+	}
2356
+
2357
+
2358
+	/**
2359
+	 * Saves
2360
+	 *
2361
+	 * @param bool $REG_ID
2362
+	 * @return bool
2363
+	 * @throws EE_Error
2364
+	 * @throws InvalidArgumentException
2365
+	 * @throws InvalidDataTypeException
2366
+	 * @throws InvalidInterfaceException
2367
+	 * @throws ReflectionException
2368
+	 */
2369
+	private function _save_reg_custom_questions_form($REG_ID = 0)
2370
+	{
2371
+		if (! $REG_ID) {
2372
+			EE_Error::add_error(
2373
+				esc_html__(
2374
+					'An error occurred. No registration ID was received.',
2375
+					'event_espresso'
2376
+				),
2377
+				__FILE__,
2378
+				__FUNCTION__,
2379
+				__LINE__
2380
+			);
2381
+		}
2382
+		$form = $this->_get_reg_custom_questions_form($REG_ID);
2383
+		$form->receive_form_submission($this->request->requestParams());
2384
+		$success = false;
2385
+		if ($form->is_valid()) {
2386
+			foreach ($form->subforms() as $question_group_form) {
2387
+				foreach ($question_group_form->inputs() as $question_id => $input) {
2388
+					$where_conditions    = [
2389
+						'QST_ID' => $question_id,
2390
+						'REG_ID' => $REG_ID,
2391
+					];
2392
+					$possibly_new_values = [
2393
+						'ANS_value' => $input->normalized_value(),
2394
+					];
2395
+					$answer              = EEM_Answer::instance()->get_one([$where_conditions]);
2396
+					if ($answer instanceof EE_Answer) {
2397
+						$success = $answer->save($possibly_new_values);
2398
+					} else {
2399
+						// insert it then
2400
+						$cols_n_vals = array_merge($where_conditions, $possibly_new_values);
2401
+						$answer      = EE_Answer::new_instance($cols_n_vals);
2402
+						$success     = $answer->save();
2403
+					}
2404
+				}
2405
+			}
2406
+		} else {
2407
+			EE_Error::add_error($form->get_validation_error_string(), __FILE__, __FUNCTION__, __LINE__);
2408
+		}
2409
+		return $success;
2410
+	}
2411
+
2412
+
2413
+	/**
2414
+	 * generates HTML for the Registration main meta box
2415
+	 *
2416
+	 * @return void
2417
+	 * @throws DomainException
2418
+	 * @throws EE_Error
2419
+	 * @throws InvalidArgumentException
2420
+	 * @throws InvalidDataTypeException
2421
+	 * @throws InvalidInterfaceException
2422
+	 * @throws ReflectionException
2423
+	 */
2424
+	public function _reg_attendees_meta_box()
2425
+	{
2426
+		$REG = $this->getRegistrationModel();
2427
+		// get all other registrations on this transaction, and cache
2428
+		// the attendees for them so we don't have to run another query using force_join
2429
+		$registrations                           = $REG->get_all(
2430
+			[
2431
+				[
2432
+					'TXN_ID' => $this->_registration->transaction_ID(),
2433
+					'REG_ID' => ['!=', $this->_registration->ID()],
2434
+				],
2435
+				'force_join'               => ['Attendee'],
2436
+				'default_where_conditions' => 'other_models_only',
2437
+			]
2438
+		);
2439
+		$this->_template_args['attendees']       = [];
2440
+		$this->_template_args['attendee_notice'] = '';
2441
+		if (
2442
+			empty($registrations)
2443
+			|| (is_array($registrations)
2444
+				&& ! EEH_Array::get_one_item_from_array($registrations))
2445
+		) {
2446
+			EE_Error::add_error(
2447
+				esc_html__(
2448
+					'There are no records attached to this registration. Something may have gone wrong with the registration',
2449
+					'event_espresso'
2450
+				),
2451
+				__FILE__,
2452
+				__FUNCTION__,
2453
+				__LINE__
2454
+			);
2455
+			$this->_template_args['attendee_notice'] = EE_Error::get_notices();
2456
+		} else {
2457
+			$att_nmbr = 1;
2458
+			foreach ($registrations as $registration) {
2459
+				/* @var $registration EE_Registration */
2460
+				$attendee                                                      = $registration->attendee()
2461
+					? $registration->attendee()
2462
+					: $this->getAttendeeModel()->create_default_object();
2463
+				$this->_template_args['attendees'][ $att_nmbr ]['STS_ID']      = $registration->status_ID();
2464
+				$this->_template_args['attendees'][ $att_nmbr ]['fname']       = $attendee->fname();
2465
+				$this->_template_args['attendees'][ $att_nmbr ]['lname']       = $attendee->lname();
2466
+				$this->_template_args['attendees'][ $att_nmbr ]['email']       = $attendee->email();
2467
+				$this->_template_args['attendees'][ $att_nmbr ]['final_price'] = $registration->final_price();
2468
+				$this->_template_args['attendees'][ $att_nmbr ]['address']     = implode(
2469
+					', ',
2470
+					$attendee->full_address_as_array()
2471
+				);
2472
+				$this->_template_args['attendees'][ $att_nmbr ]['att_link']    = self::add_query_args_and_nonce(
2473
+					[
2474
+						'action' => 'edit_attendee',
2475
+						'post'   => $attendee->ID(),
2476
+					],
2477
+					REG_ADMIN_URL
2478
+				);
2479
+				$this->_template_args['attendees'][ $att_nmbr ]['event_name']  =
2480
+					$registration->event_obj() instanceof EE_Event
2481
+						? $registration->event_obj()->name()
2482
+						: '';
2483
+				$att_nmbr++;
2484
+			}
2485
+			$this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
2486
+		}
2487
+		$template_path = REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_attendees.template.php';
2488
+		EEH_Template::display_template($template_path, $this->_template_args);
2489
+	}
2490
+
2491
+
2492
+	/**
2493
+	 * generates HTML for the Edit Registration side meta box
2494
+	 *
2495
+	 * @return void
2496
+	 * @throws DomainException
2497
+	 * @throws EE_Error
2498
+	 * @throws InvalidArgumentException
2499
+	 * @throws InvalidDataTypeException
2500
+	 * @throws InvalidInterfaceException
2501
+	 * @throws ReflectionException
2502
+	 */
2503
+	public function _reg_registrant_side_meta_box()
2504
+	{
2505
+		/*@var $attendee EE_Attendee */
2506
+		$att_check = $this->_registration->attendee();
2507
+		$attendee  = $att_check instanceof EE_Attendee
2508
+			? $att_check
2509
+			: $this->getAttendeeModel()->create_default_object();
2510
+		// now let's determine if this is not the primary registration.  If it isn't then we set the
2511
+		// primary_registration object for reference BUT ONLY if the Attendee object loaded is not the same as the
2512
+		// primary registration object (that way we know if we need to show create button or not)
2513
+		if (! $this->_registration->is_primary_registrant()) {
2514
+			$primary_registration = $this->_registration->get_primary_registration();
2515
+			$primary_attendee     = $primary_registration instanceof EE_Registration ? $primary_registration->attendee()
2516
+				: null;
2517
+			if (! $primary_attendee instanceof EE_Attendee || $attendee->ID() !== $primary_attendee->ID()) {
2518
+				// in here?  This means the displayed registration is not the primary registrant but ALREADY HAS its own
2519
+				// custom attendee object so let's not worry about the primary reg.
2520
+				$primary_registration = null;
2521
+			}
2522
+		} else {
2523
+			$primary_registration = null;
2524
+		}
2525
+		$this->_template_args['ATT_ID']            = $attendee->ID();
2526
+		$this->_template_args['fname']             = $attendee->fname();
2527
+		$this->_template_args['lname']             = $attendee->lname();
2528
+		$this->_template_args['email']             = $attendee->email();
2529
+		$this->_template_args['phone']             = $attendee->phone();
2530
+		$this->_template_args['formatted_address'] = EEH_Address::format($attendee);
2531
+		// edit link
2532
+		$this->_template_args['att_edit_link']  = EE_Admin_Page::add_query_args_and_nonce(
2533
+			[
2534
+				'action' => 'edit_attendee',
2535
+				'post'   => $attendee->ID(),
2536
+			],
2537
+			REG_ADMIN_URL
2538
+		);
2539
+		$this->_template_args['att_edit_label'] = esc_html__('View/Edit Contact', 'event_espresso');
2540
+		// create link
2541
+		$this->_template_args['create_link']  = $primary_registration instanceof EE_Registration
2542
+			? EE_Admin_Page::add_query_args_and_nonce(
2543
+				[
2544
+					'action'  => 'duplicate_attendee',
2545
+					'_REG_ID' => $this->_registration->ID(),
2546
+				],
2547
+				REG_ADMIN_URL
2548
+			) : '';
2549
+		$this->_template_args['create_label'] = esc_html__('Create Contact', 'event_espresso');
2550
+		$this->_template_args['att_check']    = $att_check;
2551
+		$template_path                        =
2552
+			REG_TEMPLATE_PATH . 'reg_admin_details_side_meta_box_registrant.template.php';
2553
+		EEH_Template::display_template($template_path, $this->_template_args);
2554
+	}
2555
+
2556
+
2557
+	/**
2558
+	 * trash or restore registrations
2559
+	 *
2560
+	 * @param boolean $trash whether to archive or restore
2561
+	 * @return void
2562
+	 * @throws DomainException
2563
+	 * @throws EE_Error
2564
+	 * @throws EntityNotFoundException
2565
+	 * @throws InvalidArgumentException
2566
+	 * @throws InvalidDataTypeException
2567
+	 * @throws InvalidInterfaceException
2568
+	 * @throws ReflectionException
2569
+	 * @throws RuntimeException
2570
+	 * @throws UnexpectedEntityException
2571
+	 */
2572
+	protected function _trash_or_restore_registrations($trash = true)
2573
+	{
2574
+		// if empty _REG_ID then get out because there's nothing to do
2575
+		$REG_IDs = $this->request->getRequestParam('_REG_ID', [], 'int', true);
2576
+		if (empty($REG_IDs)) {
2577
+			EE_Error::add_error(
2578
+				sprintf(
2579
+					esc_html__(
2580
+						'In order to %1$s registrations you must select which ones you wish to %1$s by clicking the checkboxes.',
2581
+						'event_espresso'
2582
+					),
2583
+					$trash ? 'trash' : 'restore'
2584
+				),
2585
+				__FILE__,
2586
+				__LINE__,
2587
+				__FUNCTION__
2588
+			);
2589
+			$this->_redirect_after_action(false, '', '', [], true);
2590
+		}
2591
+		$success        = 0;
2592
+		$overwrite_msgs = false;
2593
+		// Checkboxes
2594
+		$reg_count = count($REG_IDs);
2595
+		// cycle thru checkboxes
2596
+		foreach ($REG_IDs as $REG_ID) {
2597
+			/** @var EE_Registration $REG */
2598
+			$REG      = $this->getRegistrationModel()->get_one_by_ID($REG_ID);
2599
+			$payments = $REG->registration_payments();
2600
+			if (! empty($payments)) {
2601
+				$name           = $REG->attendee() instanceof EE_Attendee
2602
+					? $REG->attendee()->full_name()
2603
+					: esc_html__('Unknown Attendee', 'event_espresso');
2604
+				$overwrite_msgs = true;
2605
+				EE_Error::add_error(
2606
+					sprintf(
2607
+						esc_html__(
2608
+							'The registration for %s could not be trashed because it has payments attached to the related transaction.  If you wish to trash this registration you must first delete the payments on the related transaction.',
2609
+							'event_espresso'
2610
+						),
2611
+						$name
2612
+					),
2613
+					__FILE__,
2614
+					__FUNCTION__,
2615
+					__LINE__
2616
+				);
2617
+				// can't trash this registration because it has payments.
2618
+				continue;
2619
+			}
2620
+			$updated = $trash ? $REG->delete(__METHOD__) : $REG->restore(__METHOD__);
2621
+			if ($updated) {
2622
+				$success++;
2623
+			}
2624
+		}
2625
+		$this->_redirect_after_action(
2626
+			$success === $reg_count, // were ALL registrations affected?
2627
+			$success > 1
2628
+				? esc_html__('Registrations', 'event_espresso')
2629
+				: esc_html__('Registration', 'event_espresso'),
2630
+			$trash
2631
+				? esc_html__('moved to the trash', 'event_espresso')
2632
+				: esc_html__('restored', 'event_espresso'),
2633
+			$this->mergeExistingRequestParamsWithRedirectArgs(['action' => 'default']),
2634
+			$overwrite_msgs
2635
+		);
2636
+	}
2637
+
2638
+
2639
+	/**
2640
+	 * This is used to permanently delete registrations.  Note, this will handle not only deleting permanently the
2641
+	 * registration but also.
2642
+	 * 1. Removing relations to EE_Attendee
2643
+	 * 2. Deleting permanently the related transaction, but ONLY if all related registrations to the transaction are
2644
+	 * ALSO trashed.
2645
+	 * 3. Deleting permanently any related Line items but only if the above conditions are met.
2646
+	 * 4. Removing relationships between all tickets and the related registrations
2647
+	 * 5. Deleting permanently any related Answers (and the answers for other related registrations that were deleted.)
2648
+	 * 6. Deleting permanently any related Checkins.
2649
+	 *
2650
+	 * @return void
2651
+	 * @throws EE_Error
2652
+	 * @throws InvalidArgumentException
2653
+	 * @throws InvalidDataTypeException
2654
+	 * @throws InvalidInterfaceException
2655
+	 * @throws ReflectionException
2656
+	 */
2657
+	protected function _delete_registrations()
2658
+	{
2659
+		$REG_MDL = $this->getRegistrationModel();
2660
+		$success = 0;
2661
+		// Checkboxes
2662
+		$REG_IDs = $this->request->getRequestParam('_REG_ID', [], 'int', true);
2663
+
2664
+		if (! empty($REG_IDs)) {
2665
+			// if array has more than one element than success message should be plural
2666
+			$success = count($REG_IDs) > 1 ? 2 : 1;
2667
+			// cycle thru checkboxes
2668
+			foreach ($REG_IDs as $REG_ID) {
2669
+				$REG = $REG_MDL->get_one_by_ID($REG_ID);
2670
+				if (! $REG instanceof EE_Registration) {
2671
+					continue;
2672
+				}
2673
+				$deleted = $this->_delete_registration($REG);
2674
+				if (! $deleted) {
2675
+					$success = 0;
2676
+				}
2677
+			}
2678
+		}
2679
+
2680
+		$what        = $success > 1
2681
+			? esc_html__('Registrations', 'event_espresso')
2682
+			: esc_html__('Registration', 'event_espresso');
2683
+		$action_desc = esc_html__('permanently deleted.', 'event_espresso');
2684
+		$this->_redirect_after_action(
2685
+			$success,
2686
+			$what,
2687
+			$action_desc,
2688
+			$this->mergeExistingRequestParamsWithRedirectArgs(['action' => 'default']),
2689
+			true
2690
+		);
2691
+	}
2692
+
2693
+
2694
+	/**
2695
+	 * handles the permanent deletion of a registration.  See comments with _delete_registrations() for details on what
2696
+	 * models get affected.
2697
+	 *
2698
+	 * @param EE_Registration $REG registration to be deleted permanently
2699
+	 * @return bool true = successful deletion, false = fail.
2700
+	 * @throws EE_Error
2701
+	 * @throws InvalidArgumentException
2702
+	 * @throws InvalidDataTypeException
2703
+	 * @throws InvalidInterfaceException
2704
+	 * @throws ReflectionException
2705
+	 */
2706
+	protected function _delete_registration(EE_Registration $REG)
2707
+	{
2708
+		// first we start with the transaction... ultimately, we WILL not delete permanently if there are any related
2709
+		// registrations on the transaction that are NOT trashed.
2710
+		$TXN = $REG->get_first_related('Transaction');
2711
+		if (! $TXN instanceof EE_Transaction) {
2712
+			EE_Error::add_error(
2713
+				sprintf(
2714
+					esc_html__(
2715
+						'Unable to permanently delete registration %d because its related transaction has already been deleted. If you can restore the related transaction to the database then this registration can be deleted.',
2716
+						'event_espresso'
2717
+					),
2718
+					$REG->id()
2719
+				),
2720
+				__FILE__,
2721
+				__FUNCTION__,
2722
+				__LINE__
2723
+			);
2724
+			return false;
2725
+		}
2726
+		$REGS        = $TXN->get_many_related('Registration');
2727
+		$all_trashed = true;
2728
+		foreach ($REGS as $registration) {
2729
+			if (! $registration->get('REG_deleted')) {
2730
+				$all_trashed = false;
2731
+			}
2732
+		}
2733
+		if (! $all_trashed) {
2734
+			EE_Error::add_error(
2735
+				esc_html__(
2736
+					'Unable to permanently delete this registration. Before this registration can be permanently deleted, all registrations made in the same transaction must be trashed as well.  These registrations will be permanently deleted in the same action.',
2737
+					'event_espresso'
2738
+				),
2739
+				__FILE__,
2740
+				__FUNCTION__,
2741
+				__LINE__
2742
+			);
2743
+			return false;
2744
+		}
2745
+		// k made it here so that means we can delete all the related transactions and their answers (but let's do them
2746
+		// separately from THIS one).
2747
+		foreach ($REGS as $registration) {
2748
+			// delete related answers
2749
+			$registration->delete_related_permanently('Answer');
2750
+			// remove relationship to EE_Attendee (but we ALWAYS leave the contact record intact)
2751
+			$attendee = $registration->get_first_related('Attendee');
2752
+			if ($attendee instanceof EE_Attendee) {
2753
+				$registration->_remove_relation_to($attendee, 'Attendee');
2754
+			}
2755
+			// now remove relationships to tickets on this registration.
2756
+			$registration->_remove_relations('Ticket');
2757
+			// now delete permanently the checkins related to this registration.
2758
+			$registration->delete_related_permanently('Checkin');
2759
+			if ($registration->ID() === $REG->ID()) {
2760
+				continue;
2761
+			} //we don't want to delete permanently the existing registration just yet.
2762
+			// remove relation to transaction for these registrations if NOT the existing registrations
2763
+			$registration->_remove_relations('Transaction');
2764
+			// delete permanently any related messages.
2765
+			$registration->delete_related_permanently('Message');
2766
+			// now delete this registration permanently
2767
+			$registration->delete_permanently();
2768
+		}
2769
+		// now all related registrations on the transaction are handled.  So let's just handle this registration itself
2770
+		// (the transaction and line items should be all that's left).
2771
+		// delete the line items related to the transaction for this registration.
2772
+		$TXN->delete_related_permanently('Line_Item');
2773
+		// we need to remove all the relationships on the transaction
2774
+		$TXN->delete_related_permanently('Payment');
2775
+		$TXN->delete_related_permanently('Extra_Meta');
2776
+		$TXN->delete_related_permanently('Message');
2777
+		// now we can delete this REG permanently (and the transaction of course)
2778
+		$REG->delete_related_permanently('Transaction');
2779
+		return $REG->delete_permanently();
2780
+	}
2781
+
2782
+
2783
+	/**
2784
+	 *    generates HTML for the Register New Attendee Admin page
2785
+	 *
2786
+	 * @throws DomainException
2787
+	 * @throws EE_Error
2788
+	 * @throws InvalidArgumentException
2789
+	 * @throws InvalidDataTypeException
2790
+	 * @throws InvalidInterfaceException
2791
+	 * @throws ReflectionException
2792
+	 */
2793
+	public function new_registration()
2794
+	{
2795
+		if (! $this->_set_reg_event()) {
2796
+			throw new EE_Error(
2797
+				esc_html__(
2798
+					'Unable to continue with registering because there is no Event ID in the request',
2799
+					'event_espresso'
2800
+				)
2801
+			);
2802
+		}
2803
+		/** @var CurrentPage $current_page */
2804
+		$current_page = $this->loader->getShared(CurrentPage::class);
2805
+		$current_page->setEspressoPage(true);
2806
+		// gotta start with a clean slate if we're not coming here via ajax
2807
+		if (
2808
+			! $this->request->isAjax()
2809
+			&& (
2810
+				! $this->request->requestParamIsSet('processing_registration')
2811
+				|| $this->request->requestParamIsSet('step_error')
2812
+			)
2813
+		) {
2814
+			EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
2815
+		}
2816
+		$this->_template_args['event_name'] = '';
2817
+		// event name
2818
+		if ($this->_reg_event) {
2819
+			$this->_template_args['event_name'] = $this->_reg_event->name();
2820
+			$edit_event_url                     = self::add_query_args_and_nonce(
2821
+				[
2822
+					'action' => 'edit',
2823
+					'post'   => $this->_reg_event->ID(),
2824
+				],
2825
+				EVENTS_ADMIN_URL
2826
+			);
2827
+			$edit_event_lnk                     = '<a href="'
2828
+												  . $edit_event_url
2829
+												  . '" title="'
2830
+												  . esc_attr__('Edit ', 'event_espresso')
2831
+												  . $this->_reg_event->name()
2832
+												  . '">'
2833
+												  . esc_html__('Edit Event', 'event_espresso')
2834
+												  . '</a>';
2835
+			$this->_template_args['event_name'] .= ' <span class="admin-page-header-edit-lnk not-bold">'
2836
+												   . $edit_event_lnk
2837
+												   . '</span>';
2838
+		}
2839
+		$this->_template_args['step_content'] = $this->_get_registration_step_content();
2840
+		if ($this->request->isAjax()) {
2841
+			$this->_return_json();
2842
+		}
2843
+		// grab header
2844
+		$template_path                              =
2845
+			REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee.template.php';
2846
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
2847
+			$template_path,
2848
+			$this->_template_args,
2849
+			true
2850
+		);
2851
+		// $this->_set_publish_post_box_vars( NULL, FALSE, FALSE, NULL, FALSE );
2852
+		// the details template wrapper
2853
+		$this->display_admin_page_with_sidebar();
2854
+	}
2855
+
2856
+
2857
+	/**
2858
+	 * This returns the content for a registration step
2859
+	 *
2860
+	 * @return string html
2861
+	 * @throws DomainException
2862
+	 * @throws EE_Error
2863
+	 * @throws InvalidArgumentException
2864
+	 * @throws InvalidDataTypeException
2865
+	 * @throws InvalidInterfaceException
2866
+	 * @throws ReflectionException
2867
+	 */
2868
+	protected function _get_registration_step_content()
2869
+	{
2870
+		if (isset($_COOKIE['ee_registration_added']) && $_COOKIE['ee_registration_added']) {
2871
+			$warning_msg = sprintf(
2872
+				esc_html__(
2873
+					'%2$sWARNING!!!%3$s%1$sPlease do not use the back button to return to this page for the purpose of adding another registration.%1$sThis can result in lost and/or corrupted data.%1$sIf you wish to add another registration, then please click the%1$s%7$s"Add Another New Registration to Event"%8$s button%1$son the Transaction details page, after you are redirected.%1$s%1$s%4$s redirecting in %5$s seconds %6$s',
2874
+					'event_espresso'
2875
+				),
2876
+				'<br />',
2877
+				'<h3 class="important-notice">',
2878
+				'</h3>',
2879
+				'<div class="float-right">',
2880
+				'<span id="redirect_timer" class="important-notice">30</span>',
2881
+				'</div>',
2882
+				'<b>',
2883
+				'</b>'
2884
+			);
2885
+			return '
2886 2886
 	<div id="ee-add-reg-back-button-dv"><p>' . $warning_msg . '</p></div>
2887 2887
 	<script >
2888 2888
 		// WHOAH !!! it appears that someone is using the back button from the Transaction admin page
@@ -2895,852 +2895,852 @@  discard block
 block discarded – undo
2895 2895
 	        }
2896 2896
 	    }, 800 );
2897 2897
 	</script >';
2898
-        }
2899
-        $template_args = [
2900
-            'title'                    => '',
2901
-            'content'                  => '',
2902
-            'step_button_text'         => '',
2903
-            'show_notification_toggle' => false,
2904
-        ];
2905
-        // to indicate we're processing a new registration
2906
-        $hidden_fields = [
2907
-            'processing_registration' => [
2908
-                'type'  => 'hidden',
2909
-                'value' => 0,
2910
-            ],
2911
-            'event_id'                => [
2912
-                'type'  => 'hidden',
2913
-                'value' => $this->_reg_event->ID(),
2914
-            ],
2915
-        ];
2916
-        // if the cart is empty then we know we're at step one, so we'll display the ticket selector
2917
-        $cart = EE_Registry::instance()->SSN->cart();
2918
-        $step = ! $cart instanceof EE_Cart ? 'ticket' : 'questions';
2919
-        switch ($step) {
2920
-            case 'ticket':
2921
-                $hidden_fields['processing_registration']['value'] = 1;
2922
-                $template_args['title']                            = esc_html__(
2923
-                    'Step One: Select the Ticket for this registration',
2924
-                    'event_espresso'
2925
-                );
2926
-                $template_args['content']                          =
2927
-                    EED_Ticket_Selector::instance()->display_ticket_selector($this->_reg_event);
2928
-                $template_args['content']                          .= '</div>';
2929
-                $template_args['step_button_text']                 = esc_html__(
2930
-                    'Add Tickets and Continue to Registrant Details',
2931
-                    'event_espresso'
2932
-                );
2933
-                $template_args['show_notification_toggle']         = false;
2934
-                break;
2935
-            case 'questions':
2936
-                $hidden_fields['processing_registration']['value'] = 2;
2937
-                $template_args['title']                            = esc_html__(
2938
-                    'Step Two: Add Registrant Details for this Registration',
2939
-                    'event_espresso'
2940
-                );
2941
-                // in theory, we should be able to run EED_SPCO at this point
2942
-                // because the cart should have been set up properly by the first process_reg_step run.
2943
-                $template_args['content']                  =
2944
-                    EED_Single_Page_Checkout::registration_checkout_for_admin();
2945
-                $template_args['step_button_text']         = esc_html__(
2946
-                    'Save Registration and Continue to Details',
2947
-                    'event_espresso'
2948
-                );
2949
-                $template_args['show_notification_toggle'] = true;
2950
-                break;
2951
-        }
2952
-        // we come back to the process_registration_step route.
2953
-        $this->_set_add_edit_form_tags('process_reg_step', $hidden_fields);
2954
-        return EEH_Template::display_template(
2955
-            REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee_step_content.template.php',
2956
-            $template_args,
2957
-            true
2958
-        );
2959
-    }
2960
-
2961
-
2962
-    /**
2963
-     * set_reg_event
2964
-     *
2965
-     * @return bool
2966
-     * @throws EE_Error
2967
-     * @throws InvalidArgumentException
2968
-     * @throws InvalidDataTypeException
2969
-     * @throws InvalidInterfaceException
2970
-     */
2971
-    private function _set_reg_event()
2972
-    {
2973
-        if (is_object($this->_reg_event)) {
2974
-            return true;
2975
-        }
2976
-
2977
-        $EVT_ID = $this->request->getRequestParam('event_id', 0, 'int');
2978
-        if (! $EVT_ID) {
2979
-            return false;
2980
-        }
2981
-        $this->_reg_event = $this->getEventModel()->get_one_by_ID($EVT_ID);
2982
-        return true;
2983
-    }
2984
-
2985
-
2986
-    /**
2987
-     * process_reg_step
2988
-     *
2989
-     * @return void
2990
-     * @throws DomainException
2991
-     * @throws EE_Error
2992
-     * @throws InvalidArgumentException
2993
-     * @throws InvalidDataTypeException
2994
-     * @throws InvalidInterfaceException
2995
-     * @throws ReflectionException
2996
-     * @throws RuntimeException
2997
-     */
2998
-    public function process_reg_step()
2999
-    {
3000
-        EE_System::do_not_cache();
3001
-        $this->_set_reg_event();
3002
-        /** @var CurrentPage $current_page */
3003
-        $current_page = $this->loader->getShared(CurrentPage::class);
3004
-        $current_page->setEspressoPage(true);
3005
-        $this->request->setRequestParam('uts', time());
3006
-        // what step are we on?
3007
-        $cart = EE_Registry::instance()->SSN->cart();
3008
-        $step = ! $cart instanceof EE_Cart ? 'ticket' : 'questions';
3009
-        // if doing ajax then we need to verify the nonce
3010
-        if ($this->request->isAjax()) {
3011
-            $nonce = $this->request->getRequestParam($this->_req_nonce, '');
3012
-            $this->_verify_nonce($nonce, $this->_req_nonce);
3013
-        }
3014
-        switch ($step) {
3015
-            case 'ticket':
3016
-                // process ticket selection
3017
-                $success = EED_Ticket_Selector::instance()->process_ticket_selections();
3018
-                if ($success) {
3019
-                    EE_Error::add_success(
3020
-                        esc_html__(
3021
-                            'Tickets Selected. Now complete the registration.',
3022
-                            'event_espresso'
3023
-                        )
3024
-                    );
3025
-                } else {
3026
-                    $this->request->setRequestParam('step_error', true);
3027
-                    $query_args['step_error'] = $this->request->getRequestParam('step_error', true, 'bool');
3028
-                }
3029
-                if ($this->request->isAjax()) {
3030
-                    $this->new_registration(); // display next step
3031
-                } else {
3032
-                    $query_args = [
3033
-                        'action'                  => 'new_registration',
3034
-                        'processing_registration' => 1,
3035
-                        'event_id'                => $this->_reg_event->ID(),
3036
-                        'uts'                     => time(),
3037
-                    ];
3038
-                    $this->_redirect_after_action(
3039
-                        false,
3040
-                        '',
3041
-                        '',
3042
-                        $query_args,
3043
-                        true
3044
-                    );
3045
-                }
3046
-                break;
3047
-            case 'questions':
3048
-                if (! $this->request->requestParamIsSet('txn_reg_status_change[send_notifications]')) {
3049
-                    add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_false', 15);
3050
-                }
3051
-                // process registration
3052
-                $transaction = EED_Single_Page_Checkout::instance()->process_registration_from_admin();
3053
-                if ($cart instanceof EE_Cart) {
3054
-                    $grand_total = $cart->get_grand_total();
3055
-                    if ($grand_total instanceof EE_Line_Item) {
3056
-                        $grand_total->save_this_and_descendants_to_txn();
3057
-                    }
3058
-                }
3059
-                if (! $transaction instanceof EE_Transaction) {
3060
-                    $query_args = [
3061
-                        'action'                  => 'new_registration',
3062
-                        'processing_registration' => 2,
3063
-                        'event_id'                => $this->_reg_event->ID(),
3064
-                        'uts'                     => time(),
3065
-                    ];
3066
-                    if ($this->request->isAjax()) {
3067
-                        // display registration form again because there are errors (maybe validation?)
3068
-                        $this->new_registration();
3069
-                        return;
3070
-                    }
3071
-                    $this->_redirect_after_action(
3072
-                        false,
3073
-                        '',
3074
-                        '',
3075
-                        $query_args,
3076
-                        true
3077
-                    );
3078
-                    return;
3079
-                }
3080
-                // maybe update status, and make sure to save transaction if not done already
3081
-                if (! $transaction->update_status_based_on_total_paid()) {
3082
-                    $transaction->save();
3083
-                }
3084
-                EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
3085
-                $query_args = [
3086
-                    'action'        => 'redirect_to_txn',
3087
-                    'TXN_ID'        => $transaction->ID(),
3088
-                    'EVT_ID'        => $this->_reg_event->ID(),
3089
-                    'event_name'    => urlencode($this->_reg_event->name()),
3090
-                    'redirect_from' => 'new_registration',
3091
-                ];
3092
-                $this->_redirect_after_action(false, '', '', $query_args, true);
3093
-                break;
3094
-        }
3095
-        // what are you looking here for?  Should be nothing to do at this point.
3096
-    }
3097
-
3098
-
3099
-    /**
3100
-     * redirect_to_txn
3101
-     *
3102
-     * @return void
3103
-     * @throws EE_Error
3104
-     * @throws InvalidArgumentException
3105
-     * @throws InvalidDataTypeException
3106
-     * @throws InvalidInterfaceException
3107
-     * @throws ReflectionException
3108
-     */
3109
-    public function redirect_to_txn()
3110
-    {
3111
-        EE_System::do_not_cache();
3112
-        EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
3113
-        $query_args = [
3114
-            'action' => 'view_transaction',
3115
-            'TXN_ID' => $this->request->getRequestParam('TXN_ID', 0, 'int'),
3116
-            'page'   => 'espresso_transactions',
3117
-        ];
3118
-        if ($this->request->requestParamIsSet('EVT_ID') && $this->request->requestParamIsSet('redirect_from')) {
3119
-            $query_args['EVT_ID']        = $this->request->getRequestParam('EVT_ID', 0, 'int');
3120
-            $query_args['event_name']    = urlencode($this->request->getRequestParam('event_name'));
3121
-            $query_args['redirect_from'] = $this->request->getRequestParam('redirect_from');
3122
-        }
3123
-        EE_Error::add_success(
3124
-            esc_html__(
3125
-                'Registration Created.  Please review the transaction and add any payments as necessary',
3126
-                'event_espresso'
3127
-            )
3128
-        );
3129
-        $this->_redirect_after_action(false, '', '', $query_args, true);
3130
-    }
3131
-
3132
-
3133
-    /**
3134
-     * generates HTML for the Attendee Contact List
3135
-     *
3136
-     * @return void
3137
-     * @throws DomainException
3138
-     * @throws EE_Error
3139
-     */
3140
-    protected function _attendee_contact_list_table()
3141
-    {
3142
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3143
-        $this->_search_btn_label = esc_html__('Contacts', 'event_espresso');
3144
-        $this->display_admin_list_table_page_with_no_sidebar();
3145
-    }
3146
-
3147
-
3148
-    /**
3149
-     * get_attendees
3150
-     *
3151
-     * @param      $per_page
3152
-     * @param bool $count whether to return count or data.
3153
-     * @param bool $trash
3154
-     * @return array|int
3155
-     * @throws EE_Error
3156
-     * @throws InvalidArgumentException
3157
-     * @throws InvalidDataTypeException
3158
-     * @throws InvalidInterfaceException
3159
-     */
3160
-    public function get_attendees($per_page, $count = false, $trash = false)
3161
-    {
3162
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3163
-        require_once(REG_ADMIN . 'EE_Attendee_Contact_List_Table.class.php');
3164
-        $orderby = $this->request->getRequestParam('orderby');
3165
-        switch ($orderby) {
3166
-            case 'ATT_ID':
3167
-            case 'ATT_fname':
3168
-            case 'ATT_email':
3169
-            case 'ATT_city':
3170
-            case 'STA_ID':
3171
-            case 'CNT_ID':
3172
-                break;
3173
-            case 'Registration_Count':
3174
-                $orderby = 'Registration_Count';
3175
-                break;
3176
-            default:
3177
-                $orderby = 'ATT_lname';
3178
-        }
3179
-        $sort         = $this->request->getRequestParam('order', 'ASC');
3180
-        $current_page = $this->request->getRequestParam('paged', 1, 'int');
3181
-        $per_page     = absint($per_page) ? $per_page : 10;
3182
-        $per_page     = $this->request->getRequestParam('perpage', $per_page, 'int');
3183
-        $_where       = [];
3184
-        $search_term  = $this->request->getRequestParam('s');
3185
-        if ($search_term) {
3186
-            $search_term  = '%' . $search_term . '%';
3187
-            $_where['OR'] = [
3188
-                'Registration.Event.EVT_name'       => ['LIKE', $search_term],
3189
-                'Registration.Event.EVT_desc'       => ['LIKE', $search_term],
3190
-                'Registration.Event.EVT_short_desc' => ['LIKE', $search_term],
3191
-                'ATT_fname'                         => ['LIKE', $search_term],
3192
-                'ATT_lname'                         => ['LIKE', $search_term],
3193
-                'ATT_short_bio'                     => ['LIKE', $search_term],
3194
-                'ATT_email'                         => ['LIKE', $search_term],
3195
-                'ATT_address'                       => ['LIKE', $search_term],
3196
-                'ATT_address2'                      => ['LIKE', $search_term],
3197
-                'ATT_city'                          => ['LIKE', $search_term],
3198
-                'Country.CNT_name'                  => ['LIKE', $search_term],
3199
-                'State.STA_name'                    => ['LIKE', $search_term],
3200
-                'ATT_phone'                         => ['LIKE', $search_term],
3201
-                'Registration.REG_final_price'      => ['LIKE', $search_term],
3202
-                'Registration.REG_code'             => ['LIKE', $search_term],
3203
-                'Registration.REG_group_size'       => ['LIKE', $search_term],
3204
-            ];
3205
-        }
3206
-        $offset     = ($current_page - 1) * $per_page;
3207
-        $limit      = $count ? null : [$offset, $per_page];
3208
-        $query_args = [
3209
-            $_where,
3210
-            'extra_selects' => ['Registration_Count' => ['Registration.REG_ID', 'count', '%d']],
3211
-            'limit'         => $limit,
3212
-        ];
3213
-        if (! $count) {
3214
-            $query_args['order_by'] = [$orderby => $sort];
3215
-        }
3216
-        $query_args[0]['status'] = $trash ? ['!=', 'publish'] : ['IN', ['publish']];
3217
-        return $count
3218
-            ? $this->getAttendeeModel()->count($query_args, 'ATT_ID', true)
3219
-            : $this->getAttendeeModel()->get_all($query_args);
3220
-    }
3221
-
3222
-
3223
-    /**
3224
-     * This is just taking care of resending the registration confirmation
3225
-     *
3226
-     * @return void
3227
-     * @throws EE_Error
3228
-     * @throws InvalidArgumentException
3229
-     * @throws InvalidDataTypeException
3230
-     * @throws InvalidInterfaceException
3231
-     * @throws ReflectionException
3232
-     */
3233
-    protected function _resend_registration()
3234
-    {
3235
-        $this->_process_resend_registration();
3236
-        $REG_ID      = $this->request->getRequestParam('_REG_ID', 0, 'int');
3237
-        $redirect_to = $this->request->getRequestParam('redirect_to');
3238
-        $query_args  = $redirect_to
3239
-            ? ['action' => $redirect_to, '_REG_ID' => $REG_ID]
3240
-            : ['action' => 'default'];
3241
-        $this->_redirect_after_action(false, '', '', $query_args, true);
3242
-    }
3243
-
3244
-
3245
-    /**
3246
-     * Creates a registration report, but accepts the name of a method to use for preparing the query parameters
3247
-     * to use when selecting registrations
3248
-     *
3249
-     * @param string $method_name_for_getting_query_params the name of the method (on this class) to use for preparing
3250
-     *                                                     the query parameters from the request
3251
-     * @return void ends the request with a redirect or download
3252
-     */
3253
-    public function _registrations_report_base($method_name_for_getting_query_params)
3254
-    {
3255
-        $EVT_ID = $this->request->requestParamIsSet('EVT_ID')
3256
-            ? $this->request->getRequestParam('EVT_ID', 0, 'int')
3257
-            : null;
3258
-
3259
-        if (! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3260
-            $request_params = $this->request->requestParams();
3261
-            wp_redirect(
3262
-                EE_Admin_Page::add_query_args_and_nonce(
3263
-                    [
3264
-                        'page'        => 'espresso_batch',
3265
-                        'batch'       => 'file',
3266
-                        'EVT_ID'      => $EVT_ID,
3267
-                        'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\RegistrationsReport'),
3268
-                        'return_url'  => urlencode($this->request->getRequestParam('return_url', '', DataType::URL)),
3269
-                        'filters'     => urlencode(
3270
-                            serialize(
3271
-                                $this->$method_name_for_getting_query_params(
3272
-                                    (isset($request_params['filters']) ? $request_params['filters'] : [])
3273
-                                )
3274
-                            )
3275
-                        ),
3276
-                        'use_filters' => $this->request->getRequestParam('use_filters', false, DataType::BOOL)
3277
-                    ]
3278
-                )
3279
-            );
3280
-        } else {
3281
-            // Pull the current request params
3282
-            $request_args = $this->request->requestParams();
3283
-            // Set the required request_args to be passed to the export
3284
-            $required_request_args = [
3285
-                'export' => 'report',
3286
-                'action' => 'registrations_report_for_event',
3287
-                'EVT_ID' => $EVT_ID,
3288
-            ];
3289
-            // Merge required request args, overriding any currently set
3290
-            $request_args = array_merge($request_args, $required_request_args);
3291
-            if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3292
-                require_once(EE_CLASSES . 'EE_Export.class.php');
3293
-                $EE_Export = EE_Export::instance($request_args);
3294
-                $EE_Export->export();
3295
-            }
3296
-        }
3297
-    }
3298
-
3299
-
3300
-    /**
3301
-     * Creates a registration report using only query parameters in the request
3302
-     *
3303
-     * @return void
3304
-     */
3305
-    public function _registrations_report()
3306
-    {
3307
-        $this->_registrations_report_base('_get_registration_query_parameters');
3308
-    }
3309
-
3310
-
3311
-    public function _contact_list_export()
3312
-    {
3313
-        if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3314
-            require_once(EE_CLASSES . 'EE_Export.class.php');
3315
-            $EE_Export = EE_Export::instance($this->request->requestParams());
3316
-            $EE_Export->export_attendees();
3317
-        }
3318
-    }
3319
-
3320
-
3321
-    public function _contact_list_report()
3322
-    {
3323
-        if (! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3324
-            wp_redirect(
3325
-                EE_Admin_Page::add_query_args_and_nonce(
3326
-                    [
3327
-                        'page'        => 'espresso_batch',
3328
-                        'batch'       => 'file',
3329
-                        'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\AttendeesReport'),
3330
-                        'return_url'  => urlencode($this->request->getRequestParam('return_url', '', 'url')),
3331
-                    ]
3332
-                )
3333
-            );
3334
-        } else {
3335
-            if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3336
-                require_once(EE_CLASSES . 'EE_Export.class.php');
3337
-                $EE_Export = EE_Export::instance($this->request->requestParams());
3338
-                $EE_Export->report_attendees();
3339
-            }
3340
-        }
3341
-    }
3342
-
3343
-
3344
-
3345
-
3346
-
3347
-    /***************************************        ATTENDEE DETAILS        ***************************************/
3348
-    /**
3349
-     * This duplicates the attendee object for the given incoming registration id and attendee_id.
3350
-     *
3351
-     * @return void
3352
-     * @throws EE_Error
3353
-     * @throws InvalidArgumentException
3354
-     * @throws InvalidDataTypeException
3355
-     * @throws InvalidInterfaceException
3356
-     * @throws ReflectionException
3357
-     */
3358
-    protected function _duplicate_attendee()
3359
-    {
3360
-        $REG_ID = $this->request->getRequestParam('_REG_ID', 0, 'int');
3361
-        $action = $this->request->getRequestParam('return', 'default');
3362
-        // verify we have necessary info
3363
-        if (! $REG_ID) {
3364
-            EE_Error::add_error(
3365
-                esc_html__(
3366
-                    'Unable to create the contact for the registration because the required parameters are not present (_REG_ID )',
3367
-                    'event_espresso'
3368
-                ),
3369
-                __FILE__,
3370
-                __LINE__,
3371
-                __FUNCTION__
3372
-            );
3373
-            $query_args = ['action' => $action];
3374
-            $this->_redirect_after_action('', '', '', $query_args, true);
3375
-        }
3376
-        // okay necessary deets present... let's dupe the incoming attendee and attach to incoming registration.
3377
-        $registration = $this->getRegistrationModel()->get_one_by_ID($REG_ID);
3378
-        if (! $registration instanceof EE_Registration) {
3379
-            throw new RuntimeException(
3380
-                sprintf(
3381
-                    esc_html__(
3382
-                        'Unable to create the contact because a valid registration could not be retrieved for REG ID: %1$d',
3383
-                        'event_espresso'
3384
-                    ),
3385
-                    $REG_ID
3386
-                )
3387
-            );
3388
-        }
3389
-        $attendee = $registration->attendee();
3390
-        // remove relation of existing attendee on registration
3391
-        $registration->_remove_relation_to($attendee, 'Attendee');
3392
-        // new attendee
3393
-        $new_attendee = clone $attendee;
3394
-        $new_attendee->set('ATT_ID', 0);
3395
-        $new_attendee->save();
3396
-        // add new attendee to reg
3397
-        $registration->_add_relation_to($new_attendee, 'Attendee');
3398
-        EE_Error::add_success(
3399
-            esc_html__(
3400
-                'New Contact record created.  Now make any edits you wish to make for this contact.',
3401
-                'event_espresso'
3402
-            )
3403
-        );
3404
-        // redirect to edit page for attendee
3405
-        $query_args = ['post' => $new_attendee->ID(), 'action' => 'edit_attendee'];
3406
-        $this->_redirect_after_action('', '', '', $query_args, true);
3407
-    }
3408
-
3409
-
3410
-    /**
3411
-     * Callback invoked by parent EE_Admin_CPT class hooked in on `save_post` wp hook.
3412
-     *
3413
-     * @param int     $post_id
3414
-     * @param WP_Post $post
3415
-     * @throws DomainException
3416
-     * @throws EE_Error
3417
-     * @throws InvalidArgumentException
3418
-     * @throws InvalidDataTypeException
3419
-     * @throws InvalidInterfaceException
3420
-     * @throws LogicException
3421
-     * @throws InvalidFormSubmissionException
3422
-     * @throws ReflectionException
3423
-     */
3424
-    protected function _insert_update_cpt_item($post_id, $post)
3425
-    {
3426
-        $success  = true;
3427
-        $attendee = $post instanceof WP_Post && $post->post_type === 'espresso_attendees'
3428
-            ? $this->getAttendeeModel()->get_one_by_ID($post_id)
3429
-            : null;
3430
-        // for attendee updates
3431
-        if ($attendee instanceof EE_Attendee) {
3432
-            // note we should only be UPDATING attendees at this point.
3433
-            $fname          = $this->request->getRequestParam('ATT_fname', '');
3434
-            $lname          = $this->request->getRequestParam('ATT_lname', '');
3435
-            $updated_fields = [
3436
-                'ATT_fname'     => $fname,
3437
-                'ATT_lname'     => $lname,
3438
-                'ATT_full_name' => "{$fname} {$lname}",
3439
-                'ATT_address'   => $this->request->getRequestParam('ATT_address', ''),
3440
-                'ATT_address2'  => $this->request->getRequestParam('ATT_address2', ''),
3441
-                'ATT_city'      => $this->request->getRequestParam('ATT_city', ''),
3442
-                'STA_ID'        => $this->request->getRequestParam('STA_ID', ''),
3443
-                'CNT_ISO'       => $this->request->getRequestParam('CNT_ISO', ''),
3444
-                'ATT_zip'       => $this->request->getRequestParam('ATT_zip', ''),
3445
-            ];
3446
-            foreach ($updated_fields as $field => $value) {
3447
-                $attendee->set($field, $value);
3448
-            }
3449
-
3450
-            // process contact details metabox form handler (which will also save the attendee)
3451
-            $contact_details_form = $this->getAttendeeContactDetailsMetaboxFormHandler($attendee);
3452
-            $success              = $contact_details_form->process($this->request->requestParams());
3453
-
3454
-            $attendee_update_callbacks = apply_filters(
3455
-                'FHEE__Registrations_Admin_Page__insert_update_cpt_item__attendee_update',
3456
-                []
3457
-            );
3458
-            foreach ($attendee_update_callbacks as $a_callback) {
3459
-                if (false === call_user_func_array($a_callback, [$attendee, $this->request->requestParams()])) {
3460
-                    throw new EE_Error(
3461
-                        sprintf(
3462
-                            esc_html__(
3463
-                                'The %s callback given for the "FHEE__Registrations_Admin_Page__insert_update_cpt_item__attendee_update" filter is not a valid callback.  Please check the spelling.',
3464
-                                'event_espresso'
3465
-                            ),
3466
-                            $a_callback
3467
-                        )
3468
-                    );
3469
-                }
3470
-            }
3471
-        }
3472
-
3473
-        if ($success === false) {
3474
-            EE_Error::add_error(
3475
-                esc_html__(
3476
-                    'Something went wrong with updating the meta table data for the registration.',
3477
-                    'event_espresso'
3478
-                ),
3479
-                __FILE__,
3480
-                __FUNCTION__,
3481
-                __LINE__
3482
-            );
3483
-        }
3484
-    }
3485
-
3486
-
3487
-    public function trash_cpt_item($post_id)
3488
-    {
3489
-    }
3490
-
3491
-
3492
-    public function delete_cpt_item($post_id)
3493
-    {
3494
-    }
3495
-
3496
-
3497
-    public function restore_cpt_item($post_id)
3498
-    {
3499
-    }
3500
-
3501
-
3502
-    protected function _restore_cpt_item($post_id, $revision_id)
3503
-    {
3504
-    }
3505
-
3506
-
3507
-    /**
3508
-     * @throws EE_Error
3509
-     * @throws ReflectionException
3510
-     * @since 4.10.2.p
3511
-     */
3512
-    public function attendee_editor_metaboxes()
3513
-    {
3514
-        $this->verify_cpt_object();
3515
-        remove_meta_box(
3516
-            'postexcerpt',
3517
-            $this->_cpt_routes[ $this->_req_action ],
3518
-            'normal'
3519
-        );
3520
-        remove_meta_box('commentstatusdiv', $this->_cpt_routes[ $this->_req_action ], 'normal');
3521
-        if (post_type_supports('espresso_attendees', 'excerpt')) {
3522
-            add_meta_box(
3523
-                'postexcerpt',
3524
-                esc_html__('Short Biography', 'event_espresso'),
3525
-                'post_excerpt_meta_box',
3526
-                $this->_cpt_routes[ $this->_req_action ],
3527
-                'normal'
3528
-            );
3529
-        }
3530
-        if (post_type_supports('espresso_attendees', 'comments')) {
3531
-            add_meta_box(
3532
-                'commentsdiv',
3533
-                esc_html__('Notes on the Contact', 'event_espresso'),
3534
-                'post_comment_meta_box',
3535
-                $this->_cpt_routes[ $this->_req_action ],
3536
-                'normal',
3537
-                'core'
3538
-            );
3539
-        }
3540
-        add_meta_box(
3541
-            'attendee_contact_info',
3542
-            esc_html__('Contact Info', 'event_espresso'),
3543
-            [$this, 'attendee_contact_info'],
3544
-            $this->_cpt_routes[ $this->_req_action ],
3545
-            'side',
3546
-            'core'
3547
-        );
3548
-        add_meta_box(
3549
-            'attendee_details_address',
3550
-            esc_html__('Address Details', 'event_espresso'),
3551
-            [$this, 'attendee_address_details'],
3552
-            $this->_cpt_routes[ $this->_req_action ],
3553
-            'normal',
3554
-            'core'
3555
-        );
3556
-        add_meta_box(
3557
-            'attendee_registrations',
3558
-            esc_html__('Registrations for this Contact', 'event_espresso'),
3559
-            [$this, 'attendee_registrations_meta_box'],
3560
-            $this->_cpt_routes[ $this->_req_action ],
3561
-            'normal',
3562
-            'high'
3563
-        );
3564
-    }
3565
-
3566
-
3567
-    /**
3568
-     * Metabox for attendee contact info
3569
-     *
3570
-     * @param WP_Post $post wp post object
3571
-     * @return void attendee contact info ( and form )
3572
-     * @throws EE_Error
3573
-     * @throws InvalidArgumentException
3574
-     * @throws InvalidDataTypeException
3575
-     * @throws InvalidInterfaceException
3576
-     * @throws LogicException
3577
-     * @throws DomainException
3578
-     */
3579
-    public function attendee_contact_info($post)
3580
-    {
3581
-        // get attendee object ( should already have it )
3582
-        $form = $this->getAttendeeContactDetailsMetaboxFormHandler($this->_cpt_model_obj);
3583
-        $form->enqueueStylesAndScripts();
3584
-        echo wp_kses($form->display(), AllowedTags::getWithFormTags());
3585
-    }
3586
-
3587
-
3588
-    /**
3589
-     * Return form handler for the contact details metabox
3590
-     *
3591
-     * @param EE_Attendee $attendee
3592
-     * @return AttendeeContactDetailsMetaboxFormHandler
3593
-     * @throws DomainException
3594
-     * @throws InvalidArgumentException
3595
-     * @throws InvalidDataTypeException
3596
-     * @throws InvalidInterfaceException
3597
-     */
3598
-    protected function getAttendeeContactDetailsMetaboxFormHandler(EE_Attendee $attendee)
3599
-    {
3600
-        return new AttendeeContactDetailsMetaboxFormHandler($attendee, EE_Registry::instance());
3601
-    }
3602
-
3603
-
3604
-    /**
3605
-     * Metabox for attendee details
3606
-     *
3607
-     * @param WP_Post $post wp post object
3608
-     * @throws EE_Error
3609
-     * @throws ReflectionException
3610
-     */
3611
-    public function attendee_address_details($post)
3612
-    {
3613
-        // get attendee object (should already have it)
3614
-        $this->_template_args['attendee']     = $this->_cpt_model_obj;
3615
-        $this->_template_args['state_html']   = EEH_Form_Fields::generate_form_input(
3616
-            new EE_Question_Form_Input(
3617
-                EE_Question::new_instance(
3618
-                    [
3619
-                        'QST_ID'           => 0,
3620
-                        'QST_display_text' => esc_html__('State/Province', 'event_espresso'),
3621
-                        'QST_system'       => 'admin-state',
3622
-                    ]
3623
-                ),
3624
-                EE_Answer::new_instance(
3625
-                    [
3626
-                        'ANS_ID'    => 0,
3627
-                        'ANS_value' => $this->_cpt_model_obj->state_ID(),
3628
-                    ]
3629
-                ),
3630
-                [
3631
-                    'input_id'       => 'STA_ID',
3632
-                    'input_name'     => 'STA_ID',
3633
-                    'input_prefix'   => '',
3634
-                    'append_qstn_id' => false,
3635
-                ]
3636
-            )
3637
-        );
3638
-        $this->_template_args['country_html'] = EEH_Form_Fields::generate_form_input(
3639
-            new EE_Question_Form_Input(
3640
-                EE_Question::new_instance(
3641
-                    [
3642
-                        'QST_ID'           => 0,
3643
-                        'QST_display_text' => esc_html__('Country', 'event_espresso'),
3644
-                        'QST_system'       => 'admin-country',
3645
-                    ]
3646
-                ),
3647
-                EE_Answer::new_instance(
3648
-                    [
3649
-                        'ANS_ID'    => 0,
3650
-                        'ANS_value' => $this->_cpt_model_obj->country_ID(),
3651
-                    ]
3652
-                ),
3653
-                [
3654
-                    'input_id'       => 'CNT_ISO',
3655
-                    'input_name'     => 'CNT_ISO',
3656
-                    'input_prefix'   => '',
3657
-                    'append_qstn_id' => false,
3658
-                ]
3659
-            )
3660
-        );
3661
-        $template                             =
3662
-            REG_TEMPLATE_PATH . 'attendee_address_details_metabox_content.template.php';
3663
-        EEH_Template::display_template($template, $this->_template_args);
3664
-    }
3665
-
3666
-
3667
-    /**
3668
-     * _attendee_details
3669
-     *
3670
-     * @param $post
3671
-     * @return void
3672
-     * @throws DomainException
3673
-     * @throws EE_Error
3674
-     * @throws InvalidArgumentException
3675
-     * @throws InvalidDataTypeException
3676
-     * @throws InvalidInterfaceException
3677
-     * @throws ReflectionException
3678
-     */
3679
-    public function attendee_registrations_meta_box($post)
3680
-    {
3681
-        $this->_template_args['attendee']      = $this->_cpt_model_obj;
3682
-        $this->_template_args['registrations'] = $this->_cpt_model_obj->get_many_related('Registration');
3683
-        $template                              =
3684
-            REG_TEMPLATE_PATH . 'attendee_registrations_main_meta_box.template.php';
3685
-        EEH_Template::display_template($template, $this->_template_args);
3686
-    }
3687
-
3688
-
3689
-    /**
3690
-     * add in the form fields for the attendee edit
3691
-     *
3692
-     * @param WP_Post $post wp post object
3693
-     * @return void echos html for new form.
3694
-     * @throws DomainException
3695
-     */
3696
-    public function after_title_form_fields($post)
3697
-    {
3698
-        if ($post->post_type === 'espresso_attendees') {
3699
-            $template                  = REG_TEMPLATE_PATH . 'attendee_details_after_title_form_fields.template.php';
3700
-            $template_args['attendee'] = $this->_cpt_model_obj;
3701
-            EEH_Template::display_template($template, $template_args);
3702
-        }
3703
-    }
3704
-
3705
-
3706
-    /**
3707
-     * _trash_or_restore_attendee
3708
-     *
3709
-     * @param boolean $trash - whether to move item to trash (TRUE) or restore it (FALSE)
3710
-     * @return void
3711
-     * @throws EE_Error
3712
-     * @throws InvalidArgumentException
3713
-     * @throws InvalidDataTypeException
3714
-     * @throws InvalidInterfaceException
3715
-     */
3716
-    protected function _trash_or_restore_attendees($trash = true)
3717
-    {
3718
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3719
-        $status = $trash ? 'trash' : 'publish';
3720
-        // Checkboxes
3721
-        if ($this->request->requestParamIsSet('checkbox')) {
3722
-            $ATT_IDs = $this->request->getRequestParam('checkbox', [], 'int', true);
3723
-            // if array has more than one element than success message should be plural
3724
-            $success = count($ATT_IDs) > 1 ? 2 : 1;
3725
-            // cycle thru checkboxes
3726
-            foreach ($ATT_IDs as $ATT_ID) {
3727
-                $updated = $this->getAttendeeModel()->update_by_ID(['status' => $status], $ATT_ID);
3728
-                if (! $updated) {
3729
-                    $success = 0;
3730
-                }
3731
-            }
3732
-        } else {
3733
-            // grab single id and delete
3734
-            $ATT_ID = $this->request->getRequestParam('ATT_ID', 0, 'int');
3735
-            // update attendee
3736
-            $success = $this->getAttendeeModel()->update_by_ID(['status' => $status], $ATT_ID) ? 1 : 0;
3737
-        }
3738
-        $what        = $success > 1
3739
-            ? esc_html__('Contacts', 'event_espresso')
3740
-            : esc_html__('Contact', 'event_espresso');
3741
-        $action_desc = $trash
3742
-            ? esc_html__('moved to the trash', 'event_espresso')
3743
-            : esc_html__('restored', 'event_espresso');
3744
-        $this->_redirect_after_action($success, $what, $action_desc, ['action' => 'contact_list']);
3745
-    }
2898
+		}
2899
+		$template_args = [
2900
+			'title'                    => '',
2901
+			'content'                  => '',
2902
+			'step_button_text'         => '',
2903
+			'show_notification_toggle' => false,
2904
+		];
2905
+		// to indicate we're processing a new registration
2906
+		$hidden_fields = [
2907
+			'processing_registration' => [
2908
+				'type'  => 'hidden',
2909
+				'value' => 0,
2910
+			],
2911
+			'event_id'                => [
2912
+				'type'  => 'hidden',
2913
+				'value' => $this->_reg_event->ID(),
2914
+			],
2915
+		];
2916
+		// if the cart is empty then we know we're at step one, so we'll display the ticket selector
2917
+		$cart = EE_Registry::instance()->SSN->cart();
2918
+		$step = ! $cart instanceof EE_Cart ? 'ticket' : 'questions';
2919
+		switch ($step) {
2920
+			case 'ticket':
2921
+				$hidden_fields['processing_registration']['value'] = 1;
2922
+				$template_args['title']                            = esc_html__(
2923
+					'Step One: Select the Ticket for this registration',
2924
+					'event_espresso'
2925
+				);
2926
+				$template_args['content']                          =
2927
+					EED_Ticket_Selector::instance()->display_ticket_selector($this->_reg_event);
2928
+				$template_args['content']                          .= '</div>';
2929
+				$template_args['step_button_text']                 = esc_html__(
2930
+					'Add Tickets and Continue to Registrant Details',
2931
+					'event_espresso'
2932
+				);
2933
+				$template_args['show_notification_toggle']         = false;
2934
+				break;
2935
+			case 'questions':
2936
+				$hidden_fields['processing_registration']['value'] = 2;
2937
+				$template_args['title']                            = esc_html__(
2938
+					'Step Two: Add Registrant Details for this Registration',
2939
+					'event_espresso'
2940
+				);
2941
+				// in theory, we should be able to run EED_SPCO at this point
2942
+				// because the cart should have been set up properly by the first process_reg_step run.
2943
+				$template_args['content']                  =
2944
+					EED_Single_Page_Checkout::registration_checkout_for_admin();
2945
+				$template_args['step_button_text']         = esc_html__(
2946
+					'Save Registration and Continue to Details',
2947
+					'event_espresso'
2948
+				);
2949
+				$template_args['show_notification_toggle'] = true;
2950
+				break;
2951
+		}
2952
+		// we come back to the process_registration_step route.
2953
+		$this->_set_add_edit_form_tags('process_reg_step', $hidden_fields);
2954
+		return EEH_Template::display_template(
2955
+			REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee_step_content.template.php',
2956
+			$template_args,
2957
+			true
2958
+		);
2959
+	}
2960
+
2961
+
2962
+	/**
2963
+	 * set_reg_event
2964
+	 *
2965
+	 * @return bool
2966
+	 * @throws EE_Error
2967
+	 * @throws InvalidArgumentException
2968
+	 * @throws InvalidDataTypeException
2969
+	 * @throws InvalidInterfaceException
2970
+	 */
2971
+	private function _set_reg_event()
2972
+	{
2973
+		if (is_object($this->_reg_event)) {
2974
+			return true;
2975
+		}
2976
+
2977
+		$EVT_ID = $this->request->getRequestParam('event_id', 0, 'int');
2978
+		if (! $EVT_ID) {
2979
+			return false;
2980
+		}
2981
+		$this->_reg_event = $this->getEventModel()->get_one_by_ID($EVT_ID);
2982
+		return true;
2983
+	}
2984
+
2985
+
2986
+	/**
2987
+	 * process_reg_step
2988
+	 *
2989
+	 * @return void
2990
+	 * @throws DomainException
2991
+	 * @throws EE_Error
2992
+	 * @throws InvalidArgumentException
2993
+	 * @throws InvalidDataTypeException
2994
+	 * @throws InvalidInterfaceException
2995
+	 * @throws ReflectionException
2996
+	 * @throws RuntimeException
2997
+	 */
2998
+	public function process_reg_step()
2999
+	{
3000
+		EE_System::do_not_cache();
3001
+		$this->_set_reg_event();
3002
+		/** @var CurrentPage $current_page */
3003
+		$current_page = $this->loader->getShared(CurrentPage::class);
3004
+		$current_page->setEspressoPage(true);
3005
+		$this->request->setRequestParam('uts', time());
3006
+		// what step are we on?
3007
+		$cart = EE_Registry::instance()->SSN->cart();
3008
+		$step = ! $cart instanceof EE_Cart ? 'ticket' : 'questions';
3009
+		// if doing ajax then we need to verify the nonce
3010
+		if ($this->request->isAjax()) {
3011
+			$nonce = $this->request->getRequestParam($this->_req_nonce, '');
3012
+			$this->_verify_nonce($nonce, $this->_req_nonce);
3013
+		}
3014
+		switch ($step) {
3015
+			case 'ticket':
3016
+				// process ticket selection
3017
+				$success = EED_Ticket_Selector::instance()->process_ticket_selections();
3018
+				if ($success) {
3019
+					EE_Error::add_success(
3020
+						esc_html__(
3021
+							'Tickets Selected. Now complete the registration.',
3022
+							'event_espresso'
3023
+						)
3024
+					);
3025
+				} else {
3026
+					$this->request->setRequestParam('step_error', true);
3027
+					$query_args['step_error'] = $this->request->getRequestParam('step_error', true, 'bool');
3028
+				}
3029
+				if ($this->request->isAjax()) {
3030
+					$this->new_registration(); // display next step
3031
+				} else {
3032
+					$query_args = [
3033
+						'action'                  => 'new_registration',
3034
+						'processing_registration' => 1,
3035
+						'event_id'                => $this->_reg_event->ID(),
3036
+						'uts'                     => time(),
3037
+					];
3038
+					$this->_redirect_after_action(
3039
+						false,
3040
+						'',
3041
+						'',
3042
+						$query_args,
3043
+						true
3044
+					);
3045
+				}
3046
+				break;
3047
+			case 'questions':
3048
+				if (! $this->request->requestParamIsSet('txn_reg_status_change[send_notifications]')) {
3049
+					add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_false', 15);
3050
+				}
3051
+				// process registration
3052
+				$transaction = EED_Single_Page_Checkout::instance()->process_registration_from_admin();
3053
+				if ($cart instanceof EE_Cart) {
3054
+					$grand_total = $cart->get_grand_total();
3055
+					if ($grand_total instanceof EE_Line_Item) {
3056
+						$grand_total->save_this_and_descendants_to_txn();
3057
+					}
3058
+				}
3059
+				if (! $transaction instanceof EE_Transaction) {
3060
+					$query_args = [
3061
+						'action'                  => 'new_registration',
3062
+						'processing_registration' => 2,
3063
+						'event_id'                => $this->_reg_event->ID(),
3064
+						'uts'                     => time(),
3065
+					];
3066
+					if ($this->request->isAjax()) {
3067
+						// display registration form again because there are errors (maybe validation?)
3068
+						$this->new_registration();
3069
+						return;
3070
+					}
3071
+					$this->_redirect_after_action(
3072
+						false,
3073
+						'',
3074
+						'',
3075
+						$query_args,
3076
+						true
3077
+					);
3078
+					return;
3079
+				}
3080
+				// maybe update status, and make sure to save transaction if not done already
3081
+				if (! $transaction->update_status_based_on_total_paid()) {
3082
+					$transaction->save();
3083
+				}
3084
+				EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
3085
+				$query_args = [
3086
+					'action'        => 'redirect_to_txn',
3087
+					'TXN_ID'        => $transaction->ID(),
3088
+					'EVT_ID'        => $this->_reg_event->ID(),
3089
+					'event_name'    => urlencode($this->_reg_event->name()),
3090
+					'redirect_from' => 'new_registration',
3091
+				];
3092
+				$this->_redirect_after_action(false, '', '', $query_args, true);
3093
+				break;
3094
+		}
3095
+		// what are you looking here for?  Should be nothing to do at this point.
3096
+	}
3097
+
3098
+
3099
+	/**
3100
+	 * redirect_to_txn
3101
+	 *
3102
+	 * @return void
3103
+	 * @throws EE_Error
3104
+	 * @throws InvalidArgumentException
3105
+	 * @throws InvalidDataTypeException
3106
+	 * @throws InvalidInterfaceException
3107
+	 * @throws ReflectionException
3108
+	 */
3109
+	public function redirect_to_txn()
3110
+	{
3111
+		EE_System::do_not_cache();
3112
+		EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
3113
+		$query_args = [
3114
+			'action' => 'view_transaction',
3115
+			'TXN_ID' => $this->request->getRequestParam('TXN_ID', 0, 'int'),
3116
+			'page'   => 'espresso_transactions',
3117
+		];
3118
+		if ($this->request->requestParamIsSet('EVT_ID') && $this->request->requestParamIsSet('redirect_from')) {
3119
+			$query_args['EVT_ID']        = $this->request->getRequestParam('EVT_ID', 0, 'int');
3120
+			$query_args['event_name']    = urlencode($this->request->getRequestParam('event_name'));
3121
+			$query_args['redirect_from'] = $this->request->getRequestParam('redirect_from');
3122
+		}
3123
+		EE_Error::add_success(
3124
+			esc_html__(
3125
+				'Registration Created.  Please review the transaction and add any payments as necessary',
3126
+				'event_espresso'
3127
+			)
3128
+		);
3129
+		$this->_redirect_after_action(false, '', '', $query_args, true);
3130
+	}
3131
+
3132
+
3133
+	/**
3134
+	 * generates HTML for the Attendee Contact List
3135
+	 *
3136
+	 * @return void
3137
+	 * @throws DomainException
3138
+	 * @throws EE_Error
3139
+	 */
3140
+	protected function _attendee_contact_list_table()
3141
+	{
3142
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3143
+		$this->_search_btn_label = esc_html__('Contacts', 'event_espresso');
3144
+		$this->display_admin_list_table_page_with_no_sidebar();
3145
+	}
3146
+
3147
+
3148
+	/**
3149
+	 * get_attendees
3150
+	 *
3151
+	 * @param      $per_page
3152
+	 * @param bool $count whether to return count or data.
3153
+	 * @param bool $trash
3154
+	 * @return array|int
3155
+	 * @throws EE_Error
3156
+	 * @throws InvalidArgumentException
3157
+	 * @throws InvalidDataTypeException
3158
+	 * @throws InvalidInterfaceException
3159
+	 */
3160
+	public function get_attendees($per_page, $count = false, $trash = false)
3161
+	{
3162
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3163
+		require_once(REG_ADMIN . 'EE_Attendee_Contact_List_Table.class.php');
3164
+		$orderby = $this->request->getRequestParam('orderby');
3165
+		switch ($orderby) {
3166
+			case 'ATT_ID':
3167
+			case 'ATT_fname':
3168
+			case 'ATT_email':
3169
+			case 'ATT_city':
3170
+			case 'STA_ID':
3171
+			case 'CNT_ID':
3172
+				break;
3173
+			case 'Registration_Count':
3174
+				$orderby = 'Registration_Count';
3175
+				break;
3176
+			default:
3177
+				$orderby = 'ATT_lname';
3178
+		}
3179
+		$sort         = $this->request->getRequestParam('order', 'ASC');
3180
+		$current_page = $this->request->getRequestParam('paged', 1, 'int');
3181
+		$per_page     = absint($per_page) ? $per_page : 10;
3182
+		$per_page     = $this->request->getRequestParam('perpage', $per_page, 'int');
3183
+		$_where       = [];
3184
+		$search_term  = $this->request->getRequestParam('s');
3185
+		if ($search_term) {
3186
+			$search_term  = '%' . $search_term . '%';
3187
+			$_where['OR'] = [
3188
+				'Registration.Event.EVT_name'       => ['LIKE', $search_term],
3189
+				'Registration.Event.EVT_desc'       => ['LIKE', $search_term],
3190
+				'Registration.Event.EVT_short_desc' => ['LIKE', $search_term],
3191
+				'ATT_fname'                         => ['LIKE', $search_term],
3192
+				'ATT_lname'                         => ['LIKE', $search_term],
3193
+				'ATT_short_bio'                     => ['LIKE', $search_term],
3194
+				'ATT_email'                         => ['LIKE', $search_term],
3195
+				'ATT_address'                       => ['LIKE', $search_term],
3196
+				'ATT_address2'                      => ['LIKE', $search_term],
3197
+				'ATT_city'                          => ['LIKE', $search_term],
3198
+				'Country.CNT_name'                  => ['LIKE', $search_term],
3199
+				'State.STA_name'                    => ['LIKE', $search_term],
3200
+				'ATT_phone'                         => ['LIKE', $search_term],
3201
+				'Registration.REG_final_price'      => ['LIKE', $search_term],
3202
+				'Registration.REG_code'             => ['LIKE', $search_term],
3203
+				'Registration.REG_group_size'       => ['LIKE', $search_term],
3204
+			];
3205
+		}
3206
+		$offset     = ($current_page - 1) * $per_page;
3207
+		$limit      = $count ? null : [$offset, $per_page];
3208
+		$query_args = [
3209
+			$_where,
3210
+			'extra_selects' => ['Registration_Count' => ['Registration.REG_ID', 'count', '%d']],
3211
+			'limit'         => $limit,
3212
+		];
3213
+		if (! $count) {
3214
+			$query_args['order_by'] = [$orderby => $sort];
3215
+		}
3216
+		$query_args[0]['status'] = $trash ? ['!=', 'publish'] : ['IN', ['publish']];
3217
+		return $count
3218
+			? $this->getAttendeeModel()->count($query_args, 'ATT_ID', true)
3219
+			: $this->getAttendeeModel()->get_all($query_args);
3220
+	}
3221
+
3222
+
3223
+	/**
3224
+	 * This is just taking care of resending the registration confirmation
3225
+	 *
3226
+	 * @return void
3227
+	 * @throws EE_Error
3228
+	 * @throws InvalidArgumentException
3229
+	 * @throws InvalidDataTypeException
3230
+	 * @throws InvalidInterfaceException
3231
+	 * @throws ReflectionException
3232
+	 */
3233
+	protected function _resend_registration()
3234
+	{
3235
+		$this->_process_resend_registration();
3236
+		$REG_ID      = $this->request->getRequestParam('_REG_ID', 0, 'int');
3237
+		$redirect_to = $this->request->getRequestParam('redirect_to');
3238
+		$query_args  = $redirect_to
3239
+			? ['action' => $redirect_to, '_REG_ID' => $REG_ID]
3240
+			: ['action' => 'default'];
3241
+		$this->_redirect_after_action(false, '', '', $query_args, true);
3242
+	}
3243
+
3244
+
3245
+	/**
3246
+	 * Creates a registration report, but accepts the name of a method to use for preparing the query parameters
3247
+	 * to use when selecting registrations
3248
+	 *
3249
+	 * @param string $method_name_for_getting_query_params the name of the method (on this class) to use for preparing
3250
+	 *                                                     the query parameters from the request
3251
+	 * @return void ends the request with a redirect or download
3252
+	 */
3253
+	public function _registrations_report_base($method_name_for_getting_query_params)
3254
+	{
3255
+		$EVT_ID = $this->request->requestParamIsSet('EVT_ID')
3256
+			? $this->request->getRequestParam('EVT_ID', 0, 'int')
3257
+			: null;
3258
+
3259
+		if (! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3260
+			$request_params = $this->request->requestParams();
3261
+			wp_redirect(
3262
+				EE_Admin_Page::add_query_args_and_nonce(
3263
+					[
3264
+						'page'        => 'espresso_batch',
3265
+						'batch'       => 'file',
3266
+						'EVT_ID'      => $EVT_ID,
3267
+						'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\RegistrationsReport'),
3268
+						'return_url'  => urlencode($this->request->getRequestParam('return_url', '', DataType::URL)),
3269
+						'filters'     => urlencode(
3270
+							serialize(
3271
+								$this->$method_name_for_getting_query_params(
3272
+									(isset($request_params['filters']) ? $request_params['filters'] : [])
3273
+								)
3274
+							)
3275
+						),
3276
+						'use_filters' => $this->request->getRequestParam('use_filters', false, DataType::BOOL)
3277
+					]
3278
+				)
3279
+			);
3280
+		} else {
3281
+			// Pull the current request params
3282
+			$request_args = $this->request->requestParams();
3283
+			// Set the required request_args to be passed to the export
3284
+			$required_request_args = [
3285
+				'export' => 'report',
3286
+				'action' => 'registrations_report_for_event',
3287
+				'EVT_ID' => $EVT_ID,
3288
+			];
3289
+			// Merge required request args, overriding any currently set
3290
+			$request_args = array_merge($request_args, $required_request_args);
3291
+			if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3292
+				require_once(EE_CLASSES . 'EE_Export.class.php');
3293
+				$EE_Export = EE_Export::instance($request_args);
3294
+				$EE_Export->export();
3295
+			}
3296
+		}
3297
+	}
3298
+
3299
+
3300
+	/**
3301
+	 * Creates a registration report using only query parameters in the request
3302
+	 *
3303
+	 * @return void
3304
+	 */
3305
+	public function _registrations_report()
3306
+	{
3307
+		$this->_registrations_report_base('_get_registration_query_parameters');
3308
+	}
3309
+
3310
+
3311
+	public function _contact_list_export()
3312
+	{
3313
+		if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3314
+			require_once(EE_CLASSES . 'EE_Export.class.php');
3315
+			$EE_Export = EE_Export::instance($this->request->requestParams());
3316
+			$EE_Export->export_attendees();
3317
+		}
3318
+	}
3319
+
3320
+
3321
+	public function _contact_list_report()
3322
+	{
3323
+		if (! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3324
+			wp_redirect(
3325
+				EE_Admin_Page::add_query_args_and_nonce(
3326
+					[
3327
+						'page'        => 'espresso_batch',
3328
+						'batch'       => 'file',
3329
+						'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\AttendeesReport'),
3330
+						'return_url'  => urlencode($this->request->getRequestParam('return_url', '', 'url')),
3331
+					]
3332
+				)
3333
+			);
3334
+		} else {
3335
+			if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3336
+				require_once(EE_CLASSES . 'EE_Export.class.php');
3337
+				$EE_Export = EE_Export::instance($this->request->requestParams());
3338
+				$EE_Export->report_attendees();
3339
+			}
3340
+		}
3341
+	}
3342
+
3343
+
3344
+
3345
+
3346
+
3347
+	/***************************************        ATTENDEE DETAILS        ***************************************/
3348
+	/**
3349
+	 * This duplicates the attendee object for the given incoming registration id and attendee_id.
3350
+	 *
3351
+	 * @return void
3352
+	 * @throws EE_Error
3353
+	 * @throws InvalidArgumentException
3354
+	 * @throws InvalidDataTypeException
3355
+	 * @throws InvalidInterfaceException
3356
+	 * @throws ReflectionException
3357
+	 */
3358
+	protected function _duplicate_attendee()
3359
+	{
3360
+		$REG_ID = $this->request->getRequestParam('_REG_ID', 0, 'int');
3361
+		$action = $this->request->getRequestParam('return', 'default');
3362
+		// verify we have necessary info
3363
+		if (! $REG_ID) {
3364
+			EE_Error::add_error(
3365
+				esc_html__(
3366
+					'Unable to create the contact for the registration because the required parameters are not present (_REG_ID )',
3367
+					'event_espresso'
3368
+				),
3369
+				__FILE__,
3370
+				__LINE__,
3371
+				__FUNCTION__
3372
+			);
3373
+			$query_args = ['action' => $action];
3374
+			$this->_redirect_after_action('', '', '', $query_args, true);
3375
+		}
3376
+		// okay necessary deets present... let's dupe the incoming attendee and attach to incoming registration.
3377
+		$registration = $this->getRegistrationModel()->get_one_by_ID($REG_ID);
3378
+		if (! $registration instanceof EE_Registration) {
3379
+			throw new RuntimeException(
3380
+				sprintf(
3381
+					esc_html__(
3382
+						'Unable to create the contact because a valid registration could not be retrieved for REG ID: %1$d',
3383
+						'event_espresso'
3384
+					),
3385
+					$REG_ID
3386
+				)
3387
+			);
3388
+		}
3389
+		$attendee = $registration->attendee();
3390
+		// remove relation of existing attendee on registration
3391
+		$registration->_remove_relation_to($attendee, 'Attendee');
3392
+		// new attendee
3393
+		$new_attendee = clone $attendee;
3394
+		$new_attendee->set('ATT_ID', 0);
3395
+		$new_attendee->save();
3396
+		// add new attendee to reg
3397
+		$registration->_add_relation_to($new_attendee, 'Attendee');
3398
+		EE_Error::add_success(
3399
+			esc_html__(
3400
+				'New Contact record created.  Now make any edits you wish to make for this contact.',
3401
+				'event_espresso'
3402
+			)
3403
+		);
3404
+		// redirect to edit page for attendee
3405
+		$query_args = ['post' => $new_attendee->ID(), 'action' => 'edit_attendee'];
3406
+		$this->_redirect_after_action('', '', '', $query_args, true);
3407
+	}
3408
+
3409
+
3410
+	/**
3411
+	 * Callback invoked by parent EE_Admin_CPT class hooked in on `save_post` wp hook.
3412
+	 *
3413
+	 * @param int     $post_id
3414
+	 * @param WP_Post $post
3415
+	 * @throws DomainException
3416
+	 * @throws EE_Error
3417
+	 * @throws InvalidArgumentException
3418
+	 * @throws InvalidDataTypeException
3419
+	 * @throws InvalidInterfaceException
3420
+	 * @throws LogicException
3421
+	 * @throws InvalidFormSubmissionException
3422
+	 * @throws ReflectionException
3423
+	 */
3424
+	protected function _insert_update_cpt_item($post_id, $post)
3425
+	{
3426
+		$success  = true;
3427
+		$attendee = $post instanceof WP_Post && $post->post_type === 'espresso_attendees'
3428
+			? $this->getAttendeeModel()->get_one_by_ID($post_id)
3429
+			: null;
3430
+		// for attendee updates
3431
+		if ($attendee instanceof EE_Attendee) {
3432
+			// note we should only be UPDATING attendees at this point.
3433
+			$fname          = $this->request->getRequestParam('ATT_fname', '');
3434
+			$lname          = $this->request->getRequestParam('ATT_lname', '');
3435
+			$updated_fields = [
3436
+				'ATT_fname'     => $fname,
3437
+				'ATT_lname'     => $lname,
3438
+				'ATT_full_name' => "{$fname} {$lname}",
3439
+				'ATT_address'   => $this->request->getRequestParam('ATT_address', ''),
3440
+				'ATT_address2'  => $this->request->getRequestParam('ATT_address2', ''),
3441
+				'ATT_city'      => $this->request->getRequestParam('ATT_city', ''),
3442
+				'STA_ID'        => $this->request->getRequestParam('STA_ID', ''),
3443
+				'CNT_ISO'       => $this->request->getRequestParam('CNT_ISO', ''),
3444
+				'ATT_zip'       => $this->request->getRequestParam('ATT_zip', ''),
3445
+			];
3446
+			foreach ($updated_fields as $field => $value) {
3447
+				$attendee->set($field, $value);
3448
+			}
3449
+
3450
+			// process contact details metabox form handler (which will also save the attendee)
3451
+			$contact_details_form = $this->getAttendeeContactDetailsMetaboxFormHandler($attendee);
3452
+			$success              = $contact_details_form->process($this->request->requestParams());
3453
+
3454
+			$attendee_update_callbacks = apply_filters(
3455
+				'FHEE__Registrations_Admin_Page__insert_update_cpt_item__attendee_update',
3456
+				[]
3457
+			);
3458
+			foreach ($attendee_update_callbacks as $a_callback) {
3459
+				if (false === call_user_func_array($a_callback, [$attendee, $this->request->requestParams()])) {
3460
+					throw new EE_Error(
3461
+						sprintf(
3462
+							esc_html__(
3463
+								'The %s callback given for the "FHEE__Registrations_Admin_Page__insert_update_cpt_item__attendee_update" filter is not a valid callback.  Please check the spelling.',
3464
+								'event_espresso'
3465
+							),
3466
+							$a_callback
3467
+						)
3468
+					);
3469
+				}
3470
+			}
3471
+		}
3472
+
3473
+		if ($success === false) {
3474
+			EE_Error::add_error(
3475
+				esc_html__(
3476
+					'Something went wrong with updating the meta table data for the registration.',
3477
+					'event_espresso'
3478
+				),
3479
+				__FILE__,
3480
+				__FUNCTION__,
3481
+				__LINE__
3482
+			);
3483
+		}
3484
+	}
3485
+
3486
+
3487
+	public function trash_cpt_item($post_id)
3488
+	{
3489
+	}
3490
+
3491
+
3492
+	public function delete_cpt_item($post_id)
3493
+	{
3494
+	}
3495
+
3496
+
3497
+	public function restore_cpt_item($post_id)
3498
+	{
3499
+	}
3500
+
3501
+
3502
+	protected function _restore_cpt_item($post_id, $revision_id)
3503
+	{
3504
+	}
3505
+
3506
+
3507
+	/**
3508
+	 * @throws EE_Error
3509
+	 * @throws ReflectionException
3510
+	 * @since 4.10.2.p
3511
+	 */
3512
+	public function attendee_editor_metaboxes()
3513
+	{
3514
+		$this->verify_cpt_object();
3515
+		remove_meta_box(
3516
+			'postexcerpt',
3517
+			$this->_cpt_routes[ $this->_req_action ],
3518
+			'normal'
3519
+		);
3520
+		remove_meta_box('commentstatusdiv', $this->_cpt_routes[ $this->_req_action ], 'normal');
3521
+		if (post_type_supports('espresso_attendees', 'excerpt')) {
3522
+			add_meta_box(
3523
+				'postexcerpt',
3524
+				esc_html__('Short Biography', 'event_espresso'),
3525
+				'post_excerpt_meta_box',
3526
+				$this->_cpt_routes[ $this->_req_action ],
3527
+				'normal'
3528
+			);
3529
+		}
3530
+		if (post_type_supports('espresso_attendees', 'comments')) {
3531
+			add_meta_box(
3532
+				'commentsdiv',
3533
+				esc_html__('Notes on the Contact', 'event_espresso'),
3534
+				'post_comment_meta_box',
3535
+				$this->_cpt_routes[ $this->_req_action ],
3536
+				'normal',
3537
+				'core'
3538
+			);
3539
+		}
3540
+		add_meta_box(
3541
+			'attendee_contact_info',
3542
+			esc_html__('Contact Info', 'event_espresso'),
3543
+			[$this, 'attendee_contact_info'],
3544
+			$this->_cpt_routes[ $this->_req_action ],
3545
+			'side',
3546
+			'core'
3547
+		);
3548
+		add_meta_box(
3549
+			'attendee_details_address',
3550
+			esc_html__('Address Details', 'event_espresso'),
3551
+			[$this, 'attendee_address_details'],
3552
+			$this->_cpt_routes[ $this->_req_action ],
3553
+			'normal',
3554
+			'core'
3555
+		);
3556
+		add_meta_box(
3557
+			'attendee_registrations',
3558
+			esc_html__('Registrations for this Contact', 'event_espresso'),
3559
+			[$this, 'attendee_registrations_meta_box'],
3560
+			$this->_cpt_routes[ $this->_req_action ],
3561
+			'normal',
3562
+			'high'
3563
+		);
3564
+	}
3565
+
3566
+
3567
+	/**
3568
+	 * Metabox for attendee contact info
3569
+	 *
3570
+	 * @param WP_Post $post wp post object
3571
+	 * @return void attendee contact info ( and form )
3572
+	 * @throws EE_Error
3573
+	 * @throws InvalidArgumentException
3574
+	 * @throws InvalidDataTypeException
3575
+	 * @throws InvalidInterfaceException
3576
+	 * @throws LogicException
3577
+	 * @throws DomainException
3578
+	 */
3579
+	public function attendee_contact_info($post)
3580
+	{
3581
+		// get attendee object ( should already have it )
3582
+		$form = $this->getAttendeeContactDetailsMetaboxFormHandler($this->_cpt_model_obj);
3583
+		$form->enqueueStylesAndScripts();
3584
+		echo wp_kses($form->display(), AllowedTags::getWithFormTags());
3585
+	}
3586
+
3587
+
3588
+	/**
3589
+	 * Return form handler for the contact details metabox
3590
+	 *
3591
+	 * @param EE_Attendee $attendee
3592
+	 * @return AttendeeContactDetailsMetaboxFormHandler
3593
+	 * @throws DomainException
3594
+	 * @throws InvalidArgumentException
3595
+	 * @throws InvalidDataTypeException
3596
+	 * @throws InvalidInterfaceException
3597
+	 */
3598
+	protected function getAttendeeContactDetailsMetaboxFormHandler(EE_Attendee $attendee)
3599
+	{
3600
+		return new AttendeeContactDetailsMetaboxFormHandler($attendee, EE_Registry::instance());
3601
+	}
3602
+
3603
+
3604
+	/**
3605
+	 * Metabox for attendee details
3606
+	 *
3607
+	 * @param WP_Post $post wp post object
3608
+	 * @throws EE_Error
3609
+	 * @throws ReflectionException
3610
+	 */
3611
+	public function attendee_address_details($post)
3612
+	{
3613
+		// get attendee object (should already have it)
3614
+		$this->_template_args['attendee']     = $this->_cpt_model_obj;
3615
+		$this->_template_args['state_html']   = EEH_Form_Fields::generate_form_input(
3616
+			new EE_Question_Form_Input(
3617
+				EE_Question::new_instance(
3618
+					[
3619
+						'QST_ID'           => 0,
3620
+						'QST_display_text' => esc_html__('State/Province', 'event_espresso'),
3621
+						'QST_system'       => 'admin-state',
3622
+					]
3623
+				),
3624
+				EE_Answer::new_instance(
3625
+					[
3626
+						'ANS_ID'    => 0,
3627
+						'ANS_value' => $this->_cpt_model_obj->state_ID(),
3628
+					]
3629
+				),
3630
+				[
3631
+					'input_id'       => 'STA_ID',
3632
+					'input_name'     => 'STA_ID',
3633
+					'input_prefix'   => '',
3634
+					'append_qstn_id' => false,
3635
+				]
3636
+			)
3637
+		);
3638
+		$this->_template_args['country_html'] = EEH_Form_Fields::generate_form_input(
3639
+			new EE_Question_Form_Input(
3640
+				EE_Question::new_instance(
3641
+					[
3642
+						'QST_ID'           => 0,
3643
+						'QST_display_text' => esc_html__('Country', 'event_espresso'),
3644
+						'QST_system'       => 'admin-country',
3645
+					]
3646
+				),
3647
+				EE_Answer::new_instance(
3648
+					[
3649
+						'ANS_ID'    => 0,
3650
+						'ANS_value' => $this->_cpt_model_obj->country_ID(),
3651
+					]
3652
+				),
3653
+				[
3654
+					'input_id'       => 'CNT_ISO',
3655
+					'input_name'     => 'CNT_ISO',
3656
+					'input_prefix'   => '',
3657
+					'append_qstn_id' => false,
3658
+				]
3659
+			)
3660
+		);
3661
+		$template                             =
3662
+			REG_TEMPLATE_PATH . 'attendee_address_details_metabox_content.template.php';
3663
+		EEH_Template::display_template($template, $this->_template_args);
3664
+	}
3665
+
3666
+
3667
+	/**
3668
+	 * _attendee_details
3669
+	 *
3670
+	 * @param $post
3671
+	 * @return void
3672
+	 * @throws DomainException
3673
+	 * @throws EE_Error
3674
+	 * @throws InvalidArgumentException
3675
+	 * @throws InvalidDataTypeException
3676
+	 * @throws InvalidInterfaceException
3677
+	 * @throws ReflectionException
3678
+	 */
3679
+	public function attendee_registrations_meta_box($post)
3680
+	{
3681
+		$this->_template_args['attendee']      = $this->_cpt_model_obj;
3682
+		$this->_template_args['registrations'] = $this->_cpt_model_obj->get_many_related('Registration');
3683
+		$template                              =
3684
+			REG_TEMPLATE_PATH . 'attendee_registrations_main_meta_box.template.php';
3685
+		EEH_Template::display_template($template, $this->_template_args);
3686
+	}
3687
+
3688
+
3689
+	/**
3690
+	 * add in the form fields for the attendee edit
3691
+	 *
3692
+	 * @param WP_Post $post wp post object
3693
+	 * @return void echos html for new form.
3694
+	 * @throws DomainException
3695
+	 */
3696
+	public function after_title_form_fields($post)
3697
+	{
3698
+		if ($post->post_type === 'espresso_attendees') {
3699
+			$template                  = REG_TEMPLATE_PATH . 'attendee_details_after_title_form_fields.template.php';
3700
+			$template_args['attendee'] = $this->_cpt_model_obj;
3701
+			EEH_Template::display_template($template, $template_args);
3702
+		}
3703
+	}
3704
+
3705
+
3706
+	/**
3707
+	 * _trash_or_restore_attendee
3708
+	 *
3709
+	 * @param boolean $trash - whether to move item to trash (TRUE) or restore it (FALSE)
3710
+	 * @return void
3711
+	 * @throws EE_Error
3712
+	 * @throws InvalidArgumentException
3713
+	 * @throws InvalidDataTypeException
3714
+	 * @throws InvalidInterfaceException
3715
+	 */
3716
+	protected function _trash_or_restore_attendees($trash = true)
3717
+	{
3718
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3719
+		$status = $trash ? 'trash' : 'publish';
3720
+		// Checkboxes
3721
+		if ($this->request->requestParamIsSet('checkbox')) {
3722
+			$ATT_IDs = $this->request->getRequestParam('checkbox', [], 'int', true);
3723
+			// if array has more than one element than success message should be plural
3724
+			$success = count($ATT_IDs) > 1 ? 2 : 1;
3725
+			// cycle thru checkboxes
3726
+			foreach ($ATT_IDs as $ATT_ID) {
3727
+				$updated = $this->getAttendeeModel()->update_by_ID(['status' => $status], $ATT_ID);
3728
+				if (! $updated) {
3729
+					$success = 0;
3730
+				}
3731
+			}
3732
+		} else {
3733
+			// grab single id and delete
3734
+			$ATT_ID = $this->request->getRequestParam('ATT_ID', 0, 'int');
3735
+			// update attendee
3736
+			$success = $this->getAttendeeModel()->update_by_ID(['status' => $status], $ATT_ID) ? 1 : 0;
3737
+		}
3738
+		$what        = $success > 1
3739
+			? esc_html__('Contacts', 'event_espresso')
3740
+			: esc_html__('Contact', 'event_espresso');
3741
+		$action_desc = $trash
3742
+			? esc_html__('moved to the trash', 'event_espresso')
3743
+			: esc_html__('restored', 'event_espresso');
3744
+		$this->_redirect_after_action($success, $what, $action_desc, ['action' => 'contact_list']);
3745
+	}
3746 3746
 }
Please login to merge, or discard this patch.