Completed
Branch master (d3e57f)
by
unknown
52:16 queued 43:59
created
modules/ticket_selector/DisplayTicketSelector.php 3 patches
Doc Comments   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -761,7 +761,7 @@
 block discarded – undo
761 761
      * handleMissingEvent
762 762
      * Returns either false or an error to display when no valid event is passed.
763 763
      *
764
-     * @return mixed
764
+     * @return false|string
765 765
      * @throws ExceptionStackTraceDisplay
766 766
      * @throws InvalidInterfaceException
767 767
      */
Please login to merge, or discard this patch.
Indentation   +761 added lines, -761 removed lines patch added patch discarded remove patch
@@ -34,768 +34,768 @@
 block discarded – undo
34 34
 class DisplayTicketSelector
35 35
 {
36 36
 
37
-    /**
38
-     * event that ticket selector is being generated for
39
-     *
40
-     * @access protected
41
-     * @var EE_Event $event
42
-     */
43
-    protected $event;
44
-
45
-    /**
46
-     * Used to flag when the ticket selector is being called from an external iframe.
47
-     *
48
-     * @var bool $iframe
49
-     */
50
-    protected $iframe = false;
51
-
52
-    /**
53
-     * max attendees that can register for event at one time
54
-     *
55
-     * @var int $max_attendees
56
-     */
57
-    private $max_attendees = EE_INF;
58
-
59
-    /**
60
-     * @var string $date_format
61
-     */
62
-    private $date_format;
63
-
64
-    /**
65
-     * @var string $time_format
66
-     */
67
-    private $time_format;
68
-
69
-    /**
70
-     * @var boolean $display_full_ui
71
-     */
72
-    private $display_full_ui;
73
-
74
-
75
-    /**
76
-     * DisplayTicketSelector constructor.
77
-     *
78
-     * @param bool $iframe
79
-     */
80
-    public function __construct($iframe = false)
81
-    {
82
-        $this->iframe = $iframe;
83
-        $this->date_format = apply_filters(
84
-            'FHEE__EED_Ticket_Selector__display_ticket_selector__date_format',
85
-            get_option('date_format')
86
-        );
87
-        $this->time_format = apply_filters(
88
-            'FHEE__EED_Ticket_Selector__display_ticket_selector__time_format',
89
-            get_option('time_format')
90
-        );
91
-    }
92
-
93
-
94
-    /**
95
-     * @return bool
96
-     */
97
-    public function isIframe()
98
-    {
99
-        return $this->iframe;
100
-    }
101
-
102
-
103
-    /**
104
-     * @param boolean $iframe
105
-     */
106
-    public function setIframe($iframe = true)
107
-    {
108
-        $this->iframe = filter_var($iframe, FILTER_VALIDATE_BOOLEAN);
109
-    }
110
-
111
-
112
-    /**
113
-     * finds and sets the \EE_Event object for use throughout class
114
-     *
115
-     * @param mixed $event
116
-     * @return bool
117
-     * @throws EE_Error
118
-     * @throws InvalidDataTypeException
119
-     * @throws InvalidInterfaceException
120
-     * @throws InvalidArgumentException
121
-     */
122
-    protected function setEvent($event = null)
123
-    {
124
-        if ($event === null) {
125
-            global $post;
126
-            $event = $post;
127
-        }
128
-        if ($event instanceof EE_Event) {
129
-            $this->event = $event;
130
-        } elseif ($event instanceof WP_Post) {
131
-            if (isset($event->EE_Event) && $event->EE_Event instanceof EE_Event) {
132
-                $this->event = $event->EE_Event;
133
-            } elseif ($event->post_type === 'espresso_events') {
134
-                $event->EE_Event = EEM_Event::instance()->instantiate_class_from_post_object($event);
135
-                $this->event = $event->EE_Event;
136
-            }
137
-        } else {
138
-            $user_msg = __('No Event object or an invalid Event object was supplied.', 'event_espresso');
139
-            $dev_msg = $user_msg . __(
140
-                'In order to generate a ticket selector, please ensure you are passing either an EE_Event object or a WP_Post object of the post type "espresso_event" to the EE_Ticket_Selector class constructor.',
141
-                'event_espresso'
142
-            );
143
-            EE_Error::add_error($user_msg . '||' . $dev_msg, __FILE__, __FUNCTION__, __LINE__);
144
-            return false;
145
-        }
146
-        return true;
147
-    }
148
-
149
-
150
-    /**
151
-     * @return int
152
-     */
153
-    public function getMaxAttendees()
154
-    {
155
-        return $this->max_attendees;
156
-    }
157
-
158
-
159
-    /**
160
-     * @param int $max_attendees
161
-     */
162
-    public function setMaxAttendees($max_attendees)
163
-    {
164
-        $this->max_attendees = absint(
165
-            apply_filters(
166
-                'FHEE__EE_Ticket_Selector__display_ticket_selector__max_tickets',
167
-                $max_attendees
168
-            )
169
-        );
170
-    }
171
-
172
-
173
-    /**
174
-     * Returns whether or not the full ticket selector should be shown or not.
175
-     * Currently, it displays on the frontend (including ajax requests) but not the backend
176
-     *
177
-     * @return bool
178
-     */
179
-    private function display_full_ui()
180
-    {
181
-        if ($this->display_full_ui === null) {
182
-            $this->display_full_ui = ! is_admin() || (defined('DOING_AJAX') && DOING_AJAX);
183
-        }
184
-        return $this->display_full_ui;
185
-    }
186
-
187
-
188
-    /**
189
-     * creates buttons for selecting number of attendees for an event
190
-     *
191
-     * @param WP_Post|int $event
192
-     * @param bool        $view_details
193
-     * @return string
194
-     * @throws EE_Error
195
-     * @throws InvalidArgumentException
196
-     * @throws InvalidDataTypeException
197
-     * @throws InvalidInterfaceException
198
-     */
199
-    public function display($event = null, $view_details = false)
200
-    {
201
-        // reset filter for displaying submit button
202
-        remove_filter('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_true');
203
-        // poke and prod incoming event till it tells us what it is
204
-        if (! $this->setEvent($event)) {
205
-            return $this->handleMissingEvent();
206
-        }
207
-        // is the event expired ?
208
-        $template_args['event_is_expired'] = ! is_admin() ? $this->event->is_expired() : false;
209
-        if ($template_args['event_is_expired']) {
210
-            return is_single() ? $this->expiredEventMessage() : $this->expiredEventMessage() . $this->displayViewDetailsButton();
211
-        }
212
-        // begin gathering template arguments by getting event status
213
-        $template_args = array('event_status' => $this->event->get_active_status());
214
-        if ($this->activeEventAndShowTicketSelector(
215
-            $event,
216
-            $template_args['event_status'],
217
-            $view_details
218
-        )) {
219
-            return ! is_single() ? $this->displayViewDetailsButton() : '';
220
-        }
221
-        // filter the maximum qty that can appear in the Ticket Selector qty dropdowns
222
-        $this->setMaxAttendees($this->event->additional_limit());
223
-        if ($this->getMaxAttendees() < 1) {
224
-            return $this->ticketSalesClosedMessage();
225
-        }
226
-        // get all tickets for this event ordered by the datetime
227
-        $tickets = $this->getTickets();
228
-        if (count($tickets) < 1) {
229
-            return $this->noTicketAvailableMessage();
230
-        }
231
-        // redirecting to another site for registration ??
232
-        $external_url = (string) $this->event->external_url()
233
-            && $this->event->external_url() !== get_the_permalink()
234
-            ? $this->event->external_url()
235
-            : '';
236
-        // if redirecting to another site for registration, then we don't load the TS
237
-        $ticket_selector = $external_url
238
-            ? $this->externalEventRegistration()
239
-            : $this->loadTicketSelector($tickets, $template_args);
240
-        // now set up the form (but not for the admin)
241
-        $ticket_selector = $this->display_full_ui()
242
-            ? $this->formOpen($this->event->ID(), $external_url) . $ticket_selector
243
-            : $ticket_selector;
244
-        // submit button and form close tag
245
-        $ticket_selector .= $this->display_full_ui() ? $this->displaySubmitButton($external_url) : '';
246
-        return $ticket_selector;
247
-    }
248
-
249
-
250
-    /**
251
-     * displayTicketSelector
252
-     * examines the event properties and determines whether a Ticket Selector should be displayed
253
-     *
254
-     * @param WP_Post|int $event
255
-     * @param string      $_event_active_status
256
-     * @param bool        $view_details
257
-     * @return bool
258
-     * @throws EE_Error
259
-     */
260
-    protected function activeEventAndShowTicketSelector($event, $_event_active_status, $view_details)
261
-    {
262
-        $event_post = $this->event instanceof EE_Event ? $this->event->ID() : $event;
263
-        return $this->display_full_ui()
264
-               && (
265
-                   ! $this->event->display_ticket_selector()
266
-                   || $view_details
267
-                   || post_password_required($event_post)
268
-                   || (
269
-                       $_event_active_status !== EE_Datetime::active
270
-                       && $_event_active_status !== EE_Datetime::upcoming
271
-                       && $_event_active_status !== EE_Datetime::sold_out
272
-                       && ! (
273
-                           $_event_active_status === EE_Datetime::inactive
274
-                           && is_user_logged_in()
275
-                       )
276
-                   )
277
-               );
278
-    }
279
-
280
-
281
-    /**
282
-     * noTicketAvailableMessage
283
-     * notice displayed if event is expired
284
-     *
285
-     * @return string
286
-     * @throws EE_Error
287
-     */
288
-    protected function expiredEventMessage()
289
-    {
290
-        return '<div class="ee-event-expired-notice"><span class="important-notice">' . esc_html__(
291
-            'We\'re sorry, but all tickets sales have ended because the event is expired.',
292
-            'event_espresso'
293
-        ) . '</span></div><!-- .ee-event-expired-notice -->';
294
-    }
295
-
296
-
297
-    /**
298
-     * noTicketAvailableMessage
299
-     * notice displayed if event has no more tickets available
300
-     *
301
-     * @return string
302
-     * @throws EE_Error
303
-     */
304
-    protected function noTicketAvailableMessage()
305
-    {
306
-        $no_ticket_available_msg = esc_html__('We\'re sorry, but all ticket sales have ended.', 'event_espresso');
307
-        if (current_user_can('edit_post', $this->event->ID())) {
308
-            $no_ticket_available_msg .= sprintf(
309
-                esc_html__(
310
-                    '%1$sNote to Event Admin:%2$sNo tickets were found for this event. This effectively turns off ticket sales. Please ensure that at least one ticket is available for if you want people to be able to register.%3$s(click to edit this event)%4$s',
311
-                    'event_espresso'
312
-                ),
313
-                '<div class="ee-attention" style="text-align: left;"><b>',
314
-                '</b><br />',
315
-                '<span class="edit-link"><a class="post-edit-link" href="'
316
-                . get_edit_post_link($this->event->ID())
317
-                . '">',
318
-                '</a></span></div><!-- .ee-attention noTicketAvailableMessage -->'
319
-            );
320
-        }
321
-        return '
37
+	/**
38
+	 * event that ticket selector is being generated for
39
+	 *
40
+	 * @access protected
41
+	 * @var EE_Event $event
42
+	 */
43
+	protected $event;
44
+
45
+	/**
46
+	 * Used to flag when the ticket selector is being called from an external iframe.
47
+	 *
48
+	 * @var bool $iframe
49
+	 */
50
+	protected $iframe = false;
51
+
52
+	/**
53
+	 * max attendees that can register for event at one time
54
+	 *
55
+	 * @var int $max_attendees
56
+	 */
57
+	private $max_attendees = EE_INF;
58
+
59
+	/**
60
+	 * @var string $date_format
61
+	 */
62
+	private $date_format;
63
+
64
+	/**
65
+	 * @var string $time_format
66
+	 */
67
+	private $time_format;
68
+
69
+	/**
70
+	 * @var boolean $display_full_ui
71
+	 */
72
+	private $display_full_ui;
73
+
74
+
75
+	/**
76
+	 * DisplayTicketSelector constructor.
77
+	 *
78
+	 * @param bool $iframe
79
+	 */
80
+	public function __construct($iframe = false)
81
+	{
82
+		$this->iframe = $iframe;
83
+		$this->date_format = apply_filters(
84
+			'FHEE__EED_Ticket_Selector__display_ticket_selector__date_format',
85
+			get_option('date_format')
86
+		);
87
+		$this->time_format = apply_filters(
88
+			'FHEE__EED_Ticket_Selector__display_ticket_selector__time_format',
89
+			get_option('time_format')
90
+		);
91
+	}
92
+
93
+
94
+	/**
95
+	 * @return bool
96
+	 */
97
+	public function isIframe()
98
+	{
99
+		return $this->iframe;
100
+	}
101
+
102
+
103
+	/**
104
+	 * @param boolean $iframe
105
+	 */
106
+	public function setIframe($iframe = true)
107
+	{
108
+		$this->iframe = filter_var($iframe, FILTER_VALIDATE_BOOLEAN);
109
+	}
110
+
111
+
112
+	/**
113
+	 * finds and sets the \EE_Event object for use throughout class
114
+	 *
115
+	 * @param mixed $event
116
+	 * @return bool
117
+	 * @throws EE_Error
118
+	 * @throws InvalidDataTypeException
119
+	 * @throws InvalidInterfaceException
120
+	 * @throws InvalidArgumentException
121
+	 */
122
+	protected function setEvent($event = null)
123
+	{
124
+		if ($event === null) {
125
+			global $post;
126
+			$event = $post;
127
+		}
128
+		if ($event instanceof EE_Event) {
129
+			$this->event = $event;
130
+		} elseif ($event instanceof WP_Post) {
131
+			if (isset($event->EE_Event) && $event->EE_Event instanceof EE_Event) {
132
+				$this->event = $event->EE_Event;
133
+			} elseif ($event->post_type === 'espresso_events') {
134
+				$event->EE_Event = EEM_Event::instance()->instantiate_class_from_post_object($event);
135
+				$this->event = $event->EE_Event;
136
+			}
137
+		} else {
138
+			$user_msg = __('No Event object or an invalid Event object was supplied.', 'event_espresso');
139
+			$dev_msg = $user_msg . __(
140
+				'In order to generate a ticket selector, please ensure you are passing either an EE_Event object or a WP_Post object of the post type "espresso_event" to the EE_Ticket_Selector class constructor.',
141
+				'event_espresso'
142
+			);
143
+			EE_Error::add_error($user_msg . '||' . $dev_msg, __FILE__, __FUNCTION__, __LINE__);
144
+			return false;
145
+		}
146
+		return true;
147
+	}
148
+
149
+
150
+	/**
151
+	 * @return int
152
+	 */
153
+	public function getMaxAttendees()
154
+	{
155
+		return $this->max_attendees;
156
+	}
157
+
158
+
159
+	/**
160
+	 * @param int $max_attendees
161
+	 */
162
+	public function setMaxAttendees($max_attendees)
163
+	{
164
+		$this->max_attendees = absint(
165
+			apply_filters(
166
+				'FHEE__EE_Ticket_Selector__display_ticket_selector__max_tickets',
167
+				$max_attendees
168
+			)
169
+		);
170
+	}
171
+
172
+
173
+	/**
174
+	 * Returns whether or not the full ticket selector should be shown or not.
175
+	 * Currently, it displays on the frontend (including ajax requests) but not the backend
176
+	 *
177
+	 * @return bool
178
+	 */
179
+	private function display_full_ui()
180
+	{
181
+		if ($this->display_full_ui === null) {
182
+			$this->display_full_ui = ! is_admin() || (defined('DOING_AJAX') && DOING_AJAX);
183
+		}
184
+		return $this->display_full_ui;
185
+	}
186
+
187
+
188
+	/**
189
+	 * creates buttons for selecting number of attendees for an event
190
+	 *
191
+	 * @param WP_Post|int $event
192
+	 * @param bool        $view_details
193
+	 * @return string
194
+	 * @throws EE_Error
195
+	 * @throws InvalidArgumentException
196
+	 * @throws InvalidDataTypeException
197
+	 * @throws InvalidInterfaceException
198
+	 */
199
+	public function display($event = null, $view_details = false)
200
+	{
201
+		// reset filter for displaying submit button
202
+		remove_filter('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_true');
203
+		// poke and prod incoming event till it tells us what it is
204
+		if (! $this->setEvent($event)) {
205
+			return $this->handleMissingEvent();
206
+		}
207
+		// is the event expired ?
208
+		$template_args['event_is_expired'] = ! is_admin() ? $this->event->is_expired() : false;
209
+		if ($template_args['event_is_expired']) {
210
+			return is_single() ? $this->expiredEventMessage() : $this->expiredEventMessage() . $this->displayViewDetailsButton();
211
+		}
212
+		// begin gathering template arguments by getting event status
213
+		$template_args = array('event_status' => $this->event->get_active_status());
214
+		if ($this->activeEventAndShowTicketSelector(
215
+			$event,
216
+			$template_args['event_status'],
217
+			$view_details
218
+		)) {
219
+			return ! is_single() ? $this->displayViewDetailsButton() : '';
220
+		}
221
+		// filter the maximum qty that can appear in the Ticket Selector qty dropdowns
222
+		$this->setMaxAttendees($this->event->additional_limit());
223
+		if ($this->getMaxAttendees() < 1) {
224
+			return $this->ticketSalesClosedMessage();
225
+		}
226
+		// get all tickets for this event ordered by the datetime
227
+		$tickets = $this->getTickets();
228
+		if (count($tickets) < 1) {
229
+			return $this->noTicketAvailableMessage();
230
+		}
231
+		// redirecting to another site for registration ??
232
+		$external_url = (string) $this->event->external_url()
233
+			&& $this->event->external_url() !== get_the_permalink()
234
+			? $this->event->external_url()
235
+			: '';
236
+		// if redirecting to another site for registration, then we don't load the TS
237
+		$ticket_selector = $external_url
238
+			? $this->externalEventRegistration()
239
+			: $this->loadTicketSelector($tickets, $template_args);
240
+		// now set up the form (but not for the admin)
241
+		$ticket_selector = $this->display_full_ui()
242
+			? $this->formOpen($this->event->ID(), $external_url) . $ticket_selector
243
+			: $ticket_selector;
244
+		// submit button and form close tag
245
+		$ticket_selector .= $this->display_full_ui() ? $this->displaySubmitButton($external_url) : '';
246
+		return $ticket_selector;
247
+	}
248
+
249
+
250
+	/**
251
+	 * displayTicketSelector
252
+	 * examines the event properties and determines whether a Ticket Selector should be displayed
253
+	 *
254
+	 * @param WP_Post|int $event
255
+	 * @param string      $_event_active_status
256
+	 * @param bool        $view_details
257
+	 * @return bool
258
+	 * @throws EE_Error
259
+	 */
260
+	protected function activeEventAndShowTicketSelector($event, $_event_active_status, $view_details)
261
+	{
262
+		$event_post = $this->event instanceof EE_Event ? $this->event->ID() : $event;
263
+		return $this->display_full_ui()
264
+			   && (
265
+				   ! $this->event->display_ticket_selector()
266
+				   || $view_details
267
+				   || post_password_required($event_post)
268
+				   || (
269
+					   $_event_active_status !== EE_Datetime::active
270
+					   && $_event_active_status !== EE_Datetime::upcoming
271
+					   && $_event_active_status !== EE_Datetime::sold_out
272
+					   && ! (
273
+						   $_event_active_status === EE_Datetime::inactive
274
+						   && is_user_logged_in()
275
+					   )
276
+				   )
277
+			   );
278
+	}
279
+
280
+
281
+	/**
282
+	 * noTicketAvailableMessage
283
+	 * notice displayed if event is expired
284
+	 *
285
+	 * @return string
286
+	 * @throws EE_Error
287
+	 */
288
+	protected function expiredEventMessage()
289
+	{
290
+		return '<div class="ee-event-expired-notice"><span class="important-notice">' . esc_html__(
291
+			'We\'re sorry, but all tickets sales have ended because the event is expired.',
292
+			'event_espresso'
293
+		) . '</span></div><!-- .ee-event-expired-notice -->';
294
+	}
295
+
296
+
297
+	/**
298
+	 * noTicketAvailableMessage
299
+	 * notice displayed if event has no more tickets available
300
+	 *
301
+	 * @return string
302
+	 * @throws EE_Error
303
+	 */
304
+	protected function noTicketAvailableMessage()
305
+	{
306
+		$no_ticket_available_msg = esc_html__('We\'re sorry, but all ticket sales have ended.', 'event_espresso');
307
+		if (current_user_can('edit_post', $this->event->ID())) {
308
+			$no_ticket_available_msg .= sprintf(
309
+				esc_html__(
310
+					'%1$sNote to Event Admin:%2$sNo tickets were found for this event. This effectively turns off ticket sales. Please ensure that at least one ticket is available for if you want people to be able to register.%3$s(click to edit this event)%4$s',
311
+					'event_espresso'
312
+				),
313
+				'<div class="ee-attention" style="text-align: left;"><b>',
314
+				'</b><br />',
315
+				'<span class="edit-link"><a class="post-edit-link" href="'
316
+				. get_edit_post_link($this->event->ID())
317
+				. '">',
318
+				'</a></span></div><!-- .ee-attention noTicketAvailableMessage -->'
319
+			);
320
+		}
321
+		return '
322 322
             <div class="ee-event-expired-notice">
323 323
                 <span class="important-notice">' . $no_ticket_available_msg . '</span>
324 324
             </div><!-- .ee-event-expired-notice -->';
325
-    }
326
-
327
-
328
-    /**
329
-     * ticketSalesClosed
330
-     * notice displayed if event ticket sales are turned off
331
-     *
332
-     * @return string
333
-     * @throws EE_Error
334
-     */
335
-    protected function ticketSalesClosedMessage()
336
-    {
337
-        $sales_closed_msg = esc_html__(
338
-            'We\'re sorry, but ticket sales have been closed at this time. Please check back again later.',
339
-            'event_espresso'
340
-        );
341
-        if (current_user_can('edit_post', $this->event->ID())) {
342
-            $sales_closed_msg .= sprintf(
343
-                esc_html__(
344
-                    '%sNote to Event Admin:%sThe "Maximum number of tickets allowed per order for this event" in the Event Registration Options has been set to "0". This effectively turns off ticket sales. %s(click to edit this event)%s',
345
-                    'event_espresso'
346
-                ),
347
-                '<div class="ee-attention" style="text-align: left;"><b>',
348
-                '</b><br />',
349
-                '<span class="edit-link"><a class="post-edit-link" href="'
350
-                . get_edit_post_link($this->event->ID())
351
-                . '">',
352
-                '</a></span></div><!-- .ee-attention ticketSalesClosedMessage -->'
353
-            );
354
-        }
355
-        return '<p><span class="important-notice">' . $sales_closed_msg . '</span></p>';
356
-    }
357
-
358
-
359
-    /**
360
-     * getTickets
361
-     *
362
-     * @return \EE_Base_Class[]|\EE_Ticket[]
363
-     * @throws EE_Error
364
-     * @throws InvalidDataTypeException
365
-     * @throws InvalidInterfaceException
366
-     * @throws InvalidArgumentException
367
-     */
368
-    protected function getTickets()
369
-    {
370
-        $show_expired_tickets = is_admin() || (
371
-            EE_Registry::instance()->CFG->template_settings->EED_Ticket_Selector instanceof EE_Ticket_Selector_Config
372
-            && EE_Registry::instance()->CFG->template_settings->EED_Ticket_Selector->show_expired_tickets
373
-        );
374
-
375
-        $ticket_query_args = array(
376
-            array('Datetime.EVT_ID' => $this->event->ID()),
377
-            'order_by' => array(
378
-                'TKT_order'              => 'ASC',
379
-                'TKT_required'           => 'DESC',
380
-                'TKT_start_date'         => 'ASC',
381
-                'TKT_end_date'           => 'ASC',
382
-                'Datetime.DTT_EVT_start' => 'DESC',
383
-            ),
384
-        );
385
-        if (! $show_expired_tickets) {
386
-            // use the correct applicable time query depending on what version of core is being run.
387
-            $current_time = method_exists('EEM_Datetime', 'current_time_for_query')
388
-                ? time()
389
-                : current_time('timestamp');
390
-            $ticket_query_args[0]['TKT_end_date'] = array('>', $current_time);
391
-        }
392
-        return EEM_Ticket::instance()->get_all($ticket_query_args);
393
-    }
394
-
395
-
396
-    /**
397
-     * loadTicketSelector
398
-     * begins to assemble template arguments
399
-     * and decides whether to load a "simple" ticket selector, or the standard
400
-     *
401
-     * @param \EE_Ticket[] $tickets
402
-     * @param array        $template_args
403
-     * @return string
404
-     * @throws EE_Error
405
-     */
406
-    protected function loadTicketSelector(array $tickets, array $template_args)
407
-    {
408
-        $template_args['event'] = $this->event;
409
-        $template_args['EVT_ID'] = $this->event->ID();
410
-        $template_args['event_is_expired'] = $this->event->is_expired();
411
-        $template_args['max_atndz'] = $this->getMaxAttendees();
412
-        $template_args['date_format'] = $this->date_format;
413
-        $template_args['time_format'] = $this->time_format;
414
-        /**
415
-         * Filters the anchor ID used when redirecting to the Ticket Selector if no quantity selected
416
-         *
417
-         * @since 4.9.13
418
-         * @param     string  '#tkt-slctr-tbl-' . $EVT_ID The html ID to anchor to
419
-         * @param int $EVT_ID The Event ID
420
-         */
421
-        $template_args['anchor_id'] = apply_filters(
422
-            'FHEE__EE_Ticket_Selector__redirect_anchor_id',
423
-            '#tkt-slctr-tbl-' . $this->event->ID(),
424
-            $this->event->ID()
425
-        );
426
-        $template_args['tickets'] = $tickets;
427
-        $template_args['ticket_count'] = count($tickets);
428
-        $ticket_selector = $this->simpleTicketSelector($tickets, $template_args);
429
-        return $ticket_selector instanceof TicketSelectorSimple
430
-            ? $ticket_selector
431
-            : new TicketSelectorStandard(
432
-                $this->event,
433
-                $tickets,
434
-                $this->getMaxAttendees(),
435
-                $template_args,
436
-                $this->date_format,
437
-                $this->time_format
438
-            );
439
-    }
440
-
441
-
442
-    /**
443
-     * simpleTicketSelector
444
-     * there's one ticket, and max attendees is set to one,
445
-     * so if the event is free, then this is a "simple" ticket selector
446
-     * a.k.a. "Dude Where's my Ticket Selector?"
447
-     *
448
-     * @param \EE_Ticket[] $tickets
449
-     * @param array        $template_args
450
-     * @return string
451
-     * @throws EE_Error
452
-     */
453
-    protected function simpleTicketSelector($tickets, array $template_args)
454
-    {
455
-        // if there is only ONE ticket with a max qty of ONE
456
-        if (count($tickets) > 1 || $this->getMaxAttendees() !== 1) {
457
-            return '';
458
-        }
459
-        /** @var \EE_Ticket $ticket */
460
-        $ticket = reset($tickets);
461
-        // if the ticket is free... then not much need for the ticket selector
462
-        if (apply_filters(
463
-            'FHEE__ticket_selector_chart_template__hide_ticket_selector',
464
-            $ticket->is_free(),
465
-            $this->event->ID()
466
-        )) {
467
-            return new TicketSelectorSimple(
468
-                $this->event,
469
-                $ticket,
470
-                $this->getMaxAttendees(),
471
-                $template_args
472
-            );
473
-        }
474
-        return '';
475
-    }
476
-
477
-
478
-    /**
479
-     * externalEventRegistration
480
-     *
481
-     * @return string
482
-     */
483
-    public function externalEventRegistration()
484
-    {
485
-        // if not we still need to trigger the display of the submit button
486
-        add_filter('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_true');
487
-        // display notice to admin that registration is external
488
-        return $this->display_full_ui()
489
-            ? esc_html__(
490
-                'Registration is at an external URL for this event.',
491
-                'event_espresso'
492
-            )
493
-            : '';
494
-    }
495
-
496
-
497
-    /**
498
-     * formOpen
499
-     *
500
-     * @param        int    $ID
501
-     * @param        string $external_url
502
-     * @return        string
503
-     */
504
-    public function formOpen($ID = 0, $external_url = '')
505
-    {
506
-        // if redirecting, we don't need any anything else
507
-        if ($external_url) {
508
-            $html = '<form method="GET" ';
509
-            $html .= 'action="' . EEH_URL::refactor_url($external_url) . '" ';
510
-            $html .= 'name="ticket-selector-form-' . $ID . '"';
511
-            // open link in new window ?
512
-            $html .= apply_filters(
513
-                'FHEE__EventEspresso_modules_ticket_selector_DisplayTicketSelector__formOpen__external_url_target_blank',
514
-                $this->isIframe(),
515
-                $this
516
-            )
517
-                ? ' target="_blank"'
518
-                : '';
519
-            $html .= '>';
520
-            $query_args = EEH_URL::get_query_string($external_url);
521
-            foreach ((array) $query_args as $query_arg => $value) {
522
-                $html .= '<input type="hidden" name="' . $query_arg . '" value="' . $value . '">';
523
-            }
524
-            return $html;
525
-        }
526
-        // if there is no submit button, then don't start building a form
527
-        // because the "View Details" button will build its own form
528
-        if (! apply_filters('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', false)) {
529
-            return '';
530
-        }
531
-        $checkout_url = EEH_Event_View::event_link_url($ID);
532
-        if (! $checkout_url) {
533
-            EE_Error::add_error(
534
-                esc_html__('The URL for the Event Details page could not be retrieved.', 'event_espresso'),
535
-                __FILE__,
536
-                __FUNCTION__,
537
-                __LINE__
538
-            );
539
-        }
540
-        // set no cache headers and constants
541
-        EE_System::do_not_cache();
542
-        $html = '<form method="POST" ';
543
-        $html .= 'action="' . $checkout_url . '" ';
544
-        $html .= 'name="ticket-selector-form-' . $ID . '"';
545
-        $html .= $this->iframe ? ' target="_blank"' : '';
546
-        $html .= '>';
547
-        $html .= '<input type="hidden" name="ee" value="process_ticket_selections">';
548
-        $html = apply_filters('FHEE__EE_Ticket_Selector__ticket_selector_form_open__html', $html, $this->event);
549
-        return $html;
550
-    }
551
-
552
-
553
-    /**
554
-     * displaySubmitButton
555
-     *
556
-     * @param  string $external_url
557
-     * @return string
558
-     * @throws EE_Error
559
-     */
560
-    public function displaySubmitButton($external_url = '')
561
-    {
562
-        $html = '';
563
-        if ($this->display_full_ui()) {
564
-            // standard TS displayed with submit button, ie: "Register Now"
565
-            if (apply_filters('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', false)) {
566
-                $html .= $this->displayRegisterNowButton();
567
-                $html .= empty($external_url)
568
-                    ? $this->ticketSelectorEndDiv()
569
-                    : $this->clearTicketSelector();
570
-                $html .= '<br/>' . $this->formClose();
571
-            } elseif ($this->getMaxAttendees() === 1) {
572
-                // its a "Dude Where's my Ticket Selector?" (DWMTS) type event (ie: $_max_atndz === 1)
573
-                if ($this->event->is_sold_out()) {
574
-                    // then instead of a View Details or Submit button, just display a "Sold Out" message
575
-                    $html .= apply_filters(
576
-                        'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__sold_out_msg',
577
-                        sprintf(
578
-                            __(
579
-                                '%1$s"%2$s" is currently sold out.%4$sPlease check back again later, as spots may become available.%3$s',
580
-                                'event_espresso'
581
-                            ),
582
-                            '<p class="no-ticket-selector-msg clear-float">',
583
-                            $this->event->name(),
584
-                            '</p>',
585
-                            '<br />'
586
-                        ),
587
-                        $this->event
588
-                    );
589
-                    if (apply_filters(
590
-                        'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__no_tickets_but_display_register_now_button',
591
-                        false,
592
-                        $this->event
593
-                    )) {
594
-                        $html .= $this->displayRegisterNowButton();
595
-                    }
596
-                    // sold out DWMTS event, no TS, no submit or view details button, but has additional content
597
-                    $html .= $this->ticketSelectorEndDiv();
598
-                } elseif (apply_filters('FHEE__EE_Ticket_Selector__hide_ticket_selector', false)
599
-                          && ! is_single()
600
-                ) {
601
-                    // this is a "Dude Where's my Ticket Selector?" (DWMTS) type event,
602
-                    // but no tickets are available, so display event's "View Details" button.
603
-                    // it is being viewed via somewhere other than a single post
604
-                    $html .= $this->displayViewDetailsButton(true);
605
-                } else {
606
-                    $html .= $this->ticketSelectorEndDiv();
607
-                }
608
-            } elseif (is_archive()) {
609
-                // event list, no tickets available so display event's "View Details" button
610
-                $html .= $this->ticketSelectorEndDiv();
611
-                $html .= $this->displayViewDetailsButton();
612
-            } else {
613
-                if (apply_filters(
614
-                    'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__no_tickets_but_display_register_now_button',
615
-                    false,
616
-                    $this->event
617
-                )) {
618
-                    $html .= $this->displayRegisterNowButton();
619
-                }
620
-                // no submit or view details button, and no additional content
621
-                $html .= $this->ticketSelectorEndDiv();
622
-            }
623
-            if (! $this->iframe && ! is_archive()) {
624
-                $html .= EEH_Template::powered_by_event_espresso('', '', array('utm_content' => 'ticket_selector'));
625
-            }
626
-        }
627
-        return apply_filters(
628
-            'FHEE__EventEspresso_modules_ticket_selector_DisplayTicketSelector__displaySubmitButton__html',
629
-            $html,
630
-            $this->event,
631
-            $this
632
-        );
633
-    }
634
-
635
-
636
-    /**
637
-     * @return string
638
-     * @throws EE_Error
639
-     */
640
-    public function displayRegisterNowButton()
641
-    {
642
-        $btn_text = apply_filters(
643
-            'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__btn_text',
644
-            __('Register Now', 'event_espresso'),
645
-            $this->event
646
-        );
647
-        $external_url = (string) $this->event->external_url()
648
-            && $this->event->external_url() !== get_the_permalink()
649
-            ? $this->event->external_url()
650
-            : '';
651
-        $html = EEH_HTML::div(
652
-            '',
653
-            'ticket-selector-submit-' . $this->event->ID() . '-btn-wrap',
654
-            'ticket-selector-submit-btn-wrap'
655
-        );
656
-        $html .= '<input id="ticket-selector-submit-' . $this->event->ID() . '-btn"';
657
-        $html .= ' class="ticket-selector-submit-btn ';
658
-        $html .= empty($external_url) ? 'ticket-selector-submit-ajax"' : '"';
659
-        $html .= ' type="submit" value="' . $btn_text . '" data-ee-disable-after-recaptcha="true" />';
660
-        $html .= EEH_HTML::divx() . '<!-- .ticket-selector-submit-btn-wrap -->';
661
-        $html .= apply_filters(
662
-            'FHEE__EE_Ticket_Selector__after_ticket_selector_submit',
663
-            '',
664
-            $this->event,
665
-            $this->iframe
666
-        );
667
-        return $html;
668
-    }
669
-
670
-
671
-    /**
672
-     * displayViewDetailsButton
673
-     *
674
-     * @param bool $DWMTS indicates a "Dude Where's my Ticket Selector?" (DWMTS) type event
675
-     *                    (ie: $_max_atndz === 1) where there are no available tickets,
676
-     *                    either because they are sold out, expired, or not yet on sale.
677
-     *                    In this case, we need to close the form BEFORE adding any closing divs
678
-     * @return string
679
-     * @throws EE_Error
680
-     */
681
-    public function displayViewDetailsButton($DWMTS = false)
682
-    {
683
-        if (! $this->event->get_permalink()) {
684
-            EE_Error::add_error(
685
-                esc_html__('The URL for the Event Details page could not be retrieved.', 'event_espresso'),
686
-                __FILE__,
687
-                __FUNCTION__,
688
-                __LINE__
689
-            );
690
-        }
691
-        $view_details_btn = '<form method="GET" action="';
692
-        $view_details_btn .= apply_filters(
693
-            'FHEE__EE_Ticket_Selector__display_view_details_btn__btn_url',
694
-            $this->event->get_permalink(),
695
-            $this->event
696
-        );
697
-        $view_details_btn .= '"';
698
-        // open link in new window ?
699
-        $view_details_btn .= apply_filters(
700
-            'FHEE__EventEspresso_modules_ticket_selector_DisplayTicketSelector__displayViewDetailsButton__url_target_blank',
701
-            $this->isIframe(),
702
-            $this
703
-        )
704
-            ? ' target="_blank"'
705
-            : '';
706
-        $view_details_btn .= '>';
707
-        $btn_text = apply_filters(
708
-            'FHEE__EE_Ticket_Selector__display_view_details_btn__btn_text',
709
-            esc_html__('View Details', 'event_espresso'),
710
-            $this->event
711
-        );
712
-        $view_details_btn .= '<input id="ticket-selector-submit-'
713
-                             . $this->event->ID()
714
-                             . '-btn" class="ticket-selector-submit-btn view-details-btn" type="submit" value="'
715
-                             . $btn_text
716
-                             . '" />';
717
-        $view_details_btn .= apply_filters('FHEE__EE_Ticket_Selector__after_view_details_btn', '', $this->event);
718
-        if ($DWMTS) {
719
-            $view_details_btn .= $this->formClose();
720
-            $view_details_btn .= $this->ticketSelectorEndDiv();
721
-            $view_details_btn .= '<br/>';
722
-        } else {
723
-            $view_details_btn .= $this->clearTicketSelector();
724
-            $view_details_btn .= '<br/>';
725
-            $view_details_btn .= $this->formClose();
726
-        }
727
-        return $view_details_btn;
728
-    }
729
-
730
-
731
-    /**
732
-     * @return string
733
-     */
734
-    public function ticketSelectorEndDiv()
735
-    {
736
-        return $this->clearTicketSelector() . '</div><!-- ticketSelectorEndDiv -->';
737
-    }
738
-
739
-
740
-    /**
741
-     * @return string
742
-     */
743
-    public function clearTicketSelector()
744
-    {
745
-        // standard TS displayed, appears after a "Register Now" or "view Details" button
746
-        return '<div class="clear"></div><!-- clearTicketSelector -->';
747
-    }
748
-
749
-
750
-    /**
751
-     * @access        public
752
-     * @return        string
753
-     */
754
-    public function formClose()
755
-    {
756
-        return '</form>';
757
-    }
758
-
759
-
760
-    /**
761
-     * handleMissingEvent
762
-     * Returns either false or an error to display when no valid event is passed.
763
-     *
764
-     * @return mixed
765
-     * @throws ExceptionStackTraceDisplay
766
-     * @throws InvalidInterfaceException
767
-     */
768
-    protected function handleMissingEvent()
769
-    {
770
-        // If this is not an iFrame request, simply return false.
771
-        if (! $this->isIframe()) {
772
-            return false;
773
-        }
774
-        // This is an iFrame so return an error.
775
-        // Display stack trace if WP_DEBUG is enabled.
776
-        if (WP_DEBUG === true && current_user_can('edit_pages')) {
777
-            $event_id = EE_Registry::instance()->REQ->get('event', 0);
778
-            new ExceptionStackTraceDisplay(
779
-                new InvalidArgumentException(
780
-                    sprintf(
781
-                        esc_html__(
782
-                            'A valid Event ID is required to display the ticket selector.%3$sAn Event with an ID of "%1$s" could not be found.%3$sPlease verify that the embed code added to this post\'s content includes an "%2$s" argument and that its value corresponds to a valid Event ID.',
783
-                            'event_espresso'
784
-                        ),
785
-                        $event_id,
786
-                        'event',
787
-                        '<br />'
788
-                    )
789
-                )
790
-            );
791
-            return '';
792
-        }
793
-        // If WP_DEBUG is not enabled, display a message stating the event could not be found.
794
-        return EEH_HTML::p(
795
-            esc_html__(
796
-                'A valid Event could not be found. Please contact the event administrator for assistance.',
797
-                'event_espresso'
798
-            )
799
-        );
800
-    }
325
+	}
326
+
327
+
328
+	/**
329
+	 * ticketSalesClosed
330
+	 * notice displayed if event ticket sales are turned off
331
+	 *
332
+	 * @return string
333
+	 * @throws EE_Error
334
+	 */
335
+	protected function ticketSalesClosedMessage()
336
+	{
337
+		$sales_closed_msg = esc_html__(
338
+			'We\'re sorry, but ticket sales have been closed at this time. Please check back again later.',
339
+			'event_espresso'
340
+		);
341
+		if (current_user_can('edit_post', $this->event->ID())) {
342
+			$sales_closed_msg .= sprintf(
343
+				esc_html__(
344
+					'%sNote to Event Admin:%sThe "Maximum number of tickets allowed per order for this event" in the Event Registration Options has been set to "0". This effectively turns off ticket sales. %s(click to edit this event)%s',
345
+					'event_espresso'
346
+				),
347
+				'<div class="ee-attention" style="text-align: left;"><b>',
348
+				'</b><br />',
349
+				'<span class="edit-link"><a class="post-edit-link" href="'
350
+				. get_edit_post_link($this->event->ID())
351
+				. '">',
352
+				'</a></span></div><!-- .ee-attention ticketSalesClosedMessage -->'
353
+			);
354
+		}
355
+		return '<p><span class="important-notice">' . $sales_closed_msg . '</span></p>';
356
+	}
357
+
358
+
359
+	/**
360
+	 * getTickets
361
+	 *
362
+	 * @return \EE_Base_Class[]|\EE_Ticket[]
363
+	 * @throws EE_Error
364
+	 * @throws InvalidDataTypeException
365
+	 * @throws InvalidInterfaceException
366
+	 * @throws InvalidArgumentException
367
+	 */
368
+	protected function getTickets()
369
+	{
370
+		$show_expired_tickets = is_admin() || (
371
+			EE_Registry::instance()->CFG->template_settings->EED_Ticket_Selector instanceof EE_Ticket_Selector_Config
372
+			&& EE_Registry::instance()->CFG->template_settings->EED_Ticket_Selector->show_expired_tickets
373
+		);
374
+
375
+		$ticket_query_args = array(
376
+			array('Datetime.EVT_ID' => $this->event->ID()),
377
+			'order_by' => array(
378
+				'TKT_order'              => 'ASC',
379
+				'TKT_required'           => 'DESC',
380
+				'TKT_start_date'         => 'ASC',
381
+				'TKT_end_date'           => 'ASC',
382
+				'Datetime.DTT_EVT_start' => 'DESC',
383
+			),
384
+		);
385
+		if (! $show_expired_tickets) {
386
+			// use the correct applicable time query depending on what version of core is being run.
387
+			$current_time = method_exists('EEM_Datetime', 'current_time_for_query')
388
+				? time()
389
+				: current_time('timestamp');
390
+			$ticket_query_args[0]['TKT_end_date'] = array('>', $current_time);
391
+		}
392
+		return EEM_Ticket::instance()->get_all($ticket_query_args);
393
+	}
394
+
395
+
396
+	/**
397
+	 * loadTicketSelector
398
+	 * begins to assemble template arguments
399
+	 * and decides whether to load a "simple" ticket selector, or the standard
400
+	 *
401
+	 * @param \EE_Ticket[] $tickets
402
+	 * @param array        $template_args
403
+	 * @return string
404
+	 * @throws EE_Error
405
+	 */
406
+	protected function loadTicketSelector(array $tickets, array $template_args)
407
+	{
408
+		$template_args['event'] = $this->event;
409
+		$template_args['EVT_ID'] = $this->event->ID();
410
+		$template_args['event_is_expired'] = $this->event->is_expired();
411
+		$template_args['max_atndz'] = $this->getMaxAttendees();
412
+		$template_args['date_format'] = $this->date_format;
413
+		$template_args['time_format'] = $this->time_format;
414
+		/**
415
+		 * Filters the anchor ID used when redirecting to the Ticket Selector if no quantity selected
416
+		 *
417
+		 * @since 4.9.13
418
+		 * @param     string  '#tkt-slctr-tbl-' . $EVT_ID The html ID to anchor to
419
+		 * @param int $EVT_ID The Event ID
420
+		 */
421
+		$template_args['anchor_id'] = apply_filters(
422
+			'FHEE__EE_Ticket_Selector__redirect_anchor_id',
423
+			'#tkt-slctr-tbl-' . $this->event->ID(),
424
+			$this->event->ID()
425
+		);
426
+		$template_args['tickets'] = $tickets;
427
+		$template_args['ticket_count'] = count($tickets);
428
+		$ticket_selector = $this->simpleTicketSelector($tickets, $template_args);
429
+		return $ticket_selector instanceof TicketSelectorSimple
430
+			? $ticket_selector
431
+			: new TicketSelectorStandard(
432
+				$this->event,
433
+				$tickets,
434
+				$this->getMaxAttendees(),
435
+				$template_args,
436
+				$this->date_format,
437
+				$this->time_format
438
+			);
439
+	}
440
+
441
+
442
+	/**
443
+	 * simpleTicketSelector
444
+	 * there's one ticket, and max attendees is set to one,
445
+	 * so if the event is free, then this is a "simple" ticket selector
446
+	 * a.k.a. "Dude Where's my Ticket Selector?"
447
+	 *
448
+	 * @param \EE_Ticket[] $tickets
449
+	 * @param array        $template_args
450
+	 * @return string
451
+	 * @throws EE_Error
452
+	 */
453
+	protected function simpleTicketSelector($tickets, array $template_args)
454
+	{
455
+		// if there is only ONE ticket with a max qty of ONE
456
+		if (count($tickets) > 1 || $this->getMaxAttendees() !== 1) {
457
+			return '';
458
+		}
459
+		/** @var \EE_Ticket $ticket */
460
+		$ticket = reset($tickets);
461
+		// if the ticket is free... then not much need for the ticket selector
462
+		if (apply_filters(
463
+			'FHEE__ticket_selector_chart_template__hide_ticket_selector',
464
+			$ticket->is_free(),
465
+			$this->event->ID()
466
+		)) {
467
+			return new TicketSelectorSimple(
468
+				$this->event,
469
+				$ticket,
470
+				$this->getMaxAttendees(),
471
+				$template_args
472
+			);
473
+		}
474
+		return '';
475
+	}
476
+
477
+
478
+	/**
479
+	 * externalEventRegistration
480
+	 *
481
+	 * @return string
482
+	 */
483
+	public function externalEventRegistration()
484
+	{
485
+		// if not we still need to trigger the display of the submit button
486
+		add_filter('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_true');
487
+		// display notice to admin that registration is external
488
+		return $this->display_full_ui()
489
+			? esc_html__(
490
+				'Registration is at an external URL for this event.',
491
+				'event_espresso'
492
+			)
493
+			: '';
494
+	}
495
+
496
+
497
+	/**
498
+	 * formOpen
499
+	 *
500
+	 * @param        int    $ID
501
+	 * @param        string $external_url
502
+	 * @return        string
503
+	 */
504
+	public function formOpen($ID = 0, $external_url = '')
505
+	{
506
+		// if redirecting, we don't need any anything else
507
+		if ($external_url) {
508
+			$html = '<form method="GET" ';
509
+			$html .= 'action="' . EEH_URL::refactor_url($external_url) . '" ';
510
+			$html .= 'name="ticket-selector-form-' . $ID . '"';
511
+			// open link in new window ?
512
+			$html .= apply_filters(
513
+				'FHEE__EventEspresso_modules_ticket_selector_DisplayTicketSelector__formOpen__external_url_target_blank',
514
+				$this->isIframe(),
515
+				$this
516
+			)
517
+				? ' target="_blank"'
518
+				: '';
519
+			$html .= '>';
520
+			$query_args = EEH_URL::get_query_string($external_url);
521
+			foreach ((array) $query_args as $query_arg => $value) {
522
+				$html .= '<input type="hidden" name="' . $query_arg . '" value="' . $value . '">';
523
+			}
524
+			return $html;
525
+		}
526
+		// if there is no submit button, then don't start building a form
527
+		// because the "View Details" button will build its own form
528
+		if (! apply_filters('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', false)) {
529
+			return '';
530
+		}
531
+		$checkout_url = EEH_Event_View::event_link_url($ID);
532
+		if (! $checkout_url) {
533
+			EE_Error::add_error(
534
+				esc_html__('The URL for the Event Details page could not be retrieved.', 'event_espresso'),
535
+				__FILE__,
536
+				__FUNCTION__,
537
+				__LINE__
538
+			);
539
+		}
540
+		// set no cache headers and constants
541
+		EE_System::do_not_cache();
542
+		$html = '<form method="POST" ';
543
+		$html .= 'action="' . $checkout_url . '" ';
544
+		$html .= 'name="ticket-selector-form-' . $ID . '"';
545
+		$html .= $this->iframe ? ' target="_blank"' : '';
546
+		$html .= '>';
547
+		$html .= '<input type="hidden" name="ee" value="process_ticket_selections">';
548
+		$html = apply_filters('FHEE__EE_Ticket_Selector__ticket_selector_form_open__html', $html, $this->event);
549
+		return $html;
550
+	}
551
+
552
+
553
+	/**
554
+	 * displaySubmitButton
555
+	 *
556
+	 * @param  string $external_url
557
+	 * @return string
558
+	 * @throws EE_Error
559
+	 */
560
+	public function displaySubmitButton($external_url = '')
561
+	{
562
+		$html = '';
563
+		if ($this->display_full_ui()) {
564
+			// standard TS displayed with submit button, ie: "Register Now"
565
+			if (apply_filters('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', false)) {
566
+				$html .= $this->displayRegisterNowButton();
567
+				$html .= empty($external_url)
568
+					? $this->ticketSelectorEndDiv()
569
+					: $this->clearTicketSelector();
570
+				$html .= '<br/>' . $this->formClose();
571
+			} elseif ($this->getMaxAttendees() === 1) {
572
+				// its a "Dude Where's my Ticket Selector?" (DWMTS) type event (ie: $_max_atndz === 1)
573
+				if ($this->event->is_sold_out()) {
574
+					// then instead of a View Details or Submit button, just display a "Sold Out" message
575
+					$html .= apply_filters(
576
+						'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__sold_out_msg',
577
+						sprintf(
578
+							__(
579
+								'%1$s"%2$s" is currently sold out.%4$sPlease check back again later, as spots may become available.%3$s',
580
+								'event_espresso'
581
+							),
582
+							'<p class="no-ticket-selector-msg clear-float">',
583
+							$this->event->name(),
584
+							'</p>',
585
+							'<br />'
586
+						),
587
+						$this->event
588
+					);
589
+					if (apply_filters(
590
+						'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__no_tickets_but_display_register_now_button',
591
+						false,
592
+						$this->event
593
+					)) {
594
+						$html .= $this->displayRegisterNowButton();
595
+					}
596
+					// sold out DWMTS event, no TS, no submit or view details button, but has additional content
597
+					$html .= $this->ticketSelectorEndDiv();
598
+				} elseif (apply_filters('FHEE__EE_Ticket_Selector__hide_ticket_selector', false)
599
+						  && ! is_single()
600
+				) {
601
+					// this is a "Dude Where's my Ticket Selector?" (DWMTS) type event,
602
+					// but no tickets are available, so display event's "View Details" button.
603
+					// it is being viewed via somewhere other than a single post
604
+					$html .= $this->displayViewDetailsButton(true);
605
+				} else {
606
+					$html .= $this->ticketSelectorEndDiv();
607
+				}
608
+			} elseif (is_archive()) {
609
+				// event list, no tickets available so display event's "View Details" button
610
+				$html .= $this->ticketSelectorEndDiv();
611
+				$html .= $this->displayViewDetailsButton();
612
+			} else {
613
+				if (apply_filters(
614
+					'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__no_tickets_but_display_register_now_button',
615
+					false,
616
+					$this->event
617
+				)) {
618
+					$html .= $this->displayRegisterNowButton();
619
+				}
620
+				// no submit or view details button, and no additional content
621
+				$html .= $this->ticketSelectorEndDiv();
622
+			}
623
+			if (! $this->iframe && ! is_archive()) {
624
+				$html .= EEH_Template::powered_by_event_espresso('', '', array('utm_content' => 'ticket_selector'));
625
+			}
626
+		}
627
+		return apply_filters(
628
+			'FHEE__EventEspresso_modules_ticket_selector_DisplayTicketSelector__displaySubmitButton__html',
629
+			$html,
630
+			$this->event,
631
+			$this
632
+		);
633
+	}
634
+
635
+
636
+	/**
637
+	 * @return string
638
+	 * @throws EE_Error
639
+	 */
640
+	public function displayRegisterNowButton()
641
+	{
642
+		$btn_text = apply_filters(
643
+			'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__btn_text',
644
+			__('Register Now', 'event_espresso'),
645
+			$this->event
646
+		);
647
+		$external_url = (string) $this->event->external_url()
648
+			&& $this->event->external_url() !== get_the_permalink()
649
+			? $this->event->external_url()
650
+			: '';
651
+		$html = EEH_HTML::div(
652
+			'',
653
+			'ticket-selector-submit-' . $this->event->ID() . '-btn-wrap',
654
+			'ticket-selector-submit-btn-wrap'
655
+		);
656
+		$html .= '<input id="ticket-selector-submit-' . $this->event->ID() . '-btn"';
657
+		$html .= ' class="ticket-selector-submit-btn ';
658
+		$html .= empty($external_url) ? 'ticket-selector-submit-ajax"' : '"';
659
+		$html .= ' type="submit" value="' . $btn_text . '" data-ee-disable-after-recaptcha="true" />';
660
+		$html .= EEH_HTML::divx() . '<!-- .ticket-selector-submit-btn-wrap -->';
661
+		$html .= apply_filters(
662
+			'FHEE__EE_Ticket_Selector__after_ticket_selector_submit',
663
+			'',
664
+			$this->event,
665
+			$this->iframe
666
+		);
667
+		return $html;
668
+	}
669
+
670
+
671
+	/**
672
+	 * displayViewDetailsButton
673
+	 *
674
+	 * @param bool $DWMTS indicates a "Dude Where's my Ticket Selector?" (DWMTS) type event
675
+	 *                    (ie: $_max_atndz === 1) where there are no available tickets,
676
+	 *                    either because they are sold out, expired, or not yet on sale.
677
+	 *                    In this case, we need to close the form BEFORE adding any closing divs
678
+	 * @return string
679
+	 * @throws EE_Error
680
+	 */
681
+	public function displayViewDetailsButton($DWMTS = false)
682
+	{
683
+		if (! $this->event->get_permalink()) {
684
+			EE_Error::add_error(
685
+				esc_html__('The URL for the Event Details page could not be retrieved.', 'event_espresso'),
686
+				__FILE__,
687
+				__FUNCTION__,
688
+				__LINE__
689
+			);
690
+		}
691
+		$view_details_btn = '<form method="GET" action="';
692
+		$view_details_btn .= apply_filters(
693
+			'FHEE__EE_Ticket_Selector__display_view_details_btn__btn_url',
694
+			$this->event->get_permalink(),
695
+			$this->event
696
+		);
697
+		$view_details_btn .= '"';
698
+		// open link in new window ?
699
+		$view_details_btn .= apply_filters(
700
+			'FHEE__EventEspresso_modules_ticket_selector_DisplayTicketSelector__displayViewDetailsButton__url_target_blank',
701
+			$this->isIframe(),
702
+			$this
703
+		)
704
+			? ' target="_blank"'
705
+			: '';
706
+		$view_details_btn .= '>';
707
+		$btn_text = apply_filters(
708
+			'FHEE__EE_Ticket_Selector__display_view_details_btn__btn_text',
709
+			esc_html__('View Details', 'event_espresso'),
710
+			$this->event
711
+		);
712
+		$view_details_btn .= '<input id="ticket-selector-submit-'
713
+							 . $this->event->ID()
714
+							 . '-btn" class="ticket-selector-submit-btn view-details-btn" type="submit" value="'
715
+							 . $btn_text
716
+							 . '" />';
717
+		$view_details_btn .= apply_filters('FHEE__EE_Ticket_Selector__after_view_details_btn', '', $this->event);
718
+		if ($DWMTS) {
719
+			$view_details_btn .= $this->formClose();
720
+			$view_details_btn .= $this->ticketSelectorEndDiv();
721
+			$view_details_btn .= '<br/>';
722
+		} else {
723
+			$view_details_btn .= $this->clearTicketSelector();
724
+			$view_details_btn .= '<br/>';
725
+			$view_details_btn .= $this->formClose();
726
+		}
727
+		return $view_details_btn;
728
+	}
729
+
730
+
731
+	/**
732
+	 * @return string
733
+	 */
734
+	public function ticketSelectorEndDiv()
735
+	{
736
+		return $this->clearTicketSelector() . '</div><!-- ticketSelectorEndDiv -->';
737
+	}
738
+
739
+
740
+	/**
741
+	 * @return string
742
+	 */
743
+	public function clearTicketSelector()
744
+	{
745
+		// standard TS displayed, appears after a "Register Now" or "view Details" button
746
+		return '<div class="clear"></div><!-- clearTicketSelector -->';
747
+	}
748
+
749
+
750
+	/**
751
+	 * @access        public
752
+	 * @return        string
753
+	 */
754
+	public function formClose()
755
+	{
756
+		return '</form>';
757
+	}
758
+
759
+
760
+	/**
761
+	 * handleMissingEvent
762
+	 * Returns either false or an error to display when no valid event is passed.
763
+	 *
764
+	 * @return mixed
765
+	 * @throws ExceptionStackTraceDisplay
766
+	 * @throws InvalidInterfaceException
767
+	 */
768
+	protected function handleMissingEvent()
769
+	{
770
+		// If this is not an iFrame request, simply return false.
771
+		if (! $this->isIframe()) {
772
+			return false;
773
+		}
774
+		// This is an iFrame so return an error.
775
+		// Display stack trace if WP_DEBUG is enabled.
776
+		if (WP_DEBUG === true && current_user_can('edit_pages')) {
777
+			$event_id = EE_Registry::instance()->REQ->get('event', 0);
778
+			new ExceptionStackTraceDisplay(
779
+				new InvalidArgumentException(
780
+					sprintf(
781
+						esc_html__(
782
+							'A valid Event ID is required to display the ticket selector.%3$sAn Event with an ID of "%1$s" could not be found.%3$sPlease verify that the embed code added to this post\'s content includes an "%2$s" argument and that its value corresponds to a valid Event ID.',
783
+							'event_espresso'
784
+						),
785
+						$event_id,
786
+						'event',
787
+						'<br />'
788
+					)
789
+				)
790
+			);
791
+			return '';
792
+		}
793
+		// If WP_DEBUG is not enabled, display a message stating the event could not be found.
794
+		return EEH_HTML::p(
795
+			esc_html__(
796
+				'A valid Event could not be found. Please contact the event administrator for assistance.',
797
+				'event_espresso'
798
+			)
799
+		);
800
+	}
801 801
 }
Please login to merge, or discard this patch.
Spacing   +27 added lines, -27 removed lines patch added patch discarded remove patch
@@ -136,11 +136,11 @@  discard block
 block discarded – undo
136 136
             }
137 137
         } else {
138 138
             $user_msg = __('No Event object or an invalid Event object was supplied.', 'event_espresso');
139
-            $dev_msg = $user_msg . __(
139
+            $dev_msg = $user_msg.__(
140 140
                 'In order to generate a ticket selector, please ensure you are passing either an EE_Event object or a WP_Post object of the post type "espresso_event" to the EE_Ticket_Selector class constructor.',
141 141
                 'event_espresso'
142 142
             );
143
-            EE_Error::add_error($user_msg . '||' . $dev_msg, __FILE__, __FUNCTION__, __LINE__);
143
+            EE_Error::add_error($user_msg.'||'.$dev_msg, __FILE__, __FUNCTION__, __LINE__);
144 144
             return false;
145 145
         }
146 146
         return true;
@@ -201,13 +201,13 @@  discard block
 block discarded – undo
201 201
         // reset filter for displaying submit button
202 202
         remove_filter('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_true');
203 203
         // poke and prod incoming event till it tells us what it is
204
-        if (! $this->setEvent($event)) {
204
+        if ( ! $this->setEvent($event)) {
205 205
             return $this->handleMissingEvent();
206 206
         }
207 207
         // is the event expired ?
208 208
         $template_args['event_is_expired'] = ! is_admin() ? $this->event->is_expired() : false;
209 209
         if ($template_args['event_is_expired']) {
210
-            return is_single() ? $this->expiredEventMessage() : $this->expiredEventMessage() . $this->displayViewDetailsButton();
210
+            return is_single() ? $this->expiredEventMessage() : $this->expiredEventMessage().$this->displayViewDetailsButton();
211 211
         }
212 212
         // begin gathering template arguments by getting event status
213 213
         $template_args = array('event_status' => $this->event->get_active_status());
@@ -239,7 +239,7 @@  discard block
 block discarded – undo
239 239
             : $this->loadTicketSelector($tickets, $template_args);
240 240
         // now set up the form (but not for the admin)
241 241
         $ticket_selector = $this->display_full_ui()
242
-            ? $this->formOpen($this->event->ID(), $external_url) . $ticket_selector
242
+            ? $this->formOpen($this->event->ID(), $external_url).$ticket_selector
243 243
             : $ticket_selector;
244 244
         // submit button and form close tag
245 245
         $ticket_selector .= $this->display_full_ui() ? $this->displaySubmitButton($external_url) : '';
@@ -287,10 +287,10 @@  discard block
 block discarded – undo
287 287
      */
288 288
     protected function expiredEventMessage()
289 289
     {
290
-        return '<div class="ee-event-expired-notice"><span class="important-notice">' . esc_html__(
290
+        return '<div class="ee-event-expired-notice"><span class="important-notice">'.esc_html__(
291 291
             'We\'re sorry, but all tickets sales have ended because the event is expired.',
292 292
             'event_espresso'
293
-        ) . '</span></div><!-- .ee-event-expired-notice -->';
293
+        ).'</span></div><!-- .ee-event-expired-notice -->';
294 294
     }
295 295
 
296 296
 
@@ -320,7 +320,7 @@  discard block
 block discarded – undo
320 320
         }
321 321
         return '
322 322
             <div class="ee-event-expired-notice">
323
-                <span class="important-notice">' . $no_ticket_available_msg . '</span>
323
+                <span class="important-notice">' . $no_ticket_available_msg.'</span>
324 324
             </div><!-- .ee-event-expired-notice -->';
325 325
     }
326 326
 
@@ -352,7 +352,7 @@  discard block
 block discarded – undo
352 352
                 '</a></span></div><!-- .ee-attention ticketSalesClosedMessage -->'
353 353
             );
354 354
         }
355
-        return '<p><span class="important-notice">' . $sales_closed_msg . '</span></p>';
355
+        return '<p><span class="important-notice">'.$sales_closed_msg.'</span></p>';
356 356
     }
357 357
 
358 358
 
@@ -382,7 +382,7 @@  discard block
 block discarded – undo
382 382
                 'Datetime.DTT_EVT_start' => 'DESC',
383 383
             ),
384 384
         );
385
-        if (! $show_expired_tickets) {
385
+        if ( ! $show_expired_tickets) {
386 386
             // use the correct applicable time query depending on what version of core is being run.
387 387
             $current_time = method_exists('EEM_Datetime', 'current_time_for_query')
388 388
                 ? time()
@@ -420,7 +420,7 @@  discard block
 block discarded – undo
420 420
          */
421 421
         $template_args['anchor_id'] = apply_filters(
422 422
             'FHEE__EE_Ticket_Selector__redirect_anchor_id',
423
-            '#tkt-slctr-tbl-' . $this->event->ID(),
423
+            '#tkt-slctr-tbl-'.$this->event->ID(),
424 424
             $this->event->ID()
425 425
         );
426 426
         $template_args['tickets'] = $tickets;
@@ -506,8 +506,8 @@  discard block
 block discarded – undo
506 506
         // if redirecting, we don't need any anything else
507 507
         if ($external_url) {
508 508
             $html = '<form method="GET" ';
509
-            $html .= 'action="' . EEH_URL::refactor_url($external_url) . '" ';
510
-            $html .= 'name="ticket-selector-form-' . $ID . '"';
509
+            $html .= 'action="'.EEH_URL::refactor_url($external_url).'" ';
510
+            $html .= 'name="ticket-selector-form-'.$ID.'"';
511 511
             // open link in new window ?
512 512
             $html .= apply_filters(
513 513
                 'FHEE__EventEspresso_modules_ticket_selector_DisplayTicketSelector__formOpen__external_url_target_blank',
@@ -519,17 +519,17 @@  discard block
 block discarded – undo
519 519
             $html .= '>';
520 520
             $query_args = EEH_URL::get_query_string($external_url);
521 521
             foreach ((array) $query_args as $query_arg => $value) {
522
-                $html .= '<input type="hidden" name="' . $query_arg . '" value="' . $value . '">';
522
+                $html .= '<input type="hidden" name="'.$query_arg.'" value="'.$value.'">';
523 523
             }
524 524
             return $html;
525 525
         }
526 526
         // if there is no submit button, then don't start building a form
527 527
         // because the "View Details" button will build its own form
528
-        if (! apply_filters('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', false)) {
528
+        if ( ! apply_filters('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', false)) {
529 529
             return '';
530 530
         }
531 531
         $checkout_url = EEH_Event_View::event_link_url($ID);
532
-        if (! $checkout_url) {
532
+        if ( ! $checkout_url) {
533 533
             EE_Error::add_error(
534 534
                 esc_html__('The URL for the Event Details page could not be retrieved.', 'event_espresso'),
535 535
                 __FILE__,
@@ -540,8 +540,8 @@  discard block
 block discarded – undo
540 540
         // set no cache headers and constants
541 541
         EE_System::do_not_cache();
542 542
         $html = '<form method="POST" ';
543
-        $html .= 'action="' . $checkout_url . '" ';
544
-        $html .= 'name="ticket-selector-form-' . $ID . '"';
543
+        $html .= 'action="'.$checkout_url.'" ';
544
+        $html .= 'name="ticket-selector-form-'.$ID.'"';
545 545
         $html .= $this->iframe ? ' target="_blank"' : '';
546 546
         $html .= '>';
547 547
         $html .= '<input type="hidden" name="ee" value="process_ticket_selections">';
@@ -567,7 +567,7 @@  discard block
 block discarded – undo
567 567
                 $html .= empty($external_url)
568 568
                     ? $this->ticketSelectorEndDiv()
569 569
                     : $this->clearTicketSelector();
570
-                $html .= '<br/>' . $this->formClose();
570
+                $html .= '<br/>'.$this->formClose();
571 571
             } elseif ($this->getMaxAttendees() === 1) {
572 572
                 // its a "Dude Where's my Ticket Selector?" (DWMTS) type event (ie: $_max_atndz === 1)
573 573
                 if ($this->event->is_sold_out()) {
@@ -620,7 +620,7 @@  discard block
 block discarded – undo
620 620
                 // no submit or view details button, and no additional content
621 621
                 $html .= $this->ticketSelectorEndDiv();
622 622
             }
623
-            if (! $this->iframe && ! is_archive()) {
623
+            if ( ! $this->iframe && ! is_archive()) {
624 624
                 $html .= EEH_Template::powered_by_event_espresso('', '', array('utm_content' => 'ticket_selector'));
625 625
             }
626 626
         }
@@ -650,14 +650,14 @@  discard block
 block discarded – undo
650 650
             : '';
651 651
         $html = EEH_HTML::div(
652 652
             '',
653
-            'ticket-selector-submit-' . $this->event->ID() . '-btn-wrap',
653
+            'ticket-selector-submit-'.$this->event->ID().'-btn-wrap',
654 654
             'ticket-selector-submit-btn-wrap'
655 655
         );
656
-        $html .= '<input id="ticket-selector-submit-' . $this->event->ID() . '-btn"';
656
+        $html .= '<input id="ticket-selector-submit-'.$this->event->ID().'-btn"';
657 657
         $html .= ' class="ticket-selector-submit-btn ';
658 658
         $html .= empty($external_url) ? 'ticket-selector-submit-ajax"' : '"';
659
-        $html .= ' type="submit" value="' . $btn_text . '" data-ee-disable-after-recaptcha="true" />';
660
-        $html .= EEH_HTML::divx() . '<!-- .ticket-selector-submit-btn-wrap -->';
659
+        $html .= ' type="submit" value="'.$btn_text.'" data-ee-disable-after-recaptcha="true" />';
660
+        $html .= EEH_HTML::divx().'<!-- .ticket-selector-submit-btn-wrap -->';
661 661
         $html .= apply_filters(
662 662
             'FHEE__EE_Ticket_Selector__after_ticket_selector_submit',
663 663
             '',
@@ -680,7 +680,7 @@  discard block
 block discarded – undo
680 680
      */
681 681
     public function displayViewDetailsButton($DWMTS = false)
682 682
     {
683
-        if (! $this->event->get_permalink()) {
683
+        if ( ! $this->event->get_permalink()) {
684 684
             EE_Error::add_error(
685 685
                 esc_html__('The URL for the Event Details page could not be retrieved.', 'event_espresso'),
686 686
                 __FILE__,
@@ -733,7 +733,7 @@  discard block
 block discarded – undo
733 733
      */
734 734
     public function ticketSelectorEndDiv()
735 735
     {
736
-        return $this->clearTicketSelector() . '</div><!-- ticketSelectorEndDiv -->';
736
+        return $this->clearTicketSelector().'</div><!-- ticketSelectorEndDiv -->';
737 737
     }
738 738
 
739 739
 
@@ -768,7 +768,7 @@  discard block
 block discarded – undo
768 768
     protected function handleMissingEvent()
769 769
     {
770 770
         // If this is not an iFrame request, simply return false.
771
-        if (! $this->isIframe()) {
771
+        if ( ! $this->isIframe()) {
772 772
             return false;
773 773
         }
774 774
         // This is an iFrame so return an error.
Please login to merge, or discard this patch.
core/EE_Cron_Tasks.core.php 1 patch
Indentation   +598 added lines, -598 removed lines patch added patch discarded remove patch
@@ -15,602 +15,602 @@
 block discarded – undo
15 15
 class EE_Cron_Tasks extends EE_Base
16 16
 {
17 17
 
18
-    /**
19
-     * WordPress doesn't allow duplicate crons within 10 minutes of the original,
20
-     * so we'll set our retry time for just over 10 minutes to avoid that
21
-     */
22
-    const reschedule_timeout = 605;
23
-
24
-
25
-    /**
26
-     * @var EE_Cron_Tasks
27
-     */
28
-    private static $_instance;
29
-
30
-
31
-    /**
32
-     * @return EE_Cron_Tasks
33
-     * @throws ReflectionException
34
-     * @throws EE_Error
35
-     * @throws InvalidArgumentException
36
-     * @throws InvalidInterfaceException
37
-     * @throws InvalidDataTypeException
38
-     */
39
-    public static function instance()
40
-    {
41
-        if (! self::$_instance instanceof EE_Cron_Tasks) {
42
-            self::$_instance = new self();
43
-        }
44
-        return self::$_instance;
45
-    }
46
-
47
-
48
-    /**
49
-     * @access private
50
-     * @throws InvalidDataTypeException
51
-     * @throws InvalidInterfaceException
52
-     * @throws InvalidArgumentException
53
-     * @throws EE_Error
54
-     * @throws ReflectionException
55
-     */
56
-    private function __construct()
57
-    {
58
-        do_action('AHEE_log', __CLASS__, __FUNCTION__);
59
-        // verify that WP Cron is enabled
60
-        if (defined('DISABLE_WP_CRON')
61
-            && DISABLE_WP_CRON
62
-            && is_admin()
63
-            && ! get_option('ee_disabled_wp_cron_check')
64
-        ) {
65
-            /**
66
-             * This needs to be delayed until after the config is loaded because EE_Cron_Tasks is constructed before
67
-             * config is loaded.
68
-             * This is intentionally using a anonymous function so that its not easily de-registered.  Client code
69
-             * wanting to not have this functionality can just register its own action at a priority after this one to
70
-             * reverse any changes.
71
-             */
72
-            add_action(
73
-                'AHEE__EE_System__load_core_configuration__complete',
74
-                function () {
75
-                    EE_Registry::instance()->NET_CFG->core->do_messages_on_same_request = true;
76
-                    EE_Registry::instance()->NET_CFG->update_config(true, false);
77
-                    add_option('ee_disabled_wp_cron_check', 1, '', false);
78
-                }
79
-            );
80
-        }
81
-        // UPDATE TRANSACTION WITH PAYMENT
82
-        add_action(
83
-            'AHEE__EE_Cron_Tasks__update_transaction_with_payment_2',
84
-            array('EE_Cron_Tasks', 'setup_update_for_transaction_with_payment'),
85
-            10,
86
-            2
87
-        );
88
-        // ABANDONED / EXPIRED TRANSACTION CHECK
89
-        add_action(
90
-            'AHEE__EE_Cron_Tasks__expired_transaction_check',
91
-            array('EE_Cron_Tasks', 'expired_transaction_check'),
92
-            10,
93
-            1
94
-        );
95
-        // CLEAN OUT JUNK TRANSACTIONS AND RELATED DATA
96
-        add_action(
97
-            'AHEE__EE_Cron_Tasks__clean_up_junk_transactions',
98
-            array('EE_Cron_Tasks', 'clean_out_junk_transactions')
99
-        );
100
-        // logging
101
-        add_action(
102
-            'AHEE__EE_System__load_core_configuration__complete',
103
-            array('EE_Cron_Tasks', 'log_scheduled_ee_crons')
104
-        );
105
-        EE_Registry::instance()->load_lib('Messages_Scheduler');
106
-        // clean out old gateway logs
107
-        add_action(
108
-            'AHEE_EE_Cron_Tasks__clean_out_old_gateway_logs',
109
-            array('EE_Cron_Tasks', 'clean_out_old_gateway_logs')
110
-        );
111
-    }
112
-
113
-
114
-    /**
115
-     * @access protected
116
-     * @return void
117
-     */
118
-    public static function log_scheduled_ee_crons()
119
-    {
120
-        $ee_crons = array(
121
-            'AHEE__EE_Cron_Tasks__update_transaction_with_payment',
122
-            'AHEE__EE_Cron_Tasks__finalize_abandoned_transactions',
123
-            'AHEE__EE_Cron_Tasks__clean_up_junk_transactions',
124
-        );
125
-        $crons = (array) get_option('cron');
126
-        if (! is_array($crons)) {
127
-            return;
128
-        }
129
-        foreach ($crons as $timestamp => $cron) {
130
-            /** @var array[] $cron */
131
-            foreach ($ee_crons as $ee_cron) {
132
-                if (isset($cron[ $ee_cron ]) && is_array($cron[ $ee_cron ])) {
133
-                    do_action('AHEE_log', __CLASS__, __FUNCTION__, $ee_cron, 'scheduled EE cron');
134
-                    foreach ($cron[ $ee_cron ] as $ee_cron_details) {
135
-                        if (! empty($ee_cron_details['args'])) {
136
-                            do_action(
137
-                                'AHEE_log',
138
-                                __CLASS__,
139
-                                __FUNCTION__,
140
-                                print_r($ee_cron_details['args'], true),
141
-                                "{$ee_cron} args"
142
-                            );
143
-                        }
144
-                    }
145
-                }
146
-            }
147
-        }
148
-    }
149
-
150
-
151
-    /**
152
-     * reschedule_cron_for_transactions_if_maintenance_mode
153
-     * if Maintenance Mode is active, this will reschedule a cron to run again in 10 minutes
154
-     *
155
-     * @param string $cron_task
156
-     * @param array  $TXN_IDs
157
-     * @return bool
158
-     * @throws DomainException
159
-     */
160
-    public static function reschedule_cron_for_transactions_if_maintenance_mode($cron_task, array $TXN_IDs)
161
-    {
162
-        if (! method_exists('EE_Cron_Tasks', $cron_task)) {
163
-            throw new DomainException(
164
-                sprintf(
165
-                    __('"%1$s" is not valid method on EE_Cron_Tasks.', 'event_espresso'),
166
-                    $cron_task
167
-                )
168
-            );
169
-        }
170
-        // reschedule the cron if we can't hit the db right now
171
-        if (! EE_Maintenance_Mode::instance()->models_can_query()) {
172
-            foreach ($TXN_IDs as $TXN_ID => $additional_vars) {
173
-                // ensure $additional_vars is an array
174
-                $additional_vars = is_array($additional_vars) ? $additional_vars : array($additional_vars);
175
-                // reset cron job for the TXN
176
-                call_user_func_array(
177
-                    array('EE_Cron_Tasks', $cron_task),
178
-                    array_merge(
179
-                        array(
180
-                            time() + (10 * MINUTE_IN_SECONDS),
181
-                            $TXN_ID,
182
-                        ),
183
-                        $additional_vars
184
-                    )
185
-                );
186
-            }
187
-            return true;
188
-        }
189
-        return false;
190
-    }
191
-
192
-
193
-
194
-
195
-    /****************  UPDATE TRANSACTION WITH PAYMENT ****************/
196
-
197
-
198
-    /**
199
-     * array of TXN IDs and the payment
200
-     *
201
-     * @var array
202
-     */
203
-    protected static $_update_transactions_with_payment = array();
204
-
205
-
206
-    /**
207
-     * schedule_update_transaction_with_payment
208
-     * sets a wp_schedule_single_event() for updating any TXNs that may
209
-     * require updating due to recently received payments
210
-     *
211
-     * @param int $timestamp
212
-     * @param int $TXN_ID
213
-     * @param int $PAY_ID
214
-     */
215
-    public static function schedule_update_transaction_with_payment(
216
-        $timestamp,
217
-        $TXN_ID,
218
-        $PAY_ID
219
-    ) {
220
-        do_action('AHEE_log', __CLASS__, __FUNCTION__);
221
-        // validate $TXN_ID and $timestamp
222
-        $TXN_ID = absint($TXN_ID);
223
-        $timestamp = absint($timestamp);
224
-        if ($TXN_ID && $timestamp) {
225
-            wp_schedule_single_event(
226
-                $timestamp,
227
-                'AHEE__EE_Cron_Tasks__update_transaction_with_payment_2',
228
-                array($TXN_ID, $PAY_ID)
229
-            );
230
-        }
231
-    }
232
-
233
-
234
-    /**
235
-     * setup_update_for_transaction_with_payment
236
-     * this is the callback for the action hook:
237
-     * 'AHEE__EE_Cron_Tasks__update_transaction_with_payment'
238
-     * which is setup by EE_Cron_Tasks::schedule_update_transaction_with_payment().
239
-     * The passed TXN_ID and associated payment gets added to an array, and then
240
-     * the EE_Cron_Tasks::update_transaction_with_payment() function is hooked into
241
-     * 'shutdown' which will actually handle the processing of any
242
-     * transactions requiring updating, because doing so now would be too early
243
-     * and the required resources may not be available
244
-     *
245
-     * @param int $TXN_ID
246
-     * @param int $PAY_ID
247
-     */
248
-    public static function setup_update_for_transaction_with_payment($TXN_ID = 0, $PAY_ID = 0)
249
-    {
250
-        do_action('AHEE_log', __CLASS__, __FUNCTION__, $TXN_ID, '$TXN_ID');
251
-        if (absint($TXN_ID)) {
252
-            self::$_update_transactions_with_payment[ $TXN_ID ] = $PAY_ID;
253
-            add_action(
254
-                'shutdown',
255
-                array('EE_Cron_Tasks', 'update_transaction_with_payment'),
256
-                5
257
-            );
258
-        }
259
-    }
260
-
261
-
262
-    /**
263
-     * update_transaction_with_payment
264
-     * loops through the self::$_abandoned_transactions array
265
-     * and attempts to finalize any TXNs that have not been completed
266
-     * but have had their sessions expired, most likely due to a user not
267
-     * returning from an off-site payment gateway
268
-     *
269
-     * @throws EE_Error
270
-     * @throws DomainException
271
-     * @throws InvalidDataTypeException
272
-     * @throws InvalidInterfaceException
273
-     * @throws InvalidArgumentException
274
-     * @throws ReflectionException
275
-     * @throws RuntimeException
276
-     */
277
-    public static function update_transaction_with_payment()
278
-    {
279
-        do_action('AHEE_log', __CLASS__, __FUNCTION__);
280
-        if (// are there any TXNs that need cleaning up ?
281
-            empty(self::$_update_transactions_with_payment)
282
-            // reschedule the cron if we can't hit the db right now
283
-            || EE_Cron_Tasks::reschedule_cron_for_transactions_if_maintenance_mode(
284
-                'schedule_update_transaction_with_payment',
285
-                self::$_update_transactions_with_payment
286
-            )
287
-        ) {
288
-            return;
289
-        }
290
-        /** @type EE_Payment_Processor $payment_processor */
291
-        $payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
292
-        // set revisit flag for payment processor
293
-        $payment_processor->set_revisit();
294
-        // load EEM_Transaction
295
-        EE_Registry::instance()->load_model('Transaction');
296
-        foreach (self::$_update_transactions_with_payment as $TXN_ID => $PAY_ID) {
297
-            // reschedule the cron if we can't hit the db right now
298
-            if (! EE_Maintenance_Mode::instance()->models_can_query()) {
299
-                // reset cron job for updating the TXN
300
-                EE_Cron_Tasks::schedule_update_transaction_with_payment(
301
-                    time() + EE_Cron_Tasks::reschedule_timeout,
302
-                    $TXN_ID,
303
-                    $PAY_ID
304
-                );
305
-                continue;
306
-            }
307
-            $transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
308
-            $payment = EEM_Payment::instance()->get_one_by_ID($PAY_ID);
309
-            // verify transaction
310
-            if ($transaction instanceof EE_Transaction && $payment instanceof EE_Payment) {
311
-                // now try to update the TXN with any payments
312
-                $payment_processor->update_txn_based_on_payment($transaction, $payment, true, true);
313
-            }
314
-            unset(self::$_update_transactions_with_payment[ $TXN_ID ]);
315
-        }
316
-    }
317
-
318
-
319
-
320
-    /************  END OF UPDATE TRANSACTION WITH PAYMENT  ************/
321
-
322
-
323
-    /*****************  EXPIRED TRANSACTION CHECK *****************/
324
-
325
-
326
-    /**
327
-     * array of TXN IDs
328
-     *
329
-     * @var array
330
-     */
331
-    protected static $_expired_transactions = array();
332
-
333
-
334
-    /**
335
-     * schedule_expired_transaction_check
336
-     * sets a wp_schedule_single_event() for following up on TXNs after their session has expired
337
-     *
338
-     * @param int $timestamp
339
-     * @param int $TXN_ID
340
-     */
341
-    public static function schedule_expired_transaction_check(
342
-        $timestamp,
343
-        $TXN_ID
344
-    ) {
345
-        // validate $TXN_ID and $timestamp
346
-        $TXN_ID = absint($TXN_ID);
347
-        $timestamp = absint($timestamp);
348
-        if ($TXN_ID && $timestamp) {
349
-            wp_schedule_single_event(
350
-                $timestamp,
351
-                'AHEE__EE_Cron_Tasks__expired_transaction_check',
352
-                array($TXN_ID)
353
-            );
354
-        }
355
-    }
356
-
357
-
358
-    /**
359
-     * expired_transaction_check
360
-     * this is the callback for the action hook:
361
-     * 'AHEE__EE_Cron_Tasks__transaction_session_expiration_check'
362
-     * which is utilized by wp_schedule_single_event()
363
-     * in \EED_Single_Page_Checkout::_initialize_transaction().
364
-     * The passed TXN_ID gets added to an array, and then the
365
-     * process_expired_transactions() function is hooked into
366
-     * 'AHEE__EE_System__core_loaded_and_ready' which will actually handle the
367
-     * processing of any failed transactions, because doing so now would be
368
-     * too early and the required resources may not be available
369
-     *
370
-     * @param int $TXN_ID
371
-     */
372
-    public static function expired_transaction_check($TXN_ID = 0)
373
-    {
374
-        if (absint($TXN_ID)) {
375
-            self::$_expired_transactions[ $TXN_ID ] = $TXN_ID;
376
-            add_action(
377
-                'shutdown',
378
-                array('EE_Cron_Tasks', 'process_expired_transactions'),
379
-                5
380
-            );
381
-        }
382
-    }
383
-
384
-
385
-    /**
386
-     * process_expired_transactions
387
-     * loops through the self::$_expired_transactions array and processes any failed TXNs
388
-     *
389
-     * @throws EE_Error
390
-     * @throws InvalidDataTypeException
391
-     * @throws InvalidInterfaceException
392
-     * @throws InvalidArgumentException
393
-     * @throws ReflectionException
394
-     * @throws DomainException
395
-     * @throws RuntimeException
396
-     */
397
-    public static function process_expired_transactions()
398
-    {
399
-        if (// are there any TXNs that need cleaning up ?
400
-            empty(self::$_expired_transactions)
401
-            // reschedule the cron if we can't hit the db right now
402
-            || EE_Cron_Tasks::reschedule_cron_for_transactions_if_maintenance_mode(
403
-                'schedule_expired_transaction_check',
404
-                self::$_expired_transactions
405
-            )
406
-        ) {
407
-            return;
408
-        }
409
-        /** @type EE_Transaction_Processor $transaction_processor */
410
-        $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
411
-        // set revisit flag for txn processor
412
-        $transaction_processor->set_revisit();
413
-        // load EEM_Transaction
414
-        EE_Registry::instance()->load_model('Transaction');
415
-        foreach (self::$_expired_transactions as $TXN_ID) {
416
-            $transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
417
-            // verify transaction and whether it is failed or not
418
-            if ($transaction instanceof EE_Transaction) {
419
-                switch ($transaction->status_ID()) {
420
-                    // Completed TXNs
421
-                    case EEM_Transaction::complete_status_code:
422
-                        // Don't update the transaction/registrations if the Primary Registration is Not Approved.
423
-                        $primary_registration = $transaction->primary_registration();
424
-                        if ($primary_registration instanceof EE_Registration
425
-                            && $primary_registration->status_ID() !== EEM_Registration::status_id_not_approved
426
-                        ) {
427
-                            /** @type EE_Transaction_Processor $transaction_processor */
428
-                            $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
429
-                            $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment(
430
-                                $transaction,
431
-                                $transaction->last_payment()
432
-                            );
433
-                            do_action(
434
-                                'AHEE__EE_Cron_Tasks__process_expired_transactions__completed_transaction',
435
-                                $transaction
436
-                            );
437
-                        }
438
-                        break;
439
-                    // Overpaid TXNs
440
-                    case EEM_Transaction::overpaid_status_code:
441
-                        do_action(
442
-                            'AHEE__EE_Cron_Tasks__process_expired_transactions__overpaid_transaction',
443
-                            $transaction
444
-                        );
445
-                        break;
446
-                    // Incomplete TXNs
447
-                    case EEM_Transaction::incomplete_status_code:
448
-                        do_action(
449
-                            'AHEE__EE_Cron_Tasks__process_expired_transactions__incomplete_transaction',
450
-                            $transaction
451
-                        );
452
-                        // todo : move business logic into EE_Transaction_Processor for finalizing abandoned transactions
453
-                        break;
454
-                    // Abandoned TXNs
455
-                    case EEM_Transaction::abandoned_status_code:
456
-                        // run hook before updating transaction, primarily so
457
-                        // EED_Ticket_Sales_Monitor::process_abandoned_transactions() can release reserved tickets
458
-                        do_action(
459
-                            'AHEE__EE_Cron_Tasks__process_expired_transactions__abandoned_transaction',
460
-                            $transaction
461
-                        );
462
-                        // don't finalize the TXN if it has already been completed
463
-                        if ($transaction->all_reg_steps_completed() !== true) {
464
-                            /** @type EE_Payment_Processor $payment_processor */
465
-                            $payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
466
-                            // let's simulate an IPN here which will trigger any notifications that need to go out
467
-                            $payment_processor->update_txn_based_on_payment(
468
-                                $transaction,
469
-                                $transaction->last_payment(),
470
-                                true,
471
-                                true
472
-                            );
473
-                        }
474
-                        break;
475
-                    // Failed TXNs
476
-                    case EEM_Transaction::failed_status_code:
477
-                        do_action(
478
-                            'AHEE__EE_Cron_Tasks__process_expired_transactions__failed_transaction',
479
-                            $transaction
480
-                        );
481
-                        // todo :
482
-                        // perform garbage collection here and remove clean_out_junk_transactions()
483
-                        // $registrations = $transaction->registrations();
484
-                        // if (! empty($registrations)) {
485
-                        //     foreach ($registrations as $registration) {
486
-                        //         if ($registration instanceof EE_Registration) {
487
-                        //             $delete_registration = true;
488
-                        //             if ($registration->attendee() instanceof EE_Attendee) {
489
-                        //                 $delete_registration = false;
490
-                        //             }
491
-                        //             if ($delete_registration) {
492
-                        //                 $registration->delete_permanently();
493
-                        //                 $registration->delete_related_permanently();
494
-                        //             }
495
-                        //         }
496
-                        //     }
497
-                        // }
498
-                        break;
499
-                }
500
-            }
501
-            unset(self::$_expired_transactions[ $TXN_ID ]);
502
-        }
503
-    }
504
-
505
-
506
-
507
-    /*************  END OF EXPIRED TRANSACTION CHECK  *************/
508
-
509
-
510
-    /************* START CLEAN UP BOT TRANSACTIONS **********************/
511
-
512
-
513
-    /**
514
-     * callback for 'AHEE__EE_Cron_Tasks__clean_up_junk_transactions'
515
-     * which is setup during activation to run on an hourly cron
516
-     *
517
-     * @throws EE_Error
518
-     * @throws InvalidArgumentException
519
-     * @throws InvalidDataTypeException
520
-     * @throws InvalidInterfaceException
521
-     * @throws DomainException
522
-     */
523
-    public static function clean_out_junk_transactions()
524
-    {
525
-        if (EE_Maintenance_Mode::instance()->models_can_query()) {
526
-            EED_Ticket_Sales_Monitor::reset_reservation_counts();
527
-            EEM_Transaction::instance('')->delete_junk_transactions();
528
-            EEM_Registration::instance('')->delete_registrations_with_no_transaction();
529
-            EEM_Line_Item::instance('')->delete_line_items_with_no_transaction();
530
-        }
531
-    }
532
-
533
-
534
-    /**
535
-     * Deletes old gateway logs. After about a week we usually don't need them for debugging. But folks can filter that.
536
-     *
537
-     * @throws EE_Error
538
-     * @throws InvalidDataTypeException
539
-     * @throws InvalidInterfaceException
540
-     * @throws InvalidArgumentException
541
-     */
542
-    public static function clean_out_old_gateway_logs()
543
-    {
544
-        if (EE_Maintenance_Mode::instance()->models_can_query()) {
545
-            $reg_config = LoaderFactory::getLoader()->load('EE_Registration_Config');
546
-            $time_diff_for_comparison = apply_filters(
547
-                'FHEE__EE_Cron_Tasks__clean_out_old_gateway_logs__time_diff_for_comparison',
548
-                '-' . $reg_config->gateway_log_lifespan
549
-            );
550
-            EEM_Change_Log::instance()->delete_gateway_logs_older_than(new DateTime($time_diff_for_comparison));
551
-        }
552
-    }
553
-
554
-
555
-    /*****************  FINALIZE ABANDONED TRANSACTIONS *****************/
556
-
557
-
558
-    /**
559
-     * @var array
560
-     */
561
-    protected static $_abandoned_transactions = array();
562
-
563
-
564
-    /**
565
-     * @deprecated
566
-     * @param int $timestamp
567
-     * @param int $TXN_ID
568
-     */
569
-    public static function schedule_finalize_abandoned_transactions_check($timestamp, $TXN_ID)
570
-    {
571
-        EE_Cron_Tasks::schedule_expired_transaction_check($timestamp, $TXN_ID);
572
-    }
573
-
574
-
575
-    /**
576
-     * @deprecated
577
-     * @param int $TXN_ID
578
-     */
579
-    public static function check_for_abandoned_transactions($TXN_ID = 0)
580
-    {
581
-        EE_Cron_Tasks::expired_transaction_check($TXN_ID);
582
-    }
583
-
584
-
585
-    /**
586
-     * @deprecated
587
-     * @throws EE_Error
588
-     * @throws DomainException
589
-     * @throws InvalidDataTypeException
590
-     * @throws InvalidInterfaceException
591
-     * @throws InvalidArgumentException
592
-     * @throws ReflectionException
593
-     * @throws RuntimeException
594
-     */
595
-    public static function finalize_abandoned_transactions()
596
-    {
597
-        do_action('AHEE_log', __CLASS__, __FUNCTION__);
598
-        if (// are there any TXNs that need cleaning up ?
599
-            empty(self::$_abandoned_transactions)
600
-            // reschedule the cron if we can't hit the db right now
601
-            || EE_Cron_Tasks::reschedule_cron_for_transactions_if_maintenance_mode(
602
-                'schedule_expired_transaction_check',
603
-                self::$_abandoned_transactions
604
-            )
605
-        ) {
606
-            return;
607
-        }
608
-        // combine our arrays of transaction IDs
609
-        self::$_expired_transactions = self::$_abandoned_transactions + self::$_expired_transactions;
610
-        // and deal with abandoned transactions here now...
611
-        EE_Cron_Tasks::process_expired_transactions();
612
-    }
613
-
614
-
615
-    /*************  END OF FINALIZE ABANDONED TRANSACTIONS  *************/
18
+	/**
19
+	 * WordPress doesn't allow duplicate crons within 10 minutes of the original,
20
+	 * so we'll set our retry time for just over 10 minutes to avoid that
21
+	 */
22
+	const reschedule_timeout = 605;
23
+
24
+
25
+	/**
26
+	 * @var EE_Cron_Tasks
27
+	 */
28
+	private static $_instance;
29
+
30
+
31
+	/**
32
+	 * @return EE_Cron_Tasks
33
+	 * @throws ReflectionException
34
+	 * @throws EE_Error
35
+	 * @throws InvalidArgumentException
36
+	 * @throws InvalidInterfaceException
37
+	 * @throws InvalidDataTypeException
38
+	 */
39
+	public static function instance()
40
+	{
41
+		if (! self::$_instance instanceof EE_Cron_Tasks) {
42
+			self::$_instance = new self();
43
+		}
44
+		return self::$_instance;
45
+	}
46
+
47
+
48
+	/**
49
+	 * @access private
50
+	 * @throws InvalidDataTypeException
51
+	 * @throws InvalidInterfaceException
52
+	 * @throws InvalidArgumentException
53
+	 * @throws EE_Error
54
+	 * @throws ReflectionException
55
+	 */
56
+	private function __construct()
57
+	{
58
+		do_action('AHEE_log', __CLASS__, __FUNCTION__);
59
+		// verify that WP Cron is enabled
60
+		if (defined('DISABLE_WP_CRON')
61
+			&& DISABLE_WP_CRON
62
+			&& is_admin()
63
+			&& ! get_option('ee_disabled_wp_cron_check')
64
+		) {
65
+			/**
66
+			 * This needs to be delayed until after the config is loaded because EE_Cron_Tasks is constructed before
67
+			 * config is loaded.
68
+			 * This is intentionally using a anonymous function so that its not easily de-registered.  Client code
69
+			 * wanting to not have this functionality can just register its own action at a priority after this one to
70
+			 * reverse any changes.
71
+			 */
72
+			add_action(
73
+				'AHEE__EE_System__load_core_configuration__complete',
74
+				function () {
75
+					EE_Registry::instance()->NET_CFG->core->do_messages_on_same_request = true;
76
+					EE_Registry::instance()->NET_CFG->update_config(true, false);
77
+					add_option('ee_disabled_wp_cron_check', 1, '', false);
78
+				}
79
+			);
80
+		}
81
+		// UPDATE TRANSACTION WITH PAYMENT
82
+		add_action(
83
+			'AHEE__EE_Cron_Tasks__update_transaction_with_payment_2',
84
+			array('EE_Cron_Tasks', 'setup_update_for_transaction_with_payment'),
85
+			10,
86
+			2
87
+		);
88
+		// ABANDONED / EXPIRED TRANSACTION CHECK
89
+		add_action(
90
+			'AHEE__EE_Cron_Tasks__expired_transaction_check',
91
+			array('EE_Cron_Tasks', 'expired_transaction_check'),
92
+			10,
93
+			1
94
+		);
95
+		// CLEAN OUT JUNK TRANSACTIONS AND RELATED DATA
96
+		add_action(
97
+			'AHEE__EE_Cron_Tasks__clean_up_junk_transactions',
98
+			array('EE_Cron_Tasks', 'clean_out_junk_transactions')
99
+		);
100
+		// logging
101
+		add_action(
102
+			'AHEE__EE_System__load_core_configuration__complete',
103
+			array('EE_Cron_Tasks', 'log_scheduled_ee_crons')
104
+		);
105
+		EE_Registry::instance()->load_lib('Messages_Scheduler');
106
+		// clean out old gateway logs
107
+		add_action(
108
+			'AHEE_EE_Cron_Tasks__clean_out_old_gateway_logs',
109
+			array('EE_Cron_Tasks', 'clean_out_old_gateway_logs')
110
+		);
111
+	}
112
+
113
+
114
+	/**
115
+	 * @access protected
116
+	 * @return void
117
+	 */
118
+	public static function log_scheduled_ee_crons()
119
+	{
120
+		$ee_crons = array(
121
+			'AHEE__EE_Cron_Tasks__update_transaction_with_payment',
122
+			'AHEE__EE_Cron_Tasks__finalize_abandoned_transactions',
123
+			'AHEE__EE_Cron_Tasks__clean_up_junk_transactions',
124
+		);
125
+		$crons = (array) get_option('cron');
126
+		if (! is_array($crons)) {
127
+			return;
128
+		}
129
+		foreach ($crons as $timestamp => $cron) {
130
+			/** @var array[] $cron */
131
+			foreach ($ee_crons as $ee_cron) {
132
+				if (isset($cron[ $ee_cron ]) && is_array($cron[ $ee_cron ])) {
133
+					do_action('AHEE_log', __CLASS__, __FUNCTION__, $ee_cron, 'scheduled EE cron');
134
+					foreach ($cron[ $ee_cron ] as $ee_cron_details) {
135
+						if (! empty($ee_cron_details['args'])) {
136
+							do_action(
137
+								'AHEE_log',
138
+								__CLASS__,
139
+								__FUNCTION__,
140
+								print_r($ee_cron_details['args'], true),
141
+								"{$ee_cron} args"
142
+							);
143
+						}
144
+					}
145
+				}
146
+			}
147
+		}
148
+	}
149
+
150
+
151
+	/**
152
+	 * reschedule_cron_for_transactions_if_maintenance_mode
153
+	 * if Maintenance Mode is active, this will reschedule a cron to run again in 10 minutes
154
+	 *
155
+	 * @param string $cron_task
156
+	 * @param array  $TXN_IDs
157
+	 * @return bool
158
+	 * @throws DomainException
159
+	 */
160
+	public static function reschedule_cron_for_transactions_if_maintenance_mode($cron_task, array $TXN_IDs)
161
+	{
162
+		if (! method_exists('EE_Cron_Tasks', $cron_task)) {
163
+			throw new DomainException(
164
+				sprintf(
165
+					__('"%1$s" is not valid method on EE_Cron_Tasks.', 'event_espresso'),
166
+					$cron_task
167
+				)
168
+			);
169
+		}
170
+		// reschedule the cron if we can't hit the db right now
171
+		if (! EE_Maintenance_Mode::instance()->models_can_query()) {
172
+			foreach ($TXN_IDs as $TXN_ID => $additional_vars) {
173
+				// ensure $additional_vars is an array
174
+				$additional_vars = is_array($additional_vars) ? $additional_vars : array($additional_vars);
175
+				// reset cron job for the TXN
176
+				call_user_func_array(
177
+					array('EE_Cron_Tasks', $cron_task),
178
+					array_merge(
179
+						array(
180
+							time() + (10 * MINUTE_IN_SECONDS),
181
+							$TXN_ID,
182
+						),
183
+						$additional_vars
184
+					)
185
+				);
186
+			}
187
+			return true;
188
+		}
189
+		return false;
190
+	}
191
+
192
+
193
+
194
+
195
+	/****************  UPDATE TRANSACTION WITH PAYMENT ****************/
196
+
197
+
198
+	/**
199
+	 * array of TXN IDs and the payment
200
+	 *
201
+	 * @var array
202
+	 */
203
+	protected static $_update_transactions_with_payment = array();
204
+
205
+
206
+	/**
207
+	 * schedule_update_transaction_with_payment
208
+	 * sets a wp_schedule_single_event() for updating any TXNs that may
209
+	 * require updating due to recently received payments
210
+	 *
211
+	 * @param int $timestamp
212
+	 * @param int $TXN_ID
213
+	 * @param int $PAY_ID
214
+	 */
215
+	public static function schedule_update_transaction_with_payment(
216
+		$timestamp,
217
+		$TXN_ID,
218
+		$PAY_ID
219
+	) {
220
+		do_action('AHEE_log', __CLASS__, __FUNCTION__);
221
+		// validate $TXN_ID and $timestamp
222
+		$TXN_ID = absint($TXN_ID);
223
+		$timestamp = absint($timestamp);
224
+		if ($TXN_ID && $timestamp) {
225
+			wp_schedule_single_event(
226
+				$timestamp,
227
+				'AHEE__EE_Cron_Tasks__update_transaction_with_payment_2',
228
+				array($TXN_ID, $PAY_ID)
229
+			);
230
+		}
231
+	}
232
+
233
+
234
+	/**
235
+	 * setup_update_for_transaction_with_payment
236
+	 * this is the callback for the action hook:
237
+	 * 'AHEE__EE_Cron_Tasks__update_transaction_with_payment'
238
+	 * which is setup by EE_Cron_Tasks::schedule_update_transaction_with_payment().
239
+	 * The passed TXN_ID and associated payment gets added to an array, and then
240
+	 * the EE_Cron_Tasks::update_transaction_with_payment() function is hooked into
241
+	 * 'shutdown' which will actually handle the processing of any
242
+	 * transactions requiring updating, because doing so now would be too early
243
+	 * and the required resources may not be available
244
+	 *
245
+	 * @param int $TXN_ID
246
+	 * @param int $PAY_ID
247
+	 */
248
+	public static function setup_update_for_transaction_with_payment($TXN_ID = 0, $PAY_ID = 0)
249
+	{
250
+		do_action('AHEE_log', __CLASS__, __FUNCTION__, $TXN_ID, '$TXN_ID');
251
+		if (absint($TXN_ID)) {
252
+			self::$_update_transactions_with_payment[ $TXN_ID ] = $PAY_ID;
253
+			add_action(
254
+				'shutdown',
255
+				array('EE_Cron_Tasks', 'update_transaction_with_payment'),
256
+				5
257
+			);
258
+		}
259
+	}
260
+
261
+
262
+	/**
263
+	 * update_transaction_with_payment
264
+	 * loops through the self::$_abandoned_transactions array
265
+	 * and attempts to finalize any TXNs that have not been completed
266
+	 * but have had their sessions expired, most likely due to a user not
267
+	 * returning from an off-site payment gateway
268
+	 *
269
+	 * @throws EE_Error
270
+	 * @throws DomainException
271
+	 * @throws InvalidDataTypeException
272
+	 * @throws InvalidInterfaceException
273
+	 * @throws InvalidArgumentException
274
+	 * @throws ReflectionException
275
+	 * @throws RuntimeException
276
+	 */
277
+	public static function update_transaction_with_payment()
278
+	{
279
+		do_action('AHEE_log', __CLASS__, __FUNCTION__);
280
+		if (// are there any TXNs that need cleaning up ?
281
+			empty(self::$_update_transactions_with_payment)
282
+			// reschedule the cron if we can't hit the db right now
283
+			|| EE_Cron_Tasks::reschedule_cron_for_transactions_if_maintenance_mode(
284
+				'schedule_update_transaction_with_payment',
285
+				self::$_update_transactions_with_payment
286
+			)
287
+		) {
288
+			return;
289
+		}
290
+		/** @type EE_Payment_Processor $payment_processor */
291
+		$payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
292
+		// set revisit flag for payment processor
293
+		$payment_processor->set_revisit();
294
+		// load EEM_Transaction
295
+		EE_Registry::instance()->load_model('Transaction');
296
+		foreach (self::$_update_transactions_with_payment as $TXN_ID => $PAY_ID) {
297
+			// reschedule the cron if we can't hit the db right now
298
+			if (! EE_Maintenance_Mode::instance()->models_can_query()) {
299
+				// reset cron job for updating the TXN
300
+				EE_Cron_Tasks::schedule_update_transaction_with_payment(
301
+					time() + EE_Cron_Tasks::reschedule_timeout,
302
+					$TXN_ID,
303
+					$PAY_ID
304
+				);
305
+				continue;
306
+			}
307
+			$transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
308
+			$payment = EEM_Payment::instance()->get_one_by_ID($PAY_ID);
309
+			// verify transaction
310
+			if ($transaction instanceof EE_Transaction && $payment instanceof EE_Payment) {
311
+				// now try to update the TXN with any payments
312
+				$payment_processor->update_txn_based_on_payment($transaction, $payment, true, true);
313
+			}
314
+			unset(self::$_update_transactions_with_payment[ $TXN_ID ]);
315
+		}
316
+	}
317
+
318
+
319
+
320
+	/************  END OF UPDATE TRANSACTION WITH PAYMENT  ************/
321
+
322
+
323
+	/*****************  EXPIRED TRANSACTION CHECK *****************/
324
+
325
+
326
+	/**
327
+	 * array of TXN IDs
328
+	 *
329
+	 * @var array
330
+	 */
331
+	protected static $_expired_transactions = array();
332
+
333
+
334
+	/**
335
+	 * schedule_expired_transaction_check
336
+	 * sets a wp_schedule_single_event() for following up on TXNs after their session has expired
337
+	 *
338
+	 * @param int $timestamp
339
+	 * @param int $TXN_ID
340
+	 */
341
+	public static function schedule_expired_transaction_check(
342
+		$timestamp,
343
+		$TXN_ID
344
+	) {
345
+		// validate $TXN_ID and $timestamp
346
+		$TXN_ID = absint($TXN_ID);
347
+		$timestamp = absint($timestamp);
348
+		if ($TXN_ID && $timestamp) {
349
+			wp_schedule_single_event(
350
+				$timestamp,
351
+				'AHEE__EE_Cron_Tasks__expired_transaction_check',
352
+				array($TXN_ID)
353
+			);
354
+		}
355
+	}
356
+
357
+
358
+	/**
359
+	 * expired_transaction_check
360
+	 * this is the callback for the action hook:
361
+	 * 'AHEE__EE_Cron_Tasks__transaction_session_expiration_check'
362
+	 * which is utilized by wp_schedule_single_event()
363
+	 * in \EED_Single_Page_Checkout::_initialize_transaction().
364
+	 * The passed TXN_ID gets added to an array, and then the
365
+	 * process_expired_transactions() function is hooked into
366
+	 * 'AHEE__EE_System__core_loaded_and_ready' which will actually handle the
367
+	 * processing of any failed transactions, because doing so now would be
368
+	 * too early and the required resources may not be available
369
+	 *
370
+	 * @param int $TXN_ID
371
+	 */
372
+	public static function expired_transaction_check($TXN_ID = 0)
373
+	{
374
+		if (absint($TXN_ID)) {
375
+			self::$_expired_transactions[ $TXN_ID ] = $TXN_ID;
376
+			add_action(
377
+				'shutdown',
378
+				array('EE_Cron_Tasks', 'process_expired_transactions'),
379
+				5
380
+			);
381
+		}
382
+	}
383
+
384
+
385
+	/**
386
+	 * process_expired_transactions
387
+	 * loops through the self::$_expired_transactions array and processes any failed TXNs
388
+	 *
389
+	 * @throws EE_Error
390
+	 * @throws InvalidDataTypeException
391
+	 * @throws InvalidInterfaceException
392
+	 * @throws InvalidArgumentException
393
+	 * @throws ReflectionException
394
+	 * @throws DomainException
395
+	 * @throws RuntimeException
396
+	 */
397
+	public static function process_expired_transactions()
398
+	{
399
+		if (// are there any TXNs that need cleaning up ?
400
+			empty(self::$_expired_transactions)
401
+			// reschedule the cron if we can't hit the db right now
402
+			|| EE_Cron_Tasks::reschedule_cron_for_transactions_if_maintenance_mode(
403
+				'schedule_expired_transaction_check',
404
+				self::$_expired_transactions
405
+			)
406
+		) {
407
+			return;
408
+		}
409
+		/** @type EE_Transaction_Processor $transaction_processor */
410
+		$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
411
+		// set revisit flag for txn processor
412
+		$transaction_processor->set_revisit();
413
+		// load EEM_Transaction
414
+		EE_Registry::instance()->load_model('Transaction');
415
+		foreach (self::$_expired_transactions as $TXN_ID) {
416
+			$transaction = EEM_Transaction::instance()->get_one_by_ID($TXN_ID);
417
+			// verify transaction and whether it is failed or not
418
+			if ($transaction instanceof EE_Transaction) {
419
+				switch ($transaction->status_ID()) {
420
+					// Completed TXNs
421
+					case EEM_Transaction::complete_status_code:
422
+						// Don't update the transaction/registrations if the Primary Registration is Not Approved.
423
+						$primary_registration = $transaction->primary_registration();
424
+						if ($primary_registration instanceof EE_Registration
425
+							&& $primary_registration->status_ID() !== EEM_Registration::status_id_not_approved
426
+						) {
427
+							/** @type EE_Transaction_Processor $transaction_processor */
428
+							$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
429
+							$transaction_processor->update_transaction_and_registrations_after_checkout_or_payment(
430
+								$transaction,
431
+								$transaction->last_payment()
432
+							);
433
+							do_action(
434
+								'AHEE__EE_Cron_Tasks__process_expired_transactions__completed_transaction',
435
+								$transaction
436
+							);
437
+						}
438
+						break;
439
+					// Overpaid TXNs
440
+					case EEM_Transaction::overpaid_status_code:
441
+						do_action(
442
+							'AHEE__EE_Cron_Tasks__process_expired_transactions__overpaid_transaction',
443
+							$transaction
444
+						);
445
+						break;
446
+					// Incomplete TXNs
447
+					case EEM_Transaction::incomplete_status_code:
448
+						do_action(
449
+							'AHEE__EE_Cron_Tasks__process_expired_transactions__incomplete_transaction',
450
+							$transaction
451
+						);
452
+						// todo : move business logic into EE_Transaction_Processor for finalizing abandoned transactions
453
+						break;
454
+					// Abandoned TXNs
455
+					case EEM_Transaction::abandoned_status_code:
456
+						// run hook before updating transaction, primarily so
457
+						// EED_Ticket_Sales_Monitor::process_abandoned_transactions() can release reserved tickets
458
+						do_action(
459
+							'AHEE__EE_Cron_Tasks__process_expired_transactions__abandoned_transaction',
460
+							$transaction
461
+						);
462
+						// don't finalize the TXN if it has already been completed
463
+						if ($transaction->all_reg_steps_completed() !== true) {
464
+							/** @type EE_Payment_Processor $payment_processor */
465
+							$payment_processor = EE_Registry::instance()->load_core('Payment_Processor');
466
+							// let's simulate an IPN here which will trigger any notifications that need to go out
467
+							$payment_processor->update_txn_based_on_payment(
468
+								$transaction,
469
+								$transaction->last_payment(),
470
+								true,
471
+								true
472
+							);
473
+						}
474
+						break;
475
+					// Failed TXNs
476
+					case EEM_Transaction::failed_status_code:
477
+						do_action(
478
+							'AHEE__EE_Cron_Tasks__process_expired_transactions__failed_transaction',
479
+							$transaction
480
+						);
481
+						// todo :
482
+						// perform garbage collection here and remove clean_out_junk_transactions()
483
+						// $registrations = $transaction->registrations();
484
+						// if (! empty($registrations)) {
485
+						//     foreach ($registrations as $registration) {
486
+						//         if ($registration instanceof EE_Registration) {
487
+						//             $delete_registration = true;
488
+						//             if ($registration->attendee() instanceof EE_Attendee) {
489
+						//                 $delete_registration = false;
490
+						//             }
491
+						//             if ($delete_registration) {
492
+						//                 $registration->delete_permanently();
493
+						//                 $registration->delete_related_permanently();
494
+						//             }
495
+						//         }
496
+						//     }
497
+						// }
498
+						break;
499
+				}
500
+			}
501
+			unset(self::$_expired_transactions[ $TXN_ID ]);
502
+		}
503
+	}
504
+
505
+
506
+
507
+	/*************  END OF EXPIRED TRANSACTION CHECK  *************/
508
+
509
+
510
+	/************* START CLEAN UP BOT TRANSACTIONS **********************/
511
+
512
+
513
+	/**
514
+	 * callback for 'AHEE__EE_Cron_Tasks__clean_up_junk_transactions'
515
+	 * which is setup during activation to run on an hourly cron
516
+	 *
517
+	 * @throws EE_Error
518
+	 * @throws InvalidArgumentException
519
+	 * @throws InvalidDataTypeException
520
+	 * @throws InvalidInterfaceException
521
+	 * @throws DomainException
522
+	 */
523
+	public static function clean_out_junk_transactions()
524
+	{
525
+		if (EE_Maintenance_Mode::instance()->models_can_query()) {
526
+			EED_Ticket_Sales_Monitor::reset_reservation_counts();
527
+			EEM_Transaction::instance('')->delete_junk_transactions();
528
+			EEM_Registration::instance('')->delete_registrations_with_no_transaction();
529
+			EEM_Line_Item::instance('')->delete_line_items_with_no_transaction();
530
+		}
531
+	}
532
+
533
+
534
+	/**
535
+	 * Deletes old gateway logs. After about a week we usually don't need them for debugging. But folks can filter that.
536
+	 *
537
+	 * @throws EE_Error
538
+	 * @throws InvalidDataTypeException
539
+	 * @throws InvalidInterfaceException
540
+	 * @throws InvalidArgumentException
541
+	 */
542
+	public static function clean_out_old_gateway_logs()
543
+	{
544
+		if (EE_Maintenance_Mode::instance()->models_can_query()) {
545
+			$reg_config = LoaderFactory::getLoader()->load('EE_Registration_Config');
546
+			$time_diff_for_comparison = apply_filters(
547
+				'FHEE__EE_Cron_Tasks__clean_out_old_gateway_logs__time_diff_for_comparison',
548
+				'-' . $reg_config->gateway_log_lifespan
549
+			);
550
+			EEM_Change_Log::instance()->delete_gateway_logs_older_than(new DateTime($time_diff_for_comparison));
551
+		}
552
+	}
553
+
554
+
555
+	/*****************  FINALIZE ABANDONED TRANSACTIONS *****************/
556
+
557
+
558
+	/**
559
+	 * @var array
560
+	 */
561
+	protected static $_abandoned_transactions = array();
562
+
563
+
564
+	/**
565
+	 * @deprecated
566
+	 * @param int $timestamp
567
+	 * @param int $TXN_ID
568
+	 */
569
+	public static function schedule_finalize_abandoned_transactions_check($timestamp, $TXN_ID)
570
+	{
571
+		EE_Cron_Tasks::schedule_expired_transaction_check($timestamp, $TXN_ID);
572
+	}
573
+
574
+
575
+	/**
576
+	 * @deprecated
577
+	 * @param int $TXN_ID
578
+	 */
579
+	public static function check_for_abandoned_transactions($TXN_ID = 0)
580
+	{
581
+		EE_Cron_Tasks::expired_transaction_check($TXN_ID);
582
+	}
583
+
584
+
585
+	/**
586
+	 * @deprecated
587
+	 * @throws EE_Error
588
+	 * @throws DomainException
589
+	 * @throws InvalidDataTypeException
590
+	 * @throws InvalidInterfaceException
591
+	 * @throws InvalidArgumentException
592
+	 * @throws ReflectionException
593
+	 * @throws RuntimeException
594
+	 */
595
+	public static function finalize_abandoned_transactions()
596
+	{
597
+		do_action('AHEE_log', __CLASS__, __FUNCTION__);
598
+		if (// are there any TXNs that need cleaning up ?
599
+			empty(self::$_abandoned_transactions)
600
+			// reschedule the cron if we can't hit the db right now
601
+			|| EE_Cron_Tasks::reschedule_cron_for_transactions_if_maintenance_mode(
602
+				'schedule_expired_transaction_check',
603
+				self::$_abandoned_transactions
604
+			)
605
+		) {
606
+			return;
607
+		}
608
+		// combine our arrays of transaction IDs
609
+		self::$_expired_transactions = self::$_abandoned_transactions + self::$_expired_transactions;
610
+		// and deal with abandoned transactions here now...
611
+		EE_Cron_Tasks::process_expired_transactions();
612
+	}
613
+
614
+
615
+	/*************  END OF FINALIZE ABANDONED TRANSACTIONS  *************/
616 616
 }
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.10.rc.000');
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.10.rc.000');
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
 }
Please login to merge, or discard this patch.
core/db_classes/EE_Registration.class.php 1 patch
Indentation   +2068 added lines, -2068 removed lines patch added patch discarded remove patch
@@ -17,2072 +17,2072 @@
 block discarded – undo
17 17
 {
18 18
 
19 19
 
20
-    /**
21
-     * Used to reference when a registration has never been checked in.
22
-     *
23
-     * @deprecated use \EE_Checkin::status_checked_never instead
24
-     * @type int
25
-     */
26
-    const checkin_status_never = 2;
27
-
28
-    /**
29
-     * Used to reference when a registration has been checked in.
30
-     *
31
-     * @deprecated use \EE_Checkin::status_checked_in instead
32
-     * @type int
33
-     */
34
-    const checkin_status_in = 1;
35
-
36
-
37
-    /**
38
-     * Used to reference when a registration has been checked out.
39
-     *
40
-     * @deprecated use \EE_Checkin::status_checked_out instead
41
-     * @type int
42
-     */
43
-    const checkin_status_out = 0;
44
-
45
-
46
-    /**
47
-     * extra meta key for tracking reg status os trashed registrations
48
-     *
49
-     * @type string
50
-     */
51
-    const PRE_TRASH_REG_STATUS_KEY = 'pre_trash_registration_status';
52
-
53
-
54
-    /**
55
-     * extra meta key for tracking if registration has reserved ticket
56
-     *
57
-     * @type string
58
-     */
59
-    const HAS_RESERVED_TICKET_KEY = 'has_reserved_ticket';
60
-
61
-
62
-    /**
63
-     * @param array  $props_n_values          incoming values
64
-     * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
65
-     *                                        used.)
66
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
67
-     *                                        date_format and the second value is the time format
68
-     * @return EE_Registration
69
-     * @throws EE_Error
70
-     */
71
-    public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
72
-    {
73
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
74
-        return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
75
-    }
76
-
77
-
78
-    /**
79
-     * @param array  $props_n_values  incoming values from the database
80
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
81
-     *                                the website will be used.
82
-     * @return EE_Registration
83
-     */
84
-    public static function new_instance_from_db($props_n_values = array(), $timezone = null)
85
-    {
86
-        return new self($props_n_values, true, $timezone);
87
-    }
88
-
89
-
90
-    /**
91
-     *        Set Event ID
92
-     *
93
-     * @param        int $EVT_ID Event ID
94
-     * @throws EE_Error
95
-     * @throws RuntimeException
96
-     */
97
-    public function set_event($EVT_ID = 0)
98
-    {
99
-        $this->set('EVT_ID', $EVT_ID);
100
-    }
101
-
102
-
103
-    /**
104
-     * Overrides parent set() method so that all calls to set( 'REG_code', $REG_code ) OR set( 'STS_ID', $STS_ID ) can
105
-     * be routed to internal methods
106
-     *
107
-     * @param string $field_name
108
-     * @param mixed  $field_value
109
-     * @param bool   $use_default
110
-     * @throws EE_Error
111
-     * @throws EntityNotFoundException
112
-     * @throws InvalidArgumentException
113
-     * @throws InvalidDataTypeException
114
-     * @throws InvalidInterfaceException
115
-     * @throws ReflectionException
116
-     * @throws RuntimeException
117
-     */
118
-    public function set($field_name, $field_value, $use_default = false)
119
-    {
120
-        switch ($field_name) {
121
-            case 'REG_code':
122
-                if (! empty($field_value) && $this->reg_code() === null) {
123
-                    $this->set_reg_code($field_value, $use_default);
124
-                }
125
-                break;
126
-            case 'STS_ID':
127
-                $this->set_status($field_value, $use_default);
128
-                break;
129
-            default:
130
-                parent::set($field_name, $field_value, $use_default);
131
-        }
132
-    }
133
-
134
-
135
-    /**
136
-     * Set Status ID
137
-     * updates the registration status and ALSO...
138
-     * calls reserve_registration_space() if the reg status changes TO approved from any other reg status
139
-     * calls release_registration_space() if the reg status changes FROM approved to any other reg status
140
-     *
141
-     * @param string                $new_STS_ID
142
-     * @param boolean               $use_default
143
-     * @param ContextInterface|null $context
144
-     * @return bool
145
-     * @throws DomainException
146
-     * @throws EE_Error
147
-     * @throws EntityNotFoundException
148
-     * @throws InvalidArgumentException
149
-     * @throws InvalidDataTypeException
150
-     * @throws InvalidInterfaceException
151
-     * @throws ReflectionException
152
-     * @throws RuntimeException
153
-     * @throws UnexpectedEntityException
154
-     */
155
-    public function set_status($new_STS_ID = null, $use_default = false, ContextInterface $context = null)
156
-    {
157
-        // get current REG_Status
158
-        $old_STS_ID = $this->status_ID();
159
-        // if status has changed
160
-        if ($old_STS_ID !== $new_STS_ID // and that status has actually changed
161
-            && ! empty($old_STS_ID) // and that old status is actually set
162
-            && ! empty($new_STS_ID) // as well as the new status
163
-            && $this->ID() // ensure registration is in the db
164
-        ) {
165
-            // update internal status first
166
-            parent::set('STS_ID', $new_STS_ID, $use_default);
167
-            // THEN handle other changes that occur when reg status changes
168
-            // TO approved
169
-            if ($new_STS_ID === EEM_Registration::status_id_approved) {
170
-                // reserve a space by incrementing ticket and datetime sold values
171
-                $this->reserveRegistrationSpace();
172
-                do_action('AHEE__EE_Registration__set_status__to_approved', $this, $old_STS_ID, $new_STS_ID, $context);
173
-                // OR FROM  approved
174
-            } elseif ($old_STS_ID === EEM_Registration::status_id_approved) {
175
-                // release a space by decrementing ticket and datetime sold values
176
-                $this->releaseRegistrationSpace();
177
-                do_action(
178
-                    'AHEE__EE_Registration__set_status__from_approved',
179
-                    $this,
180
-                    $old_STS_ID,
181
-                    $new_STS_ID,
182
-                    $context
183
-                );
184
-            }
185
-            // update status
186
-            parent::set('STS_ID', $new_STS_ID, $use_default);
187
-            $this->updateIfCanceledOrReinstated($new_STS_ID, $old_STS_ID, $context);
188
-            if ($this->statusChangeUpdatesTransaction($context)) {
189
-                $this->updateTransactionAfterStatusChange();
190
-            }
191
-            do_action('AHEE__EE_Registration__set_status__after_update', $this, $old_STS_ID, $new_STS_ID, $context);
192
-            return true;
193
-        }
194
-        // even though the old value matches the new value, it's still good to
195
-        // allow the parent set method to have a say
196
-        parent::set('STS_ID', $new_STS_ID, $use_default);
197
-        return true;
198
-    }
199
-
200
-
201
-    /**
202
-     * update REGs and TXN when cancelled or declined registrations involved
203
-     *
204
-     * @param string                $new_STS_ID
205
-     * @param string                $old_STS_ID
206
-     * @param ContextInterface|null $context
207
-     * @throws EE_Error
208
-     * @throws InvalidArgumentException
209
-     * @throws InvalidDataTypeException
210
-     * @throws InvalidInterfaceException
211
-     * @throws ReflectionException
212
-     * @throws RuntimeException
213
-     */
214
-    private function updateIfCanceledOrReinstated($new_STS_ID, $old_STS_ID, ContextInterface $context = null)
215
-    {
216
-        // these reg statuses should not be considered in any calculations involving monies owing
217
-        $closed_reg_statuses = EEM_Registration::closed_reg_statuses();
218
-        // true if registration has been cancelled or declined
219
-        $this->updateIfCanceled(
220
-            $closed_reg_statuses,
221
-            $new_STS_ID,
222
-            $old_STS_ID,
223
-            $context
224
-        );
225
-        $this->updateIfReinstated(
226
-            $closed_reg_statuses,
227
-            $new_STS_ID,
228
-            $old_STS_ID,
229
-            $context
230
-        );
231
-    }
232
-
233
-
234
-    /**
235
-     * update REGs and TXN when cancelled or declined registrations involved
236
-     *
237
-     * @param array                 $closed_reg_statuses
238
-     * @param string                $new_STS_ID
239
-     * @param string                $old_STS_ID
240
-     * @param ContextInterface|null $context
241
-     * @throws EE_Error
242
-     * @throws InvalidArgumentException
243
-     * @throws InvalidDataTypeException
244
-     * @throws InvalidInterfaceException
245
-     * @throws ReflectionException
246
-     * @throws RuntimeException
247
-     */
248
-    private function updateIfCanceled(
249
-        array $closed_reg_statuses,
250
-        $new_STS_ID,
251
-        $old_STS_ID,
252
-        ContextInterface $context = null
253
-    ) {
254
-        // true if registration has been cancelled or declined
255
-        if (in_array($new_STS_ID, $closed_reg_statuses, true)
256
-            && ! in_array($old_STS_ID, $closed_reg_statuses, true)
257
-        ) {
258
-            /** @type EE_Registration_Processor $registration_processor */
259
-            $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
260
-            /** @type EE_Transaction_Processor $transaction_processor */
261
-            $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
262
-            // cancelled or declined registration
263
-            $registration_processor->update_registration_after_being_canceled_or_declined(
264
-                $this,
265
-                $closed_reg_statuses
266
-            );
267
-            $transaction_processor->update_transaction_after_canceled_or_declined_registration(
268
-                $this,
269
-                $closed_reg_statuses,
270
-                false
271
-            );
272
-            do_action(
273
-                'AHEE__EE_Registration__set_status__canceled_or_declined',
274
-                $this,
275
-                $old_STS_ID,
276
-                $new_STS_ID,
277
-                $context
278
-            );
279
-            return;
280
-        }
281
-    }
282
-
283
-
284
-    /**
285
-     * update REGs and TXN when cancelled or declined registrations involved
286
-     *
287
-     * @param array                 $closed_reg_statuses
288
-     * @param string                $new_STS_ID
289
-     * @param string                $old_STS_ID
290
-     * @param ContextInterface|null $context
291
-     * @throws EE_Error
292
-     * @throws InvalidArgumentException
293
-     * @throws InvalidDataTypeException
294
-     * @throws InvalidInterfaceException
295
-     * @throws ReflectionException
296
-     */
297
-    private function updateIfReinstated(
298
-        array $closed_reg_statuses,
299
-        $new_STS_ID,
300
-        $old_STS_ID,
301
-        ContextInterface $context = null
302
-    ) {
303
-        // true if reinstating cancelled or declined registration
304
-        if (in_array($old_STS_ID, $closed_reg_statuses, true)
305
-            && ! in_array($new_STS_ID, $closed_reg_statuses, true)
306
-        ) {
307
-            /** @type EE_Registration_Processor $registration_processor */
308
-            $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
309
-            /** @type EE_Transaction_Processor $transaction_processor */
310
-            $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
311
-            // reinstating cancelled or declined registration
312
-            $registration_processor->update_canceled_or_declined_registration_after_being_reinstated(
313
-                $this,
314
-                $closed_reg_statuses
315
-            );
316
-            $transaction_processor->update_transaction_after_reinstating_canceled_registration(
317
-                $this,
318
-                $closed_reg_statuses,
319
-                false
320
-            );
321
-            do_action(
322
-                'AHEE__EE_Registration__set_status__after_reinstated',
323
-                $this,
324
-                $old_STS_ID,
325
-                $new_STS_ID,
326
-                $context
327
-            );
328
-        }
329
-    }
330
-
331
-
332
-    /**
333
-     * @param ContextInterface|null $context
334
-     * @return bool
335
-     */
336
-    private function statusChangeUpdatesTransaction(ContextInterface $context = null)
337
-    {
338
-        $contexts_that_do_not_update_transaction = (array) apply_filters(
339
-            'AHEE__EE_Registration__statusChangeUpdatesTransaction__contexts_that_do_not_update_transaction',
340
-            array('spco_reg_step_attendee_information_process_registrations'),
341
-            $context,
342
-            $this
343
-        );
344
-        return ! (
345
-            $context instanceof ContextInterface
346
-            && in_array($context->slug(), $contexts_that_do_not_update_transaction, true)
347
-        );
348
-    }
349
-
350
-
351
-    /**
352
-     * @throws EE_Error
353
-     * @throws EntityNotFoundException
354
-     * @throws InvalidArgumentException
355
-     * @throws InvalidDataTypeException
356
-     * @throws InvalidInterfaceException
357
-     * @throws ReflectionException
358
-     * @throws RuntimeException
359
-     */
360
-    private function updateTransactionAfterStatusChange()
361
-    {
362
-        /** @type EE_Transaction_Payments $transaction_payments */
363
-        $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
364
-        $transaction_payments->recalculate_transaction_total($this->transaction(), false);
365
-        $this->transaction()->update_status_based_on_total_paid(true);
366
-    }
367
-
368
-
369
-    /**
370
-     *        get Status ID
371
-     */
372
-    public function status_ID()
373
-    {
374
-        return $this->get('STS_ID');
375
-    }
376
-
377
-
378
-    /**
379
-     * Gets the ticket this registration is for
380
-     *
381
-     * @param boolean $include_archived whether to include archived tickets or not.
382
-     *
383
-     * @return EE_Ticket|EE_Base_Class
384
-     * @throws EE_Error
385
-     */
386
-    public function ticket($include_archived = true)
387
-    {
388
-        $query_params = array();
389
-        if ($include_archived) {
390
-            $query_params['default_where_conditions'] = 'none';
391
-        }
392
-        return $this->get_first_related('Ticket', $query_params);
393
-    }
394
-
395
-
396
-    /**
397
-     * Gets the event this registration is for
398
-     *
399
-     * @return EE_Event
400
-     * @throws EE_Error
401
-     * @throws EntityNotFoundException
402
-     */
403
-    public function event()
404
-    {
405
-        $event = $this->get_first_related('Event');
406
-        if (! $event instanceof \EE_Event) {
407
-            throw new EntityNotFoundException('Event ID', $this->event_ID());
408
-        }
409
-        return $event;
410
-    }
411
-
412
-
413
-    /**
414
-     * Gets the "author" of the registration.  Note that for the purposes of registrations, the author will correspond
415
-     * with the author of the event this registration is for.
416
-     *
417
-     * @since 4.5.0
418
-     * @return int
419
-     * @throws EE_Error
420
-     * @throws EntityNotFoundException
421
-     */
422
-    public function wp_user()
423
-    {
424
-        $event = $this->event();
425
-        if ($event instanceof EE_Event) {
426
-            return $event->wp_user();
427
-        }
428
-        return 0;
429
-    }
430
-
431
-
432
-    /**
433
-     * increments this registration's related ticket sold and corresponding datetime sold values
434
-     *
435
-     * @return void
436
-     * @throws DomainException
437
-     * @throws EE_Error
438
-     * @throws EntityNotFoundException
439
-     * @throws InvalidArgumentException
440
-     * @throws InvalidDataTypeException
441
-     * @throws InvalidInterfaceException
442
-     * @throws ReflectionException
443
-     * @throws UnexpectedEntityException
444
-     */
445
-    private function reserveRegistrationSpace()
446
-    {
447
-        // reserved ticket and datetime counts will be decremented as sold counts are incremented
448
-        // so stop tracking that this reg has a ticket reserved
449
-        $this->release_reserved_ticket(false, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
450
-        $ticket = $this->ticket();
451
-        $ticket->increaseSold();
452
-        // possibly set event status to sold out
453
-        $this->event()->perform_sold_out_status_check();
454
-    }
455
-
456
-
457
-    /**
458
-     * decrements (subtracts) this registration's related ticket sold and corresponding datetime sold values
459
-     *
460
-     * @return void
461
-     * @throws DomainException
462
-     * @throws EE_Error
463
-     * @throws EntityNotFoundException
464
-     * @throws InvalidArgumentException
465
-     * @throws InvalidDataTypeException
466
-     * @throws InvalidInterfaceException
467
-     * @throws ReflectionException
468
-     * @throws UnexpectedEntityException
469
-     */
470
-    private function releaseRegistrationSpace()
471
-    {
472
-        $ticket = $this->ticket();
473
-        $ticket->decreaseSold();
474
-        // possibly change event status from sold out back to previous status
475
-        $this->event()->perform_sold_out_status_check();
476
-    }
477
-
478
-
479
-    /**
480
-     * tracks this registration's ticket reservation in extra meta
481
-     * and can increment related ticket reserved and corresponding datetime reserved values
482
-     *
483
-     * @param bool $update_ticket if true, will increment ticket and datetime reserved count
484
-     * @return void
485
-     * @throws EE_Error
486
-     * @throws InvalidArgumentException
487
-     * @throws InvalidDataTypeException
488
-     * @throws InvalidInterfaceException
489
-     * @throws ReflectionException
490
-     */
491
-    public function reserve_ticket($update_ticket = false, $source = 'unknown')
492
-    {
493
-        // only reserve ticket if space is not currently reserved
494
-        if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) !== true) {
495
-            $this->update_extra_meta('reserve_ticket', "{$this->ticket_ID()} from {$source}");
496
-            // IMPORTANT !!!
497
-            // although checking $update_ticket first would be more efficient,
498
-            // we NEED to ALWAYS call update_extra_meta(), which is why that is done first
499
-            if ($this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true)
500
-                && $update_ticket
501
-            ) {
502
-                $ticket = $this->ticket();
503
-                $ticket->increaseReserved(1, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
504
-                $ticket->save();
505
-            }
506
-        }
507
-    }
508
-
509
-
510
-    /**
511
-     * stops tracking this registration's ticket reservation in extra meta
512
-     * decrements (subtracts) related ticket reserved and corresponding datetime reserved values
513
-     *
514
-     * @param bool $update_ticket if true, will decrement ticket and datetime reserved count
515
-     * @return void
516
-     * @throws EE_Error
517
-     * @throws InvalidArgumentException
518
-     * @throws InvalidDataTypeException
519
-     * @throws InvalidInterfaceException
520
-     * @throws ReflectionException
521
-     */
522
-    public function release_reserved_ticket($update_ticket = false, $source = 'unknown')
523
-    {
524
-        // only release ticket if space is currently reserved
525
-        if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) === true) {
526
-            $this->update_extra_meta('release_reserved_ticket', "{$this->ticket_ID()} from {$source}");
527
-            // IMPORTANT !!!
528
-            // although checking $update_ticket first would be more efficient,
529
-            // we NEED to ALWAYS call update_extra_meta(), which is why that is done first
530
-            if ($this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, false)
531
-                && $update_ticket
532
-            ) {
533
-                $ticket = $this->ticket();
534
-                $ticket->decreaseReserved(1, true, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
535
-            }
536
-        }
537
-    }
538
-
539
-
540
-    /**
541
-     * Set Attendee ID
542
-     *
543
-     * @param        int $ATT_ID Attendee ID
544
-     * @throws EE_Error
545
-     * @throws RuntimeException
546
-     */
547
-    public function set_attendee_id($ATT_ID = 0)
548
-    {
549
-        $this->set('ATT_ID', $ATT_ID);
550
-    }
551
-
552
-
553
-    /**
554
-     *        Set Transaction ID
555
-     *
556
-     * @param        int $TXN_ID Transaction ID
557
-     * @throws EE_Error
558
-     * @throws RuntimeException
559
-     */
560
-    public function set_transaction_id($TXN_ID = 0)
561
-    {
562
-        $this->set('TXN_ID', $TXN_ID);
563
-    }
564
-
565
-
566
-    /**
567
-     *        Set Session
568
-     *
569
-     * @param    string $REG_session PHP Session ID
570
-     * @throws EE_Error
571
-     * @throws RuntimeException
572
-     */
573
-    public function set_session($REG_session = '')
574
-    {
575
-        $this->set('REG_session', $REG_session);
576
-    }
577
-
578
-
579
-    /**
580
-     *        Set Registration URL Link
581
-     *
582
-     * @param    string $REG_url_link Registration URL Link
583
-     * @throws EE_Error
584
-     * @throws RuntimeException
585
-     */
586
-    public function set_reg_url_link($REG_url_link = '')
587
-    {
588
-        $this->set('REG_url_link', $REG_url_link);
589
-    }
590
-
591
-
592
-    /**
593
-     *        Set Attendee Counter
594
-     *
595
-     * @param        int $REG_count Primary Attendee
596
-     * @throws EE_Error
597
-     * @throws RuntimeException
598
-     */
599
-    public function set_count($REG_count = 1)
600
-    {
601
-        $this->set('REG_count', $REG_count);
602
-    }
603
-
604
-
605
-    /**
606
-     *        Set Group Size
607
-     *
608
-     * @param        boolean $REG_group_size Group Registration
609
-     * @throws EE_Error
610
-     * @throws RuntimeException
611
-     */
612
-    public function set_group_size($REG_group_size = false)
613
-    {
614
-        $this->set('REG_group_size', $REG_group_size);
615
-    }
616
-
617
-
618
-    /**
619
-     *    is_not_approved -  convenience method that returns TRUE if REG status ID ==
620
-     *    EEM_Registration::status_id_not_approved
621
-     *
622
-     * @return        boolean
623
-     */
624
-    public function is_not_approved()
625
-    {
626
-        return $this->status_ID() == EEM_Registration::status_id_not_approved ? true : false;
627
-    }
628
-
629
-
630
-    /**
631
-     *    is_pending_payment -  convenience method that returns TRUE if REG status ID ==
632
-     *    EEM_Registration::status_id_pending_payment
633
-     *
634
-     * @return        boolean
635
-     */
636
-    public function is_pending_payment()
637
-    {
638
-        return $this->status_ID() == EEM_Registration::status_id_pending_payment ? true : false;
639
-    }
640
-
641
-
642
-    /**
643
-     *    is_approved -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_approved
644
-     *
645
-     * @return        boolean
646
-     */
647
-    public function is_approved()
648
-    {
649
-        return $this->status_ID() == EEM_Registration::status_id_approved ? true : false;
650
-    }
651
-
652
-
653
-    /**
654
-     *    is_cancelled -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_cancelled
655
-     *
656
-     * @return        boolean
657
-     */
658
-    public function is_cancelled()
659
-    {
660
-        return $this->status_ID() == EEM_Registration::status_id_cancelled ? true : false;
661
-    }
662
-
663
-
664
-    /**
665
-     *    is_declined -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_declined
666
-     *
667
-     * @return        boolean
668
-     */
669
-    public function is_declined()
670
-    {
671
-        return $this->status_ID() == EEM_Registration::status_id_declined ? true : false;
672
-    }
673
-
674
-
675
-    /**
676
-     *    is_incomplete -  convenience method that returns TRUE if REG status ID ==
677
-     *    EEM_Registration::status_id_incomplete
678
-     *
679
-     * @return        boolean
680
-     */
681
-    public function is_incomplete()
682
-    {
683
-        return $this->status_ID() == EEM_Registration::status_id_incomplete ? true : false;
684
-    }
685
-
686
-
687
-    /**
688
-     *        Set Registration Date
689
-     *
690
-     * @param        mixed ( int or string ) $REG_date Registration Date - Unix timestamp or string representation of
691
-     *                                                 Date
692
-     * @throws EE_Error
693
-     * @throws RuntimeException
694
-     */
695
-    public function set_reg_date($REG_date = false)
696
-    {
697
-        $this->set('REG_date', $REG_date);
698
-    }
699
-
700
-
701
-    /**
702
-     *    Set final price owing for this registration after all ticket/price modifications
703
-     *
704
-     * @access    public
705
-     * @param    float $REG_final_price
706
-     * @throws EE_Error
707
-     * @throws RuntimeException
708
-     */
709
-    public function set_final_price($REG_final_price = 0.00)
710
-    {
711
-        $this->set('REG_final_price', $REG_final_price);
712
-    }
713
-
714
-
715
-    /**
716
-     *    Set amount paid towards this registration's final price
717
-     *
718
-     * @access    public
719
-     * @param    float $REG_paid
720
-     * @throws EE_Error
721
-     * @throws RuntimeException
722
-     */
723
-    public function set_paid($REG_paid = 0.00)
724
-    {
725
-        $this->set('REG_paid', $REG_paid);
726
-    }
727
-
728
-
729
-    /**
730
-     *        Attendee Is Going
731
-     *
732
-     * @param        boolean $REG_att_is_going Attendee Is Going
733
-     * @throws EE_Error
734
-     * @throws RuntimeException
735
-     */
736
-    public function set_att_is_going($REG_att_is_going = false)
737
-    {
738
-        $this->set('REG_att_is_going', $REG_att_is_going);
739
-    }
740
-
741
-
742
-    /**
743
-     * Gets the related attendee
744
-     *
745
-     * @return EE_Attendee
746
-     * @throws EE_Error
747
-     */
748
-    public function attendee()
749
-    {
750
-        return $this->get_first_related('Attendee');
751
-    }
752
-
753
-
754
-    /**
755
-     *        get Event ID
756
-     */
757
-    public function event_ID()
758
-    {
759
-        return $this->get('EVT_ID');
760
-    }
761
-
762
-
763
-    /**
764
-     *        get Event ID
765
-     */
766
-    public function event_name()
767
-    {
768
-        $event = $this->event_obj();
769
-        if ($event) {
770
-            return $event->name();
771
-        } else {
772
-            return null;
773
-        }
774
-    }
775
-
776
-
777
-    /**
778
-     * Fetches the event this registration is for
779
-     *
780
-     * @return EE_Event
781
-     * @throws EE_Error
782
-     */
783
-    public function event_obj()
784
-    {
785
-        return $this->get_first_related('Event');
786
-    }
787
-
788
-
789
-    /**
790
-     *        get Attendee ID
791
-     */
792
-    public function attendee_ID()
793
-    {
794
-        return $this->get('ATT_ID');
795
-    }
796
-
797
-
798
-    /**
799
-     *        get PHP Session ID
800
-     */
801
-    public function session_ID()
802
-    {
803
-        return $this->get('REG_session');
804
-    }
805
-
806
-
807
-    /**
808
-     * Gets the string which represents the URL trigger for the receipt template in the message template system.
809
-     *
810
-     * @param string $messenger 'pdf' or 'html'.  Default 'html'.
811
-     * @return string
812
-     */
813
-    public function receipt_url($messenger = 'html')
814
-    {
815
-
816
-        /**
817
-         * The below will be deprecated one version after this.  We check first if there is a custom receipt template
818
-         * already in use on old system.  If there is then we just return the standard url for it.
819
-         *
820
-         * @since 4.5.0
821
-         */
822
-        $template_relative_path = 'modules/gateways/Invoice/lib/templates/receipt_body.template.php';
823
-        $has_custom = EEH_Template::locate_template(
824
-            $template_relative_path,
825
-            array(),
826
-            true,
827
-            true,
828
-            true
829
-        );
830
-
831
-        if ($has_custom) {
832
-            return add_query_arg(array('receipt' => 'true'), $this->invoice_url('launch'));
833
-        }
834
-        return apply_filters('FHEE__EE_Registration__receipt_url__receipt_url', '', $this, $messenger, 'receipt');
835
-    }
836
-
837
-
838
-    /**
839
-     * Gets the string which represents the URL trigger for the invoice template in the message template system.
840
-     *
841
-     * @param string $messenger 'pdf' or 'html'.  Default 'html'.
842
-     * @return string
843
-     * @throws EE_Error
844
-     */
845
-    public function invoice_url($messenger = 'html')
846
-    {
847
-        /**
848
-         * The below will be deprecated one version after this.  We check first if there is a custom invoice template
849
-         * already in use on old system.  If there is then we just return the standard url for it.
850
-         *
851
-         * @since 4.5.0
852
-         */
853
-        $template_relative_path = 'modules/gateways/Invoice/lib/templates/invoice_body.template.php';
854
-        $has_custom = EEH_Template::locate_template(
855
-            $template_relative_path,
856
-            array(),
857
-            true,
858
-            true,
859
-            true
860
-        );
861
-
862
-        if ($has_custom) {
863
-            if ($messenger == 'html') {
864
-                return $this->invoice_url('launch');
865
-            }
866
-            $route = $messenger == 'download' || $messenger == 'pdf' ? 'download_invoice' : 'launch_invoice';
867
-
868
-            $query_args = array('ee' => $route, 'id' => $this->reg_url_link());
869
-            if ($messenger == 'html') {
870
-                $query_args['html'] = true;
871
-            }
872
-            return add_query_arg($query_args, get_permalink(EE_Registry::instance()->CFG->core->thank_you_page_id));
873
-        }
874
-        return apply_filters('FHEE__EE_Registration__invoice_url__invoice_url', '', $this, $messenger, 'invoice');
875
-    }
876
-
877
-
878
-    /**
879
-     * get Registration URL Link
880
-     *
881
-     * @access public
882
-     * @return string
883
-     * @throws EE_Error
884
-     */
885
-    public function reg_url_link()
886
-    {
887
-        return (string) $this->get('REG_url_link');
888
-    }
889
-
890
-
891
-    /**
892
-     * Echoes out invoice_url()
893
-     *
894
-     * @param string $type 'download','launch', or 'html' (default is 'launch')
895
-     * @return void
896
-     * @throws EE_Error
897
-     */
898
-    public function e_invoice_url($type = 'launch')
899
-    {
900
-        echo $this->invoice_url($type);
901
-    }
902
-
903
-
904
-    /**
905
-     * Echoes out payment_overview_url
906
-     */
907
-    public function e_payment_overview_url()
908
-    {
909
-        echo $this->payment_overview_url();
910
-    }
911
-
912
-
913
-    /**
914
-     * Gets the URL for the checkout payment options reg step
915
-     * with this registration's REG_url_link added as a query parameter
916
-     *
917
-     * @param bool $clear_session Set to true when you want to clear the session on revisiting the
918
-     *                            payment overview url.
919
-     * @return string
920
-     * @throws InvalidInterfaceException
921
-     * @throws InvalidDataTypeException
922
-     * @throws EE_Error
923
-     * @throws InvalidArgumentException
924
-     */
925
-    public function payment_overview_url($clear_session = false)
926
-    {
927
-        return add_query_arg(
928
-            (array) apply_filters(
929
-                'FHEE__EE_Registration__payment_overview_url__query_args',
930
-                array(
931
-                    'e_reg_url_link' => $this->reg_url_link(),
932
-                    'step'           => 'payment_options',
933
-                    'revisit'        => true,
934
-                    'clear_session'  => (bool) $clear_session,
935
-                ),
936
-                $this
937
-            ),
938
-            EE_Registry::instance()->CFG->core->reg_page_url()
939
-        );
940
-    }
941
-
942
-
943
-    /**
944
-     * Gets the URL for the checkout attendee information reg step
945
-     * with this registration's REG_url_link added as a query parameter
946
-     *
947
-     * @return string
948
-     * @throws InvalidInterfaceException
949
-     * @throws InvalidDataTypeException
950
-     * @throws EE_Error
951
-     * @throws InvalidArgumentException
952
-     */
953
-    public function edit_attendee_information_url()
954
-    {
955
-        return add_query_arg(
956
-            (array) apply_filters(
957
-                'FHEE__EE_Registration__edit_attendee_information_url__query_args',
958
-                array(
959
-                    'e_reg_url_link' => $this->reg_url_link(),
960
-                    'step'           => 'attendee_information',
961
-                    'revisit'        => true,
962
-                ),
963
-                $this
964
-            ),
965
-            EE_Registry::instance()->CFG->core->reg_page_url()
966
-        );
967
-    }
968
-
969
-
970
-    /**
971
-     * Simply generates and returns the appropriate admin_url link to edit this registration
972
-     *
973
-     * @return string
974
-     * @throws EE_Error
975
-     */
976
-    public function get_admin_edit_url()
977
-    {
978
-        return EEH_URL::add_query_args_and_nonce(
979
-            array(
980
-                'page'    => 'espresso_registrations',
981
-                'action'  => 'view_registration',
982
-                '_REG_ID' => $this->ID(),
983
-            ),
984
-            admin_url('admin.php')
985
-        );
986
-    }
987
-
988
-
989
-    /**
990
-     *    is_primary_registrant?
991
-     */
992
-    public function is_primary_registrant()
993
-    {
994
-        return $this->get('REG_count') === 1 ? true : false;
995
-    }
996
-
997
-
998
-    /**
999
-     * This returns the primary registration object for this registration group (which may be this object).
1000
-     *
1001
-     * @return EE_Registration
1002
-     * @throws EE_Error
1003
-     */
1004
-    public function get_primary_registration()
1005
-    {
1006
-        if ($this->is_primary_registrant()) {
1007
-            return $this;
1008
-        }
1009
-
1010
-        // k reg_count !== 1 so let's get the EE_Registration object matching this txn_id and reg_count == 1
1011
-        /** @var EE_Registration $primary_registrant */
1012
-        $primary_registrant = EEM_Registration::instance()->get_one(
1013
-            array(
1014
-                array(
1015
-                    'TXN_ID'    => $this->transaction_ID(),
1016
-                    'REG_count' => 1,
1017
-                ),
1018
-            )
1019
-        );
1020
-        return $primary_registrant;
1021
-    }
1022
-
1023
-
1024
-    /**
1025
-     *        get  Attendee Number
1026
-     *
1027
-     * @access        public
1028
-     */
1029
-    public function count()
1030
-    {
1031
-        return $this->get('REG_count');
1032
-    }
1033
-
1034
-
1035
-    /**
1036
-     *        get Group Size
1037
-     */
1038
-    public function group_size()
1039
-    {
1040
-        return $this->get('REG_group_size');
1041
-    }
1042
-
1043
-
1044
-    /**
1045
-     *        get Registration Date
1046
-     */
1047
-    public function date()
1048
-    {
1049
-        return $this->get('REG_date');
1050
-    }
1051
-
1052
-
1053
-    /**
1054
-     * gets a pretty date
1055
-     *
1056
-     * @param string $date_format
1057
-     * @param string $time_format
1058
-     * @return string
1059
-     * @throws EE_Error
1060
-     */
1061
-    public function pretty_date($date_format = null, $time_format = null)
1062
-    {
1063
-        return $this->get_datetime('REG_date', $date_format, $time_format);
1064
-    }
1065
-
1066
-
1067
-    /**
1068
-     * final_price
1069
-     * the registration's share of the transaction total, so that the
1070
-     * sum of all the transaction's REG_final_prices equal the transaction's total
1071
-     *
1072
-     * @return float
1073
-     * @throws EE_Error
1074
-     */
1075
-    public function final_price()
1076
-    {
1077
-        return $this->get('REG_final_price');
1078
-    }
1079
-
1080
-
1081
-    /**
1082
-     * pretty_final_price
1083
-     *  final price as formatted string, with correct decimal places and currency symbol
1084
-     *
1085
-     * @return string
1086
-     * @throws EE_Error
1087
-     */
1088
-    public function pretty_final_price()
1089
-    {
1090
-        return $this->get_pretty('REG_final_price');
1091
-    }
1092
-
1093
-
1094
-    /**
1095
-     * get paid (yeah)
1096
-     *
1097
-     * @return float
1098
-     * @throws EE_Error
1099
-     */
1100
-    public function paid()
1101
-    {
1102
-        return $this->get('REG_paid');
1103
-    }
1104
-
1105
-
1106
-    /**
1107
-     * pretty_paid
1108
-     *
1109
-     * @return float
1110
-     * @throws EE_Error
1111
-     */
1112
-    public function pretty_paid()
1113
-    {
1114
-        return $this->get_pretty('REG_paid');
1115
-    }
1116
-
1117
-
1118
-    /**
1119
-     * owes_monies_and_can_pay
1120
-     * whether or not this registration has monies owing and it's' status allows payment
1121
-     *
1122
-     * @param array $requires_payment
1123
-     * @return bool
1124
-     * @throws EE_Error
1125
-     */
1126
-    public function owes_monies_and_can_pay($requires_payment = array())
1127
-    {
1128
-        // these reg statuses require payment (if event is not free)
1129
-        $requires_payment = ! empty($requires_payment)
1130
-            ? $requires_payment
1131
-            : EEM_Registration::reg_statuses_that_allow_payment();
1132
-        if (in_array($this->status_ID(), $requires_payment) &&
1133
-            $this->final_price() != 0 &&
1134
-            $this->final_price() != $this->paid()
1135
-        ) {
1136
-            return true;
1137
-        } else {
1138
-            return false;
1139
-        }
1140
-    }
1141
-
1142
-
1143
-    /**
1144
-     * Prints out the return value of $this->pretty_status()
1145
-     *
1146
-     * @param bool $show_icons
1147
-     * @return void
1148
-     * @throws EE_Error
1149
-     */
1150
-    public function e_pretty_status($show_icons = false)
1151
-    {
1152
-        echo $this->pretty_status($show_icons);
1153
-    }
1154
-
1155
-
1156
-    /**
1157
-     * Returns a nice version of the status for displaying to customers
1158
-     *
1159
-     * @param bool $show_icons
1160
-     * @return string
1161
-     * @throws EE_Error
1162
-     */
1163
-    public function pretty_status($show_icons = false)
1164
-    {
1165
-        $status = EEM_Status::instance()->localized_status(
1166
-            array($this->status_ID() => esc_html__('unknown', 'event_espresso')),
1167
-            false,
1168
-            'sentence'
1169
-        );
1170
-        $icon = '';
1171
-        switch ($this->status_ID()) {
1172
-            case EEM_Registration::status_id_approved:
1173
-                $icon = $show_icons
1174
-                    ? '<span class="dashicons dashicons-star-filled ee-icon-size-16 green-text"></span>'
1175
-                    : '';
1176
-                break;
1177
-            case EEM_Registration::status_id_pending_payment:
1178
-                $icon = $show_icons
1179
-                    ? '<span class="dashicons dashicons-star-half ee-icon-size-16 orange-text"></span>'
1180
-                    : '';
1181
-                break;
1182
-            case EEM_Registration::status_id_not_approved:
1183
-                $icon = $show_icons
1184
-                    ? '<span class="dashicons dashicons-marker ee-icon-size-16 orange-text"></span>'
1185
-                    : '';
1186
-                break;
1187
-            case EEM_Registration::status_id_cancelled:
1188
-                $icon = $show_icons
1189
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 lt-grey-text"></span>'
1190
-                    : '';
1191
-                break;
1192
-            case EEM_Registration::status_id_incomplete:
1193
-                $icon = $show_icons
1194
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 lt-orange-text"></span>'
1195
-                    : '';
1196
-                break;
1197
-            case EEM_Registration::status_id_declined:
1198
-                $icon = $show_icons
1199
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>'
1200
-                    : '';
1201
-                break;
1202
-            case EEM_Registration::status_id_wait_list:
1203
-                $icon = $show_icons
1204
-                    ? '<span class="dashicons dashicons-clipboard ee-icon-size-16 purple-text"></span>'
1205
-                    : '';
1206
-                break;
1207
-        }
1208
-        return $icon . $status[ $this->status_ID() ];
1209
-    }
1210
-
1211
-
1212
-    /**
1213
-     *        get Attendee Is Going
1214
-     */
1215
-    public function att_is_going()
1216
-    {
1217
-        return $this->get('REG_att_is_going');
1218
-    }
1219
-
1220
-
1221
-    /**
1222
-     * Gets related answers
1223
-     *
1224
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1225
-     * @return EE_Answer[]
1226
-     * @throws EE_Error
1227
-     */
1228
-    public function answers($query_params = null)
1229
-    {
1230
-        return $this->get_many_related('Answer', $query_params);
1231
-    }
1232
-
1233
-
1234
-    /**
1235
-     * Gets the registration's answer value to the specified question
1236
-     * (either the question's ID or a question object)
1237
-     *
1238
-     * @param EE_Question|int $question
1239
-     * @param bool            $pretty_value
1240
-     * @return array|string if pretty_value= true, the result will always be a string
1241
-     * (because the answer might be an array of answer values, so passing pretty_value=true
1242
-     * will convert it into some kind of string)
1243
-     * @throws EE_Error
1244
-     */
1245
-    public function answer_value_to_question($question, $pretty_value = true)
1246
-    {
1247
-        $question_id = EEM_Question::instance()->ensure_is_ID($question);
1248
-        return EEM_Answer::instance()->get_answer_value_to_question($this, $question_id, $pretty_value);
1249
-    }
1250
-
1251
-
1252
-    /**
1253
-     * question_groups
1254
-     * returns an array of EE_Question_Group objects for this registration
1255
-     *
1256
-     * @return EE_Question_Group[]
1257
-     * @throws EE_Error
1258
-     * @throws InvalidArgumentException
1259
-     * @throws InvalidDataTypeException
1260
-     * @throws InvalidInterfaceException
1261
-     * @throws ReflectionException
1262
-     */
1263
-    public function question_groups()
1264
-    {
1265
-        return EEM_Event::instance()->get_question_groups_for_event($this->event_ID(), $this);
1266
-    }
1267
-
1268
-
1269
-    /**
1270
-     * count_question_groups
1271
-     * returns a count of the number of EE_Question_Group objects for this registration
1272
-     *
1273
-     * @return int
1274
-     * @throws EE_Error
1275
-     * @throws EntityNotFoundException
1276
-     * @throws InvalidArgumentException
1277
-     * @throws InvalidDataTypeException
1278
-     * @throws InvalidInterfaceException
1279
-     * @throws ReflectionException
1280
-     */
1281
-    public function count_question_groups()
1282
-    {
1283
-        return EEM_Event::instance()->count_related(
1284
-            $this->event_ID(),
1285
-            'Question_Group',
1286
-            [
1287
-                [
1288
-                    'Event_Question_Group.'
1289
-                    . EEM_Event_Question_Group::instance()->fieldNameForContext($this->is_primary_registrant()) => true,
1290
-                ]
1291
-            ]
1292
-        );
1293
-    }
1294
-
1295
-
1296
-    /**
1297
-     * Returns the registration date in the 'standard' string format
1298
-     * (function may be improved in the future to allow for different formats and timezones)
1299
-     *
1300
-     * @return string
1301
-     * @throws EE_Error
1302
-     */
1303
-    public function reg_date()
1304
-    {
1305
-        return $this->get_datetime('REG_date');
1306
-    }
1307
-
1308
-
1309
-    /**
1310
-     * Gets the datetime-ticket for this registration (ie, it can be used to isolate
1311
-     * the ticket this registration purchased, or the datetime they have registered
1312
-     * to attend)
1313
-     *
1314
-     * @return EE_Datetime_Ticket
1315
-     * @throws EE_Error
1316
-     */
1317
-    public function datetime_ticket()
1318
-    {
1319
-        return $this->get_first_related('Datetime_Ticket');
1320
-    }
1321
-
1322
-
1323
-    /**
1324
-     * Sets the registration's datetime_ticket.
1325
-     *
1326
-     * @param EE_Datetime_Ticket $datetime_ticket
1327
-     * @return EE_Datetime_Ticket
1328
-     * @throws EE_Error
1329
-     */
1330
-    public function set_datetime_ticket($datetime_ticket)
1331
-    {
1332
-        return $this->_add_relation_to($datetime_ticket, 'Datetime_Ticket');
1333
-    }
1334
-
1335
-    /**
1336
-     * Gets deleted
1337
-     *
1338
-     * @return bool
1339
-     * @throws EE_Error
1340
-     */
1341
-    public function deleted()
1342
-    {
1343
-        return $this->get('REG_deleted');
1344
-    }
1345
-
1346
-    /**
1347
-     * Sets deleted
1348
-     *
1349
-     * @param boolean $deleted
1350
-     * @return bool
1351
-     * @throws EE_Error
1352
-     * @throws RuntimeException
1353
-     */
1354
-    public function set_deleted($deleted)
1355
-    {
1356
-        if ($deleted) {
1357
-            $this->delete();
1358
-        } else {
1359
-            $this->restore();
1360
-        }
1361
-    }
1362
-
1363
-
1364
-    /**
1365
-     * Get the status object of this object
1366
-     *
1367
-     * @return EE_Status
1368
-     * @throws EE_Error
1369
-     */
1370
-    public function status_obj()
1371
-    {
1372
-        return $this->get_first_related('Status');
1373
-    }
1374
-
1375
-
1376
-    /**
1377
-     * Returns the number of times this registration has checked into any of the datetimes
1378
-     * its available for
1379
-     *
1380
-     * @return int
1381
-     * @throws EE_Error
1382
-     */
1383
-    public function count_checkins()
1384
-    {
1385
-        return $this->get_model()->count_related($this, 'Checkin');
1386
-    }
1387
-
1388
-
1389
-    /**
1390
-     * Returns the number of current Check-ins this registration is checked into for any of the datetimes the
1391
-     * registration is for.  Note, this is ONLY checked in (does not include checkedout)
1392
-     *
1393
-     * @return int
1394
-     * @throws EE_Error
1395
-     */
1396
-    public function count_checkins_not_checkedout()
1397
-    {
1398
-        return $this->get_model()->count_related($this, 'Checkin', array(array('CHK_in' => 1)));
1399
-    }
1400
-
1401
-
1402
-    /**
1403
-     * The purpose of this method is simply to check whether this registration can checkin to the given datetime.
1404
-     *
1405
-     * @param int | EE_Datetime $DTT_OR_ID      The datetime the registration is being checked against
1406
-     * @param bool              $check_approved This is used to indicate whether the caller wants can_checkin to also
1407
-     *                                          consider registration status as well as datetime access.
1408
-     * @return bool
1409
-     * @throws EE_Error
1410
-     */
1411
-    public function can_checkin($DTT_OR_ID, $check_approved = true)
1412
-    {
1413
-        $DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1414
-
1415
-        // first check registration status
1416
-        if (($check_approved && ! $this->is_approved()) || ! $DTT_ID) {
1417
-            return false;
1418
-        }
1419
-        // is there a datetime ticket that matches this dtt_ID?
1420
-        if (! (EEM_Datetime_Ticket::instance()->exists(
1421
-            array(
1422
-                array(
1423
-                    'TKT_ID' => $this->get('TKT_ID'),
1424
-                    'DTT_ID' => $DTT_ID,
1425
-                ),
1426
-            )
1427
-        ))
1428
-        ) {
1429
-            return false;
1430
-        }
1431
-
1432
-        // final check is against TKT_uses
1433
-        return $this->verify_can_checkin_against_TKT_uses($DTT_ID);
1434
-    }
1435
-
1436
-
1437
-    /**
1438
-     * This method verifies whether the user can checkin for the given datetime considering the max uses value set on
1439
-     * the ticket. To do this,  a query is done to get the count of the datetime records already checked into.  If the
1440
-     * datetime given does not have a check-in record and checking in for that datetime will exceed the allowed uses,
1441
-     * then return false.  Otherwise return true.
1442
-     *
1443
-     * @param int | EE_Datetime $DTT_OR_ID The datetime the registration is being checked against
1444
-     * @return bool true means can checkin.  false means cannot checkin.
1445
-     * @throws EE_Error
1446
-     */
1447
-    public function verify_can_checkin_against_TKT_uses($DTT_OR_ID)
1448
-    {
1449
-        $DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1450
-
1451
-        if (! $DTT_ID) {
1452
-            return false;
1453
-        }
1454
-
1455
-        $max_uses = $this->ticket() instanceof EE_Ticket ? $this->ticket()->uses() : EE_INF;
1456
-
1457
-        // if max uses is not set or equals infinity then return true cause its not a factor for whether user can
1458
-        // check-in or not.
1459
-        if (! $max_uses || $max_uses === EE_INF) {
1460
-            return true;
1461
-        }
1462
-
1463
-        // does this datetime have a checkin record?  If so, then the dtt count has already been verified so we can just
1464
-        // go ahead and toggle.
1465
-        if (EEM_Checkin::instance()->exists(array(array('REG_ID' => $this->ID(), 'DTT_ID' => $DTT_ID)))) {
1466
-            return true;
1467
-        }
1468
-
1469
-        // made it here so the last check is whether the number of checkins per unique datetime on this registration
1470
-        // disallows further check-ins.
1471
-        $count_unique_dtt_checkins = EEM_Checkin::instance()->count(
1472
-            array(
1473
-                array(
1474
-                    'REG_ID' => $this->ID(),
1475
-                    'CHK_in' => true,
1476
-                ),
1477
-            ),
1478
-            'DTT_ID',
1479
-            true
1480
-        );
1481
-        // checkins have already reached their max number of uses
1482
-        // so registrant can NOT checkin
1483
-        if ($count_unique_dtt_checkins >= $max_uses) {
1484
-            EE_Error::add_error(
1485
-                esc_html__(
1486
-                    'Check-in denied because number of datetime uses for the ticket has been reached or exceeded.',
1487
-                    'event_espresso'
1488
-                ),
1489
-                __FILE__,
1490
-                __FUNCTION__,
1491
-                __LINE__
1492
-            );
1493
-            return false;
1494
-        }
1495
-        return true;
1496
-    }
1497
-
1498
-
1499
-    /**
1500
-     * toggle Check-in status for this registration
1501
-     * Check-ins are toggled in the following order:
1502
-     * never checked in -> checked in
1503
-     * checked in -> checked out
1504
-     * checked out -> checked in
1505
-     *
1506
-     * @param  int $DTT_ID  include specific datetime to toggle Check-in for.
1507
-     *                      If not included or null, then it is assumed latest datetime is being toggled.
1508
-     * @param bool $verify  If true then can_checkin() is used to verify whether the person
1509
-     *                      can be checked in or not.  Otherwise this forces change in checkin status.
1510
-     * @return bool|int     the chk_in status toggled to OR false if nothing got changed.
1511
-     * @throws EE_Error
1512
-     */
1513
-    public function toggle_checkin_status($DTT_ID = null, $verify = false)
1514
-    {
1515
-        if (empty($DTT_ID)) {
1516
-            $datetime = $this->get_latest_related_datetime();
1517
-            $DTT_ID = $datetime instanceof EE_Datetime ? $datetime->ID() : 0;
1518
-            // verify the registration can checkin for the given DTT_ID
1519
-        } elseif (! $this->can_checkin($DTT_ID, $verify)) {
1520
-            EE_Error::add_error(
1521
-                sprintf(
1522
-                    esc_html__(
1523
-                        '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',
1524
-                        'event_espresso'
1525
-                    ),
1526
-                    $this->ID(),
1527
-                    $DTT_ID
1528
-                ),
1529
-                __FILE__,
1530
-                __FUNCTION__,
1531
-                __LINE__
1532
-            );
1533
-            return false;
1534
-        }
1535
-        $status_paths = array(
1536
-            EE_Checkin::status_checked_never => EE_Checkin::status_checked_in,
1537
-            EE_Checkin::status_checked_in    => EE_Checkin::status_checked_out,
1538
-            EE_Checkin::status_checked_out   => EE_Checkin::status_checked_in,
1539
-        );
1540
-        // start by getting the current status so we know what status we'll be changing to.
1541
-        $cur_status = $this->check_in_status_for_datetime($DTT_ID, null);
1542
-        $status_to = $status_paths[ $cur_status ];
1543
-        // database only records true for checked IN or false for checked OUT
1544
-        // no record ( null ) means checked in NEVER, but we obviously don't save that
1545
-        $new_status = $status_to === EE_Checkin::status_checked_in ? true : false;
1546
-        // add relation - note Check-ins are always creating new rows
1547
-        // because we are keeping track of Check-ins over time.
1548
-        // Eventually we'll probably want to show a list table
1549
-        // for the individual Check-ins so that they can be managed.
1550
-        $checkin = EE_Checkin::new_instance(
1551
-            array(
1552
-                'REG_ID' => $this->ID(),
1553
-                'DTT_ID' => $DTT_ID,
1554
-                'CHK_in' => $new_status,
1555
-            )
1556
-        );
1557
-        // if the record could not be saved then return false
1558
-        if ($checkin->save() === 0) {
1559
-            if (WP_DEBUG) {
1560
-                global $wpdb;
1561
-                $error = sprintf(
1562
-                    esc_html__(
1563
-                        'Registration check in update failed because of the following database error: %1$s%2$s',
1564
-                        'event_espresso'
1565
-                    ),
1566
-                    '<br />',
1567
-                    $wpdb->last_error
1568
-                );
1569
-            } else {
1570
-                $error = esc_html__(
1571
-                    'Registration check in update failed because of an unknown database error',
1572
-                    'event_espresso'
1573
-                );
1574
-            }
1575
-            EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
1576
-            return false;
1577
-        }
1578
-        // Fire a checked_in and checkout_out action.
1579
-        $checked_status = $status_to === EE_Checkin::status_checked_in ? 'checked_in' : 'checked_out';
1580
-        do_action("AHEE__EE_Registration__toggle_checkin_status__{$checked_status}", $this, $DTT_ID);
1581
-        return $status_to;
1582
-    }
1583
-
1584
-
1585
-    /**
1586
-     * Returns the latest datetime related to this registration (via the ticket attached to the registration).
1587
-     * "Latest" is defined by the `DTT_EVT_start` column.
1588
-     *
1589
-     * @return EE_Datetime|null
1590
-     * @throws EE_Error
1591
-     */
1592
-    public function get_latest_related_datetime()
1593
-    {
1594
-        return EEM_Datetime::instance()->get_one(
1595
-            array(
1596
-                array(
1597
-                    'Ticket.Registration.REG_ID' => $this->ID(),
1598
-                ),
1599
-                'order_by' => array('DTT_EVT_start' => 'DESC'),
1600
-            )
1601
-        );
1602
-    }
1603
-
1604
-
1605
-    /**
1606
-     * Returns the earliest datetime related to this registration (via the ticket attached to the registration).
1607
-     * "Earliest" is defined by the `DTT_EVT_start` column.
1608
-     *
1609
-     * @throws EE_Error
1610
-     */
1611
-    public function get_earliest_related_datetime()
1612
-    {
1613
-        return EEM_Datetime::instance()->get_one(
1614
-            array(
1615
-                array(
1616
-                    'Ticket.Registration.REG_ID' => $this->ID(),
1617
-                ),
1618
-                'order_by' => array('DTT_EVT_start' => 'ASC'),
1619
-            )
1620
-        );
1621
-    }
1622
-
1623
-
1624
-    /**
1625
-     * This method simply returns the check-in status for this registration and the given datetime.
1626
-     * If neither the datetime nor the checkin values are provided as arguments,
1627
-     * then this will return the LATEST check-in status for the registration across all datetimes it belongs to.
1628
-     *
1629
-     * @param  int       $DTT_ID  The ID of the datetime we're checking against
1630
-     *                            (if empty we'll get the primary datetime for
1631
-     *                            this registration (via event) and use it's ID);
1632
-     * @param EE_Checkin $checkin If present, we use the given checkin object rather than the dtt_id.
1633
-     *
1634
-     * @return int                Integer representing Check-in status.
1635
-     * @throws EE_Error
1636
-     */
1637
-    public function check_in_status_for_datetime($DTT_ID = 0, $checkin = null)
1638
-    {
1639
-        $checkin_query_params = array(
1640
-            'order_by' => array('CHK_timestamp' => 'DESC'),
1641
-        );
1642
-
1643
-        if ($DTT_ID > 0) {
1644
-            $checkin_query_params[0] = array('DTT_ID' => $DTT_ID);
1645
-        }
1646
-
1647
-        // get checkin object (if exists)
1648
-        $checkin = $checkin instanceof EE_Checkin
1649
-            ? $checkin
1650
-            : $this->get_first_related('Checkin', $checkin_query_params);
1651
-        if ($checkin instanceof EE_Checkin) {
1652
-            if ($checkin->get('CHK_in')) {
1653
-                return EE_Checkin::status_checked_in; // checked in
1654
-            }
1655
-            return EE_Checkin::status_checked_out; // had checked in but is now checked out.
1656
-        }
1657
-        return EE_Checkin::status_checked_never; // never been checked in
1658
-    }
1659
-
1660
-
1661
-    /**
1662
-     * This method returns a localized message for the toggled Check-in message.
1663
-     *
1664
-     * @param  int $DTT_ID include specific datetime to get the correct Check-in message.  If not included or null,
1665
-     *                     then it is assumed Check-in for primary datetime was toggled.
1666
-     * @param bool $error  This just flags that you want an error message returned. This is put in so that the error
1667
-     *                     message can be customized with the attendee name.
1668
-     * @return string internationalized message
1669
-     * @throws EE_Error
1670
-     */
1671
-    public function get_checkin_msg($DTT_ID, $error = false)
1672
-    {
1673
-        // let's get the attendee first so we can include the name of the attendee
1674
-        $attendee = $this->get_first_related('Attendee');
1675
-        if ($attendee instanceof EE_Attendee) {
1676
-            if ($error) {
1677
-                return sprintf(__("%s's check-in status was not changed.", "event_espresso"), $attendee->full_name());
1678
-            }
1679
-            $cur_status = $this->check_in_status_for_datetime($DTT_ID);
1680
-            // what is the status message going to be?
1681
-            switch ($cur_status) {
1682
-                case EE_Checkin::status_checked_never:
1683
-                    return sprintf(
1684
-                        __("%s has been removed from Check-in records", "event_espresso"),
1685
-                        $attendee->full_name()
1686
-                    );
1687
-                    break;
1688
-                case EE_Checkin::status_checked_in:
1689
-                    return sprintf(__('%s has been checked in', 'event_espresso'), $attendee->full_name());
1690
-                    break;
1691
-                case EE_Checkin::status_checked_out:
1692
-                    return sprintf(__('%s has been checked out', 'event_espresso'), $attendee->full_name());
1693
-                    break;
1694
-            }
1695
-        }
1696
-        return esc_html__("The check-in status could not be determined.", "event_espresso");
1697
-    }
1698
-
1699
-
1700
-    /**
1701
-     * Returns the related EE_Transaction to this registration
1702
-     *
1703
-     * @return EE_Transaction
1704
-     * @throws EE_Error
1705
-     * @throws EntityNotFoundException
1706
-     */
1707
-    public function transaction()
1708
-    {
1709
-        $transaction = $this->get_first_related('Transaction');
1710
-        if (! $transaction instanceof \EE_Transaction) {
1711
-            throw new EntityNotFoundException('Transaction ID', $this->transaction_ID());
1712
-        }
1713
-        return $transaction;
1714
-    }
1715
-
1716
-
1717
-    /**
1718
-     *        get Registration Code
1719
-     */
1720
-    public function reg_code()
1721
-    {
1722
-        return $this->get('REG_code');
1723
-    }
1724
-
1725
-
1726
-    /**
1727
-     *        get Transaction ID
1728
-     */
1729
-    public function transaction_ID()
1730
-    {
1731
-        return $this->get('TXN_ID');
1732
-    }
1733
-
1734
-
1735
-    /**
1736
-     * @return int
1737
-     * @throws EE_Error
1738
-     */
1739
-    public function ticket_ID()
1740
-    {
1741
-        return $this->get('TKT_ID');
1742
-    }
1743
-
1744
-
1745
-    /**
1746
-     *        Set Registration Code
1747
-     *
1748
-     * @access    public
1749
-     * @param    string  $REG_code Registration Code
1750
-     * @param    boolean $use_default
1751
-     * @throws EE_Error
1752
-     */
1753
-    public function set_reg_code($REG_code, $use_default = false)
1754
-    {
1755
-        if (empty($REG_code)) {
1756
-            EE_Error::add_error(
1757
-                esc_html__('REG_code can not be empty.', 'event_espresso'),
1758
-                __FILE__,
1759
-                __FUNCTION__,
1760
-                __LINE__
1761
-            );
1762
-            return;
1763
-        }
1764
-        if (! $this->reg_code()) {
1765
-            parent::set('REG_code', $REG_code, $use_default);
1766
-        } else {
1767
-            EE_Error::doing_it_wrong(
1768
-                __CLASS__ . '::' . __FUNCTION__,
1769
-                esc_html__('Can not change a registration REG_code once it has been set.', 'event_espresso'),
1770
-                '4.6.0'
1771
-            );
1772
-        }
1773
-    }
1774
-
1775
-
1776
-    /**
1777
-     * Returns all other registrations in the same group as this registrant who have the same ticket option.
1778
-     * Note, if you want to just get all registrations in the same transaction (group), use:
1779
-     *    $registration->transaction()->registrations();
1780
-     *
1781
-     * @since 4.5.0
1782
-     * @return EE_Registration[] or empty array if this isn't a group registration.
1783
-     * @throws EE_Error
1784
-     */
1785
-    public function get_all_other_registrations_in_group()
1786
-    {
1787
-        if ($this->group_size() < 2) {
1788
-            return array();
1789
-        }
1790
-
1791
-        $query[0] = array(
1792
-            'TXN_ID' => $this->transaction_ID(),
1793
-            'REG_ID' => array('!=', $this->ID()),
1794
-            'TKT_ID' => $this->ticket_ID(),
1795
-        );
1796
-        /** @var EE_Registration[] $registrations */
1797
-        $registrations = $this->get_model()->get_all($query);
1798
-        return $registrations;
1799
-    }
1800
-
1801
-    /**
1802
-     * Return the link to the admin details for the object.
1803
-     *
1804
-     * @return string
1805
-     * @throws EE_Error
1806
-     */
1807
-    public function get_admin_details_link()
1808
-    {
1809
-        EE_Registry::instance()->load_helper('URL');
1810
-        return EEH_URL::add_query_args_and_nonce(
1811
-            array(
1812
-                'page'    => 'espresso_registrations',
1813
-                'action'  => 'view_registration',
1814
-                '_REG_ID' => $this->ID(),
1815
-            ),
1816
-            admin_url('admin.php')
1817
-        );
1818
-    }
1819
-
1820
-    /**
1821
-     * Returns the link to the editor for the object.  Sometimes this is the same as the details.
1822
-     *
1823
-     * @return string
1824
-     * @throws EE_Error
1825
-     */
1826
-    public function get_admin_edit_link()
1827
-    {
1828
-        return $this->get_admin_details_link();
1829
-    }
1830
-
1831
-    /**
1832
-     * Returns the link to a settings page for the object.
1833
-     *
1834
-     * @return string
1835
-     * @throws EE_Error
1836
-     */
1837
-    public function get_admin_settings_link()
1838
-    {
1839
-        return $this->get_admin_details_link();
1840
-    }
1841
-
1842
-    /**
1843
-     * Returns the link to the "overview" for the object (typically the "list table" view).
1844
-     *
1845
-     * @return string
1846
-     */
1847
-    public function get_admin_overview_link()
1848
-    {
1849
-        EE_Registry::instance()->load_helper('URL');
1850
-        return EEH_URL::add_query_args_and_nonce(
1851
-            array(
1852
-                'page' => 'espresso_registrations',
1853
-            ),
1854
-            admin_url('admin.php')
1855
-        );
1856
-    }
1857
-
1858
-
1859
-    /**
1860
-     * @param array $query_params
1861
-     *
1862
-     * @return \EE_Registration[]
1863
-     * @throws EE_Error
1864
-     */
1865
-    public function payments($query_params = array())
1866
-    {
1867
-        return $this->get_many_related('Payment', $query_params);
1868
-    }
1869
-
1870
-
1871
-    /**
1872
-     * @param array $query_params
1873
-     *
1874
-     * @return \EE_Registration_Payment[]
1875
-     * @throws EE_Error
1876
-     */
1877
-    public function registration_payments($query_params = array())
1878
-    {
1879
-        return $this->get_many_related('Registration_Payment', $query_params);
1880
-    }
1881
-
1882
-
1883
-    /**
1884
-     * This grabs the payment method corresponding to the last payment made for the amount owing on the registration.
1885
-     * Note: if there are no payments on the registration there will be no payment method returned.
1886
-     *
1887
-     * @return EE_Payment_Method|null
1888
-     */
1889
-    public function payment_method()
1890
-    {
1891
-        return EEM_Payment_Method::instance()->get_last_used_for_registration($this);
1892
-    }
1893
-
1894
-
1895
-    /**
1896
-     * @return \EE_Line_Item
1897
-     * @throws EntityNotFoundException
1898
-     * @throws EE_Error
1899
-     */
1900
-    public function ticket_line_item()
1901
-    {
1902
-        $ticket = $this->ticket();
1903
-        $transaction = $this->transaction();
1904
-        $line_item = null;
1905
-        $ticket_line_items = \EEH_Line_Item::get_line_items_by_object_type_and_IDs(
1906
-            $transaction->total_line_item(),
1907
-            'Ticket',
1908
-            array($ticket->ID())
1909
-        );
1910
-        foreach ($ticket_line_items as $ticket_line_item) {
1911
-            if ($ticket_line_item instanceof \EE_Line_Item
1912
-                && $ticket_line_item->OBJ_type() === 'Ticket'
1913
-                && $ticket_line_item->OBJ_ID() === $ticket->ID()
1914
-            ) {
1915
-                $line_item = $ticket_line_item;
1916
-                break;
1917
-            }
1918
-        }
1919
-        if (! ($line_item instanceof \EE_Line_Item && $line_item->OBJ_type() === 'Ticket')) {
1920
-            throw new EntityNotFoundException('Line Item Ticket ID', $ticket->ID());
1921
-        }
1922
-        return $line_item;
1923
-    }
1924
-
1925
-
1926
-    /**
1927
-     * Soft Deletes this model object.
1928
-     *
1929
-     * @return boolean | int
1930
-     * @throws RuntimeException
1931
-     * @throws EE_Error
1932
-     */
1933
-    public function delete()
1934
-    {
1935
-        if ($this->update_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY, $this->status_ID()) === true) {
1936
-            $this->set_status(EEM_Registration::status_id_cancelled);
1937
-        }
1938
-        return parent::delete();
1939
-    }
1940
-
1941
-
1942
-    /**
1943
-     * Restores whatever the previous status was on a registration before it was trashed (if possible)
1944
-     *
1945
-     * @throws EE_Error
1946
-     * @throws RuntimeException
1947
-     */
1948
-    public function restore()
1949
-    {
1950
-        $previous_status = $this->get_extra_meta(
1951
-            EE_Registration::PRE_TRASH_REG_STATUS_KEY,
1952
-            true,
1953
-            EEM_Registration::status_id_cancelled
1954
-        );
1955
-        if ($previous_status) {
1956
-            $this->delete_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY);
1957
-            $this->set_status($previous_status);
1958
-        }
1959
-        return parent::restore();
1960
-    }
1961
-
1962
-
1963
-    /**
1964
-     * possibly toggle Registration status based on comparison of REG_paid vs REG_final_price
1965
-     *
1966
-     * @param  boolean $trigger_set_status_logic EE_Registration::set_status() can trigger additional logic
1967
-     *                                           depending on whether the reg status changes to or from "Approved"
1968
-     * @return boolean whether the Registration status was updated
1969
-     * @throws EE_Error
1970
-     * @throws RuntimeException
1971
-     */
1972
-    public function updateStatusBasedOnTotalPaid($trigger_set_status_logic = true)
1973
-    {
1974
-        $paid = $this->paid();
1975
-        $price = $this->final_price();
1976
-        switch (true) {
1977
-            // overpaid or paid
1978
-            case EEH_Money::compare_floats($paid, $price, '>'):
1979
-            case EEH_Money::compare_floats($paid, $price):
1980
-                $new_status = EEM_Registration::status_id_approved;
1981
-                break;
1982
-            //  underpaid
1983
-            case EEH_Money::compare_floats($paid, $price, '<'):
1984
-                $new_status = EEM_Registration::status_id_pending_payment;
1985
-                break;
1986
-            // uhhh Houston...
1987
-            default:
1988
-                throw new RuntimeException(
1989
-                    esc_html__('The total paid calculation for this registration is inaccurate.', 'event_espresso')
1990
-                );
1991
-        }
1992
-        if ($new_status !== $this->status_ID()) {
1993
-            if ($trigger_set_status_logic) {
1994
-                return $this->set_status($new_status);
1995
-            }
1996
-            parent::set('STS_ID', $new_status);
1997
-            return true;
1998
-        }
1999
-        return false;
2000
-    }
2001
-
2002
-
2003
-    /*************************** DEPRECATED ***************************/
2004
-
2005
-
2006
-    /**
2007
-     * @deprecated
2008
-     * @since     4.7.0
2009
-     * @access    public
2010
-     */
2011
-    public function price_paid()
2012
-    {
2013
-        EE_Error::doing_it_wrong(
2014
-            'EE_Registration::price_paid()',
2015
-            esc_html__(
2016
-                'This method is deprecated, please use EE_Registration::final_price() instead.',
2017
-                'event_espresso'
2018
-            ),
2019
-            '4.7.0'
2020
-        );
2021
-        return $this->final_price();
2022
-    }
2023
-
2024
-
2025
-    /**
2026
-     * @deprecated
2027
-     * @since     4.7.0
2028
-     * @access    public
2029
-     * @param    float $REG_final_price
2030
-     * @throws EE_Error
2031
-     * @throws RuntimeException
2032
-     */
2033
-    public function set_price_paid($REG_final_price = 0.00)
2034
-    {
2035
-        EE_Error::doing_it_wrong(
2036
-            'EE_Registration::set_price_paid()',
2037
-            esc_html__(
2038
-                'This method is deprecated, please use EE_Registration::set_final_price() instead.',
2039
-                'event_espresso'
2040
-            ),
2041
-            '4.7.0'
2042
-        );
2043
-        $this->set_final_price($REG_final_price);
2044
-    }
2045
-
2046
-
2047
-    /**
2048
-     * @deprecated
2049
-     * @since 4.7.0
2050
-     * @return string
2051
-     * @throws EE_Error
2052
-     */
2053
-    public function pretty_price_paid()
2054
-    {
2055
-        EE_Error::doing_it_wrong(
2056
-            'EE_Registration::pretty_price_paid()',
2057
-            esc_html__(
2058
-                'This method is deprecated, please use EE_Registration::pretty_final_price() instead.',
2059
-                'event_espresso'
2060
-            ),
2061
-            '4.7.0'
2062
-        );
2063
-        return $this->pretty_final_price();
2064
-    }
2065
-
2066
-
2067
-    /**
2068
-     * Gets the primary datetime related to this registration via the related Event to this registration
2069
-     *
2070
-     * @deprecated 4.9.17
2071
-     * @return EE_Datetime
2072
-     * @throws EE_Error
2073
-     * @throws EntityNotFoundException
2074
-     */
2075
-    public function get_related_primary_datetime()
2076
-    {
2077
-        EE_Error::doing_it_wrong(
2078
-            __METHOD__,
2079
-            esc_html__(
2080
-                'Use EE_Registration::get_latest_related_datetime() or EE_Registration::get_earliest_related_datetime()',
2081
-                'event_espresso'
2082
-            ),
2083
-            '4.9.17',
2084
-            '5.0.0'
2085
-        );
2086
-        return $this->event()->primary_datetime();
2087
-    }
20
+	/**
21
+	 * Used to reference when a registration has never been checked in.
22
+	 *
23
+	 * @deprecated use \EE_Checkin::status_checked_never instead
24
+	 * @type int
25
+	 */
26
+	const checkin_status_never = 2;
27
+
28
+	/**
29
+	 * Used to reference when a registration has been checked in.
30
+	 *
31
+	 * @deprecated use \EE_Checkin::status_checked_in instead
32
+	 * @type int
33
+	 */
34
+	const checkin_status_in = 1;
35
+
36
+
37
+	/**
38
+	 * Used to reference when a registration has been checked out.
39
+	 *
40
+	 * @deprecated use \EE_Checkin::status_checked_out instead
41
+	 * @type int
42
+	 */
43
+	const checkin_status_out = 0;
44
+
45
+
46
+	/**
47
+	 * extra meta key for tracking reg status os trashed registrations
48
+	 *
49
+	 * @type string
50
+	 */
51
+	const PRE_TRASH_REG_STATUS_KEY = 'pre_trash_registration_status';
52
+
53
+
54
+	/**
55
+	 * extra meta key for tracking if registration has reserved ticket
56
+	 *
57
+	 * @type string
58
+	 */
59
+	const HAS_RESERVED_TICKET_KEY = 'has_reserved_ticket';
60
+
61
+
62
+	/**
63
+	 * @param array  $props_n_values          incoming values
64
+	 * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
65
+	 *                                        used.)
66
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
67
+	 *                                        date_format and the second value is the time format
68
+	 * @return EE_Registration
69
+	 * @throws EE_Error
70
+	 */
71
+	public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
72
+	{
73
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
74
+		return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
75
+	}
76
+
77
+
78
+	/**
79
+	 * @param array  $props_n_values  incoming values from the database
80
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
81
+	 *                                the website will be used.
82
+	 * @return EE_Registration
83
+	 */
84
+	public static function new_instance_from_db($props_n_values = array(), $timezone = null)
85
+	{
86
+		return new self($props_n_values, true, $timezone);
87
+	}
88
+
89
+
90
+	/**
91
+	 *        Set Event ID
92
+	 *
93
+	 * @param        int $EVT_ID Event ID
94
+	 * @throws EE_Error
95
+	 * @throws RuntimeException
96
+	 */
97
+	public function set_event($EVT_ID = 0)
98
+	{
99
+		$this->set('EVT_ID', $EVT_ID);
100
+	}
101
+
102
+
103
+	/**
104
+	 * Overrides parent set() method so that all calls to set( 'REG_code', $REG_code ) OR set( 'STS_ID', $STS_ID ) can
105
+	 * be routed to internal methods
106
+	 *
107
+	 * @param string $field_name
108
+	 * @param mixed  $field_value
109
+	 * @param bool   $use_default
110
+	 * @throws EE_Error
111
+	 * @throws EntityNotFoundException
112
+	 * @throws InvalidArgumentException
113
+	 * @throws InvalidDataTypeException
114
+	 * @throws InvalidInterfaceException
115
+	 * @throws ReflectionException
116
+	 * @throws RuntimeException
117
+	 */
118
+	public function set($field_name, $field_value, $use_default = false)
119
+	{
120
+		switch ($field_name) {
121
+			case 'REG_code':
122
+				if (! empty($field_value) && $this->reg_code() === null) {
123
+					$this->set_reg_code($field_value, $use_default);
124
+				}
125
+				break;
126
+			case 'STS_ID':
127
+				$this->set_status($field_value, $use_default);
128
+				break;
129
+			default:
130
+				parent::set($field_name, $field_value, $use_default);
131
+		}
132
+	}
133
+
134
+
135
+	/**
136
+	 * Set Status ID
137
+	 * updates the registration status and ALSO...
138
+	 * calls reserve_registration_space() if the reg status changes TO approved from any other reg status
139
+	 * calls release_registration_space() if the reg status changes FROM approved to any other reg status
140
+	 *
141
+	 * @param string                $new_STS_ID
142
+	 * @param boolean               $use_default
143
+	 * @param ContextInterface|null $context
144
+	 * @return bool
145
+	 * @throws DomainException
146
+	 * @throws EE_Error
147
+	 * @throws EntityNotFoundException
148
+	 * @throws InvalidArgumentException
149
+	 * @throws InvalidDataTypeException
150
+	 * @throws InvalidInterfaceException
151
+	 * @throws ReflectionException
152
+	 * @throws RuntimeException
153
+	 * @throws UnexpectedEntityException
154
+	 */
155
+	public function set_status($new_STS_ID = null, $use_default = false, ContextInterface $context = null)
156
+	{
157
+		// get current REG_Status
158
+		$old_STS_ID = $this->status_ID();
159
+		// if status has changed
160
+		if ($old_STS_ID !== $new_STS_ID // and that status has actually changed
161
+			&& ! empty($old_STS_ID) // and that old status is actually set
162
+			&& ! empty($new_STS_ID) // as well as the new status
163
+			&& $this->ID() // ensure registration is in the db
164
+		) {
165
+			// update internal status first
166
+			parent::set('STS_ID', $new_STS_ID, $use_default);
167
+			// THEN handle other changes that occur when reg status changes
168
+			// TO approved
169
+			if ($new_STS_ID === EEM_Registration::status_id_approved) {
170
+				// reserve a space by incrementing ticket and datetime sold values
171
+				$this->reserveRegistrationSpace();
172
+				do_action('AHEE__EE_Registration__set_status__to_approved', $this, $old_STS_ID, $new_STS_ID, $context);
173
+				// OR FROM  approved
174
+			} elseif ($old_STS_ID === EEM_Registration::status_id_approved) {
175
+				// release a space by decrementing ticket and datetime sold values
176
+				$this->releaseRegistrationSpace();
177
+				do_action(
178
+					'AHEE__EE_Registration__set_status__from_approved',
179
+					$this,
180
+					$old_STS_ID,
181
+					$new_STS_ID,
182
+					$context
183
+				);
184
+			}
185
+			// update status
186
+			parent::set('STS_ID', $new_STS_ID, $use_default);
187
+			$this->updateIfCanceledOrReinstated($new_STS_ID, $old_STS_ID, $context);
188
+			if ($this->statusChangeUpdatesTransaction($context)) {
189
+				$this->updateTransactionAfterStatusChange();
190
+			}
191
+			do_action('AHEE__EE_Registration__set_status__after_update', $this, $old_STS_ID, $new_STS_ID, $context);
192
+			return true;
193
+		}
194
+		// even though the old value matches the new value, it's still good to
195
+		// allow the parent set method to have a say
196
+		parent::set('STS_ID', $new_STS_ID, $use_default);
197
+		return true;
198
+	}
199
+
200
+
201
+	/**
202
+	 * update REGs and TXN when cancelled or declined registrations involved
203
+	 *
204
+	 * @param string                $new_STS_ID
205
+	 * @param string                $old_STS_ID
206
+	 * @param ContextInterface|null $context
207
+	 * @throws EE_Error
208
+	 * @throws InvalidArgumentException
209
+	 * @throws InvalidDataTypeException
210
+	 * @throws InvalidInterfaceException
211
+	 * @throws ReflectionException
212
+	 * @throws RuntimeException
213
+	 */
214
+	private function updateIfCanceledOrReinstated($new_STS_ID, $old_STS_ID, ContextInterface $context = null)
215
+	{
216
+		// these reg statuses should not be considered in any calculations involving monies owing
217
+		$closed_reg_statuses = EEM_Registration::closed_reg_statuses();
218
+		// true if registration has been cancelled or declined
219
+		$this->updateIfCanceled(
220
+			$closed_reg_statuses,
221
+			$new_STS_ID,
222
+			$old_STS_ID,
223
+			$context
224
+		);
225
+		$this->updateIfReinstated(
226
+			$closed_reg_statuses,
227
+			$new_STS_ID,
228
+			$old_STS_ID,
229
+			$context
230
+		);
231
+	}
232
+
233
+
234
+	/**
235
+	 * update REGs and TXN when cancelled or declined registrations involved
236
+	 *
237
+	 * @param array                 $closed_reg_statuses
238
+	 * @param string                $new_STS_ID
239
+	 * @param string                $old_STS_ID
240
+	 * @param ContextInterface|null $context
241
+	 * @throws EE_Error
242
+	 * @throws InvalidArgumentException
243
+	 * @throws InvalidDataTypeException
244
+	 * @throws InvalidInterfaceException
245
+	 * @throws ReflectionException
246
+	 * @throws RuntimeException
247
+	 */
248
+	private function updateIfCanceled(
249
+		array $closed_reg_statuses,
250
+		$new_STS_ID,
251
+		$old_STS_ID,
252
+		ContextInterface $context = null
253
+	) {
254
+		// true if registration has been cancelled or declined
255
+		if (in_array($new_STS_ID, $closed_reg_statuses, true)
256
+			&& ! in_array($old_STS_ID, $closed_reg_statuses, true)
257
+		) {
258
+			/** @type EE_Registration_Processor $registration_processor */
259
+			$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
260
+			/** @type EE_Transaction_Processor $transaction_processor */
261
+			$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
262
+			// cancelled or declined registration
263
+			$registration_processor->update_registration_after_being_canceled_or_declined(
264
+				$this,
265
+				$closed_reg_statuses
266
+			);
267
+			$transaction_processor->update_transaction_after_canceled_or_declined_registration(
268
+				$this,
269
+				$closed_reg_statuses,
270
+				false
271
+			);
272
+			do_action(
273
+				'AHEE__EE_Registration__set_status__canceled_or_declined',
274
+				$this,
275
+				$old_STS_ID,
276
+				$new_STS_ID,
277
+				$context
278
+			);
279
+			return;
280
+		}
281
+	}
282
+
283
+
284
+	/**
285
+	 * update REGs and TXN when cancelled or declined registrations involved
286
+	 *
287
+	 * @param array                 $closed_reg_statuses
288
+	 * @param string                $new_STS_ID
289
+	 * @param string                $old_STS_ID
290
+	 * @param ContextInterface|null $context
291
+	 * @throws EE_Error
292
+	 * @throws InvalidArgumentException
293
+	 * @throws InvalidDataTypeException
294
+	 * @throws InvalidInterfaceException
295
+	 * @throws ReflectionException
296
+	 */
297
+	private function updateIfReinstated(
298
+		array $closed_reg_statuses,
299
+		$new_STS_ID,
300
+		$old_STS_ID,
301
+		ContextInterface $context = null
302
+	) {
303
+		// true if reinstating cancelled or declined registration
304
+		if (in_array($old_STS_ID, $closed_reg_statuses, true)
305
+			&& ! in_array($new_STS_ID, $closed_reg_statuses, true)
306
+		) {
307
+			/** @type EE_Registration_Processor $registration_processor */
308
+			$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
309
+			/** @type EE_Transaction_Processor $transaction_processor */
310
+			$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
311
+			// reinstating cancelled or declined registration
312
+			$registration_processor->update_canceled_or_declined_registration_after_being_reinstated(
313
+				$this,
314
+				$closed_reg_statuses
315
+			);
316
+			$transaction_processor->update_transaction_after_reinstating_canceled_registration(
317
+				$this,
318
+				$closed_reg_statuses,
319
+				false
320
+			);
321
+			do_action(
322
+				'AHEE__EE_Registration__set_status__after_reinstated',
323
+				$this,
324
+				$old_STS_ID,
325
+				$new_STS_ID,
326
+				$context
327
+			);
328
+		}
329
+	}
330
+
331
+
332
+	/**
333
+	 * @param ContextInterface|null $context
334
+	 * @return bool
335
+	 */
336
+	private function statusChangeUpdatesTransaction(ContextInterface $context = null)
337
+	{
338
+		$contexts_that_do_not_update_transaction = (array) apply_filters(
339
+			'AHEE__EE_Registration__statusChangeUpdatesTransaction__contexts_that_do_not_update_transaction',
340
+			array('spco_reg_step_attendee_information_process_registrations'),
341
+			$context,
342
+			$this
343
+		);
344
+		return ! (
345
+			$context instanceof ContextInterface
346
+			&& in_array($context->slug(), $contexts_that_do_not_update_transaction, true)
347
+		);
348
+	}
349
+
350
+
351
+	/**
352
+	 * @throws EE_Error
353
+	 * @throws EntityNotFoundException
354
+	 * @throws InvalidArgumentException
355
+	 * @throws InvalidDataTypeException
356
+	 * @throws InvalidInterfaceException
357
+	 * @throws ReflectionException
358
+	 * @throws RuntimeException
359
+	 */
360
+	private function updateTransactionAfterStatusChange()
361
+	{
362
+		/** @type EE_Transaction_Payments $transaction_payments */
363
+		$transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
364
+		$transaction_payments->recalculate_transaction_total($this->transaction(), false);
365
+		$this->transaction()->update_status_based_on_total_paid(true);
366
+	}
367
+
368
+
369
+	/**
370
+	 *        get Status ID
371
+	 */
372
+	public function status_ID()
373
+	{
374
+		return $this->get('STS_ID');
375
+	}
376
+
377
+
378
+	/**
379
+	 * Gets the ticket this registration is for
380
+	 *
381
+	 * @param boolean $include_archived whether to include archived tickets or not.
382
+	 *
383
+	 * @return EE_Ticket|EE_Base_Class
384
+	 * @throws EE_Error
385
+	 */
386
+	public function ticket($include_archived = true)
387
+	{
388
+		$query_params = array();
389
+		if ($include_archived) {
390
+			$query_params['default_where_conditions'] = 'none';
391
+		}
392
+		return $this->get_first_related('Ticket', $query_params);
393
+	}
394
+
395
+
396
+	/**
397
+	 * Gets the event this registration is for
398
+	 *
399
+	 * @return EE_Event
400
+	 * @throws EE_Error
401
+	 * @throws EntityNotFoundException
402
+	 */
403
+	public function event()
404
+	{
405
+		$event = $this->get_first_related('Event');
406
+		if (! $event instanceof \EE_Event) {
407
+			throw new EntityNotFoundException('Event ID', $this->event_ID());
408
+		}
409
+		return $event;
410
+	}
411
+
412
+
413
+	/**
414
+	 * Gets the "author" of the registration.  Note that for the purposes of registrations, the author will correspond
415
+	 * with the author of the event this registration is for.
416
+	 *
417
+	 * @since 4.5.0
418
+	 * @return int
419
+	 * @throws EE_Error
420
+	 * @throws EntityNotFoundException
421
+	 */
422
+	public function wp_user()
423
+	{
424
+		$event = $this->event();
425
+		if ($event instanceof EE_Event) {
426
+			return $event->wp_user();
427
+		}
428
+		return 0;
429
+	}
430
+
431
+
432
+	/**
433
+	 * increments this registration's related ticket sold and corresponding datetime sold values
434
+	 *
435
+	 * @return void
436
+	 * @throws DomainException
437
+	 * @throws EE_Error
438
+	 * @throws EntityNotFoundException
439
+	 * @throws InvalidArgumentException
440
+	 * @throws InvalidDataTypeException
441
+	 * @throws InvalidInterfaceException
442
+	 * @throws ReflectionException
443
+	 * @throws UnexpectedEntityException
444
+	 */
445
+	private function reserveRegistrationSpace()
446
+	{
447
+		// reserved ticket and datetime counts will be decremented as sold counts are incremented
448
+		// so stop tracking that this reg has a ticket reserved
449
+		$this->release_reserved_ticket(false, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
450
+		$ticket = $this->ticket();
451
+		$ticket->increaseSold();
452
+		// possibly set event status to sold out
453
+		$this->event()->perform_sold_out_status_check();
454
+	}
455
+
456
+
457
+	/**
458
+	 * decrements (subtracts) this registration's related ticket sold and corresponding datetime sold values
459
+	 *
460
+	 * @return void
461
+	 * @throws DomainException
462
+	 * @throws EE_Error
463
+	 * @throws EntityNotFoundException
464
+	 * @throws InvalidArgumentException
465
+	 * @throws InvalidDataTypeException
466
+	 * @throws InvalidInterfaceException
467
+	 * @throws ReflectionException
468
+	 * @throws UnexpectedEntityException
469
+	 */
470
+	private function releaseRegistrationSpace()
471
+	{
472
+		$ticket = $this->ticket();
473
+		$ticket->decreaseSold();
474
+		// possibly change event status from sold out back to previous status
475
+		$this->event()->perform_sold_out_status_check();
476
+	}
477
+
478
+
479
+	/**
480
+	 * tracks this registration's ticket reservation in extra meta
481
+	 * and can increment related ticket reserved and corresponding datetime reserved values
482
+	 *
483
+	 * @param bool $update_ticket if true, will increment ticket and datetime reserved count
484
+	 * @return void
485
+	 * @throws EE_Error
486
+	 * @throws InvalidArgumentException
487
+	 * @throws InvalidDataTypeException
488
+	 * @throws InvalidInterfaceException
489
+	 * @throws ReflectionException
490
+	 */
491
+	public function reserve_ticket($update_ticket = false, $source = 'unknown')
492
+	{
493
+		// only reserve ticket if space is not currently reserved
494
+		if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) !== true) {
495
+			$this->update_extra_meta('reserve_ticket', "{$this->ticket_ID()} from {$source}");
496
+			// IMPORTANT !!!
497
+			// although checking $update_ticket first would be more efficient,
498
+			// we NEED to ALWAYS call update_extra_meta(), which is why that is done first
499
+			if ($this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true)
500
+				&& $update_ticket
501
+			) {
502
+				$ticket = $this->ticket();
503
+				$ticket->increaseReserved(1, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
504
+				$ticket->save();
505
+			}
506
+		}
507
+	}
508
+
509
+
510
+	/**
511
+	 * stops tracking this registration's ticket reservation in extra meta
512
+	 * decrements (subtracts) related ticket reserved and corresponding datetime reserved values
513
+	 *
514
+	 * @param bool $update_ticket if true, will decrement ticket and datetime reserved count
515
+	 * @return void
516
+	 * @throws EE_Error
517
+	 * @throws InvalidArgumentException
518
+	 * @throws InvalidDataTypeException
519
+	 * @throws InvalidInterfaceException
520
+	 * @throws ReflectionException
521
+	 */
522
+	public function release_reserved_ticket($update_ticket = false, $source = 'unknown')
523
+	{
524
+		// only release ticket if space is currently reserved
525
+		if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) === true) {
526
+			$this->update_extra_meta('release_reserved_ticket', "{$this->ticket_ID()} from {$source}");
527
+			// IMPORTANT !!!
528
+			// although checking $update_ticket first would be more efficient,
529
+			// we NEED to ALWAYS call update_extra_meta(), which is why that is done first
530
+			if ($this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, false)
531
+				&& $update_ticket
532
+			) {
533
+				$ticket = $this->ticket();
534
+				$ticket->decreaseReserved(1, true, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
535
+			}
536
+		}
537
+	}
538
+
539
+
540
+	/**
541
+	 * Set Attendee ID
542
+	 *
543
+	 * @param        int $ATT_ID Attendee ID
544
+	 * @throws EE_Error
545
+	 * @throws RuntimeException
546
+	 */
547
+	public function set_attendee_id($ATT_ID = 0)
548
+	{
549
+		$this->set('ATT_ID', $ATT_ID);
550
+	}
551
+
552
+
553
+	/**
554
+	 *        Set Transaction ID
555
+	 *
556
+	 * @param        int $TXN_ID Transaction ID
557
+	 * @throws EE_Error
558
+	 * @throws RuntimeException
559
+	 */
560
+	public function set_transaction_id($TXN_ID = 0)
561
+	{
562
+		$this->set('TXN_ID', $TXN_ID);
563
+	}
564
+
565
+
566
+	/**
567
+	 *        Set Session
568
+	 *
569
+	 * @param    string $REG_session PHP Session ID
570
+	 * @throws EE_Error
571
+	 * @throws RuntimeException
572
+	 */
573
+	public function set_session($REG_session = '')
574
+	{
575
+		$this->set('REG_session', $REG_session);
576
+	}
577
+
578
+
579
+	/**
580
+	 *        Set Registration URL Link
581
+	 *
582
+	 * @param    string $REG_url_link Registration URL Link
583
+	 * @throws EE_Error
584
+	 * @throws RuntimeException
585
+	 */
586
+	public function set_reg_url_link($REG_url_link = '')
587
+	{
588
+		$this->set('REG_url_link', $REG_url_link);
589
+	}
590
+
591
+
592
+	/**
593
+	 *        Set Attendee Counter
594
+	 *
595
+	 * @param        int $REG_count Primary Attendee
596
+	 * @throws EE_Error
597
+	 * @throws RuntimeException
598
+	 */
599
+	public function set_count($REG_count = 1)
600
+	{
601
+		$this->set('REG_count', $REG_count);
602
+	}
603
+
604
+
605
+	/**
606
+	 *        Set Group Size
607
+	 *
608
+	 * @param        boolean $REG_group_size Group Registration
609
+	 * @throws EE_Error
610
+	 * @throws RuntimeException
611
+	 */
612
+	public function set_group_size($REG_group_size = false)
613
+	{
614
+		$this->set('REG_group_size', $REG_group_size);
615
+	}
616
+
617
+
618
+	/**
619
+	 *    is_not_approved -  convenience method that returns TRUE if REG status ID ==
620
+	 *    EEM_Registration::status_id_not_approved
621
+	 *
622
+	 * @return        boolean
623
+	 */
624
+	public function is_not_approved()
625
+	{
626
+		return $this->status_ID() == EEM_Registration::status_id_not_approved ? true : false;
627
+	}
628
+
629
+
630
+	/**
631
+	 *    is_pending_payment -  convenience method that returns TRUE if REG status ID ==
632
+	 *    EEM_Registration::status_id_pending_payment
633
+	 *
634
+	 * @return        boolean
635
+	 */
636
+	public function is_pending_payment()
637
+	{
638
+		return $this->status_ID() == EEM_Registration::status_id_pending_payment ? true : false;
639
+	}
640
+
641
+
642
+	/**
643
+	 *    is_approved -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_approved
644
+	 *
645
+	 * @return        boolean
646
+	 */
647
+	public function is_approved()
648
+	{
649
+		return $this->status_ID() == EEM_Registration::status_id_approved ? true : false;
650
+	}
651
+
652
+
653
+	/**
654
+	 *    is_cancelled -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_cancelled
655
+	 *
656
+	 * @return        boolean
657
+	 */
658
+	public function is_cancelled()
659
+	{
660
+		return $this->status_ID() == EEM_Registration::status_id_cancelled ? true : false;
661
+	}
662
+
663
+
664
+	/**
665
+	 *    is_declined -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_declined
666
+	 *
667
+	 * @return        boolean
668
+	 */
669
+	public function is_declined()
670
+	{
671
+		return $this->status_ID() == EEM_Registration::status_id_declined ? true : false;
672
+	}
673
+
674
+
675
+	/**
676
+	 *    is_incomplete -  convenience method that returns TRUE if REG status ID ==
677
+	 *    EEM_Registration::status_id_incomplete
678
+	 *
679
+	 * @return        boolean
680
+	 */
681
+	public function is_incomplete()
682
+	{
683
+		return $this->status_ID() == EEM_Registration::status_id_incomplete ? true : false;
684
+	}
685
+
686
+
687
+	/**
688
+	 *        Set Registration Date
689
+	 *
690
+	 * @param        mixed ( int or string ) $REG_date Registration Date - Unix timestamp or string representation of
691
+	 *                                                 Date
692
+	 * @throws EE_Error
693
+	 * @throws RuntimeException
694
+	 */
695
+	public function set_reg_date($REG_date = false)
696
+	{
697
+		$this->set('REG_date', $REG_date);
698
+	}
699
+
700
+
701
+	/**
702
+	 *    Set final price owing for this registration after all ticket/price modifications
703
+	 *
704
+	 * @access    public
705
+	 * @param    float $REG_final_price
706
+	 * @throws EE_Error
707
+	 * @throws RuntimeException
708
+	 */
709
+	public function set_final_price($REG_final_price = 0.00)
710
+	{
711
+		$this->set('REG_final_price', $REG_final_price);
712
+	}
713
+
714
+
715
+	/**
716
+	 *    Set amount paid towards this registration's final price
717
+	 *
718
+	 * @access    public
719
+	 * @param    float $REG_paid
720
+	 * @throws EE_Error
721
+	 * @throws RuntimeException
722
+	 */
723
+	public function set_paid($REG_paid = 0.00)
724
+	{
725
+		$this->set('REG_paid', $REG_paid);
726
+	}
727
+
728
+
729
+	/**
730
+	 *        Attendee Is Going
731
+	 *
732
+	 * @param        boolean $REG_att_is_going Attendee Is Going
733
+	 * @throws EE_Error
734
+	 * @throws RuntimeException
735
+	 */
736
+	public function set_att_is_going($REG_att_is_going = false)
737
+	{
738
+		$this->set('REG_att_is_going', $REG_att_is_going);
739
+	}
740
+
741
+
742
+	/**
743
+	 * Gets the related attendee
744
+	 *
745
+	 * @return EE_Attendee
746
+	 * @throws EE_Error
747
+	 */
748
+	public function attendee()
749
+	{
750
+		return $this->get_first_related('Attendee');
751
+	}
752
+
753
+
754
+	/**
755
+	 *        get Event ID
756
+	 */
757
+	public function event_ID()
758
+	{
759
+		return $this->get('EVT_ID');
760
+	}
761
+
762
+
763
+	/**
764
+	 *        get Event ID
765
+	 */
766
+	public function event_name()
767
+	{
768
+		$event = $this->event_obj();
769
+		if ($event) {
770
+			return $event->name();
771
+		} else {
772
+			return null;
773
+		}
774
+	}
775
+
776
+
777
+	/**
778
+	 * Fetches the event this registration is for
779
+	 *
780
+	 * @return EE_Event
781
+	 * @throws EE_Error
782
+	 */
783
+	public function event_obj()
784
+	{
785
+		return $this->get_first_related('Event');
786
+	}
787
+
788
+
789
+	/**
790
+	 *        get Attendee ID
791
+	 */
792
+	public function attendee_ID()
793
+	{
794
+		return $this->get('ATT_ID');
795
+	}
796
+
797
+
798
+	/**
799
+	 *        get PHP Session ID
800
+	 */
801
+	public function session_ID()
802
+	{
803
+		return $this->get('REG_session');
804
+	}
805
+
806
+
807
+	/**
808
+	 * Gets the string which represents the URL trigger for the receipt template in the message template system.
809
+	 *
810
+	 * @param string $messenger 'pdf' or 'html'.  Default 'html'.
811
+	 * @return string
812
+	 */
813
+	public function receipt_url($messenger = 'html')
814
+	{
815
+
816
+		/**
817
+		 * The below will be deprecated one version after this.  We check first if there is a custom receipt template
818
+		 * already in use on old system.  If there is then we just return the standard url for it.
819
+		 *
820
+		 * @since 4.5.0
821
+		 */
822
+		$template_relative_path = 'modules/gateways/Invoice/lib/templates/receipt_body.template.php';
823
+		$has_custom = EEH_Template::locate_template(
824
+			$template_relative_path,
825
+			array(),
826
+			true,
827
+			true,
828
+			true
829
+		);
830
+
831
+		if ($has_custom) {
832
+			return add_query_arg(array('receipt' => 'true'), $this->invoice_url('launch'));
833
+		}
834
+		return apply_filters('FHEE__EE_Registration__receipt_url__receipt_url', '', $this, $messenger, 'receipt');
835
+	}
836
+
837
+
838
+	/**
839
+	 * Gets the string which represents the URL trigger for the invoice template in the message template system.
840
+	 *
841
+	 * @param string $messenger 'pdf' or 'html'.  Default 'html'.
842
+	 * @return string
843
+	 * @throws EE_Error
844
+	 */
845
+	public function invoice_url($messenger = 'html')
846
+	{
847
+		/**
848
+		 * The below will be deprecated one version after this.  We check first if there is a custom invoice template
849
+		 * already in use on old system.  If there is then we just return the standard url for it.
850
+		 *
851
+		 * @since 4.5.0
852
+		 */
853
+		$template_relative_path = 'modules/gateways/Invoice/lib/templates/invoice_body.template.php';
854
+		$has_custom = EEH_Template::locate_template(
855
+			$template_relative_path,
856
+			array(),
857
+			true,
858
+			true,
859
+			true
860
+		);
861
+
862
+		if ($has_custom) {
863
+			if ($messenger == 'html') {
864
+				return $this->invoice_url('launch');
865
+			}
866
+			$route = $messenger == 'download' || $messenger == 'pdf' ? 'download_invoice' : 'launch_invoice';
867
+
868
+			$query_args = array('ee' => $route, 'id' => $this->reg_url_link());
869
+			if ($messenger == 'html') {
870
+				$query_args['html'] = true;
871
+			}
872
+			return add_query_arg($query_args, get_permalink(EE_Registry::instance()->CFG->core->thank_you_page_id));
873
+		}
874
+		return apply_filters('FHEE__EE_Registration__invoice_url__invoice_url', '', $this, $messenger, 'invoice');
875
+	}
876
+
877
+
878
+	/**
879
+	 * get Registration URL Link
880
+	 *
881
+	 * @access public
882
+	 * @return string
883
+	 * @throws EE_Error
884
+	 */
885
+	public function reg_url_link()
886
+	{
887
+		return (string) $this->get('REG_url_link');
888
+	}
889
+
890
+
891
+	/**
892
+	 * Echoes out invoice_url()
893
+	 *
894
+	 * @param string $type 'download','launch', or 'html' (default is 'launch')
895
+	 * @return void
896
+	 * @throws EE_Error
897
+	 */
898
+	public function e_invoice_url($type = 'launch')
899
+	{
900
+		echo $this->invoice_url($type);
901
+	}
902
+
903
+
904
+	/**
905
+	 * Echoes out payment_overview_url
906
+	 */
907
+	public function e_payment_overview_url()
908
+	{
909
+		echo $this->payment_overview_url();
910
+	}
911
+
912
+
913
+	/**
914
+	 * Gets the URL for the checkout payment options reg step
915
+	 * with this registration's REG_url_link added as a query parameter
916
+	 *
917
+	 * @param bool $clear_session Set to true when you want to clear the session on revisiting the
918
+	 *                            payment overview url.
919
+	 * @return string
920
+	 * @throws InvalidInterfaceException
921
+	 * @throws InvalidDataTypeException
922
+	 * @throws EE_Error
923
+	 * @throws InvalidArgumentException
924
+	 */
925
+	public function payment_overview_url($clear_session = false)
926
+	{
927
+		return add_query_arg(
928
+			(array) apply_filters(
929
+				'FHEE__EE_Registration__payment_overview_url__query_args',
930
+				array(
931
+					'e_reg_url_link' => $this->reg_url_link(),
932
+					'step'           => 'payment_options',
933
+					'revisit'        => true,
934
+					'clear_session'  => (bool) $clear_session,
935
+				),
936
+				$this
937
+			),
938
+			EE_Registry::instance()->CFG->core->reg_page_url()
939
+		);
940
+	}
941
+
942
+
943
+	/**
944
+	 * Gets the URL for the checkout attendee information reg step
945
+	 * with this registration's REG_url_link added as a query parameter
946
+	 *
947
+	 * @return string
948
+	 * @throws InvalidInterfaceException
949
+	 * @throws InvalidDataTypeException
950
+	 * @throws EE_Error
951
+	 * @throws InvalidArgumentException
952
+	 */
953
+	public function edit_attendee_information_url()
954
+	{
955
+		return add_query_arg(
956
+			(array) apply_filters(
957
+				'FHEE__EE_Registration__edit_attendee_information_url__query_args',
958
+				array(
959
+					'e_reg_url_link' => $this->reg_url_link(),
960
+					'step'           => 'attendee_information',
961
+					'revisit'        => true,
962
+				),
963
+				$this
964
+			),
965
+			EE_Registry::instance()->CFG->core->reg_page_url()
966
+		);
967
+	}
968
+
969
+
970
+	/**
971
+	 * Simply generates and returns the appropriate admin_url link to edit this registration
972
+	 *
973
+	 * @return string
974
+	 * @throws EE_Error
975
+	 */
976
+	public function get_admin_edit_url()
977
+	{
978
+		return EEH_URL::add_query_args_and_nonce(
979
+			array(
980
+				'page'    => 'espresso_registrations',
981
+				'action'  => 'view_registration',
982
+				'_REG_ID' => $this->ID(),
983
+			),
984
+			admin_url('admin.php')
985
+		);
986
+	}
987
+
988
+
989
+	/**
990
+	 *    is_primary_registrant?
991
+	 */
992
+	public function is_primary_registrant()
993
+	{
994
+		return $this->get('REG_count') === 1 ? true : false;
995
+	}
996
+
997
+
998
+	/**
999
+	 * This returns the primary registration object for this registration group (which may be this object).
1000
+	 *
1001
+	 * @return EE_Registration
1002
+	 * @throws EE_Error
1003
+	 */
1004
+	public function get_primary_registration()
1005
+	{
1006
+		if ($this->is_primary_registrant()) {
1007
+			return $this;
1008
+		}
1009
+
1010
+		// k reg_count !== 1 so let's get the EE_Registration object matching this txn_id and reg_count == 1
1011
+		/** @var EE_Registration $primary_registrant */
1012
+		$primary_registrant = EEM_Registration::instance()->get_one(
1013
+			array(
1014
+				array(
1015
+					'TXN_ID'    => $this->transaction_ID(),
1016
+					'REG_count' => 1,
1017
+				),
1018
+			)
1019
+		);
1020
+		return $primary_registrant;
1021
+	}
1022
+
1023
+
1024
+	/**
1025
+	 *        get  Attendee Number
1026
+	 *
1027
+	 * @access        public
1028
+	 */
1029
+	public function count()
1030
+	{
1031
+		return $this->get('REG_count');
1032
+	}
1033
+
1034
+
1035
+	/**
1036
+	 *        get Group Size
1037
+	 */
1038
+	public function group_size()
1039
+	{
1040
+		return $this->get('REG_group_size');
1041
+	}
1042
+
1043
+
1044
+	/**
1045
+	 *        get Registration Date
1046
+	 */
1047
+	public function date()
1048
+	{
1049
+		return $this->get('REG_date');
1050
+	}
1051
+
1052
+
1053
+	/**
1054
+	 * gets a pretty date
1055
+	 *
1056
+	 * @param string $date_format
1057
+	 * @param string $time_format
1058
+	 * @return string
1059
+	 * @throws EE_Error
1060
+	 */
1061
+	public function pretty_date($date_format = null, $time_format = null)
1062
+	{
1063
+		return $this->get_datetime('REG_date', $date_format, $time_format);
1064
+	}
1065
+
1066
+
1067
+	/**
1068
+	 * final_price
1069
+	 * the registration's share of the transaction total, so that the
1070
+	 * sum of all the transaction's REG_final_prices equal the transaction's total
1071
+	 *
1072
+	 * @return float
1073
+	 * @throws EE_Error
1074
+	 */
1075
+	public function final_price()
1076
+	{
1077
+		return $this->get('REG_final_price');
1078
+	}
1079
+
1080
+
1081
+	/**
1082
+	 * pretty_final_price
1083
+	 *  final price as formatted string, with correct decimal places and currency symbol
1084
+	 *
1085
+	 * @return string
1086
+	 * @throws EE_Error
1087
+	 */
1088
+	public function pretty_final_price()
1089
+	{
1090
+		return $this->get_pretty('REG_final_price');
1091
+	}
1092
+
1093
+
1094
+	/**
1095
+	 * get paid (yeah)
1096
+	 *
1097
+	 * @return float
1098
+	 * @throws EE_Error
1099
+	 */
1100
+	public function paid()
1101
+	{
1102
+		return $this->get('REG_paid');
1103
+	}
1104
+
1105
+
1106
+	/**
1107
+	 * pretty_paid
1108
+	 *
1109
+	 * @return float
1110
+	 * @throws EE_Error
1111
+	 */
1112
+	public function pretty_paid()
1113
+	{
1114
+		return $this->get_pretty('REG_paid');
1115
+	}
1116
+
1117
+
1118
+	/**
1119
+	 * owes_monies_and_can_pay
1120
+	 * whether or not this registration has monies owing and it's' status allows payment
1121
+	 *
1122
+	 * @param array $requires_payment
1123
+	 * @return bool
1124
+	 * @throws EE_Error
1125
+	 */
1126
+	public function owes_monies_and_can_pay($requires_payment = array())
1127
+	{
1128
+		// these reg statuses require payment (if event is not free)
1129
+		$requires_payment = ! empty($requires_payment)
1130
+			? $requires_payment
1131
+			: EEM_Registration::reg_statuses_that_allow_payment();
1132
+		if (in_array($this->status_ID(), $requires_payment) &&
1133
+			$this->final_price() != 0 &&
1134
+			$this->final_price() != $this->paid()
1135
+		) {
1136
+			return true;
1137
+		} else {
1138
+			return false;
1139
+		}
1140
+	}
1141
+
1142
+
1143
+	/**
1144
+	 * Prints out the return value of $this->pretty_status()
1145
+	 *
1146
+	 * @param bool $show_icons
1147
+	 * @return void
1148
+	 * @throws EE_Error
1149
+	 */
1150
+	public function e_pretty_status($show_icons = false)
1151
+	{
1152
+		echo $this->pretty_status($show_icons);
1153
+	}
1154
+
1155
+
1156
+	/**
1157
+	 * Returns a nice version of the status for displaying to customers
1158
+	 *
1159
+	 * @param bool $show_icons
1160
+	 * @return string
1161
+	 * @throws EE_Error
1162
+	 */
1163
+	public function pretty_status($show_icons = false)
1164
+	{
1165
+		$status = EEM_Status::instance()->localized_status(
1166
+			array($this->status_ID() => esc_html__('unknown', 'event_espresso')),
1167
+			false,
1168
+			'sentence'
1169
+		);
1170
+		$icon = '';
1171
+		switch ($this->status_ID()) {
1172
+			case EEM_Registration::status_id_approved:
1173
+				$icon = $show_icons
1174
+					? '<span class="dashicons dashicons-star-filled ee-icon-size-16 green-text"></span>'
1175
+					: '';
1176
+				break;
1177
+			case EEM_Registration::status_id_pending_payment:
1178
+				$icon = $show_icons
1179
+					? '<span class="dashicons dashicons-star-half ee-icon-size-16 orange-text"></span>'
1180
+					: '';
1181
+				break;
1182
+			case EEM_Registration::status_id_not_approved:
1183
+				$icon = $show_icons
1184
+					? '<span class="dashicons dashicons-marker ee-icon-size-16 orange-text"></span>'
1185
+					: '';
1186
+				break;
1187
+			case EEM_Registration::status_id_cancelled:
1188
+				$icon = $show_icons
1189
+					? '<span class="dashicons dashicons-no ee-icon-size-16 lt-grey-text"></span>'
1190
+					: '';
1191
+				break;
1192
+			case EEM_Registration::status_id_incomplete:
1193
+				$icon = $show_icons
1194
+					? '<span class="dashicons dashicons-no ee-icon-size-16 lt-orange-text"></span>'
1195
+					: '';
1196
+				break;
1197
+			case EEM_Registration::status_id_declined:
1198
+				$icon = $show_icons
1199
+					? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>'
1200
+					: '';
1201
+				break;
1202
+			case EEM_Registration::status_id_wait_list:
1203
+				$icon = $show_icons
1204
+					? '<span class="dashicons dashicons-clipboard ee-icon-size-16 purple-text"></span>'
1205
+					: '';
1206
+				break;
1207
+		}
1208
+		return $icon . $status[ $this->status_ID() ];
1209
+	}
1210
+
1211
+
1212
+	/**
1213
+	 *        get Attendee Is Going
1214
+	 */
1215
+	public function att_is_going()
1216
+	{
1217
+		return $this->get('REG_att_is_going');
1218
+	}
1219
+
1220
+
1221
+	/**
1222
+	 * Gets related answers
1223
+	 *
1224
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1225
+	 * @return EE_Answer[]
1226
+	 * @throws EE_Error
1227
+	 */
1228
+	public function answers($query_params = null)
1229
+	{
1230
+		return $this->get_many_related('Answer', $query_params);
1231
+	}
1232
+
1233
+
1234
+	/**
1235
+	 * Gets the registration's answer value to the specified question
1236
+	 * (either the question's ID or a question object)
1237
+	 *
1238
+	 * @param EE_Question|int $question
1239
+	 * @param bool            $pretty_value
1240
+	 * @return array|string if pretty_value= true, the result will always be a string
1241
+	 * (because the answer might be an array of answer values, so passing pretty_value=true
1242
+	 * will convert it into some kind of string)
1243
+	 * @throws EE_Error
1244
+	 */
1245
+	public function answer_value_to_question($question, $pretty_value = true)
1246
+	{
1247
+		$question_id = EEM_Question::instance()->ensure_is_ID($question);
1248
+		return EEM_Answer::instance()->get_answer_value_to_question($this, $question_id, $pretty_value);
1249
+	}
1250
+
1251
+
1252
+	/**
1253
+	 * question_groups
1254
+	 * returns an array of EE_Question_Group objects for this registration
1255
+	 *
1256
+	 * @return EE_Question_Group[]
1257
+	 * @throws EE_Error
1258
+	 * @throws InvalidArgumentException
1259
+	 * @throws InvalidDataTypeException
1260
+	 * @throws InvalidInterfaceException
1261
+	 * @throws ReflectionException
1262
+	 */
1263
+	public function question_groups()
1264
+	{
1265
+		return EEM_Event::instance()->get_question_groups_for_event($this->event_ID(), $this);
1266
+	}
1267
+
1268
+
1269
+	/**
1270
+	 * count_question_groups
1271
+	 * returns a count of the number of EE_Question_Group objects for this registration
1272
+	 *
1273
+	 * @return int
1274
+	 * @throws EE_Error
1275
+	 * @throws EntityNotFoundException
1276
+	 * @throws InvalidArgumentException
1277
+	 * @throws InvalidDataTypeException
1278
+	 * @throws InvalidInterfaceException
1279
+	 * @throws ReflectionException
1280
+	 */
1281
+	public function count_question_groups()
1282
+	{
1283
+		return EEM_Event::instance()->count_related(
1284
+			$this->event_ID(),
1285
+			'Question_Group',
1286
+			[
1287
+				[
1288
+					'Event_Question_Group.'
1289
+					. EEM_Event_Question_Group::instance()->fieldNameForContext($this->is_primary_registrant()) => true,
1290
+				]
1291
+			]
1292
+		);
1293
+	}
1294
+
1295
+
1296
+	/**
1297
+	 * Returns the registration date in the 'standard' string format
1298
+	 * (function may be improved in the future to allow for different formats and timezones)
1299
+	 *
1300
+	 * @return string
1301
+	 * @throws EE_Error
1302
+	 */
1303
+	public function reg_date()
1304
+	{
1305
+		return $this->get_datetime('REG_date');
1306
+	}
1307
+
1308
+
1309
+	/**
1310
+	 * Gets the datetime-ticket for this registration (ie, it can be used to isolate
1311
+	 * the ticket this registration purchased, or the datetime they have registered
1312
+	 * to attend)
1313
+	 *
1314
+	 * @return EE_Datetime_Ticket
1315
+	 * @throws EE_Error
1316
+	 */
1317
+	public function datetime_ticket()
1318
+	{
1319
+		return $this->get_first_related('Datetime_Ticket');
1320
+	}
1321
+
1322
+
1323
+	/**
1324
+	 * Sets the registration's datetime_ticket.
1325
+	 *
1326
+	 * @param EE_Datetime_Ticket $datetime_ticket
1327
+	 * @return EE_Datetime_Ticket
1328
+	 * @throws EE_Error
1329
+	 */
1330
+	public function set_datetime_ticket($datetime_ticket)
1331
+	{
1332
+		return $this->_add_relation_to($datetime_ticket, 'Datetime_Ticket');
1333
+	}
1334
+
1335
+	/**
1336
+	 * Gets deleted
1337
+	 *
1338
+	 * @return bool
1339
+	 * @throws EE_Error
1340
+	 */
1341
+	public function deleted()
1342
+	{
1343
+		return $this->get('REG_deleted');
1344
+	}
1345
+
1346
+	/**
1347
+	 * Sets deleted
1348
+	 *
1349
+	 * @param boolean $deleted
1350
+	 * @return bool
1351
+	 * @throws EE_Error
1352
+	 * @throws RuntimeException
1353
+	 */
1354
+	public function set_deleted($deleted)
1355
+	{
1356
+		if ($deleted) {
1357
+			$this->delete();
1358
+		} else {
1359
+			$this->restore();
1360
+		}
1361
+	}
1362
+
1363
+
1364
+	/**
1365
+	 * Get the status object of this object
1366
+	 *
1367
+	 * @return EE_Status
1368
+	 * @throws EE_Error
1369
+	 */
1370
+	public function status_obj()
1371
+	{
1372
+		return $this->get_first_related('Status');
1373
+	}
1374
+
1375
+
1376
+	/**
1377
+	 * Returns the number of times this registration has checked into any of the datetimes
1378
+	 * its available for
1379
+	 *
1380
+	 * @return int
1381
+	 * @throws EE_Error
1382
+	 */
1383
+	public function count_checkins()
1384
+	{
1385
+		return $this->get_model()->count_related($this, 'Checkin');
1386
+	}
1387
+
1388
+
1389
+	/**
1390
+	 * Returns the number of current Check-ins this registration is checked into for any of the datetimes the
1391
+	 * registration is for.  Note, this is ONLY checked in (does not include checkedout)
1392
+	 *
1393
+	 * @return int
1394
+	 * @throws EE_Error
1395
+	 */
1396
+	public function count_checkins_not_checkedout()
1397
+	{
1398
+		return $this->get_model()->count_related($this, 'Checkin', array(array('CHK_in' => 1)));
1399
+	}
1400
+
1401
+
1402
+	/**
1403
+	 * The purpose of this method is simply to check whether this registration can checkin to the given datetime.
1404
+	 *
1405
+	 * @param int | EE_Datetime $DTT_OR_ID      The datetime the registration is being checked against
1406
+	 * @param bool              $check_approved This is used to indicate whether the caller wants can_checkin to also
1407
+	 *                                          consider registration status as well as datetime access.
1408
+	 * @return bool
1409
+	 * @throws EE_Error
1410
+	 */
1411
+	public function can_checkin($DTT_OR_ID, $check_approved = true)
1412
+	{
1413
+		$DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1414
+
1415
+		// first check registration status
1416
+		if (($check_approved && ! $this->is_approved()) || ! $DTT_ID) {
1417
+			return false;
1418
+		}
1419
+		// is there a datetime ticket that matches this dtt_ID?
1420
+		if (! (EEM_Datetime_Ticket::instance()->exists(
1421
+			array(
1422
+				array(
1423
+					'TKT_ID' => $this->get('TKT_ID'),
1424
+					'DTT_ID' => $DTT_ID,
1425
+				),
1426
+			)
1427
+		))
1428
+		) {
1429
+			return false;
1430
+		}
1431
+
1432
+		// final check is against TKT_uses
1433
+		return $this->verify_can_checkin_against_TKT_uses($DTT_ID);
1434
+	}
1435
+
1436
+
1437
+	/**
1438
+	 * This method verifies whether the user can checkin for the given datetime considering the max uses value set on
1439
+	 * the ticket. To do this,  a query is done to get the count of the datetime records already checked into.  If the
1440
+	 * datetime given does not have a check-in record and checking in for that datetime will exceed the allowed uses,
1441
+	 * then return false.  Otherwise return true.
1442
+	 *
1443
+	 * @param int | EE_Datetime $DTT_OR_ID The datetime the registration is being checked against
1444
+	 * @return bool true means can checkin.  false means cannot checkin.
1445
+	 * @throws EE_Error
1446
+	 */
1447
+	public function verify_can_checkin_against_TKT_uses($DTT_OR_ID)
1448
+	{
1449
+		$DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1450
+
1451
+		if (! $DTT_ID) {
1452
+			return false;
1453
+		}
1454
+
1455
+		$max_uses = $this->ticket() instanceof EE_Ticket ? $this->ticket()->uses() : EE_INF;
1456
+
1457
+		// if max uses is not set or equals infinity then return true cause its not a factor for whether user can
1458
+		// check-in or not.
1459
+		if (! $max_uses || $max_uses === EE_INF) {
1460
+			return true;
1461
+		}
1462
+
1463
+		// does this datetime have a checkin record?  If so, then the dtt count has already been verified so we can just
1464
+		// go ahead and toggle.
1465
+		if (EEM_Checkin::instance()->exists(array(array('REG_ID' => $this->ID(), 'DTT_ID' => $DTT_ID)))) {
1466
+			return true;
1467
+		}
1468
+
1469
+		// made it here so the last check is whether the number of checkins per unique datetime on this registration
1470
+		// disallows further check-ins.
1471
+		$count_unique_dtt_checkins = EEM_Checkin::instance()->count(
1472
+			array(
1473
+				array(
1474
+					'REG_ID' => $this->ID(),
1475
+					'CHK_in' => true,
1476
+				),
1477
+			),
1478
+			'DTT_ID',
1479
+			true
1480
+		);
1481
+		// checkins have already reached their max number of uses
1482
+		// so registrant can NOT checkin
1483
+		if ($count_unique_dtt_checkins >= $max_uses) {
1484
+			EE_Error::add_error(
1485
+				esc_html__(
1486
+					'Check-in denied because number of datetime uses for the ticket has been reached or exceeded.',
1487
+					'event_espresso'
1488
+				),
1489
+				__FILE__,
1490
+				__FUNCTION__,
1491
+				__LINE__
1492
+			);
1493
+			return false;
1494
+		}
1495
+		return true;
1496
+	}
1497
+
1498
+
1499
+	/**
1500
+	 * toggle Check-in status for this registration
1501
+	 * Check-ins are toggled in the following order:
1502
+	 * never checked in -> checked in
1503
+	 * checked in -> checked out
1504
+	 * checked out -> checked in
1505
+	 *
1506
+	 * @param  int $DTT_ID  include specific datetime to toggle Check-in for.
1507
+	 *                      If not included or null, then it is assumed latest datetime is being toggled.
1508
+	 * @param bool $verify  If true then can_checkin() is used to verify whether the person
1509
+	 *                      can be checked in or not.  Otherwise this forces change in checkin status.
1510
+	 * @return bool|int     the chk_in status toggled to OR false if nothing got changed.
1511
+	 * @throws EE_Error
1512
+	 */
1513
+	public function toggle_checkin_status($DTT_ID = null, $verify = false)
1514
+	{
1515
+		if (empty($DTT_ID)) {
1516
+			$datetime = $this->get_latest_related_datetime();
1517
+			$DTT_ID = $datetime instanceof EE_Datetime ? $datetime->ID() : 0;
1518
+			// verify the registration can checkin for the given DTT_ID
1519
+		} elseif (! $this->can_checkin($DTT_ID, $verify)) {
1520
+			EE_Error::add_error(
1521
+				sprintf(
1522
+					esc_html__(
1523
+						'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',
1524
+						'event_espresso'
1525
+					),
1526
+					$this->ID(),
1527
+					$DTT_ID
1528
+				),
1529
+				__FILE__,
1530
+				__FUNCTION__,
1531
+				__LINE__
1532
+			);
1533
+			return false;
1534
+		}
1535
+		$status_paths = array(
1536
+			EE_Checkin::status_checked_never => EE_Checkin::status_checked_in,
1537
+			EE_Checkin::status_checked_in    => EE_Checkin::status_checked_out,
1538
+			EE_Checkin::status_checked_out   => EE_Checkin::status_checked_in,
1539
+		);
1540
+		// start by getting the current status so we know what status we'll be changing to.
1541
+		$cur_status = $this->check_in_status_for_datetime($DTT_ID, null);
1542
+		$status_to = $status_paths[ $cur_status ];
1543
+		// database only records true for checked IN or false for checked OUT
1544
+		// no record ( null ) means checked in NEVER, but we obviously don't save that
1545
+		$new_status = $status_to === EE_Checkin::status_checked_in ? true : false;
1546
+		// add relation - note Check-ins are always creating new rows
1547
+		// because we are keeping track of Check-ins over time.
1548
+		// Eventually we'll probably want to show a list table
1549
+		// for the individual Check-ins so that they can be managed.
1550
+		$checkin = EE_Checkin::new_instance(
1551
+			array(
1552
+				'REG_ID' => $this->ID(),
1553
+				'DTT_ID' => $DTT_ID,
1554
+				'CHK_in' => $new_status,
1555
+			)
1556
+		);
1557
+		// if the record could not be saved then return false
1558
+		if ($checkin->save() === 0) {
1559
+			if (WP_DEBUG) {
1560
+				global $wpdb;
1561
+				$error = sprintf(
1562
+					esc_html__(
1563
+						'Registration check in update failed because of the following database error: %1$s%2$s',
1564
+						'event_espresso'
1565
+					),
1566
+					'<br />',
1567
+					$wpdb->last_error
1568
+				);
1569
+			} else {
1570
+				$error = esc_html__(
1571
+					'Registration check in update failed because of an unknown database error',
1572
+					'event_espresso'
1573
+				);
1574
+			}
1575
+			EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
1576
+			return false;
1577
+		}
1578
+		// Fire a checked_in and checkout_out action.
1579
+		$checked_status = $status_to === EE_Checkin::status_checked_in ? 'checked_in' : 'checked_out';
1580
+		do_action("AHEE__EE_Registration__toggle_checkin_status__{$checked_status}", $this, $DTT_ID);
1581
+		return $status_to;
1582
+	}
1583
+
1584
+
1585
+	/**
1586
+	 * Returns the latest datetime related to this registration (via the ticket attached to the registration).
1587
+	 * "Latest" is defined by the `DTT_EVT_start` column.
1588
+	 *
1589
+	 * @return EE_Datetime|null
1590
+	 * @throws EE_Error
1591
+	 */
1592
+	public function get_latest_related_datetime()
1593
+	{
1594
+		return EEM_Datetime::instance()->get_one(
1595
+			array(
1596
+				array(
1597
+					'Ticket.Registration.REG_ID' => $this->ID(),
1598
+				),
1599
+				'order_by' => array('DTT_EVT_start' => 'DESC'),
1600
+			)
1601
+		);
1602
+	}
1603
+
1604
+
1605
+	/**
1606
+	 * Returns the earliest datetime related to this registration (via the ticket attached to the registration).
1607
+	 * "Earliest" is defined by the `DTT_EVT_start` column.
1608
+	 *
1609
+	 * @throws EE_Error
1610
+	 */
1611
+	public function get_earliest_related_datetime()
1612
+	{
1613
+		return EEM_Datetime::instance()->get_one(
1614
+			array(
1615
+				array(
1616
+					'Ticket.Registration.REG_ID' => $this->ID(),
1617
+				),
1618
+				'order_by' => array('DTT_EVT_start' => 'ASC'),
1619
+			)
1620
+		);
1621
+	}
1622
+
1623
+
1624
+	/**
1625
+	 * This method simply returns the check-in status for this registration and the given datetime.
1626
+	 * If neither the datetime nor the checkin values are provided as arguments,
1627
+	 * then this will return the LATEST check-in status for the registration across all datetimes it belongs to.
1628
+	 *
1629
+	 * @param  int       $DTT_ID  The ID of the datetime we're checking against
1630
+	 *                            (if empty we'll get the primary datetime for
1631
+	 *                            this registration (via event) and use it's ID);
1632
+	 * @param EE_Checkin $checkin If present, we use the given checkin object rather than the dtt_id.
1633
+	 *
1634
+	 * @return int                Integer representing Check-in status.
1635
+	 * @throws EE_Error
1636
+	 */
1637
+	public function check_in_status_for_datetime($DTT_ID = 0, $checkin = null)
1638
+	{
1639
+		$checkin_query_params = array(
1640
+			'order_by' => array('CHK_timestamp' => 'DESC'),
1641
+		);
1642
+
1643
+		if ($DTT_ID > 0) {
1644
+			$checkin_query_params[0] = array('DTT_ID' => $DTT_ID);
1645
+		}
1646
+
1647
+		// get checkin object (if exists)
1648
+		$checkin = $checkin instanceof EE_Checkin
1649
+			? $checkin
1650
+			: $this->get_first_related('Checkin', $checkin_query_params);
1651
+		if ($checkin instanceof EE_Checkin) {
1652
+			if ($checkin->get('CHK_in')) {
1653
+				return EE_Checkin::status_checked_in; // checked in
1654
+			}
1655
+			return EE_Checkin::status_checked_out; // had checked in but is now checked out.
1656
+		}
1657
+		return EE_Checkin::status_checked_never; // never been checked in
1658
+	}
1659
+
1660
+
1661
+	/**
1662
+	 * This method returns a localized message for the toggled Check-in message.
1663
+	 *
1664
+	 * @param  int $DTT_ID include specific datetime to get the correct Check-in message.  If not included or null,
1665
+	 *                     then it is assumed Check-in for primary datetime was toggled.
1666
+	 * @param bool $error  This just flags that you want an error message returned. This is put in so that the error
1667
+	 *                     message can be customized with the attendee name.
1668
+	 * @return string internationalized message
1669
+	 * @throws EE_Error
1670
+	 */
1671
+	public function get_checkin_msg($DTT_ID, $error = false)
1672
+	{
1673
+		// let's get the attendee first so we can include the name of the attendee
1674
+		$attendee = $this->get_first_related('Attendee');
1675
+		if ($attendee instanceof EE_Attendee) {
1676
+			if ($error) {
1677
+				return sprintf(__("%s's check-in status was not changed.", "event_espresso"), $attendee->full_name());
1678
+			}
1679
+			$cur_status = $this->check_in_status_for_datetime($DTT_ID);
1680
+			// what is the status message going to be?
1681
+			switch ($cur_status) {
1682
+				case EE_Checkin::status_checked_never:
1683
+					return sprintf(
1684
+						__("%s has been removed from Check-in records", "event_espresso"),
1685
+						$attendee->full_name()
1686
+					);
1687
+					break;
1688
+				case EE_Checkin::status_checked_in:
1689
+					return sprintf(__('%s has been checked in', 'event_espresso'), $attendee->full_name());
1690
+					break;
1691
+				case EE_Checkin::status_checked_out:
1692
+					return sprintf(__('%s has been checked out', 'event_espresso'), $attendee->full_name());
1693
+					break;
1694
+			}
1695
+		}
1696
+		return esc_html__("The check-in status could not be determined.", "event_espresso");
1697
+	}
1698
+
1699
+
1700
+	/**
1701
+	 * Returns the related EE_Transaction to this registration
1702
+	 *
1703
+	 * @return EE_Transaction
1704
+	 * @throws EE_Error
1705
+	 * @throws EntityNotFoundException
1706
+	 */
1707
+	public function transaction()
1708
+	{
1709
+		$transaction = $this->get_first_related('Transaction');
1710
+		if (! $transaction instanceof \EE_Transaction) {
1711
+			throw new EntityNotFoundException('Transaction ID', $this->transaction_ID());
1712
+		}
1713
+		return $transaction;
1714
+	}
1715
+
1716
+
1717
+	/**
1718
+	 *        get Registration Code
1719
+	 */
1720
+	public function reg_code()
1721
+	{
1722
+		return $this->get('REG_code');
1723
+	}
1724
+
1725
+
1726
+	/**
1727
+	 *        get Transaction ID
1728
+	 */
1729
+	public function transaction_ID()
1730
+	{
1731
+		return $this->get('TXN_ID');
1732
+	}
1733
+
1734
+
1735
+	/**
1736
+	 * @return int
1737
+	 * @throws EE_Error
1738
+	 */
1739
+	public function ticket_ID()
1740
+	{
1741
+		return $this->get('TKT_ID');
1742
+	}
1743
+
1744
+
1745
+	/**
1746
+	 *        Set Registration Code
1747
+	 *
1748
+	 * @access    public
1749
+	 * @param    string  $REG_code Registration Code
1750
+	 * @param    boolean $use_default
1751
+	 * @throws EE_Error
1752
+	 */
1753
+	public function set_reg_code($REG_code, $use_default = false)
1754
+	{
1755
+		if (empty($REG_code)) {
1756
+			EE_Error::add_error(
1757
+				esc_html__('REG_code can not be empty.', 'event_espresso'),
1758
+				__FILE__,
1759
+				__FUNCTION__,
1760
+				__LINE__
1761
+			);
1762
+			return;
1763
+		}
1764
+		if (! $this->reg_code()) {
1765
+			parent::set('REG_code', $REG_code, $use_default);
1766
+		} else {
1767
+			EE_Error::doing_it_wrong(
1768
+				__CLASS__ . '::' . __FUNCTION__,
1769
+				esc_html__('Can not change a registration REG_code once it has been set.', 'event_espresso'),
1770
+				'4.6.0'
1771
+			);
1772
+		}
1773
+	}
1774
+
1775
+
1776
+	/**
1777
+	 * Returns all other registrations in the same group as this registrant who have the same ticket option.
1778
+	 * Note, if you want to just get all registrations in the same transaction (group), use:
1779
+	 *    $registration->transaction()->registrations();
1780
+	 *
1781
+	 * @since 4.5.0
1782
+	 * @return EE_Registration[] or empty array if this isn't a group registration.
1783
+	 * @throws EE_Error
1784
+	 */
1785
+	public function get_all_other_registrations_in_group()
1786
+	{
1787
+		if ($this->group_size() < 2) {
1788
+			return array();
1789
+		}
1790
+
1791
+		$query[0] = array(
1792
+			'TXN_ID' => $this->transaction_ID(),
1793
+			'REG_ID' => array('!=', $this->ID()),
1794
+			'TKT_ID' => $this->ticket_ID(),
1795
+		);
1796
+		/** @var EE_Registration[] $registrations */
1797
+		$registrations = $this->get_model()->get_all($query);
1798
+		return $registrations;
1799
+	}
1800
+
1801
+	/**
1802
+	 * Return the link to the admin details for the object.
1803
+	 *
1804
+	 * @return string
1805
+	 * @throws EE_Error
1806
+	 */
1807
+	public function get_admin_details_link()
1808
+	{
1809
+		EE_Registry::instance()->load_helper('URL');
1810
+		return EEH_URL::add_query_args_and_nonce(
1811
+			array(
1812
+				'page'    => 'espresso_registrations',
1813
+				'action'  => 'view_registration',
1814
+				'_REG_ID' => $this->ID(),
1815
+			),
1816
+			admin_url('admin.php')
1817
+		);
1818
+	}
1819
+
1820
+	/**
1821
+	 * Returns the link to the editor for the object.  Sometimes this is the same as the details.
1822
+	 *
1823
+	 * @return string
1824
+	 * @throws EE_Error
1825
+	 */
1826
+	public function get_admin_edit_link()
1827
+	{
1828
+		return $this->get_admin_details_link();
1829
+	}
1830
+
1831
+	/**
1832
+	 * Returns the link to a settings page for the object.
1833
+	 *
1834
+	 * @return string
1835
+	 * @throws EE_Error
1836
+	 */
1837
+	public function get_admin_settings_link()
1838
+	{
1839
+		return $this->get_admin_details_link();
1840
+	}
1841
+
1842
+	/**
1843
+	 * Returns the link to the "overview" for the object (typically the "list table" view).
1844
+	 *
1845
+	 * @return string
1846
+	 */
1847
+	public function get_admin_overview_link()
1848
+	{
1849
+		EE_Registry::instance()->load_helper('URL');
1850
+		return EEH_URL::add_query_args_and_nonce(
1851
+			array(
1852
+				'page' => 'espresso_registrations',
1853
+			),
1854
+			admin_url('admin.php')
1855
+		);
1856
+	}
1857
+
1858
+
1859
+	/**
1860
+	 * @param array $query_params
1861
+	 *
1862
+	 * @return \EE_Registration[]
1863
+	 * @throws EE_Error
1864
+	 */
1865
+	public function payments($query_params = array())
1866
+	{
1867
+		return $this->get_many_related('Payment', $query_params);
1868
+	}
1869
+
1870
+
1871
+	/**
1872
+	 * @param array $query_params
1873
+	 *
1874
+	 * @return \EE_Registration_Payment[]
1875
+	 * @throws EE_Error
1876
+	 */
1877
+	public function registration_payments($query_params = array())
1878
+	{
1879
+		return $this->get_many_related('Registration_Payment', $query_params);
1880
+	}
1881
+
1882
+
1883
+	/**
1884
+	 * This grabs the payment method corresponding to the last payment made for the amount owing on the registration.
1885
+	 * Note: if there are no payments on the registration there will be no payment method returned.
1886
+	 *
1887
+	 * @return EE_Payment_Method|null
1888
+	 */
1889
+	public function payment_method()
1890
+	{
1891
+		return EEM_Payment_Method::instance()->get_last_used_for_registration($this);
1892
+	}
1893
+
1894
+
1895
+	/**
1896
+	 * @return \EE_Line_Item
1897
+	 * @throws EntityNotFoundException
1898
+	 * @throws EE_Error
1899
+	 */
1900
+	public function ticket_line_item()
1901
+	{
1902
+		$ticket = $this->ticket();
1903
+		$transaction = $this->transaction();
1904
+		$line_item = null;
1905
+		$ticket_line_items = \EEH_Line_Item::get_line_items_by_object_type_and_IDs(
1906
+			$transaction->total_line_item(),
1907
+			'Ticket',
1908
+			array($ticket->ID())
1909
+		);
1910
+		foreach ($ticket_line_items as $ticket_line_item) {
1911
+			if ($ticket_line_item instanceof \EE_Line_Item
1912
+				&& $ticket_line_item->OBJ_type() === 'Ticket'
1913
+				&& $ticket_line_item->OBJ_ID() === $ticket->ID()
1914
+			) {
1915
+				$line_item = $ticket_line_item;
1916
+				break;
1917
+			}
1918
+		}
1919
+		if (! ($line_item instanceof \EE_Line_Item && $line_item->OBJ_type() === 'Ticket')) {
1920
+			throw new EntityNotFoundException('Line Item Ticket ID', $ticket->ID());
1921
+		}
1922
+		return $line_item;
1923
+	}
1924
+
1925
+
1926
+	/**
1927
+	 * Soft Deletes this model object.
1928
+	 *
1929
+	 * @return boolean | int
1930
+	 * @throws RuntimeException
1931
+	 * @throws EE_Error
1932
+	 */
1933
+	public function delete()
1934
+	{
1935
+		if ($this->update_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY, $this->status_ID()) === true) {
1936
+			$this->set_status(EEM_Registration::status_id_cancelled);
1937
+		}
1938
+		return parent::delete();
1939
+	}
1940
+
1941
+
1942
+	/**
1943
+	 * Restores whatever the previous status was on a registration before it was trashed (if possible)
1944
+	 *
1945
+	 * @throws EE_Error
1946
+	 * @throws RuntimeException
1947
+	 */
1948
+	public function restore()
1949
+	{
1950
+		$previous_status = $this->get_extra_meta(
1951
+			EE_Registration::PRE_TRASH_REG_STATUS_KEY,
1952
+			true,
1953
+			EEM_Registration::status_id_cancelled
1954
+		);
1955
+		if ($previous_status) {
1956
+			$this->delete_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY);
1957
+			$this->set_status($previous_status);
1958
+		}
1959
+		return parent::restore();
1960
+	}
1961
+
1962
+
1963
+	/**
1964
+	 * possibly toggle Registration status based on comparison of REG_paid vs REG_final_price
1965
+	 *
1966
+	 * @param  boolean $trigger_set_status_logic EE_Registration::set_status() can trigger additional logic
1967
+	 *                                           depending on whether the reg status changes to or from "Approved"
1968
+	 * @return boolean whether the Registration status was updated
1969
+	 * @throws EE_Error
1970
+	 * @throws RuntimeException
1971
+	 */
1972
+	public function updateStatusBasedOnTotalPaid($trigger_set_status_logic = true)
1973
+	{
1974
+		$paid = $this->paid();
1975
+		$price = $this->final_price();
1976
+		switch (true) {
1977
+			// overpaid or paid
1978
+			case EEH_Money::compare_floats($paid, $price, '>'):
1979
+			case EEH_Money::compare_floats($paid, $price):
1980
+				$new_status = EEM_Registration::status_id_approved;
1981
+				break;
1982
+			//  underpaid
1983
+			case EEH_Money::compare_floats($paid, $price, '<'):
1984
+				$new_status = EEM_Registration::status_id_pending_payment;
1985
+				break;
1986
+			// uhhh Houston...
1987
+			default:
1988
+				throw new RuntimeException(
1989
+					esc_html__('The total paid calculation for this registration is inaccurate.', 'event_espresso')
1990
+				);
1991
+		}
1992
+		if ($new_status !== $this->status_ID()) {
1993
+			if ($trigger_set_status_logic) {
1994
+				return $this->set_status($new_status);
1995
+			}
1996
+			parent::set('STS_ID', $new_status);
1997
+			return true;
1998
+		}
1999
+		return false;
2000
+	}
2001
+
2002
+
2003
+	/*************************** DEPRECATED ***************************/
2004
+
2005
+
2006
+	/**
2007
+	 * @deprecated
2008
+	 * @since     4.7.0
2009
+	 * @access    public
2010
+	 */
2011
+	public function price_paid()
2012
+	{
2013
+		EE_Error::doing_it_wrong(
2014
+			'EE_Registration::price_paid()',
2015
+			esc_html__(
2016
+				'This method is deprecated, please use EE_Registration::final_price() instead.',
2017
+				'event_espresso'
2018
+			),
2019
+			'4.7.0'
2020
+		);
2021
+		return $this->final_price();
2022
+	}
2023
+
2024
+
2025
+	/**
2026
+	 * @deprecated
2027
+	 * @since     4.7.0
2028
+	 * @access    public
2029
+	 * @param    float $REG_final_price
2030
+	 * @throws EE_Error
2031
+	 * @throws RuntimeException
2032
+	 */
2033
+	public function set_price_paid($REG_final_price = 0.00)
2034
+	{
2035
+		EE_Error::doing_it_wrong(
2036
+			'EE_Registration::set_price_paid()',
2037
+			esc_html__(
2038
+				'This method is deprecated, please use EE_Registration::set_final_price() instead.',
2039
+				'event_espresso'
2040
+			),
2041
+			'4.7.0'
2042
+		);
2043
+		$this->set_final_price($REG_final_price);
2044
+	}
2045
+
2046
+
2047
+	/**
2048
+	 * @deprecated
2049
+	 * @since 4.7.0
2050
+	 * @return string
2051
+	 * @throws EE_Error
2052
+	 */
2053
+	public function pretty_price_paid()
2054
+	{
2055
+		EE_Error::doing_it_wrong(
2056
+			'EE_Registration::pretty_price_paid()',
2057
+			esc_html__(
2058
+				'This method is deprecated, please use EE_Registration::pretty_final_price() instead.',
2059
+				'event_espresso'
2060
+			),
2061
+			'4.7.0'
2062
+		);
2063
+		return $this->pretty_final_price();
2064
+	}
2065
+
2066
+
2067
+	/**
2068
+	 * Gets the primary datetime related to this registration via the related Event to this registration
2069
+	 *
2070
+	 * @deprecated 4.9.17
2071
+	 * @return EE_Datetime
2072
+	 * @throws EE_Error
2073
+	 * @throws EntityNotFoundException
2074
+	 */
2075
+	public function get_related_primary_datetime()
2076
+	{
2077
+		EE_Error::doing_it_wrong(
2078
+			__METHOD__,
2079
+			esc_html__(
2080
+				'Use EE_Registration::get_latest_related_datetime() or EE_Registration::get_earliest_related_datetime()',
2081
+				'event_espresso'
2082
+			),
2083
+			'4.9.17',
2084
+			'5.0.0'
2085
+		);
2086
+		return $this->event()->primary_datetime();
2087
+	}
2088 2088
 }
Please login to merge, or discard this patch.