@@ -761,7 +761,7 @@ |
||
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 | */ |
@@ -34,768 +34,768 @@ |
||
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 | } |
@@ -136,11 +136,11 @@ discard block |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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 |
||
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. |
@@ -15,602 +15,602 @@ |
||
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 | } |
@@ -15,1802 +15,1802 @@ |
||
15 | 15 | class EED_Single_Page_Checkout extends EED_Module |
16 | 16 | { |
17 | 17 | |
18 | - /** |
|
19 | - * $_initialized - has the SPCO controller already been initialized ? |
|
20 | - * |
|
21 | - * @access private |
|
22 | - * @var bool $_initialized |
|
23 | - */ |
|
24 | - private static $_initialized = false; |
|
25 | - |
|
26 | - |
|
27 | - /** |
|
28 | - * $_checkout_verified - is the EE_Checkout verified as correct for this request ? |
|
29 | - * |
|
30 | - * @access private |
|
31 | - * @var bool $_valid_checkout |
|
32 | - */ |
|
33 | - private static $_checkout_verified = true; |
|
34 | - |
|
35 | - /** |
|
36 | - * $_reg_steps_array - holds initial array of reg steps |
|
37 | - * |
|
38 | - * @access private |
|
39 | - * @var array $_reg_steps_array |
|
40 | - */ |
|
41 | - private static $_reg_steps_array = array(); |
|
42 | - |
|
43 | - /** |
|
44 | - * $checkout - EE_Checkout object for handling the properties of the current checkout process |
|
45 | - * |
|
46 | - * @access public |
|
47 | - * @var EE_Checkout $checkout |
|
48 | - */ |
|
49 | - public $checkout; |
|
50 | - |
|
51 | - |
|
52 | - /** |
|
53 | - * @return EED_Module|EED_Single_Page_Checkout |
|
54 | - */ |
|
55 | - public static function instance() |
|
56 | - { |
|
57 | - add_filter('EED_Single_Page_Checkout__SPCO_active', '__return_true'); |
|
58 | - return parent::get_instance(__CLASS__); |
|
59 | - } |
|
60 | - |
|
61 | - |
|
62 | - /** |
|
63 | - * @return EE_CART |
|
64 | - */ |
|
65 | - public function cart() |
|
66 | - { |
|
67 | - return $this->checkout->cart; |
|
68 | - } |
|
69 | - |
|
70 | - |
|
71 | - /** |
|
72 | - * @return EE_Transaction |
|
73 | - */ |
|
74 | - public function transaction() |
|
75 | - { |
|
76 | - return $this->checkout->transaction; |
|
77 | - } |
|
78 | - |
|
79 | - |
|
80 | - /** |
|
81 | - * set_hooks - for hooking into EE Core, other modules, etc |
|
82 | - * |
|
83 | - * @access public |
|
84 | - * @return void |
|
85 | - * @throws EE_Error |
|
86 | - */ |
|
87 | - public static function set_hooks() |
|
88 | - { |
|
89 | - EED_Single_Page_Checkout::set_definitions(); |
|
90 | - } |
|
91 | - |
|
92 | - |
|
93 | - /** |
|
94 | - * set_hooks_admin - for hooking into EE Admin Core, other modules, etc |
|
95 | - * |
|
96 | - * @access public |
|
97 | - * @return void |
|
98 | - * @throws EE_Error |
|
99 | - */ |
|
100 | - public static function set_hooks_admin() |
|
101 | - { |
|
102 | - EED_Single_Page_Checkout::set_definitions(); |
|
103 | - if (! (defined('DOING_AJAX') && DOING_AJAX)) { |
|
104 | - return; |
|
105 | - } |
|
106 | - // going to start an output buffer in case anything gets accidentally output |
|
107 | - // that might disrupt our JSON response |
|
108 | - ob_start(); |
|
109 | - EED_Single_Page_Checkout::load_request_handler(); |
|
110 | - EED_Single_Page_Checkout::load_reg_steps(); |
|
111 | - // set ajax hooks |
|
112 | - add_action('wp_ajax_process_reg_step', array('EED_Single_Page_Checkout', 'process_reg_step')); |
|
113 | - add_action('wp_ajax_nopriv_process_reg_step', array('EED_Single_Page_Checkout', 'process_reg_step')); |
|
114 | - add_action('wp_ajax_display_spco_reg_step', array('EED_Single_Page_Checkout', 'display_reg_step')); |
|
115 | - add_action('wp_ajax_nopriv_display_spco_reg_step', array('EED_Single_Page_Checkout', 'display_reg_step')); |
|
116 | - add_action('wp_ajax_update_reg_step', array('EED_Single_Page_Checkout', 'update_reg_step')); |
|
117 | - add_action('wp_ajax_nopriv_update_reg_step', array('EED_Single_Page_Checkout', 'update_reg_step')); |
|
118 | - } |
|
119 | - |
|
120 | - |
|
121 | - /** |
|
122 | - * process ajax request |
|
123 | - * |
|
124 | - * @param string $ajax_action |
|
125 | - * @throws EE_Error |
|
126 | - */ |
|
127 | - public static function process_ajax_request($ajax_action) |
|
128 | - { |
|
129 | - EE_Registry::instance()->REQ->set('action', $ajax_action); |
|
130 | - EED_Single_Page_Checkout::instance()->_initialize(); |
|
131 | - } |
|
132 | - |
|
133 | - |
|
134 | - /** |
|
135 | - * ajax display registration step |
|
136 | - * |
|
137 | - * @throws EE_Error |
|
138 | - */ |
|
139 | - public static function display_reg_step() |
|
140 | - { |
|
141 | - EED_Single_Page_Checkout::process_ajax_request('display_spco_reg_step'); |
|
142 | - } |
|
143 | - |
|
144 | - |
|
145 | - /** |
|
146 | - * ajax process registration step |
|
147 | - * |
|
148 | - * @throws EE_Error |
|
149 | - */ |
|
150 | - public static function process_reg_step() |
|
151 | - { |
|
152 | - EED_Single_Page_Checkout::process_ajax_request('process_reg_step'); |
|
153 | - } |
|
154 | - |
|
155 | - |
|
156 | - /** |
|
157 | - * ajax process registration step |
|
158 | - * |
|
159 | - * @throws EE_Error |
|
160 | - */ |
|
161 | - public static function update_reg_step() |
|
162 | - { |
|
163 | - EED_Single_Page_Checkout::process_ajax_request('update_reg_step'); |
|
164 | - } |
|
165 | - |
|
166 | - |
|
167 | - /** |
|
168 | - * update_checkout |
|
169 | - * |
|
170 | - * @access public |
|
171 | - * @return void |
|
172 | - * @throws EE_Error |
|
173 | - */ |
|
174 | - public static function update_checkout() |
|
175 | - { |
|
176 | - EED_Single_Page_Checkout::process_ajax_request('update_checkout'); |
|
177 | - } |
|
178 | - |
|
179 | - |
|
180 | - /** |
|
181 | - * load_request_handler |
|
182 | - * |
|
183 | - * @access public |
|
184 | - * @return void |
|
185 | - */ |
|
186 | - public static function load_request_handler() |
|
187 | - { |
|
188 | - // load core Request_Handler class |
|
189 | - if (EE_Registry::instance()->REQ !== null) { |
|
190 | - EE_Registry::instance()->load_core('Request_Handler'); |
|
191 | - } |
|
192 | - } |
|
193 | - |
|
194 | - |
|
195 | - /** |
|
196 | - * set_definitions |
|
197 | - * |
|
198 | - * @access public |
|
199 | - * @return void |
|
200 | - * @throws EE_Error |
|
201 | - */ |
|
202 | - public static function set_definitions() |
|
203 | - { |
|
204 | - if (defined('SPCO_BASE_PATH')) { |
|
205 | - return; |
|
206 | - } |
|
207 | - define( |
|
208 | - 'SPCO_BASE_PATH', |
|
209 | - rtrim(str_replace(array('\\', '/'), '/', plugin_dir_path(__FILE__)), '/') . '/' |
|
210 | - ); |
|
211 | - define('SPCO_CSS_URL', plugin_dir_url(__FILE__) . 'css/'); |
|
212 | - define('SPCO_IMG_URL', plugin_dir_url(__FILE__) . 'img/'); |
|
213 | - define('SPCO_JS_URL', plugin_dir_url(__FILE__) . 'js/'); |
|
214 | - define('SPCO_INC_PATH', SPCO_BASE_PATH . 'inc/'); |
|
215 | - define('SPCO_REG_STEPS_PATH', SPCO_BASE_PATH . 'reg_steps/'); |
|
216 | - define('SPCO_TEMPLATES_PATH', SPCO_BASE_PATH . 'templates/'); |
|
217 | - EEH_Autoloader::register_autoloaders_for_each_file_in_folder(SPCO_BASE_PATH, true); |
|
218 | - EE_Registry::$i18n_js_strings['registration_expiration_notice'] = EED_Single_Page_Checkout::getRegistrationExpirationNotice( |
|
219 | - ); |
|
220 | - } |
|
221 | - |
|
222 | - |
|
223 | - /** |
|
224 | - * load_reg_steps |
|
225 | - * loads and instantiates each reg step based on the EE_Registry::instance()->CFG->registration->reg_steps array |
|
226 | - * |
|
227 | - * @access private |
|
228 | - * @throws EE_Error |
|
229 | - */ |
|
230 | - public static function load_reg_steps() |
|
231 | - { |
|
232 | - static $reg_steps_loaded = false; |
|
233 | - if ($reg_steps_loaded) { |
|
234 | - return; |
|
235 | - } |
|
236 | - // filter list of reg_steps |
|
237 | - $reg_steps_to_load = (array) apply_filters( |
|
238 | - 'AHEE__SPCO__load_reg_steps__reg_steps_to_load', |
|
239 | - EED_Single_Page_Checkout::get_reg_steps() |
|
240 | - ); |
|
241 | - // sort by key (order) |
|
242 | - ksort($reg_steps_to_load); |
|
243 | - // loop through folders |
|
244 | - foreach ($reg_steps_to_load as $order => $reg_step) { |
|
245 | - // we need a |
|
246 | - if (isset($reg_step['file_path'], $reg_step['class_name'], $reg_step['slug'])) { |
|
247 | - // copy over to the reg_steps_array |
|
248 | - EED_Single_Page_Checkout::$_reg_steps_array[ $order ] = $reg_step; |
|
249 | - // register custom key route for each reg step |
|
250 | - // ie: step=>"slug" - this is the entire reason we load the reg steps array now |
|
251 | - EE_Config::register_route( |
|
252 | - $reg_step['slug'], |
|
253 | - 'EED_Single_Page_Checkout', |
|
254 | - 'run', |
|
255 | - 'step' |
|
256 | - ); |
|
257 | - // add AJAX or other hooks |
|
258 | - if (isset($reg_step['has_hooks']) && $reg_step['has_hooks']) { |
|
259 | - // setup autoloaders if necessary |
|
260 | - if (! class_exists($reg_step['class_name'])) { |
|
261 | - EEH_Autoloader::register_autoloaders_for_each_file_in_folder( |
|
262 | - $reg_step['file_path'], |
|
263 | - true |
|
264 | - ); |
|
265 | - } |
|
266 | - if (is_callable($reg_step['class_name'], 'set_hooks')) { |
|
267 | - call_user_func(array($reg_step['class_name'], 'set_hooks')); |
|
268 | - } |
|
269 | - } |
|
270 | - } |
|
271 | - } |
|
272 | - $reg_steps_loaded = true; |
|
273 | - } |
|
274 | - |
|
275 | - |
|
276 | - /** |
|
277 | - * get_reg_steps |
|
278 | - * |
|
279 | - * @access public |
|
280 | - * @return array |
|
281 | - */ |
|
282 | - public static function get_reg_steps() |
|
283 | - { |
|
284 | - $reg_steps = EE_Registry::instance()->CFG->registration->reg_steps; |
|
285 | - if (empty($reg_steps)) { |
|
286 | - $reg_steps = array( |
|
287 | - 10 => array( |
|
288 | - 'file_path' => SPCO_REG_STEPS_PATH . 'attendee_information', |
|
289 | - 'class_name' => 'EE_SPCO_Reg_Step_Attendee_Information', |
|
290 | - 'slug' => 'attendee_information', |
|
291 | - 'has_hooks' => false, |
|
292 | - ), |
|
293 | - 30 => array( |
|
294 | - 'file_path' => SPCO_REG_STEPS_PATH . 'payment_options', |
|
295 | - 'class_name' => 'EE_SPCO_Reg_Step_Payment_Options', |
|
296 | - 'slug' => 'payment_options', |
|
297 | - 'has_hooks' => true, |
|
298 | - ), |
|
299 | - 999 => array( |
|
300 | - 'file_path' => SPCO_REG_STEPS_PATH . 'finalize_registration', |
|
301 | - 'class_name' => 'EE_SPCO_Reg_Step_Finalize_Registration', |
|
302 | - 'slug' => 'finalize_registration', |
|
303 | - 'has_hooks' => false, |
|
304 | - ), |
|
305 | - ); |
|
306 | - } |
|
307 | - return $reg_steps; |
|
308 | - } |
|
309 | - |
|
310 | - |
|
311 | - /** |
|
312 | - * registration_checkout_for_admin |
|
313 | - * |
|
314 | - * @access public |
|
315 | - * @return string |
|
316 | - * @throws EE_Error |
|
317 | - */ |
|
318 | - public static function registration_checkout_for_admin() |
|
319 | - { |
|
320 | - EED_Single_Page_Checkout::load_request_handler(); |
|
321 | - EE_Registry::instance()->REQ->set('step', 'attendee_information'); |
|
322 | - EE_Registry::instance()->REQ->set('action', 'display_spco_reg_step'); |
|
323 | - EE_Registry::instance()->REQ->set('process_form_submission', false); |
|
324 | - EED_Single_Page_Checkout::instance()->_initialize(); |
|
325 | - EED_Single_Page_Checkout::instance()->_display_spco_reg_form(); |
|
326 | - return EE_Registry::instance()->REQ->get_output(); |
|
327 | - } |
|
328 | - |
|
329 | - |
|
330 | - /** |
|
331 | - * process_registration_from_admin |
|
332 | - * |
|
333 | - * @access public |
|
334 | - * @return \EE_Transaction |
|
335 | - * @throws EE_Error |
|
336 | - */ |
|
337 | - public static function process_registration_from_admin() |
|
338 | - { |
|
339 | - EED_Single_Page_Checkout::load_request_handler(); |
|
340 | - EE_Registry::instance()->REQ->set('step', 'attendee_information'); |
|
341 | - EE_Registry::instance()->REQ->set('action', 'process_reg_step'); |
|
342 | - EE_Registry::instance()->REQ->set('process_form_submission', true); |
|
343 | - EED_Single_Page_Checkout::instance()->_initialize(); |
|
344 | - if (EED_Single_Page_Checkout::instance()->checkout->current_step->completed()) { |
|
345 | - $final_reg_step = end(EED_Single_Page_Checkout::instance()->checkout->reg_steps); |
|
346 | - if ($final_reg_step instanceof EE_SPCO_Reg_Step_Finalize_Registration) { |
|
347 | - EED_Single_Page_Checkout::instance()->checkout->set_reg_step_initiated($final_reg_step); |
|
348 | - if ($final_reg_step->process_reg_step()) { |
|
349 | - $final_reg_step->set_completed(); |
|
350 | - EED_Single_Page_Checkout::instance()->checkout->update_txn_reg_steps_array(); |
|
351 | - return EED_Single_Page_Checkout::instance()->checkout->transaction; |
|
352 | - } |
|
353 | - } |
|
354 | - } |
|
355 | - return null; |
|
356 | - } |
|
357 | - |
|
358 | - |
|
359 | - /** |
|
360 | - * run |
|
361 | - * |
|
362 | - * @access public |
|
363 | - * @param WP_Query $WP_Query |
|
364 | - * @return void |
|
365 | - * @throws EE_Error |
|
366 | - */ |
|
367 | - public function run($WP_Query) |
|
368 | - { |
|
369 | - if ($WP_Query instanceof WP_Query |
|
370 | - && $WP_Query->is_main_query() |
|
371 | - && apply_filters('FHEE__EED_Single_Page_Checkout__run', true) |
|
372 | - && $this->_is_reg_checkout() |
|
373 | - ) { |
|
374 | - $this->_initialize(); |
|
375 | - } |
|
376 | - } |
|
377 | - |
|
378 | - |
|
379 | - /** |
|
380 | - * determines whether current url matches reg page url |
|
381 | - * |
|
382 | - * @return bool |
|
383 | - */ |
|
384 | - protected function _is_reg_checkout() |
|
385 | - { |
|
386 | - // get current permalink for reg page without any extra query args |
|
387 | - $reg_page_url = \get_permalink(EE_Config::instance()->core->reg_page_id); |
|
388 | - // get request URI for current request, but without the scheme or host |
|
389 | - $current_request_uri = \EEH_URL::filter_input_server_url('REQUEST_URI'); |
|
390 | - $current_request_uri = html_entity_decode($current_request_uri); |
|
391 | - // get array of query args from the current request URI |
|
392 | - $query_args = \EEH_URL::get_query_string($current_request_uri); |
|
393 | - // grab page id if it is set |
|
394 | - $page_id = isset($query_args['page_id']) ? absint($query_args['page_id']) : 0; |
|
395 | - // and remove the page id from the query args (we will re-add it later) |
|
396 | - unset($query_args['page_id']); |
|
397 | - // now strip all query args from current request URI |
|
398 | - $current_request_uri = remove_query_arg(array_keys($query_args), $current_request_uri); |
|
399 | - // and re-add the page id if it was set |
|
400 | - if ($page_id) { |
|
401 | - $current_request_uri = add_query_arg('page_id', $page_id, $current_request_uri); |
|
402 | - } |
|
403 | - // remove slashes and ? |
|
404 | - $current_request_uri = trim($current_request_uri, '?/'); |
|
405 | - // is current request URI part of the known full reg page URL ? |
|
406 | - return ! empty($current_request_uri) && strpos($reg_page_url, $current_request_uri) !== false; |
|
407 | - } |
|
408 | - |
|
409 | - |
|
410 | - /** |
|
411 | - * @param WP_Query $wp_query |
|
412 | - * @return void |
|
413 | - * @throws EE_Error |
|
414 | - */ |
|
415 | - public static function init($wp_query) |
|
416 | - { |
|
417 | - EED_Single_Page_Checkout::instance()->run($wp_query); |
|
418 | - } |
|
419 | - |
|
420 | - |
|
421 | - /** |
|
422 | - * _initialize - initial module setup |
|
423 | - * |
|
424 | - * @access private |
|
425 | - * @throws EE_Error |
|
426 | - * @return void |
|
427 | - */ |
|
428 | - private function _initialize() |
|
429 | - { |
|
430 | - // ensure SPCO doesn't run twice |
|
431 | - if (EED_Single_Page_Checkout::$_initialized) { |
|
432 | - return; |
|
433 | - } |
|
434 | - try { |
|
435 | - EED_Single_Page_Checkout::load_reg_steps(); |
|
436 | - $this->_verify_session(); |
|
437 | - // setup the EE_Checkout object |
|
438 | - $this->checkout = $this->_initialize_checkout(); |
|
439 | - // filter checkout |
|
440 | - $this->checkout = apply_filters('FHEE__EED_Single_Page_Checkout___initialize__checkout', $this->checkout); |
|
441 | - // get the $_GET |
|
442 | - $this->_get_request_vars(); |
|
443 | - if ($this->_block_bots()) { |
|
444 | - return; |
|
445 | - } |
|
446 | - // filter continue_reg |
|
447 | - $this->checkout->continue_reg = apply_filters( |
|
448 | - 'FHEE__EED_Single_Page_Checkout__init___continue_reg', |
|
449 | - true, |
|
450 | - $this->checkout |
|
451 | - ); |
|
452 | - // load the reg steps array |
|
453 | - if (! $this->_load_and_instantiate_reg_steps()) { |
|
454 | - EED_Single_Page_Checkout::$_initialized = true; |
|
455 | - return; |
|
456 | - } |
|
457 | - // set the current step |
|
458 | - $this->checkout->set_current_step($this->checkout->step); |
|
459 | - // and the next step |
|
460 | - $this->checkout->set_next_step(); |
|
461 | - // verify that everything has been setup correctly |
|
462 | - if (! ($this->_verify_transaction_and_get_registrations() && $this->_final_verifications())) { |
|
463 | - EED_Single_Page_Checkout::$_initialized = true; |
|
464 | - return; |
|
465 | - } |
|
466 | - // lock the transaction |
|
467 | - $this->checkout->transaction->lock(); |
|
468 | - // make sure all of our cached objects are added to their respective model entity mappers |
|
469 | - $this->checkout->refresh_all_entities(); |
|
470 | - // set amount owing |
|
471 | - $this->checkout->amount_owing = $this->checkout->transaction->remaining(); |
|
472 | - // initialize each reg step, which gives them the chance to potentially alter the process |
|
473 | - $this->_initialize_reg_steps(); |
|
474 | - // DEBUG LOG |
|
475 | - // $this->checkout->log( __CLASS__, __FUNCTION__, __LINE__ ); |
|
476 | - // get reg form |
|
477 | - if (! $this->_check_form_submission()) { |
|
478 | - EED_Single_Page_Checkout::$_initialized = true; |
|
479 | - return; |
|
480 | - } |
|
481 | - // checkout the action!!! |
|
482 | - $this->_process_form_action(); |
|
483 | - // add some style and make it dance |
|
484 | - $this->add_styles_and_scripts($this); |
|
485 | - // kk... SPCO has successfully run |
|
486 | - EED_Single_Page_Checkout::$_initialized = true; |
|
487 | - // set no cache headers and constants |
|
488 | - EE_System::do_not_cache(); |
|
489 | - // add anchor |
|
490 | - add_action('loop_start', array($this, 'set_checkout_anchor'), 1); |
|
491 | - // remove transaction lock |
|
492 | - add_action('shutdown', array($this, 'unlock_transaction'), 1); |
|
493 | - } catch (Exception $e) { |
|
494 | - EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__); |
|
495 | - } |
|
496 | - } |
|
497 | - |
|
498 | - |
|
499 | - /** |
|
500 | - * _verify_session |
|
501 | - * checks that the session is valid and not expired |
|
502 | - * |
|
503 | - * @access private |
|
504 | - * @throws EE_Error |
|
505 | - */ |
|
506 | - private function _verify_session() |
|
507 | - { |
|
508 | - if (! EE_Registry::instance()->SSN instanceof EE_Session) { |
|
509 | - throw new EE_Error(esc_html__('The EE_Session class could not be loaded.', 'event_espresso')); |
|
510 | - } |
|
511 | - $clear_session_requested = filter_var( |
|
512 | - EE_Registry::instance()->REQ->get('clear_session', false), |
|
513 | - FILTER_VALIDATE_BOOLEAN |
|
514 | - ); |
|
515 | - // is session still valid ? |
|
516 | - if ($clear_session_requested |
|
517 | - || (EE_Registry::instance()->SSN->expired() |
|
518 | - && EE_Registry::instance()->REQ->get('e_reg_url_link', '') === '' |
|
519 | - ) |
|
520 | - ) { |
|
521 | - $this->checkout = new EE_Checkout(); |
|
522 | - EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__); |
|
523 | - // EE_Registry::instance()->SSN->reset_cart(); |
|
524 | - // EE_Registry::instance()->SSN->reset_checkout(); |
|
525 | - // EE_Registry::instance()->SSN->reset_transaction(); |
|
526 | - if (! $clear_session_requested) { |
|
527 | - EE_Error::add_attention( |
|
528 | - EE_Registry::$i18n_js_strings['registration_expiration_notice'], |
|
529 | - __FILE__, |
|
530 | - __FUNCTION__, |
|
531 | - __LINE__ |
|
532 | - ); |
|
533 | - } |
|
534 | - // EE_Registry::instance()->SSN->reset_expired(); |
|
535 | - } |
|
536 | - } |
|
537 | - |
|
538 | - |
|
539 | - /** |
|
540 | - * _initialize_checkout |
|
541 | - * loads and instantiates EE_Checkout |
|
542 | - * |
|
543 | - * @access private |
|
544 | - * @throws EE_Error |
|
545 | - * @return EE_Checkout |
|
546 | - */ |
|
547 | - private function _initialize_checkout() |
|
548 | - { |
|
549 | - // look in session for existing checkout |
|
550 | - /** @type EE_Checkout $checkout */ |
|
551 | - $checkout = EE_Registry::instance()->SSN->checkout(); |
|
552 | - // verify |
|
553 | - if (! $checkout instanceof EE_Checkout) { |
|
554 | - // instantiate EE_Checkout object for handling the properties of the current checkout process |
|
555 | - $checkout = EE_Registry::instance()->load_file( |
|
556 | - SPCO_INC_PATH, |
|
557 | - 'EE_Checkout', |
|
558 | - 'class', |
|
559 | - array(), |
|
560 | - false |
|
561 | - ); |
|
562 | - } else { |
|
563 | - if ($checkout->current_step->is_final_step() && $checkout->exit_spco() === true) { |
|
564 | - $this->unlock_transaction(); |
|
565 | - wp_safe_redirect($checkout->redirect_url); |
|
566 | - exit(); |
|
567 | - } |
|
568 | - } |
|
569 | - $checkout = apply_filters('FHEE__EED_Single_Page_Checkout___initialize_checkout__checkout', $checkout); |
|
570 | - // verify again |
|
571 | - if (! $checkout instanceof EE_Checkout) { |
|
572 | - throw new EE_Error(esc_html__('The EE_Checkout class could not be loaded.', 'event_espresso')); |
|
573 | - } |
|
574 | - // reset anything that needs a clean slate for each request |
|
575 | - $checkout->reset_for_current_request(); |
|
576 | - return $checkout; |
|
577 | - } |
|
578 | - |
|
579 | - |
|
580 | - /** |
|
581 | - * _get_request_vars |
|
582 | - * |
|
583 | - * @access private |
|
584 | - * @return void |
|
585 | - * @throws EE_Error |
|
586 | - */ |
|
587 | - private function _get_request_vars() |
|
588 | - { |
|
589 | - // load classes |
|
590 | - EED_Single_Page_Checkout::load_request_handler(); |
|
591 | - // make sure this request is marked as belonging to EE |
|
592 | - EE_Registry::instance()->REQ->set_espresso_page(true); |
|
593 | - // which step is being requested ? |
|
594 | - $this->checkout->step = EE_Registry::instance()->REQ->get('step', $this->_get_first_step()); |
|
595 | - // which step is being edited ? |
|
596 | - $this->checkout->edit_step = EE_Registry::instance()->REQ->get('edit_step', ''); |
|
597 | - // and what we're doing on the current step |
|
598 | - $this->checkout->action = EE_Registry::instance()->REQ->get('action', 'display_spco_reg_step'); |
|
599 | - // timestamp |
|
600 | - $this->checkout->uts = EE_Registry::instance()->REQ->get('uts', 0); |
|
601 | - // returning to edit ? |
|
602 | - $this->checkout->reg_url_link = EE_Registry::instance()->REQ->get('e_reg_url_link', ''); |
|
603 | - // add reg url link to registration query params |
|
604 | - if ($this->checkout->reg_url_link && strpos($this->checkout->reg_url_link, '1-') !== 0) { |
|
605 | - $this->checkout->reg_cache_where_params[0]['REG_url_link'] = $this->checkout->reg_url_link; |
|
606 | - } |
|
607 | - // or some other kind of revisit ? |
|
608 | - $this->checkout->revisit = filter_var( |
|
609 | - EE_Registry::instance()->REQ->get('revisit', false), |
|
610 | - FILTER_VALIDATE_BOOLEAN |
|
611 | - ); |
|
612 | - // and whether or not to generate a reg form for this request |
|
613 | - $this->checkout->generate_reg_form = filter_var( |
|
614 | - EE_Registry::instance()->REQ->get('generate_reg_form', true), |
|
615 | - FILTER_VALIDATE_BOOLEAN |
|
616 | - ); |
|
617 | - // and whether or not to process a reg form submission for this request |
|
618 | - $this->checkout->process_form_submission = filter_var( |
|
619 | - EE_Registry::instance()->REQ->get( |
|
620 | - 'process_form_submission', |
|
621 | - $this->checkout->action === 'process_reg_step' |
|
622 | - ), |
|
623 | - FILTER_VALIDATE_BOOLEAN |
|
624 | - ); |
|
625 | - $this->checkout->process_form_submission = filter_var( |
|
626 | - $this->checkout->action !== 'display_spco_reg_step' |
|
627 | - ? $this->checkout->process_form_submission |
|
628 | - : false, |
|
629 | - FILTER_VALIDATE_BOOLEAN |
|
630 | - ); |
|
631 | - // $this->_display_request_vars(); |
|
632 | - } |
|
633 | - |
|
634 | - |
|
635 | - /** |
|
636 | - * _display_request_vars |
|
637 | - * |
|
638 | - * @access protected |
|
639 | - * @return void |
|
640 | - */ |
|
641 | - protected function _display_request_vars() |
|
642 | - { |
|
643 | - if (! WP_DEBUG) { |
|
644 | - return; |
|
645 | - } |
|
646 | - EEH_Debug_Tools::printr($_REQUEST, '$_REQUEST', __FILE__, __LINE__); |
|
647 | - EEH_Debug_Tools::printr($this->checkout->step, '$this->checkout->step', __FILE__, __LINE__); |
|
648 | - EEH_Debug_Tools::printr($this->checkout->edit_step, '$this->checkout->edit_step', __FILE__, __LINE__); |
|
649 | - EEH_Debug_Tools::printr($this->checkout->action, '$this->checkout->action', __FILE__, __LINE__); |
|
650 | - EEH_Debug_Tools::printr($this->checkout->reg_url_link, '$this->checkout->reg_url_link', __FILE__, __LINE__); |
|
651 | - EEH_Debug_Tools::printr($this->checkout->revisit, '$this->checkout->revisit', __FILE__, __LINE__); |
|
652 | - EEH_Debug_Tools::printr( |
|
653 | - $this->checkout->generate_reg_form, |
|
654 | - '$this->checkout->generate_reg_form', |
|
655 | - __FILE__, |
|
656 | - __LINE__ |
|
657 | - ); |
|
658 | - EEH_Debug_Tools::printr( |
|
659 | - $this->checkout->process_form_submission, |
|
660 | - '$this->checkout->process_form_submission', |
|
661 | - __FILE__, |
|
662 | - __LINE__ |
|
663 | - ); |
|
664 | - } |
|
665 | - |
|
666 | - |
|
667 | - /** |
|
668 | - * _block_bots |
|
669 | - * checks that the incoming request has either of the following set: |
|
670 | - * a uts (unix timestamp) which indicates that the request was redirected from the Ticket Selector |
|
671 | - * a REG URL Link, which indicates that the request is a return visit to SPCO for a valid TXN |
|
672 | - * so if you're not coming from the Ticket Selector nor returning for a valid IP... |
|
673 | - * then where you coming from man? |
|
674 | - * |
|
675 | - * @return boolean |
|
676 | - */ |
|
677 | - private function _block_bots() |
|
678 | - { |
|
679 | - $invalid_checkout_access = EED_Invalid_Checkout_Access::getInvalidCheckoutAccess(); |
|
680 | - if ($invalid_checkout_access->checkoutAccessIsInvalid($this->checkout)) { |
|
681 | - return true; |
|
682 | - } |
|
683 | - return false; |
|
684 | - } |
|
685 | - |
|
686 | - |
|
687 | - /** |
|
688 | - * _get_first_step |
|
689 | - * gets slug for first step in $_reg_steps_array |
|
690 | - * |
|
691 | - * @access private |
|
692 | - * @throws EE_Error |
|
693 | - * @return string |
|
694 | - */ |
|
695 | - private function _get_first_step() |
|
696 | - { |
|
697 | - $first_step = reset(EED_Single_Page_Checkout::$_reg_steps_array); |
|
698 | - return isset($first_step['slug']) ? $first_step['slug'] : 'attendee_information'; |
|
699 | - } |
|
700 | - |
|
701 | - |
|
702 | - /** |
|
703 | - * instantiates each reg step based on the loaded reg_steps array |
|
704 | - * |
|
705 | - * @return bool |
|
706 | - * @throws EE_Error |
|
707 | - * @throws InvalidArgumentException |
|
708 | - * @throws InvalidDataTypeException |
|
709 | - * @throws InvalidInterfaceException |
|
710 | - */ |
|
711 | - private function _load_and_instantiate_reg_steps() |
|
712 | - { |
|
713 | - do_action('AHEE__Single_Page_Checkout___load_and_instantiate_reg_steps__start', $this->checkout); |
|
714 | - // have reg_steps already been instantiated ? |
|
715 | - if (empty($this->checkout->reg_steps) |
|
716 | - || apply_filters('FHEE__Single_Page_Checkout__load_reg_steps__reload_reg_steps', false, $this->checkout) |
|
717 | - ) { |
|
718 | - // if not, then loop through raw reg steps array |
|
719 | - foreach (EED_Single_Page_Checkout::$_reg_steps_array as $order => $reg_step) { |
|
720 | - if (! $this->_load_and_instantiate_reg_step($reg_step, $order)) { |
|
721 | - return false; |
|
722 | - } |
|
723 | - } |
|
724 | - if (isset($this->checkout->reg_steps['registration_confirmation'])) { |
|
725 | - // skip the registration_confirmation page ? |
|
726 | - if (EE_Registry::instance()->CFG->registration->skip_reg_confirmation) { |
|
727 | - // just remove it from the reg steps array |
|
728 | - $this->checkout->remove_reg_step('registration_confirmation', false); |
|
729 | - } elseif (EE_Registry::instance()->CFG->registration->reg_confirmation_last |
|
730 | - ) { |
|
731 | - // set the order to something big like 100 |
|
732 | - $this->checkout->set_reg_step_order('registration_confirmation', 100); |
|
733 | - } |
|
734 | - } |
|
735 | - // filter the array for good luck |
|
736 | - $this->checkout->reg_steps = apply_filters( |
|
737 | - 'FHEE__Single_Page_Checkout__load_reg_steps__reg_steps', |
|
738 | - $this->checkout->reg_steps |
|
739 | - ); |
|
740 | - // finally re-sort based on the reg step class order properties |
|
741 | - $this->checkout->sort_reg_steps(); |
|
742 | - } else { |
|
743 | - foreach ($this->checkout->reg_steps as $reg_step) { |
|
744 | - // set all current step stati to FALSE |
|
745 | - $reg_step->set_is_current_step(false); |
|
746 | - } |
|
747 | - } |
|
748 | - if (empty($this->checkout->reg_steps)) { |
|
749 | - EE_Error::add_error( |
|
750 | - esc_html__('No Reg Steps were loaded..', 'event_espresso'), |
|
751 | - __FILE__, |
|
752 | - __FUNCTION__, |
|
753 | - __LINE__ |
|
754 | - ); |
|
755 | - return false; |
|
756 | - } |
|
757 | - // make reg step details available to JS |
|
758 | - $this->checkout->set_reg_step_JSON_info(); |
|
759 | - return true; |
|
760 | - } |
|
761 | - |
|
762 | - |
|
763 | - /** |
|
764 | - * _load_and_instantiate_reg_step |
|
765 | - * |
|
766 | - * @access private |
|
767 | - * @param array $reg_step |
|
768 | - * @param int $order |
|
769 | - * @return bool |
|
770 | - */ |
|
771 | - private function _load_and_instantiate_reg_step($reg_step = array(), $order = 0) |
|
772 | - { |
|
773 | - // we need a file_path, class_name, and slug to add a reg step |
|
774 | - if (isset($reg_step['file_path'], $reg_step['class_name'], $reg_step['slug'])) { |
|
775 | - // if editing a specific step, but this is NOT that step... (and it's not the 'finalize_registration' step) |
|
776 | - if ($this->checkout->reg_url_link |
|
777 | - && $this->checkout->step !== $reg_step['slug'] |
|
778 | - && $reg_step['slug'] !== 'finalize_registration' |
|
779 | - // normally at this point we would NOT load the reg step, but this filter can change that |
|
780 | - && apply_filters( |
|
781 | - 'FHEE__Single_Page_Checkout___load_and_instantiate_reg_step__bypass_reg_step', |
|
782 | - true, |
|
783 | - $reg_step, |
|
784 | - $this->checkout |
|
785 | - ) |
|
786 | - ) { |
|
787 | - return true; |
|
788 | - } |
|
789 | - // instantiate step class using file path and class name |
|
790 | - $reg_step_obj = EE_Registry::instance()->load_file( |
|
791 | - $reg_step['file_path'], |
|
792 | - $reg_step['class_name'], |
|
793 | - 'class', |
|
794 | - $this->checkout, |
|
795 | - false |
|
796 | - ); |
|
797 | - // did we gets the goods ? |
|
798 | - if ($reg_step_obj instanceof EE_SPCO_Reg_Step) { |
|
799 | - // set reg step order based on config |
|
800 | - $reg_step_obj->set_order($order); |
|
801 | - // add instantiated reg step object to the master reg steps array |
|
802 | - $this->checkout->add_reg_step($reg_step_obj); |
|
803 | - } else { |
|
804 | - EE_Error::add_error( |
|
805 | - esc_html__('The current step could not be set.', 'event_espresso'), |
|
806 | - __FILE__, |
|
807 | - __FUNCTION__, |
|
808 | - __LINE__ |
|
809 | - ); |
|
810 | - return false; |
|
811 | - } |
|
812 | - } else { |
|
813 | - if (WP_DEBUG) { |
|
814 | - EE_Error::add_error( |
|
815 | - sprintf( |
|
816 | - esc_html__( |
|
817 | - 'A registration step could not be loaded. One or more of the following data points is invalid:%4$s%5$sFile Path: %1$s%6$s%5$sClass Name: %2$s%6$s%5$sSlug: %3$s%6$s%7$s', |
|
818 | - 'event_espresso' |
|
819 | - ), |
|
820 | - isset($reg_step['file_path']) ? $reg_step['file_path'] : '', |
|
821 | - isset($reg_step['class_name']) ? $reg_step['class_name'] : '', |
|
822 | - isset($reg_step['slug']) ? $reg_step['slug'] : '', |
|
823 | - '<ul>', |
|
824 | - '<li>', |
|
825 | - '</li>', |
|
826 | - '</ul>' |
|
827 | - ), |
|
828 | - __FILE__, |
|
829 | - __FUNCTION__, |
|
830 | - __LINE__ |
|
831 | - ); |
|
832 | - } |
|
833 | - return false; |
|
834 | - } |
|
835 | - return true; |
|
836 | - } |
|
837 | - |
|
838 | - |
|
839 | - /** |
|
840 | - * _verify_transaction_and_get_registrations |
|
841 | - * |
|
842 | - * @access private |
|
843 | - * @return bool |
|
844 | - * @throws InvalidDataTypeException |
|
845 | - * @throws InvalidEntityException |
|
846 | - * @throws EE_Error |
|
847 | - */ |
|
848 | - private function _verify_transaction_and_get_registrations() |
|
849 | - { |
|
850 | - // was there already a valid transaction in the checkout from the session ? |
|
851 | - if (! $this->checkout->transaction instanceof EE_Transaction) { |
|
852 | - // get transaction from db or session |
|
853 | - $this->checkout->transaction = $this->checkout->reg_url_link && ! is_admin() |
|
854 | - ? $this->_get_transaction_and_cart_for_previous_visit() |
|
855 | - : $this->_get_cart_for_current_session_and_setup_new_transaction(); |
|
856 | - if (! $this->checkout->transaction instanceof EE_Transaction) { |
|
857 | - EE_Error::add_error( |
|
858 | - esc_html__( |
|
859 | - 'Your Registration and Transaction information could not be retrieved from the db.', |
|
860 | - 'event_espresso' |
|
861 | - ), |
|
862 | - __FILE__, |
|
863 | - __FUNCTION__, |
|
864 | - __LINE__ |
|
865 | - ); |
|
866 | - $this->checkout->transaction = EE_Transaction::new_instance(); |
|
867 | - // add some style and make it dance |
|
868 | - $this->add_styles_and_scripts($this); |
|
869 | - EED_Single_Page_Checkout::$_initialized = true; |
|
870 | - return false; |
|
871 | - } |
|
872 | - // and the registrations for the transaction |
|
873 | - $this->_get_registrations($this->checkout->transaction); |
|
874 | - } |
|
875 | - return true; |
|
876 | - } |
|
877 | - |
|
878 | - |
|
879 | - /** |
|
880 | - * _get_transaction_and_cart_for_previous_visit |
|
881 | - * |
|
882 | - * @access private |
|
883 | - * @return mixed EE_Transaction|NULL |
|
884 | - */ |
|
885 | - private function _get_transaction_and_cart_for_previous_visit() |
|
886 | - { |
|
887 | - /** @var $TXN_model EEM_Transaction */ |
|
888 | - $TXN_model = EE_Registry::instance()->load_model('Transaction'); |
|
889 | - // because the reg_url_link is present in the request, |
|
890 | - // this is a return visit to SPCO, so we'll get the transaction data from the db |
|
891 | - $transaction = $TXN_model->get_transaction_from_reg_url_link($this->checkout->reg_url_link); |
|
892 | - // verify transaction |
|
893 | - if ($transaction instanceof EE_Transaction) { |
|
894 | - // and get the cart that was used for that transaction |
|
895 | - $this->checkout->cart = $this->_get_cart_for_transaction($transaction); |
|
896 | - return $transaction; |
|
897 | - } |
|
898 | - EE_Error::add_error( |
|
899 | - esc_html__('Your Registration and Transaction information could not be retrieved from the db.', 'event_espresso'), |
|
900 | - __FILE__, |
|
901 | - __FUNCTION__, |
|
902 | - __LINE__ |
|
903 | - ); |
|
904 | - return null; |
|
905 | - } |
|
906 | - |
|
907 | - |
|
908 | - /** |
|
909 | - * _get_cart_for_transaction |
|
910 | - * |
|
911 | - * @access private |
|
912 | - * @param EE_Transaction $transaction |
|
913 | - * @return EE_Cart |
|
914 | - */ |
|
915 | - private function _get_cart_for_transaction($transaction) |
|
916 | - { |
|
917 | - return $this->checkout->get_cart_for_transaction($transaction); |
|
918 | - } |
|
919 | - |
|
920 | - |
|
921 | - /** |
|
922 | - * get_cart_for_transaction |
|
923 | - * |
|
924 | - * @access public |
|
925 | - * @param EE_Transaction $transaction |
|
926 | - * @return EE_Cart |
|
927 | - */ |
|
928 | - public function get_cart_for_transaction(EE_Transaction $transaction) |
|
929 | - { |
|
930 | - return $this->checkout->get_cart_for_transaction($transaction); |
|
931 | - } |
|
932 | - |
|
933 | - |
|
934 | - /** |
|
935 | - * _get_transaction_and_cart_for_current_session |
|
936 | - * generates a new EE_Transaction object and adds it to the $_transaction property. |
|
937 | - * |
|
938 | - * @access private |
|
939 | - * @return EE_Transaction |
|
940 | - * @throws EE_Error |
|
941 | - */ |
|
942 | - private function _get_cart_for_current_session_and_setup_new_transaction() |
|
943 | - { |
|
944 | - // if there's no transaction, then this is the FIRST visit to SPCO |
|
945 | - // so load up the cart ( passing nothing for the TXN because it doesn't exist yet ) |
|
946 | - $this->checkout->cart = $this->_get_cart_for_transaction(null); |
|
947 | - // and then create a new transaction |
|
948 | - $transaction = $this->_initialize_transaction(); |
|
949 | - // verify transaction |
|
950 | - if ($transaction instanceof EE_Transaction) { |
|
951 | - // save it so that we have an ID for other objects to use |
|
952 | - $transaction->save(); |
|
953 | - // and save TXN data to the cart |
|
954 | - $this->checkout->cart->get_grand_total()->save_this_and_descendants_to_txn($transaction->ID()); |
|
955 | - } else { |
|
956 | - EE_Error::add_error( |
|
957 | - esc_html__('A Valid Transaction could not be initialized.', 'event_espresso'), |
|
958 | - __FILE__, |
|
959 | - __FUNCTION__, |
|
960 | - __LINE__ |
|
961 | - ); |
|
962 | - } |
|
963 | - return $transaction; |
|
964 | - } |
|
965 | - |
|
966 | - |
|
967 | - /** |
|
968 | - * generates a new EE_Transaction object and adds it to the $_transaction property. |
|
969 | - * |
|
970 | - * @access private |
|
971 | - * @return mixed EE_Transaction|NULL |
|
972 | - */ |
|
973 | - private function _initialize_transaction() |
|
974 | - { |
|
975 | - try { |
|
976 | - // ensure cart totals have been calculated |
|
977 | - $this->checkout->cart->get_grand_total()->recalculate_total_including_taxes(); |
|
978 | - // grab the cart grand total |
|
979 | - $cart_total = $this->checkout->cart->get_cart_grand_total(); |
|
980 | - // create new TXN |
|
981 | - $transaction = EE_Transaction::new_instance( |
|
982 | - array( |
|
983 | - 'TXN_reg_steps' => $this->checkout->initialize_txn_reg_steps_array(), |
|
984 | - 'TXN_total' => $cart_total > 0 ? $cart_total : 0, |
|
985 | - 'TXN_paid' => 0, |
|
986 | - 'STS_ID' => EEM_Transaction::failed_status_code, |
|
987 | - ) |
|
988 | - ); |
|
989 | - // save it so that we have an ID for other objects to use |
|
990 | - $transaction->save(); |
|
991 | - // set cron job for following up on TXNs after their session has expired |
|
992 | - EE_Cron_Tasks::schedule_expired_transaction_check( |
|
993 | - EE_Registry::instance()->SSN->expiration() + 1, |
|
994 | - $transaction->ID() |
|
995 | - ); |
|
996 | - return $transaction; |
|
997 | - } catch (Exception $e) { |
|
998 | - EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__); |
|
999 | - } |
|
1000 | - return null; |
|
1001 | - } |
|
1002 | - |
|
1003 | - |
|
1004 | - /** |
|
1005 | - * _get_registrations |
|
1006 | - * |
|
1007 | - * @access private |
|
1008 | - * @param EE_Transaction $transaction |
|
1009 | - * @return void |
|
1010 | - * @throws InvalidDataTypeException |
|
1011 | - * @throws InvalidEntityException |
|
1012 | - * @throws EE_Error |
|
1013 | - */ |
|
1014 | - private function _get_registrations(EE_Transaction $transaction) |
|
1015 | - { |
|
1016 | - // first step: grab the registrants { : o |
|
1017 | - $registrations = $transaction->registrations($this->checkout->reg_cache_where_params, false); |
|
1018 | - $this->checkout->total_ticket_count = count($registrations); |
|
1019 | - // verify registrations have been set |
|
1020 | - if (empty($registrations)) { |
|
1021 | - // if no cached registrations, then check the db |
|
1022 | - $registrations = $transaction->registrations($this->checkout->reg_cache_where_params, false); |
|
1023 | - // still nothing ? well as long as this isn't a revisit |
|
1024 | - if (empty($registrations) && ! $this->checkout->revisit) { |
|
1025 | - // generate new registrations from scratch |
|
1026 | - $registrations = $this->_initialize_registrations($transaction); |
|
1027 | - } |
|
1028 | - } |
|
1029 | - // sort by their original registration order |
|
1030 | - usort($registrations, array('EED_Single_Page_Checkout', 'sort_registrations_by_REG_count')); |
|
1031 | - // then loop thru the array |
|
1032 | - foreach ($registrations as $registration) { |
|
1033 | - // verify each registration |
|
1034 | - if ($registration instanceof EE_Registration) { |
|
1035 | - // we display all attendee info for the primary registrant |
|
1036 | - if ($this->checkout->reg_url_link === $registration->reg_url_link() |
|
1037 | - && $registration->is_primary_registrant() |
|
1038 | - ) { |
|
1039 | - $this->checkout->primary_revisit = true; |
|
1040 | - break; |
|
1041 | - } |
|
1042 | - if ($this->checkout->revisit && $this->checkout->reg_url_link !== $registration->reg_url_link()) { |
|
1043 | - // but hide info if it doesn't belong to you |
|
1044 | - $transaction->clear_cache('Registration', $registration->ID()); |
|
1045 | - $this->checkout->total_ticket_count--; |
|
1046 | - } |
|
1047 | - $this->checkout->set_reg_status_updated($registration->ID(), false); |
|
1048 | - } |
|
1049 | - } |
|
1050 | - } |
|
1051 | - |
|
1052 | - |
|
1053 | - /** |
|
1054 | - * adds related EE_Registration objects for each ticket in the cart to the current EE_Transaction object |
|
1055 | - * |
|
1056 | - * @access private |
|
1057 | - * @param EE_Transaction $transaction |
|
1058 | - * @return array |
|
1059 | - * @throws InvalidDataTypeException |
|
1060 | - * @throws InvalidEntityException |
|
1061 | - * @throws EE_Error |
|
1062 | - */ |
|
1063 | - private function _initialize_registrations(EE_Transaction $transaction) |
|
1064 | - { |
|
1065 | - $att_nmbr = 0; |
|
1066 | - $registrations = array(); |
|
1067 | - if ($transaction instanceof EE_Transaction) { |
|
1068 | - /** @type EE_Registration_Processor $registration_processor */ |
|
1069 | - $registration_processor = EE_Registry::instance()->load_class('Registration_Processor'); |
|
1070 | - $this->checkout->total_ticket_count = $this->checkout->cart->all_ticket_quantity_count(); |
|
1071 | - // now let's add the cart items to the $transaction |
|
1072 | - foreach ($this->checkout->cart->get_tickets() as $line_item) { |
|
1073 | - // do the following for each ticket of this type they selected |
|
1074 | - for ($x = 1; $x <= $line_item->quantity(); $x++) { |
|
1075 | - $att_nmbr++; |
|
1076 | - /** @var EventEspresso\core\services\commands\registration\CreateRegistrationCommand $CreateRegistrationCommand */ |
|
1077 | - $CreateRegistrationCommand = EE_Registry::instance()->create( |
|
1078 | - 'EventEspresso\core\services\commands\registration\CreateRegistrationCommand', |
|
1079 | - array( |
|
1080 | - $transaction, |
|
1081 | - $line_item, |
|
1082 | - $att_nmbr, |
|
1083 | - $this->checkout->total_ticket_count, |
|
1084 | - ) |
|
1085 | - ); |
|
1086 | - // override capabilities for frontend registrations |
|
1087 | - if (! is_admin()) { |
|
1088 | - $CreateRegistrationCommand->setCapCheck( |
|
1089 | - new PublicCapabilities('', 'create_new_registration') |
|
1090 | - ); |
|
1091 | - } |
|
1092 | - $registration = EE_Registry::instance()->BUS->execute($CreateRegistrationCommand); |
|
1093 | - if (! $registration instanceof EE_Registration) { |
|
1094 | - throw new InvalidEntityException($registration, 'EE_Registration'); |
|
1095 | - } |
|
1096 | - $registrations[ $registration->ID() ] = $registration; |
|
1097 | - } |
|
1098 | - } |
|
1099 | - $registration_processor->fix_reg_final_price_rounding_issue($transaction); |
|
1100 | - } |
|
1101 | - return $registrations; |
|
1102 | - } |
|
1103 | - |
|
1104 | - |
|
1105 | - /** |
|
1106 | - * sorts registrations by REG_count |
|
1107 | - * |
|
1108 | - * @access public |
|
1109 | - * @param EE_Registration $reg_A |
|
1110 | - * @param EE_Registration $reg_B |
|
1111 | - * @return int |
|
1112 | - */ |
|
1113 | - public static function sort_registrations_by_REG_count(EE_Registration $reg_A, EE_Registration $reg_B) |
|
1114 | - { |
|
1115 | - // this shouldn't ever happen within the same TXN, but oh well |
|
1116 | - if ($reg_A->count() === $reg_B->count()) { |
|
1117 | - return 0; |
|
1118 | - } |
|
1119 | - return ($reg_A->count() > $reg_B->count()) ? 1 : -1; |
|
1120 | - } |
|
1121 | - |
|
1122 | - |
|
1123 | - /** |
|
1124 | - * _final_verifications |
|
1125 | - * just makes sure that everything is set up correctly before proceeding |
|
1126 | - * |
|
1127 | - * @access private |
|
1128 | - * @return bool |
|
1129 | - * @throws EE_Error |
|
1130 | - */ |
|
1131 | - private function _final_verifications() |
|
1132 | - { |
|
1133 | - // filter checkout |
|
1134 | - $this->checkout = apply_filters( |
|
1135 | - 'FHEE__EED_Single_Page_Checkout___final_verifications__checkout', |
|
1136 | - $this->checkout |
|
1137 | - ); |
|
1138 | - // verify that current step is still set correctly |
|
1139 | - if (! $this->checkout->current_step instanceof EE_SPCO_Reg_Step) { |
|
1140 | - EE_Error::add_error( |
|
1141 | - esc_html__( |
|
1142 | - 'We\'re sorry but the registration process can not proceed because one or more registration steps were not setup correctly. Please refresh the page and try again or contact support.', |
|
1143 | - 'event_espresso' |
|
1144 | - ), |
|
1145 | - __FILE__, |
|
1146 | - __FUNCTION__, |
|
1147 | - __LINE__ |
|
1148 | - ); |
|
1149 | - return false; |
|
1150 | - } |
|
1151 | - // if returning to SPCO, then verify that primary registrant is set |
|
1152 | - if (! empty($this->checkout->reg_url_link)) { |
|
1153 | - $valid_registrant = $this->checkout->transaction->primary_registration(); |
|
1154 | - if (! $valid_registrant instanceof EE_Registration) { |
|
1155 | - EE_Error::add_error( |
|
1156 | - esc_html__( |
|
1157 | - 'We\'re sorry but there appears to be an error with the "reg_url_link" or the primary registrant for this transaction. Please refresh the page and try again or contact support.', |
|
1158 | - 'event_espresso' |
|
1159 | - ), |
|
1160 | - __FILE__, |
|
1161 | - __FUNCTION__, |
|
1162 | - __LINE__ |
|
1163 | - ); |
|
1164 | - return false; |
|
1165 | - } |
|
1166 | - $valid_registrant = null; |
|
1167 | - foreach ($this->checkout->transaction->registrations($this->checkout->reg_cache_where_params) as $registration) { |
|
1168 | - if ($registration instanceof EE_Registration |
|
1169 | - && $registration->reg_url_link() === $this->checkout->reg_url_link |
|
1170 | - ) { |
|
1171 | - $valid_registrant = $registration; |
|
1172 | - } |
|
1173 | - } |
|
1174 | - if (! $valid_registrant instanceof EE_Registration) { |
|
1175 | - // hmmm... maybe we have the wrong session because the user is opening multiple tabs ? |
|
1176 | - if (EED_Single_Page_Checkout::$_checkout_verified) { |
|
1177 | - // clear the session, mark the checkout as unverified, and try again |
|
1178 | - EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__); |
|
1179 | - EED_Single_Page_Checkout::$_initialized = false; |
|
1180 | - EED_Single_Page_Checkout::$_checkout_verified = false; |
|
1181 | - $this->_initialize(); |
|
1182 | - EE_Error::reset_notices(); |
|
1183 | - return false; |
|
1184 | - } |
|
1185 | - EE_Error::add_error( |
|
1186 | - esc_html__( |
|
1187 | - 'We\'re sorry but there appears to be an error with the "reg_url_link" or the transaction itself. Please refresh the page and try again or contact support.', |
|
1188 | - 'event_espresso' |
|
1189 | - ), |
|
1190 | - __FILE__, |
|
1191 | - __FUNCTION__, |
|
1192 | - __LINE__ |
|
1193 | - ); |
|
1194 | - return false; |
|
1195 | - } |
|
1196 | - } |
|
1197 | - // now that things have been kinda sufficiently verified, |
|
1198 | - // let's add the checkout to the session so that it's available to other systems |
|
1199 | - EE_Registry::instance()->SSN->set_checkout($this->checkout); |
|
1200 | - return true; |
|
1201 | - } |
|
1202 | - |
|
1203 | - |
|
1204 | - /** |
|
1205 | - * _initialize_reg_steps |
|
1206 | - * first makes sure that EE_Transaction_Processor::set_reg_step_initiated() is called as required |
|
1207 | - * then loops thru all of the active reg steps and calls the initialize_reg_step() method |
|
1208 | - * |
|
1209 | - * @access private |
|
1210 | - * @param bool $reinitializing |
|
1211 | - * @throws EE_Error |
|
1212 | - */ |
|
1213 | - private function _initialize_reg_steps($reinitializing = false) |
|
1214 | - { |
|
1215 | - $this->checkout->set_reg_step_initiated($this->checkout->current_step); |
|
1216 | - // loop thru all steps to call their individual "initialize" methods and set i18n strings for JS |
|
1217 | - foreach ($this->checkout->reg_steps as $reg_step) { |
|
1218 | - if (! $reg_step->initialize_reg_step()) { |
|
1219 | - // if not initialized then maybe this step is being removed... |
|
1220 | - if (! $reinitializing && $reg_step->is_current_step()) { |
|
1221 | - // if it was the current step, then we need to start over here |
|
1222 | - $this->_initialize_reg_steps(true); |
|
1223 | - return; |
|
1224 | - } |
|
1225 | - continue; |
|
1226 | - } |
|
1227 | - // add css and JS for current step |
|
1228 | - $this->add_styles_and_scripts($reg_step); |
|
1229 | - if ($reg_step->is_current_step()) { |
|
1230 | - // the text that appears on the reg step form submit button |
|
1231 | - $reg_step->set_submit_button_text(); |
|
1232 | - } |
|
1233 | - } |
|
1234 | - // dynamically creates hook point like: AHEE__Single_Page_Checkout___initialize_reg_step__attendee_information |
|
1235 | - do_action( |
|
1236 | - "AHEE__Single_Page_Checkout___initialize_reg_step__{$this->checkout->current_step->slug()}", |
|
1237 | - $this->checkout->current_step |
|
1238 | - ); |
|
1239 | - } |
|
1240 | - |
|
1241 | - |
|
1242 | - /** |
|
1243 | - * _check_form_submission |
|
1244 | - * |
|
1245 | - * @access private |
|
1246 | - * @return boolean |
|
1247 | - */ |
|
1248 | - private function _check_form_submission() |
|
1249 | - { |
|
1250 | - // does this request require the reg form to be generated ? |
|
1251 | - if ($this->checkout->generate_reg_form) { |
|
1252 | - // ever heard that song by Blue Rodeo ? |
|
1253 | - try { |
|
1254 | - $this->checkout->current_step->reg_form = $this->checkout->current_step->generate_reg_form(); |
|
1255 | - // if not displaying a form, then check for form submission |
|
1256 | - if ($this->checkout->process_form_submission |
|
1257 | - && $this->checkout->current_step->reg_form->was_submitted() |
|
1258 | - ) { |
|
1259 | - // clear out any old data in case this step is being run again |
|
1260 | - $this->checkout->current_step->set_valid_data(array()); |
|
1261 | - // capture submitted form data |
|
1262 | - $this->checkout->current_step->reg_form->receive_form_submission( |
|
1263 | - apply_filters( |
|
1264 | - 'FHEE__Single_Page_Checkout___check_form_submission__request_params', |
|
1265 | - EE_Registry::instance()->REQ->params(), |
|
1266 | - $this->checkout |
|
1267 | - ) |
|
1268 | - ); |
|
1269 | - // validate submitted form data |
|
1270 | - if (! $this->checkout->continue_reg || ! $this->checkout->current_step->reg_form->is_valid()) { |
|
1271 | - // thou shall not pass !!! |
|
1272 | - $this->checkout->continue_reg = false; |
|
1273 | - // any form validation errors? |
|
1274 | - if ($this->checkout->current_step->reg_form->submission_error_message() !== '') { |
|
1275 | - EE_Error::add_error( |
|
1276 | - $this->checkout->current_step->reg_form->submission_error_message(), |
|
1277 | - __FILE__, |
|
1278 | - __FUNCTION__, |
|
1279 | - __LINE__ |
|
1280 | - ); |
|
1281 | - } |
|
1282 | - // well not really... what will happen is |
|
1283 | - // we'll just get redirected back to redo the current step |
|
1284 | - $this->go_to_next_step(); |
|
1285 | - return false; |
|
1286 | - } |
|
1287 | - } |
|
1288 | - } catch (EE_Error $e) { |
|
1289 | - $e->get_error(); |
|
1290 | - } |
|
1291 | - } |
|
1292 | - return true; |
|
1293 | - } |
|
1294 | - |
|
1295 | - |
|
1296 | - /** |
|
1297 | - * _process_action |
|
1298 | - * |
|
1299 | - * @access private |
|
1300 | - * @return void |
|
1301 | - * @throws EE_Error |
|
1302 | - */ |
|
1303 | - private function _process_form_action() |
|
1304 | - { |
|
1305 | - // what cha wanna do? |
|
1306 | - switch ($this->checkout->action) { |
|
1307 | - // AJAX next step reg form |
|
1308 | - case 'display_spco_reg_step': |
|
1309 | - $this->checkout->redirect = false; |
|
1310 | - if (EE_Registry::instance()->REQ->ajax) { |
|
1311 | - $this->checkout->json_response->set_reg_step_html( |
|
1312 | - $this->checkout->current_step->display_reg_form() |
|
1313 | - ); |
|
1314 | - } |
|
1315 | - break; |
|
1316 | - default: |
|
1317 | - // meh... do one of those other steps first |
|
1318 | - if (! empty($this->checkout->action) |
|
1319 | - && is_callable(array($this->checkout->current_step, $this->checkout->action)) |
|
1320 | - ) { |
|
1321 | - // dynamically creates hook point like: |
|
1322 | - // AHEE__Single_Page_Checkout__before_attendee_information__process_reg_step |
|
1323 | - do_action( |
|
1324 | - "AHEE__Single_Page_Checkout__before_{$this->checkout->current_step->slug()}__{$this->checkout->action}", |
|
1325 | - $this->checkout->current_step |
|
1326 | - ); |
|
1327 | - $process_reg_step = apply_filters( |
|
1328 | - "AHEE__Single_Page_Checkout__process_reg_step__{$this->checkout->current_step->slug()}__{$this->checkout->action}", |
|
1329 | - true, |
|
1330 | - $this->checkout->current_step, |
|
1331 | - $this |
|
1332 | - ); |
|
1333 | - // call action on current step |
|
1334 | - if ($process_reg_step && call_user_func([$this->checkout->current_step, $this->checkout->action])) { |
|
1335 | - // good registrant, you get to proceed |
|
1336 | - if ($this->checkout->current_step->success_message() !== '' |
|
1337 | - && apply_filters( |
|
1338 | - 'FHEE__Single_Page_Checkout___process_form_action__display_success', |
|
1339 | - false |
|
1340 | - ) |
|
1341 | - ) { |
|
1342 | - EE_Error::add_success( |
|
1343 | - $this->checkout->current_step->success_message() |
|
1344 | - . '<br />' . $this->checkout->next_step->_instructions() |
|
1345 | - ); |
|
1346 | - } |
|
1347 | - // pack it up, pack it in... |
|
1348 | - $this->_setup_redirect(); |
|
1349 | - } |
|
1350 | - // dynamically creates hook point like: |
|
1351 | - // AHEE__Single_Page_Checkout__after_payment_options__process_reg_step |
|
1352 | - do_action( |
|
1353 | - "AHEE__Single_Page_Checkout__after_{$this->checkout->current_step->slug()}__{$this->checkout->action}", |
|
1354 | - $this->checkout->current_step |
|
1355 | - ); |
|
1356 | - } else { |
|
1357 | - EE_Error::add_error( |
|
1358 | - sprintf( |
|
1359 | - esc_html__( |
|
1360 | - 'The requested form action "%s" does not exist for the current "%s" registration step.', |
|
1361 | - 'event_espresso' |
|
1362 | - ), |
|
1363 | - $this->checkout->action, |
|
1364 | - $this->checkout->current_step->name() |
|
1365 | - ), |
|
1366 | - __FILE__, |
|
1367 | - __FUNCTION__, |
|
1368 | - __LINE__ |
|
1369 | - ); |
|
1370 | - } |
|
1371 | - // end default |
|
1372 | - } |
|
1373 | - // store our progress so far |
|
1374 | - $this->checkout->stash_transaction_and_checkout(); |
|
1375 | - // advance to the next step! If you pass GO, collect $200 |
|
1376 | - $this->go_to_next_step(); |
|
1377 | - } |
|
1378 | - |
|
1379 | - |
|
1380 | - /** |
|
1381 | - * @param EED_Single_Page_Checkout|EE_SPCO_Reg_Step $target |
|
1382 | - * @param object $target an object with the method `translate_js_strings` and `enqueue_styles_and_scripts`. |
|
1383 | - * @return void |
|
1384 | - */ |
|
1385 | - public function add_styles_and_scripts($target) |
|
1386 | - { |
|
1387 | - // i18n |
|
1388 | - $target->translate_js_strings(); |
|
1389 | - if ($this->checkout->admin_request) { |
|
1390 | - add_action('admin_enqueue_scripts', array($target, 'enqueue_styles_and_scripts'), 10); |
|
1391 | - } else { |
|
1392 | - add_action('wp_enqueue_scripts', array($target, 'enqueue_styles_and_scripts'), 10); |
|
1393 | - } |
|
1394 | - } |
|
1395 | - |
|
1396 | - /** |
|
1397 | - * translate_js_strings |
|
1398 | - * |
|
1399 | - * @access public |
|
1400 | - * @return void |
|
1401 | - */ |
|
1402 | - public function translate_js_strings() |
|
1403 | - { |
|
1404 | - EE_Registry::$i18n_js_strings['revisit'] = $this->checkout->revisit; |
|
1405 | - EE_Registry::$i18n_js_strings['e_reg_url_link'] = $this->checkout->reg_url_link; |
|
1406 | - EE_Registry::$i18n_js_strings['server_error'] = esc_html__( |
|
1407 | - 'An unknown error occurred on the server while attempting to process your request. Please refresh the page and try again or contact support.', |
|
1408 | - 'event_espresso' |
|
1409 | - ); |
|
1410 | - EE_Registry::$i18n_js_strings['invalid_json_response'] = esc_html__( |
|
1411 | - 'An invalid response was returned from the server while attempting to process your request. Please refresh the page and try again or contact support.', |
|
1412 | - 'event_espresso' |
|
1413 | - ); |
|
1414 | - EE_Registry::$i18n_js_strings['validation_error'] = esc_html__( |
|
1415 | - 'There appears to be a problem with the form validation configuration! Please check the admin settings or contact support.', |
|
1416 | - 'event_espresso' |
|
1417 | - ); |
|
1418 | - EE_Registry::$i18n_js_strings['invalid_payment_method'] = esc_html__( |
|
1419 | - 'There appears to be a problem with the payment method configuration! Please refresh the page and try again or contact support.', |
|
1420 | - 'event_espresso' |
|
1421 | - ); |
|
1422 | - EE_Registry::$i18n_js_strings['reg_step_error'] = esc_html__( |
|
1423 | - 'This registration step could not be completed. Please refresh the page and try again.', |
|
1424 | - 'event_espresso' |
|
1425 | - ); |
|
1426 | - EE_Registry::$i18n_js_strings['invalid_coupon'] = esc_html__( |
|
1427 | - 'We\'re sorry but that coupon code does not appear to be valid. If this is incorrect, please contact the site administrator.', |
|
1428 | - 'event_espresso' |
|
1429 | - ); |
|
1430 | - EE_Registry::$i18n_js_strings['process_registration'] = sprintf( |
|
1431 | - esc_html__( |
|
1432 | - 'Please wait while we process your registration.%sDo not refresh the page or navigate away while this is happening.%sThank you for your patience.', |
|
1433 | - 'event_espresso' |
|
1434 | - ), |
|
1435 | - '<br/>', |
|
1436 | - '<br/>' |
|
1437 | - ); |
|
1438 | - EE_Registry::$i18n_js_strings['language'] = get_bloginfo('language'); |
|
1439 | - EE_Registry::$i18n_js_strings['EESID'] = EE_Registry::instance()->SSN->id(); |
|
1440 | - EE_Registry::$i18n_js_strings['currency'] = EE_Registry::instance()->CFG->currency; |
|
1441 | - EE_Registry::$i18n_js_strings['datepicker_yearRange'] = '-150:+20'; |
|
1442 | - EE_Registry::$i18n_js_strings['timer_years'] = esc_html__('years', 'event_espresso'); |
|
1443 | - EE_Registry::$i18n_js_strings['timer_months'] = esc_html__('months', 'event_espresso'); |
|
1444 | - EE_Registry::$i18n_js_strings['timer_weeks'] = esc_html__('weeks', 'event_espresso'); |
|
1445 | - EE_Registry::$i18n_js_strings['timer_days'] = esc_html__('days', 'event_espresso'); |
|
1446 | - EE_Registry::$i18n_js_strings['timer_hours'] = esc_html__('hours', 'event_espresso'); |
|
1447 | - EE_Registry::$i18n_js_strings['timer_minutes'] = esc_html__('minutes', 'event_espresso'); |
|
1448 | - EE_Registry::$i18n_js_strings['timer_seconds'] = esc_html__('seconds', 'event_espresso'); |
|
1449 | - EE_Registry::$i18n_js_strings['timer_year'] = esc_html__('year', 'event_espresso'); |
|
1450 | - EE_Registry::$i18n_js_strings['timer_month'] = esc_html__('month', 'event_espresso'); |
|
1451 | - EE_Registry::$i18n_js_strings['timer_week'] = esc_html__('week', 'event_espresso'); |
|
1452 | - EE_Registry::$i18n_js_strings['timer_day'] = esc_html__('day', 'event_espresso'); |
|
1453 | - EE_Registry::$i18n_js_strings['timer_hour'] = esc_html__('hour', 'event_espresso'); |
|
1454 | - EE_Registry::$i18n_js_strings['timer_minute'] = esc_html__('minute', 'event_espresso'); |
|
1455 | - EE_Registry::$i18n_js_strings['timer_second'] = esc_html__('second', 'event_espresso'); |
|
1456 | - EE_Registry::$i18n_js_strings['registration_expiration_notice'] = EED_Single_Page_Checkout::getRegistrationExpirationNotice( |
|
1457 | - ); |
|
1458 | - EE_Registry::$i18n_js_strings['ajax_submit'] = apply_filters( |
|
1459 | - 'FHEE__Single_Page_Checkout__translate_js_strings__ajax_submit', |
|
1460 | - true |
|
1461 | - ); |
|
1462 | - EE_Registry::$i18n_js_strings['session_extension'] = absint( |
|
1463 | - apply_filters('FHEE__EE_Session__extend_expiration__seconds_added', 10 * MINUTE_IN_SECONDS) |
|
1464 | - ); |
|
1465 | - EE_Registry::$i18n_js_strings['session_expiration'] = gmdate( |
|
1466 | - 'M d, Y H:i:s', |
|
1467 | - EE_Registry::instance()->SSN->expiration() + (get_option('gmt_offset') * HOUR_IN_SECONDS) |
|
1468 | - ); |
|
1469 | - } |
|
1470 | - |
|
1471 | - |
|
1472 | - /** |
|
1473 | - * enqueue_styles_and_scripts |
|
1474 | - * |
|
1475 | - * @access public |
|
1476 | - * @return void |
|
1477 | - * @throws EE_Error |
|
1478 | - */ |
|
1479 | - public function enqueue_styles_and_scripts() |
|
1480 | - { |
|
1481 | - // load css |
|
1482 | - wp_register_style( |
|
1483 | - 'single_page_checkout', |
|
1484 | - SPCO_CSS_URL . 'single_page_checkout.css', |
|
1485 | - array('espresso_default'), |
|
1486 | - EVENT_ESPRESSO_VERSION |
|
1487 | - ); |
|
1488 | - wp_enqueue_style('single_page_checkout'); |
|
1489 | - // load JS |
|
1490 | - wp_register_script( |
|
1491 | - 'jquery_plugin', |
|
1492 | - EE_THIRD_PARTY_URL . 'jquery .plugin.min.js', |
|
1493 | - array('jquery'), |
|
1494 | - '1.0.1', |
|
1495 | - true |
|
1496 | - ); |
|
1497 | - wp_register_script( |
|
1498 | - 'jquery_countdown', |
|
1499 | - EE_THIRD_PARTY_URL . 'jquery .countdown.min.js', |
|
1500 | - array('jquery_plugin'), |
|
1501 | - '2.1.0', |
|
1502 | - true |
|
1503 | - ); |
|
1504 | - wp_register_script( |
|
1505 | - 'single_page_checkout', |
|
1506 | - SPCO_JS_URL . 'single_page_checkout.js', |
|
1507 | - array('espresso_core', 'underscore', 'ee_form_section_validation'), |
|
1508 | - EVENT_ESPRESSO_VERSION, |
|
1509 | - true |
|
1510 | - ); |
|
1511 | - if ($this->checkout->registration_form instanceof EE_Form_Section_Proper) { |
|
1512 | - $this->checkout->registration_form->enqueue_js(); |
|
1513 | - } |
|
1514 | - if ($this->checkout->current_step->reg_form instanceof EE_Form_Section_Proper) { |
|
1515 | - $this->checkout->current_step->reg_form->enqueue_js(); |
|
1516 | - } |
|
1517 | - wp_enqueue_script('single_page_checkout'); |
|
1518 | - if (apply_filters('FHEE__registration_page_wrapper_template__display_time_limit', false)) { |
|
1519 | - wp_enqueue_script('jquery_countdown'); |
|
1520 | - } |
|
1521 | - /** |
|
1522 | - * global action hook for enqueueing styles and scripts with |
|
1523 | - * spco calls. |
|
1524 | - */ |
|
1525 | - do_action('AHEE__EED_Single_Page_Checkout__enqueue_styles_and_scripts', $this); |
|
1526 | - /** |
|
1527 | - * dynamic action hook for enqueueing styles and scripts with spco calls. |
|
1528 | - * The hook will end up being something like: |
|
1529 | - * AHEE__EED_Single_Page_Checkout__enqueue_styles_and_scripts__attendee_information |
|
1530 | - */ |
|
1531 | - do_action( |
|
1532 | - 'AHEE__EED_Single_Page_Checkout__enqueue_styles_and_scripts__' . $this->checkout->current_step->slug(), |
|
1533 | - $this |
|
1534 | - ); |
|
1535 | - } |
|
1536 | - |
|
1537 | - |
|
1538 | - /** |
|
1539 | - * display the Registration Single Page Checkout Form |
|
1540 | - * |
|
1541 | - * @access private |
|
1542 | - * @return void |
|
1543 | - * @throws EE_Error |
|
1544 | - */ |
|
1545 | - private function _display_spco_reg_form() |
|
1546 | - { |
|
1547 | - // if registering via the admin, just display the reg form for the current step |
|
1548 | - if ($this->checkout->admin_request) { |
|
1549 | - EE_Registry::instance()->REQ->add_output($this->checkout->current_step->display_reg_form()); |
|
1550 | - } else { |
|
1551 | - // add powered by EE msg |
|
1552 | - add_action('AHEE__SPCO__reg_form_footer', array('EED_Single_Page_Checkout', 'display_registration_footer')); |
|
1553 | - $empty_cart = count($this->checkout->transaction |
|
1554 | - ->registrations($this->checkout->reg_cache_where_params)) < 1; |
|
1555 | - EE_Registry::$i18n_js_strings['empty_cart'] = $empty_cart; |
|
1556 | - $cookies_not_set_msg = ''; |
|
1557 | - if ($empty_cart) { |
|
1558 | - $cookies_not_set_msg = apply_filters( |
|
1559 | - 'FHEE__Single_Page_Checkout__display_spco_reg_form__cookies_not_set_msg', |
|
1560 | - sprintf( |
|
1561 | - esc_html__( |
|
1562 | - '%1$s%3$sIt appears your browser is not currently set to accept Cookies%4$s%5$sIn order to register for events, you need to enable cookies.%7$sIf you require assistance, then click the following link to learn how to %8$senable cookies%9$s%6$s%2$s', |
|
1563 | - 'event_espresso' |
|
1564 | - ), |
|
1565 | - '<div class="ee-attention hidden" id="ee-cookies-not-set-msg">', |
|
1566 | - '</div>', |
|
1567 | - '<h6 class="important-notice">', |
|
1568 | - '</h6>', |
|
1569 | - '<p>', |
|
1570 | - '</p>', |
|
1571 | - '<br />', |
|
1572 | - '<a href="http://www.whatarecookies.com/enable.asp" target="_blank" rel="noopener noreferrer">', |
|
1573 | - '</a>' |
|
1574 | - ) |
|
1575 | - ); |
|
1576 | - } |
|
1577 | - $this->checkout->registration_form = new EE_Form_Section_Proper( |
|
1578 | - array( |
|
1579 | - 'name' => 'single-page-checkout', |
|
1580 | - 'html_id' => 'ee-single-page-checkout-dv', |
|
1581 | - 'layout_strategy' => |
|
1582 | - new EE_Template_Layout( |
|
1583 | - array( |
|
1584 | - 'layout_template_file' => SPCO_TEMPLATES_PATH . 'registration_page_wrapper.template.php', |
|
1585 | - 'template_args' => array( |
|
1586 | - 'empty_cart' => $empty_cart, |
|
1587 | - 'revisit' => $this->checkout->revisit, |
|
1588 | - 'reg_steps' => $this->checkout->reg_steps, |
|
1589 | - 'next_step' => $this->checkout->next_step instanceof EE_SPCO_Reg_Step |
|
1590 | - ? $this->checkout->next_step->slug() |
|
1591 | - : '', |
|
1592 | - 'empty_msg' => apply_filters( |
|
1593 | - 'FHEE__Single_Page_Checkout__display_spco_reg_form__empty_msg', |
|
1594 | - sprintf( |
|
1595 | - esc_html__( |
|
1596 | - 'You need to %1$sReturn to Events list%2$sselect at least one event%3$s before you can proceed with the registration process.', |
|
1597 | - 'event_espresso' |
|
1598 | - ), |
|
1599 | - '<a href="' |
|
1600 | - . get_post_type_archive_link('espresso_events') |
|
1601 | - . '" title="', |
|
1602 | - '">', |
|
1603 | - '</a>' |
|
1604 | - ) |
|
1605 | - ), |
|
1606 | - 'cookies_not_set_msg' => $cookies_not_set_msg, |
|
1607 | - 'registration_time_limit' => $this->checkout->get_registration_time_limit(), |
|
1608 | - 'session_expiration' => gmdate( |
|
1609 | - 'M d, Y H:i:s', |
|
1610 | - EE_Registry::instance()->SSN->expiration() |
|
1611 | - + (get_option('gmt_offset') * HOUR_IN_SECONDS) |
|
1612 | - ), |
|
1613 | - ), |
|
1614 | - ) |
|
1615 | - ), |
|
1616 | - ) |
|
1617 | - ); |
|
1618 | - // load template and add to output sent that gets filtered into the_content() |
|
1619 | - EE_Registry::instance()->REQ->add_output($this->checkout->registration_form->get_html()); |
|
1620 | - } |
|
1621 | - } |
|
1622 | - |
|
1623 | - |
|
1624 | - /** |
|
1625 | - * add_extra_finalize_registration_inputs |
|
1626 | - * |
|
1627 | - * @access public |
|
1628 | - * @param $next_step |
|
1629 | - * @internal param string $label |
|
1630 | - * @return void |
|
1631 | - */ |
|
1632 | - public function add_extra_finalize_registration_inputs($next_step) |
|
1633 | - { |
|
1634 | - if ($next_step === 'finalize_registration') { |
|
1635 | - echo '<div id="spco-extra-finalize_registration-inputs-dv"></div>'; |
|
1636 | - } |
|
1637 | - } |
|
1638 | - |
|
1639 | - |
|
1640 | - /** |
|
1641 | - * display_registration_footer |
|
1642 | - * |
|
1643 | - * @access public |
|
1644 | - * @return string |
|
1645 | - */ |
|
1646 | - public static function display_registration_footer() |
|
1647 | - { |
|
1648 | - if (apply_filters( |
|
1649 | - 'FHEE__EE_Front__Controller__show_reg_footer', |
|
1650 | - EE_Registry::instance()->CFG->admin->show_reg_footer |
|
1651 | - )) { |
|
1652 | - add_filter( |
|
1653 | - 'FHEE__EEH_Template__powered_by_event_espresso__url', |
|
1654 | - function ($url) { |
|
1655 | - return apply_filters('FHEE__EE_Front_Controller__registration_footer__url', $url); |
|
1656 | - } |
|
1657 | - ); |
|
1658 | - echo apply_filters( |
|
1659 | - 'FHEE__EE_Front_Controller__display_registration_footer', |
|
1660 | - \EEH_Template::powered_by_event_espresso( |
|
1661 | - '', |
|
1662 | - 'espresso-registration-footer-dv', |
|
1663 | - array('utm_content' => 'registration_checkout') |
|
1664 | - ) |
|
1665 | - ); |
|
1666 | - } |
|
1667 | - return ''; |
|
1668 | - } |
|
1669 | - |
|
1670 | - |
|
1671 | - /** |
|
1672 | - * unlock_transaction |
|
1673 | - * |
|
1674 | - * @access public |
|
1675 | - * @return void |
|
1676 | - * @throws EE_Error |
|
1677 | - */ |
|
1678 | - public function unlock_transaction() |
|
1679 | - { |
|
1680 | - if ($this->checkout->transaction instanceof EE_Transaction) { |
|
1681 | - $this->checkout->transaction->unlock(); |
|
1682 | - } |
|
1683 | - } |
|
1684 | - |
|
1685 | - |
|
1686 | - /** |
|
1687 | - * _setup_redirect |
|
1688 | - * |
|
1689 | - * @access private |
|
1690 | - * @return void |
|
1691 | - */ |
|
1692 | - private function _setup_redirect() |
|
1693 | - { |
|
1694 | - if ($this->checkout->continue_reg && $this->checkout->next_step instanceof EE_SPCO_Reg_Step) { |
|
1695 | - $this->checkout->redirect = true; |
|
1696 | - if (empty($this->checkout->redirect_url)) { |
|
1697 | - $this->checkout->redirect_url = $this->checkout->next_step->reg_step_url(); |
|
1698 | - } |
|
1699 | - $this->checkout->redirect_url = apply_filters( |
|
1700 | - 'FHEE__EED_Single_Page_Checkout___setup_redirect__checkout_redirect_url', |
|
1701 | - $this->checkout->redirect_url, |
|
1702 | - $this->checkout |
|
1703 | - ); |
|
1704 | - } |
|
1705 | - } |
|
1706 | - |
|
1707 | - |
|
1708 | - /** |
|
1709 | - * handle ajax message responses and redirects |
|
1710 | - * |
|
1711 | - * @access public |
|
1712 | - * @return void |
|
1713 | - * @throws EE_Error |
|
1714 | - */ |
|
1715 | - public function go_to_next_step() |
|
1716 | - { |
|
1717 | - if (EE_Registry::instance()->REQ->ajax) { |
|
1718 | - // capture contents of output buffer we started earlier in the request, and insert into JSON response |
|
1719 | - $this->checkout->json_response->set_unexpected_errors(ob_get_clean()); |
|
1720 | - } |
|
1721 | - $this->unlock_transaction(); |
|
1722 | - // just return for these conditions |
|
1723 | - if ($this->checkout->admin_request |
|
1724 | - || $this->checkout->action === 'redirect_form' |
|
1725 | - || $this->checkout->action === 'update_checkout' |
|
1726 | - ) { |
|
1727 | - return; |
|
1728 | - } |
|
1729 | - // AJAX response |
|
1730 | - $this->_handle_json_response(); |
|
1731 | - // redirect to next step or the Thank You page |
|
1732 | - $this->_handle_html_redirects(); |
|
1733 | - // hmmm... must be something wrong, so let's just display the form again ! |
|
1734 | - $this->_display_spco_reg_form(); |
|
1735 | - } |
|
1736 | - |
|
1737 | - |
|
1738 | - /** |
|
1739 | - * _handle_json_response |
|
1740 | - * |
|
1741 | - * @access protected |
|
1742 | - * @return void |
|
1743 | - */ |
|
1744 | - protected function _handle_json_response() |
|
1745 | - { |
|
1746 | - // if this is an ajax request |
|
1747 | - if (EE_Registry::instance()->REQ->ajax) { |
|
1748 | - $this->checkout->json_response->set_registration_time_limit( |
|
1749 | - $this->checkout->get_registration_time_limit() |
|
1750 | - ); |
|
1751 | - $this->checkout->json_response->set_payment_amount($this->checkout->amount_owing); |
|
1752 | - // just send the ajax ( |
|
1753 | - $json_response = apply_filters( |
|
1754 | - 'FHEE__EE_Single_Page_Checkout__JSON_response', |
|
1755 | - $this->checkout->json_response |
|
1756 | - ); |
|
1757 | - echo $json_response; |
|
1758 | - exit(); |
|
1759 | - } |
|
1760 | - } |
|
1761 | - |
|
1762 | - |
|
1763 | - /** |
|
1764 | - * _handle_redirects |
|
1765 | - * |
|
1766 | - * @access protected |
|
1767 | - * @return void |
|
1768 | - */ |
|
1769 | - protected function _handle_html_redirects() |
|
1770 | - { |
|
1771 | - // going somewhere ? |
|
1772 | - if ($this->checkout->redirect && ! empty($this->checkout->redirect_url)) { |
|
1773 | - // store notices in a transient |
|
1774 | - EE_Error::get_notices(false, true, true); |
|
1775 | - wp_safe_redirect($this->checkout->redirect_url); |
|
1776 | - exit(); |
|
1777 | - } |
|
1778 | - } |
|
1779 | - |
|
1780 | - |
|
1781 | - /** |
|
1782 | - * set_checkout_anchor |
|
1783 | - * |
|
1784 | - * @access public |
|
1785 | - * @return void |
|
1786 | - */ |
|
1787 | - public function set_checkout_anchor() |
|
1788 | - { |
|
1789 | - echo '<a id="checkout" style="float: left; margin-left: -999em;"></a>'; |
|
1790 | - } |
|
1791 | - |
|
1792 | - /** |
|
1793 | - * getRegistrationExpirationNotice |
|
1794 | - * |
|
1795 | - * @since 4.9.59.p |
|
1796 | - * @access public |
|
1797 | - * @return string |
|
1798 | - */ |
|
1799 | - public static function getRegistrationExpirationNotice() |
|
1800 | - { |
|
1801 | - return sprintf( |
|
1802 | - esc_html__( |
|
1803 | - '%1$sWe\'re sorry, but your registration time has expired.%2$s%3$s%4$sIf you still wish to complete your registration, please return to the %5$sEvent List%6$sEvent List%7$s and reselect your tickets if available. Please accept our apologies for any inconvenience this may have caused.%8$s', |
|
1804 | - 'event_espresso' |
|
1805 | - ), |
|
1806 | - '<h4 class="important-notice">', |
|
1807 | - '</h4>', |
|
1808 | - '<br />', |
|
1809 | - '<p>', |
|
1810 | - '<a href="' . get_post_type_archive_link('espresso_events') . '" title="', |
|
1811 | - '">', |
|
1812 | - '</a>', |
|
1813 | - '</p>' |
|
1814 | - ); |
|
1815 | - } |
|
18 | + /** |
|
19 | + * $_initialized - has the SPCO controller already been initialized ? |
|
20 | + * |
|
21 | + * @access private |
|
22 | + * @var bool $_initialized |
|
23 | + */ |
|
24 | + private static $_initialized = false; |
|
25 | + |
|
26 | + |
|
27 | + /** |
|
28 | + * $_checkout_verified - is the EE_Checkout verified as correct for this request ? |
|
29 | + * |
|
30 | + * @access private |
|
31 | + * @var bool $_valid_checkout |
|
32 | + */ |
|
33 | + private static $_checkout_verified = true; |
|
34 | + |
|
35 | + /** |
|
36 | + * $_reg_steps_array - holds initial array of reg steps |
|
37 | + * |
|
38 | + * @access private |
|
39 | + * @var array $_reg_steps_array |
|
40 | + */ |
|
41 | + private static $_reg_steps_array = array(); |
|
42 | + |
|
43 | + /** |
|
44 | + * $checkout - EE_Checkout object for handling the properties of the current checkout process |
|
45 | + * |
|
46 | + * @access public |
|
47 | + * @var EE_Checkout $checkout |
|
48 | + */ |
|
49 | + public $checkout; |
|
50 | + |
|
51 | + |
|
52 | + /** |
|
53 | + * @return EED_Module|EED_Single_Page_Checkout |
|
54 | + */ |
|
55 | + public static function instance() |
|
56 | + { |
|
57 | + add_filter('EED_Single_Page_Checkout__SPCO_active', '__return_true'); |
|
58 | + return parent::get_instance(__CLASS__); |
|
59 | + } |
|
60 | + |
|
61 | + |
|
62 | + /** |
|
63 | + * @return EE_CART |
|
64 | + */ |
|
65 | + public function cart() |
|
66 | + { |
|
67 | + return $this->checkout->cart; |
|
68 | + } |
|
69 | + |
|
70 | + |
|
71 | + /** |
|
72 | + * @return EE_Transaction |
|
73 | + */ |
|
74 | + public function transaction() |
|
75 | + { |
|
76 | + return $this->checkout->transaction; |
|
77 | + } |
|
78 | + |
|
79 | + |
|
80 | + /** |
|
81 | + * set_hooks - for hooking into EE Core, other modules, etc |
|
82 | + * |
|
83 | + * @access public |
|
84 | + * @return void |
|
85 | + * @throws EE_Error |
|
86 | + */ |
|
87 | + public static function set_hooks() |
|
88 | + { |
|
89 | + EED_Single_Page_Checkout::set_definitions(); |
|
90 | + } |
|
91 | + |
|
92 | + |
|
93 | + /** |
|
94 | + * set_hooks_admin - for hooking into EE Admin Core, other modules, etc |
|
95 | + * |
|
96 | + * @access public |
|
97 | + * @return void |
|
98 | + * @throws EE_Error |
|
99 | + */ |
|
100 | + public static function set_hooks_admin() |
|
101 | + { |
|
102 | + EED_Single_Page_Checkout::set_definitions(); |
|
103 | + if (! (defined('DOING_AJAX') && DOING_AJAX)) { |
|
104 | + return; |
|
105 | + } |
|
106 | + // going to start an output buffer in case anything gets accidentally output |
|
107 | + // that might disrupt our JSON response |
|
108 | + ob_start(); |
|
109 | + EED_Single_Page_Checkout::load_request_handler(); |
|
110 | + EED_Single_Page_Checkout::load_reg_steps(); |
|
111 | + // set ajax hooks |
|
112 | + add_action('wp_ajax_process_reg_step', array('EED_Single_Page_Checkout', 'process_reg_step')); |
|
113 | + add_action('wp_ajax_nopriv_process_reg_step', array('EED_Single_Page_Checkout', 'process_reg_step')); |
|
114 | + add_action('wp_ajax_display_spco_reg_step', array('EED_Single_Page_Checkout', 'display_reg_step')); |
|
115 | + add_action('wp_ajax_nopriv_display_spco_reg_step', array('EED_Single_Page_Checkout', 'display_reg_step')); |
|
116 | + add_action('wp_ajax_update_reg_step', array('EED_Single_Page_Checkout', 'update_reg_step')); |
|
117 | + add_action('wp_ajax_nopriv_update_reg_step', array('EED_Single_Page_Checkout', 'update_reg_step')); |
|
118 | + } |
|
119 | + |
|
120 | + |
|
121 | + /** |
|
122 | + * process ajax request |
|
123 | + * |
|
124 | + * @param string $ajax_action |
|
125 | + * @throws EE_Error |
|
126 | + */ |
|
127 | + public static function process_ajax_request($ajax_action) |
|
128 | + { |
|
129 | + EE_Registry::instance()->REQ->set('action', $ajax_action); |
|
130 | + EED_Single_Page_Checkout::instance()->_initialize(); |
|
131 | + } |
|
132 | + |
|
133 | + |
|
134 | + /** |
|
135 | + * ajax display registration step |
|
136 | + * |
|
137 | + * @throws EE_Error |
|
138 | + */ |
|
139 | + public static function display_reg_step() |
|
140 | + { |
|
141 | + EED_Single_Page_Checkout::process_ajax_request('display_spco_reg_step'); |
|
142 | + } |
|
143 | + |
|
144 | + |
|
145 | + /** |
|
146 | + * ajax process registration step |
|
147 | + * |
|
148 | + * @throws EE_Error |
|
149 | + */ |
|
150 | + public static function process_reg_step() |
|
151 | + { |
|
152 | + EED_Single_Page_Checkout::process_ajax_request('process_reg_step'); |
|
153 | + } |
|
154 | + |
|
155 | + |
|
156 | + /** |
|
157 | + * ajax process registration step |
|
158 | + * |
|
159 | + * @throws EE_Error |
|
160 | + */ |
|
161 | + public static function update_reg_step() |
|
162 | + { |
|
163 | + EED_Single_Page_Checkout::process_ajax_request('update_reg_step'); |
|
164 | + } |
|
165 | + |
|
166 | + |
|
167 | + /** |
|
168 | + * update_checkout |
|
169 | + * |
|
170 | + * @access public |
|
171 | + * @return void |
|
172 | + * @throws EE_Error |
|
173 | + */ |
|
174 | + public static function update_checkout() |
|
175 | + { |
|
176 | + EED_Single_Page_Checkout::process_ajax_request('update_checkout'); |
|
177 | + } |
|
178 | + |
|
179 | + |
|
180 | + /** |
|
181 | + * load_request_handler |
|
182 | + * |
|
183 | + * @access public |
|
184 | + * @return void |
|
185 | + */ |
|
186 | + public static function load_request_handler() |
|
187 | + { |
|
188 | + // load core Request_Handler class |
|
189 | + if (EE_Registry::instance()->REQ !== null) { |
|
190 | + EE_Registry::instance()->load_core('Request_Handler'); |
|
191 | + } |
|
192 | + } |
|
193 | + |
|
194 | + |
|
195 | + /** |
|
196 | + * set_definitions |
|
197 | + * |
|
198 | + * @access public |
|
199 | + * @return void |
|
200 | + * @throws EE_Error |
|
201 | + */ |
|
202 | + public static function set_definitions() |
|
203 | + { |
|
204 | + if (defined('SPCO_BASE_PATH')) { |
|
205 | + return; |
|
206 | + } |
|
207 | + define( |
|
208 | + 'SPCO_BASE_PATH', |
|
209 | + rtrim(str_replace(array('\\', '/'), '/', plugin_dir_path(__FILE__)), '/') . '/' |
|
210 | + ); |
|
211 | + define('SPCO_CSS_URL', plugin_dir_url(__FILE__) . 'css/'); |
|
212 | + define('SPCO_IMG_URL', plugin_dir_url(__FILE__) . 'img/'); |
|
213 | + define('SPCO_JS_URL', plugin_dir_url(__FILE__) . 'js/'); |
|
214 | + define('SPCO_INC_PATH', SPCO_BASE_PATH . 'inc/'); |
|
215 | + define('SPCO_REG_STEPS_PATH', SPCO_BASE_PATH . 'reg_steps/'); |
|
216 | + define('SPCO_TEMPLATES_PATH', SPCO_BASE_PATH . 'templates/'); |
|
217 | + EEH_Autoloader::register_autoloaders_for_each_file_in_folder(SPCO_BASE_PATH, true); |
|
218 | + EE_Registry::$i18n_js_strings['registration_expiration_notice'] = EED_Single_Page_Checkout::getRegistrationExpirationNotice( |
|
219 | + ); |
|
220 | + } |
|
221 | + |
|
222 | + |
|
223 | + /** |
|
224 | + * load_reg_steps |
|
225 | + * loads and instantiates each reg step based on the EE_Registry::instance()->CFG->registration->reg_steps array |
|
226 | + * |
|
227 | + * @access private |
|
228 | + * @throws EE_Error |
|
229 | + */ |
|
230 | + public static function load_reg_steps() |
|
231 | + { |
|
232 | + static $reg_steps_loaded = false; |
|
233 | + if ($reg_steps_loaded) { |
|
234 | + return; |
|
235 | + } |
|
236 | + // filter list of reg_steps |
|
237 | + $reg_steps_to_load = (array) apply_filters( |
|
238 | + 'AHEE__SPCO__load_reg_steps__reg_steps_to_load', |
|
239 | + EED_Single_Page_Checkout::get_reg_steps() |
|
240 | + ); |
|
241 | + // sort by key (order) |
|
242 | + ksort($reg_steps_to_load); |
|
243 | + // loop through folders |
|
244 | + foreach ($reg_steps_to_load as $order => $reg_step) { |
|
245 | + // we need a |
|
246 | + if (isset($reg_step['file_path'], $reg_step['class_name'], $reg_step['slug'])) { |
|
247 | + // copy over to the reg_steps_array |
|
248 | + EED_Single_Page_Checkout::$_reg_steps_array[ $order ] = $reg_step; |
|
249 | + // register custom key route for each reg step |
|
250 | + // ie: step=>"slug" - this is the entire reason we load the reg steps array now |
|
251 | + EE_Config::register_route( |
|
252 | + $reg_step['slug'], |
|
253 | + 'EED_Single_Page_Checkout', |
|
254 | + 'run', |
|
255 | + 'step' |
|
256 | + ); |
|
257 | + // add AJAX or other hooks |
|
258 | + if (isset($reg_step['has_hooks']) && $reg_step['has_hooks']) { |
|
259 | + // setup autoloaders if necessary |
|
260 | + if (! class_exists($reg_step['class_name'])) { |
|
261 | + EEH_Autoloader::register_autoloaders_for_each_file_in_folder( |
|
262 | + $reg_step['file_path'], |
|
263 | + true |
|
264 | + ); |
|
265 | + } |
|
266 | + if (is_callable($reg_step['class_name'], 'set_hooks')) { |
|
267 | + call_user_func(array($reg_step['class_name'], 'set_hooks')); |
|
268 | + } |
|
269 | + } |
|
270 | + } |
|
271 | + } |
|
272 | + $reg_steps_loaded = true; |
|
273 | + } |
|
274 | + |
|
275 | + |
|
276 | + /** |
|
277 | + * get_reg_steps |
|
278 | + * |
|
279 | + * @access public |
|
280 | + * @return array |
|
281 | + */ |
|
282 | + public static function get_reg_steps() |
|
283 | + { |
|
284 | + $reg_steps = EE_Registry::instance()->CFG->registration->reg_steps; |
|
285 | + if (empty($reg_steps)) { |
|
286 | + $reg_steps = array( |
|
287 | + 10 => array( |
|
288 | + 'file_path' => SPCO_REG_STEPS_PATH . 'attendee_information', |
|
289 | + 'class_name' => 'EE_SPCO_Reg_Step_Attendee_Information', |
|
290 | + 'slug' => 'attendee_information', |
|
291 | + 'has_hooks' => false, |
|
292 | + ), |
|
293 | + 30 => array( |
|
294 | + 'file_path' => SPCO_REG_STEPS_PATH . 'payment_options', |
|
295 | + 'class_name' => 'EE_SPCO_Reg_Step_Payment_Options', |
|
296 | + 'slug' => 'payment_options', |
|
297 | + 'has_hooks' => true, |
|
298 | + ), |
|
299 | + 999 => array( |
|
300 | + 'file_path' => SPCO_REG_STEPS_PATH . 'finalize_registration', |
|
301 | + 'class_name' => 'EE_SPCO_Reg_Step_Finalize_Registration', |
|
302 | + 'slug' => 'finalize_registration', |
|
303 | + 'has_hooks' => false, |
|
304 | + ), |
|
305 | + ); |
|
306 | + } |
|
307 | + return $reg_steps; |
|
308 | + } |
|
309 | + |
|
310 | + |
|
311 | + /** |
|
312 | + * registration_checkout_for_admin |
|
313 | + * |
|
314 | + * @access public |
|
315 | + * @return string |
|
316 | + * @throws EE_Error |
|
317 | + */ |
|
318 | + public static function registration_checkout_for_admin() |
|
319 | + { |
|
320 | + EED_Single_Page_Checkout::load_request_handler(); |
|
321 | + EE_Registry::instance()->REQ->set('step', 'attendee_information'); |
|
322 | + EE_Registry::instance()->REQ->set('action', 'display_spco_reg_step'); |
|
323 | + EE_Registry::instance()->REQ->set('process_form_submission', false); |
|
324 | + EED_Single_Page_Checkout::instance()->_initialize(); |
|
325 | + EED_Single_Page_Checkout::instance()->_display_spco_reg_form(); |
|
326 | + return EE_Registry::instance()->REQ->get_output(); |
|
327 | + } |
|
328 | + |
|
329 | + |
|
330 | + /** |
|
331 | + * process_registration_from_admin |
|
332 | + * |
|
333 | + * @access public |
|
334 | + * @return \EE_Transaction |
|
335 | + * @throws EE_Error |
|
336 | + */ |
|
337 | + public static function process_registration_from_admin() |
|
338 | + { |
|
339 | + EED_Single_Page_Checkout::load_request_handler(); |
|
340 | + EE_Registry::instance()->REQ->set('step', 'attendee_information'); |
|
341 | + EE_Registry::instance()->REQ->set('action', 'process_reg_step'); |
|
342 | + EE_Registry::instance()->REQ->set('process_form_submission', true); |
|
343 | + EED_Single_Page_Checkout::instance()->_initialize(); |
|
344 | + if (EED_Single_Page_Checkout::instance()->checkout->current_step->completed()) { |
|
345 | + $final_reg_step = end(EED_Single_Page_Checkout::instance()->checkout->reg_steps); |
|
346 | + if ($final_reg_step instanceof EE_SPCO_Reg_Step_Finalize_Registration) { |
|
347 | + EED_Single_Page_Checkout::instance()->checkout->set_reg_step_initiated($final_reg_step); |
|
348 | + if ($final_reg_step->process_reg_step()) { |
|
349 | + $final_reg_step->set_completed(); |
|
350 | + EED_Single_Page_Checkout::instance()->checkout->update_txn_reg_steps_array(); |
|
351 | + return EED_Single_Page_Checkout::instance()->checkout->transaction; |
|
352 | + } |
|
353 | + } |
|
354 | + } |
|
355 | + return null; |
|
356 | + } |
|
357 | + |
|
358 | + |
|
359 | + /** |
|
360 | + * run |
|
361 | + * |
|
362 | + * @access public |
|
363 | + * @param WP_Query $WP_Query |
|
364 | + * @return void |
|
365 | + * @throws EE_Error |
|
366 | + */ |
|
367 | + public function run($WP_Query) |
|
368 | + { |
|
369 | + if ($WP_Query instanceof WP_Query |
|
370 | + && $WP_Query->is_main_query() |
|
371 | + && apply_filters('FHEE__EED_Single_Page_Checkout__run', true) |
|
372 | + && $this->_is_reg_checkout() |
|
373 | + ) { |
|
374 | + $this->_initialize(); |
|
375 | + } |
|
376 | + } |
|
377 | + |
|
378 | + |
|
379 | + /** |
|
380 | + * determines whether current url matches reg page url |
|
381 | + * |
|
382 | + * @return bool |
|
383 | + */ |
|
384 | + protected function _is_reg_checkout() |
|
385 | + { |
|
386 | + // get current permalink for reg page without any extra query args |
|
387 | + $reg_page_url = \get_permalink(EE_Config::instance()->core->reg_page_id); |
|
388 | + // get request URI for current request, but without the scheme or host |
|
389 | + $current_request_uri = \EEH_URL::filter_input_server_url('REQUEST_URI'); |
|
390 | + $current_request_uri = html_entity_decode($current_request_uri); |
|
391 | + // get array of query args from the current request URI |
|
392 | + $query_args = \EEH_URL::get_query_string($current_request_uri); |
|
393 | + // grab page id if it is set |
|
394 | + $page_id = isset($query_args['page_id']) ? absint($query_args['page_id']) : 0; |
|
395 | + // and remove the page id from the query args (we will re-add it later) |
|
396 | + unset($query_args['page_id']); |
|
397 | + // now strip all query args from current request URI |
|
398 | + $current_request_uri = remove_query_arg(array_keys($query_args), $current_request_uri); |
|
399 | + // and re-add the page id if it was set |
|
400 | + if ($page_id) { |
|
401 | + $current_request_uri = add_query_arg('page_id', $page_id, $current_request_uri); |
|
402 | + } |
|
403 | + // remove slashes and ? |
|
404 | + $current_request_uri = trim($current_request_uri, '?/'); |
|
405 | + // is current request URI part of the known full reg page URL ? |
|
406 | + return ! empty($current_request_uri) && strpos($reg_page_url, $current_request_uri) !== false; |
|
407 | + } |
|
408 | + |
|
409 | + |
|
410 | + /** |
|
411 | + * @param WP_Query $wp_query |
|
412 | + * @return void |
|
413 | + * @throws EE_Error |
|
414 | + */ |
|
415 | + public static function init($wp_query) |
|
416 | + { |
|
417 | + EED_Single_Page_Checkout::instance()->run($wp_query); |
|
418 | + } |
|
419 | + |
|
420 | + |
|
421 | + /** |
|
422 | + * _initialize - initial module setup |
|
423 | + * |
|
424 | + * @access private |
|
425 | + * @throws EE_Error |
|
426 | + * @return void |
|
427 | + */ |
|
428 | + private function _initialize() |
|
429 | + { |
|
430 | + // ensure SPCO doesn't run twice |
|
431 | + if (EED_Single_Page_Checkout::$_initialized) { |
|
432 | + return; |
|
433 | + } |
|
434 | + try { |
|
435 | + EED_Single_Page_Checkout::load_reg_steps(); |
|
436 | + $this->_verify_session(); |
|
437 | + // setup the EE_Checkout object |
|
438 | + $this->checkout = $this->_initialize_checkout(); |
|
439 | + // filter checkout |
|
440 | + $this->checkout = apply_filters('FHEE__EED_Single_Page_Checkout___initialize__checkout', $this->checkout); |
|
441 | + // get the $_GET |
|
442 | + $this->_get_request_vars(); |
|
443 | + if ($this->_block_bots()) { |
|
444 | + return; |
|
445 | + } |
|
446 | + // filter continue_reg |
|
447 | + $this->checkout->continue_reg = apply_filters( |
|
448 | + 'FHEE__EED_Single_Page_Checkout__init___continue_reg', |
|
449 | + true, |
|
450 | + $this->checkout |
|
451 | + ); |
|
452 | + // load the reg steps array |
|
453 | + if (! $this->_load_and_instantiate_reg_steps()) { |
|
454 | + EED_Single_Page_Checkout::$_initialized = true; |
|
455 | + return; |
|
456 | + } |
|
457 | + // set the current step |
|
458 | + $this->checkout->set_current_step($this->checkout->step); |
|
459 | + // and the next step |
|
460 | + $this->checkout->set_next_step(); |
|
461 | + // verify that everything has been setup correctly |
|
462 | + if (! ($this->_verify_transaction_and_get_registrations() && $this->_final_verifications())) { |
|
463 | + EED_Single_Page_Checkout::$_initialized = true; |
|
464 | + return; |
|
465 | + } |
|
466 | + // lock the transaction |
|
467 | + $this->checkout->transaction->lock(); |
|
468 | + // make sure all of our cached objects are added to their respective model entity mappers |
|
469 | + $this->checkout->refresh_all_entities(); |
|
470 | + // set amount owing |
|
471 | + $this->checkout->amount_owing = $this->checkout->transaction->remaining(); |
|
472 | + // initialize each reg step, which gives them the chance to potentially alter the process |
|
473 | + $this->_initialize_reg_steps(); |
|
474 | + // DEBUG LOG |
|
475 | + // $this->checkout->log( __CLASS__, __FUNCTION__, __LINE__ ); |
|
476 | + // get reg form |
|
477 | + if (! $this->_check_form_submission()) { |
|
478 | + EED_Single_Page_Checkout::$_initialized = true; |
|
479 | + return; |
|
480 | + } |
|
481 | + // checkout the action!!! |
|
482 | + $this->_process_form_action(); |
|
483 | + // add some style and make it dance |
|
484 | + $this->add_styles_and_scripts($this); |
|
485 | + // kk... SPCO has successfully run |
|
486 | + EED_Single_Page_Checkout::$_initialized = true; |
|
487 | + // set no cache headers and constants |
|
488 | + EE_System::do_not_cache(); |
|
489 | + // add anchor |
|
490 | + add_action('loop_start', array($this, 'set_checkout_anchor'), 1); |
|
491 | + // remove transaction lock |
|
492 | + add_action('shutdown', array($this, 'unlock_transaction'), 1); |
|
493 | + } catch (Exception $e) { |
|
494 | + EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__); |
|
495 | + } |
|
496 | + } |
|
497 | + |
|
498 | + |
|
499 | + /** |
|
500 | + * _verify_session |
|
501 | + * checks that the session is valid and not expired |
|
502 | + * |
|
503 | + * @access private |
|
504 | + * @throws EE_Error |
|
505 | + */ |
|
506 | + private function _verify_session() |
|
507 | + { |
|
508 | + if (! EE_Registry::instance()->SSN instanceof EE_Session) { |
|
509 | + throw new EE_Error(esc_html__('The EE_Session class could not be loaded.', 'event_espresso')); |
|
510 | + } |
|
511 | + $clear_session_requested = filter_var( |
|
512 | + EE_Registry::instance()->REQ->get('clear_session', false), |
|
513 | + FILTER_VALIDATE_BOOLEAN |
|
514 | + ); |
|
515 | + // is session still valid ? |
|
516 | + if ($clear_session_requested |
|
517 | + || (EE_Registry::instance()->SSN->expired() |
|
518 | + && EE_Registry::instance()->REQ->get('e_reg_url_link', '') === '' |
|
519 | + ) |
|
520 | + ) { |
|
521 | + $this->checkout = new EE_Checkout(); |
|
522 | + EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__); |
|
523 | + // EE_Registry::instance()->SSN->reset_cart(); |
|
524 | + // EE_Registry::instance()->SSN->reset_checkout(); |
|
525 | + // EE_Registry::instance()->SSN->reset_transaction(); |
|
526 | + if (! $clear_session_requested) { |
|
527 | + EE_Error::add_attention( |
|
528 | + EE_Registry::$i18n_js_strings['registration_expiration_notice'], |
|
529 | + __FILE__, |
|
530 | + __FUNCTION__, |
|
531 | + __LINE__ |
|
532 | + ); |
|
533 | + } |
|
534 | + // EE_Registry::instance()->SSN->reset_expired(); |
|
535 | + } |
|
536 | + } |
|
537 | + |
|
538 | + |
|
539 | + /** |
|
540 | + * _initialize_checkout |
|
541 | + * loads and instantiates EE_Checkout |
|
542 | + * |
|
543 | + * @access private |
|
544 | + * @throws EE_Error |
|
545 | + * @return EE_Checkout |
|
546 | + */ |
|
547 | + private function _initialize_checkout() |
|
548 | + { |
|
549 | + // look in session for existing checkout |
|
550 | + /** @type EE_Checkout $checkout */ |
|
551 | + $checkout = EE_Registry::instance()->SSN->checkout(); |
|
552 | + // verify |
|
553 | + if (! $checkout instanceof EE_Checkout) { |
|
554 | + // instantiate EE_Checkout object for handling the properties of the current checkout process |
|
555 | + $checkout = EE_Registry::instance()->load_file( |
|
556 | + SPCO_INC_PATH, |
|
557 | + 'EE_Checkout', |
|
558 | + 'class', |
|
559 | + array(), |
|
560 | + false |
|
561 | + ); |
|
562 | + } else { |
|
563 | + if ($checkout->current_step->is_final_step() && $checkout->exit_spco() === true) { |
|
564 | + $this->unlock_transaction(); |
|
565 | + wp_safe_redirect($checkout->redirect_url); |
|
566 | + exit(); |
|
567 | + } |
|
568 | + } |
|
569 | + $checkout = apply_filters('FHEE__EED_Single_Page_Checkout___initialize_checkout__checkout', $checkout); |
|
570 | + // verify again |
|
571 | + if (! $checkout instanceof EE_Checkout) { |
|
572 | + throw new EE_Error(esc_html__('The EE_Checkout class could not be loaded.', 'event_espresso')); |
|
573 | + } |
|
574 | + // reset anything that needs a clean slate for each request |
|
575 | + $checkout->reset_for_current_request(); |
|
576 | + return $checkout; |
|
577 | + } |
|
578 | + |
|
579 | + |
|
580 | + /** |
|
581 | + * _get_request_vars |
|
582 | + * |
|
583 | + * @access private |
|
584 | + * @return void |
|
585 | + * @throws EE_Error |
|
586 | + */ |
|
587 | + private function _get_request_vars() |
|
588 | + { |
|
589 | + // load classes |
|
590 | + EED_Single_Page_Checkout::load_request_handler(); |
|
591 | + // make sure this request is marked as belonging to EE |
|
592 | + EE_Registry::instance()->REQ->set_espresso_page(true); |
|
593 | + // which step is being requested ? |
|
594 | + $this->checkout->step = EE_Registry::instance()->REQ->get('step', $this->_get_first_step()); |
|
595 | + // which step is being edited ? |
|
596 | + $this->checkout->edit_step = EE_Registry::instance()->REQ->get('edit_step', ''); |
|
597 | + // and what we're doing on the current step |
|
598 | + $this->checkout->action = EE_Registry::instance()->REQ->get('action', 'display_spco_reg_step'); |
|
599 | + // timestamp |
|
600 | + $this->checkout->uts = EE_Registry::instance()->REQ->get('uts', 0); |
|
601 | + // returning to edit ? |
|
602 | + $this->checkout->reg_url_link = EE_Registry::instance()->REQ->get('e_reg_url_link', ''); |
|
603 | + // add reg url link to registration query params |
|
604 | + if ($this->checkout->reg_url_link && strpos($this->checkout->reg_url_link, '1-') !== 0) { |
|
605 | + $this->checkout->reg_cache_where_params[0]['REG_url_link'] = $this->checkout->reg_url_link; |
|
606 | + } |
|
607 | + // or some other kind of revisit ? |
|
608 | + $this->checkout->revisit = filter_var( |
|
609 | + EE_Registry::instance()->REQ->get('revisit', false), |
|
610 | + FILTER_VALIDATE_BOOLEAN |
|
611 | + ); |
|
612 | + // and whether or not to generate a reg form for this request |
|
613 | + $this->checkout->generate_reg_form = filter_var( |
|
614 | + EE_Registry::instance()->REQ->get('generate_reg_form', true), |
|
615 | + FILTER_VALIDATE_BOOLEAN |
|
616 | + ); |
|
617 | + // and whether or not to process a reg form submission for this request |
|
618 | + $this->checkout->process_form_submission = filter_var( |
|
619 | + EE_Registry::instance()->REQ->get( |
|
620 | + 'process_form_submission', |
|
621 | + $this->checkout->action === 'process_reg_step' |
|
622 | + ), |
|
623 | + FILTER_VALIDATE_BOOLEAN |
|
624 | + ); |
|
625 | + $this->checkout->process_form_submission = filter_var( |
|
626 | + $this->checkout->action !== 'display_spco_reg_step' |
|
627 | + ? $this->checkout->process_form_submission |
|
628 | + : false, |
|
629 | + FILTER_VALIDATE_BOOLEAN |
|
630 | + ); |
|
631 | + // $this->_display_request_vars(); |
|
632 | + } |
|
633 | + |
|
634 | + |
|
635 | + /** |
|
636 | + * _display_request_vars |
|
637 | + * |
|
638 | + * @access protected |
|
639 | + * @return void |
|
640 | + */ |
|
641 | + protected function _display_request_vars() |
|
642 | + { |
|
643 | + if (! WP_DEBUG) { |
|
644 | + return; |
|
645 | + } |
|
646 | + EEH_Debug_Tools::printr($_REQUEST, '$_REQUEST', __FILE__, __LINE__); |
|
647 | + EEH_Debug_Tools::printr($this->checkout->step, '$this->checkout->step', __FILE__, __LINE__); |
|
648 | + EEH_Debug_Tools::printr($this->checkout->edit_step, '$this->checkout->edit_step', __FILE__, __LINE__); |
|
649 | + EEH_Debug_Tools::printr($this->checkout->action, '$this->checkout->action', __FILE__, __LINE__); |
|
650 | + EEH_Debug_Tools::printr($this->checkout->reg_url_link, '$this->checkout->reg_url_link', __FILE__, __LINE__); |
|
651 | + EEH_Debug_Tools::printr($this->checkout->revisit, '$this->checkout->revisit', __FILE__, __LINE__); |
|
652 | + EEH_Debug_Tools::printr( |
|
653 | + $this->checkout->generate_reg_form, |
|
654 | + '$this->checkout->generate_reg_form', |
|
655 | + __FILE__, |
|
656 | + __LINE__ |
|
657 | + ); |
|
658 | + EEH_Debug_Tools::printr( |
|
659 | + $this->checkout->process_form_submission, |
|
660 | + '$this->checkout->process_form_submission', |
|
661 | + __FILE__, |
|
662 | + __LINE__ |
|
663 | + ); |
|
664 | + } |
|
665 | + |
|
666 | + |
|
667 | + /** |
|
668 | + * _block_bots |
|
669 | + * checks that the incoming request has either of the following set: |
|
670 | + * a uts (unix timestamp) which indicates that the request was redirected from the Ticket Selector |
|
671 | + * a REG URL Link, which indicates that the request is a return visit to SPCO for a valid TXN |
|
672 | + * so if you're not coming from the Ticket Selector nor returning for a valid IP... |
|
673 | + * then where you coming from man? |
|
674 | + * |
|
675 | + * @return boolean |
|
676 | + */ |
|
677 | + private function _block_bots() |
|
678 | + { |
|
679 | + $invalid_checkout_access = EED_Invalid_Checkout_Access::getInvalidCheckoutAccess(); |
|
680 | + if ($invalid_checkout_access->checkoutAccessIsInvalid($this->checkout)) { |
|
681 | + return true; |
|
682 | + } |
|
683 | + return false; |
|
684 | + } |
|
685 | + |
|
686 | + |
|
687 | + /** |
|
688 | + * _get_first_step |
|
689 | + * gets slug for first step in $_reg_steps_array |
|
690 | + * |
|
691 | + * @access private |
|
692 | + * @throws EE_Error |
|
693 | + * @return string |
|
694 | + */ |
|
695 | + private function _get_first_step() |
|
696 | + { |
|
697 | + $first_step = reset(EED_Single_Page_Checkout::$_reg_steps_array); |
|
698 | + return isset($first_step['slug']) ? $first_step['slug'] : 'attendee_information'; |
|
699 | + } |
|
700 | + |
|
701 | + |
|
702 | + /** |
|
703 | + * instantiates each reg step based on the loaded reg_steps array |
|
704 | + * |
|
705 | + * @return bool |
|
706 | + * @throws EE_Error |
|
707 | + * @throws InvalidArgumentException |
|
708 | + * @throws InvalidDataTypeException |
|
709 | + * @throws InvalidInterfaceException |
|
710 | + */ |
|
711 | + private function _load_and_instantiate_reg_steps() |
|
712 | + { |
|
713 | + do_action('AHEE__Single_Page_Checkout___load_and_instantiate_reg_steps__start', $this->checkout); |
|
714 | + // have reg_steps already been instantiated ? |
|
715 | + if (empty($this->checkout->reg_steps) |
|
716 | + || apply_filters('FHEE__Single_Page_Checkout__load_reg_steps__reload_reg_steps', false, $this->checkout) |
|
717 | + ) { |
|
718 | + // if not, then loop through raw reg steps array |
|
719 | + foreach (EED_Single_Page_Checkout::$_reg_steps_array as $order => $reg_step) { |
|
720 | + if (! $this->_load_and_instantiate_reg_step($reg_step, $order)) { |
|
721 | + return false; |
|
722 | + } |
|
723 | + } |
|
724 | + if (isset($this->checkout->reg_steps['registration_confirmation'])) { |
|
725 | + // skip the registration_confirmation page ? |
|
726 | + if (EE_Registry::instance()->CFG->registration->skip_reg_confirmation) { |
|
727 | + // just remove it from the reg steps array |
|
728 | + $this->checkout->remove_reg_step('registration_confirmation', false); |
|
729 | + } elseif (EE_Registry::instance()->CFG->registration->reg_confirmation_last |
|
730 | + ) { |
|
731 | + // set the order to something big like 100 |
|
732 | + $this->checkout->set_reg_step_order('registration_confirmation', 100); |
|
733 | + } |
|
734 | + } |
|
735 | + // filter the array for good luck |
|
736 | + $this->checkout->reg_steps = apply_filters( |
|
737 | + 'FHEE__Single_Page_Checkout__load_reg_steps__reg_steps', |
|
738 | + $this->checkout->reg_steps |
|
739 | + ); |
|
740 | + // finally re-sort based on the reg step class order properties |
|
741 | + $this->checkout->sort_reg_steps(); |
|
742 | + } else { |
|
743 | + foreach ($this->checkout->reg_steps as $reg_step) { |
|
744 | + // set all current step stati to FALSE |
|
745 | + $reg_step->set_is_current_step(false); |
|
746 | + } |
|
747 | + } |
|
748 | + if (empty($this->checkout->reg_steps)) { |
|
749 | + EE_Error::add_error( |
|
750 | + esc_html__('No Reg Steps were loaded..', 'event_espresso'), |
|
751 | + __FILE__, |
|
752 | + __FUNCTION__, |
|
753 | + __LINE__ |
|
754 | + ); |
|
755 | + return false; |
|
756 | + } |
|
757 | + // make reg step details available to JS |
|
758 | + $this->checkout->set_reg_step_JSON_info(); |
|
759 | + return true; |
|
760 | + } |
|
761 | + |
|
762 | + |
|
763 | + /** |
|
764 | + * _load_and_instantiate_reg_step |
|
765 | + * |
|
766 | + * @access private |
|
767 | + * @param array $reg_step |
|
768 | + * @param int $order |
|
769 | + * @return bool |
|
770 | + */ |
|
771 | + private function _load_and_instantiate_reg_step($reg_step = array(), $order = 0) |
|
772 | + { |
|
773 | + // we need a file_path, class_name, and slug to add a reg step |
|
774 | + if (isset($reg_step['file_path'], $reg_step['class_name'], $reg_step['slug'])) { |
|
775 | + // if editing a specific step, but this is NOT that step... (and it's not the 'finalize_registration' step) |
|
776 | + if ($this->checkout->reg_url_link |
|
777 | + && $this->checkout->step !== $reg_step['slug'] |
|
778 | + && $reg_step['slug'] !== 'finalize_registration' |
|
779 | + // normally at this point we would NOT load the reg step, but this filter can change that |
|
780 | + && apply_filters( |
|
781 | + 'FHEE__Single_Page_Checkout___load_and_instantiate_reg_step__bypass_reg_step', |
|
782 | + true, |
|
783 | + $reg_step, |
|
784 | + $this->checkout |
|
785 | + ) |
|
786 | + ) { |
|
787 | + return true; |
|
788 | + } |
|
789 | + // instantiate step class using file path and class name |
|
790 | + $reg_step_obj = EE_Registry::instance()->load_file( |
|
791 | + $reg_step['file_path'], |
|
792 | + $reg_step['class_name'], |
|
793 | + 'class', |
|
794 | + $this->checkout, |
|
795 | + false |
|
796 | + ); |
|
797 | + // did we gets the goods ? |
|
798 | + if ($reg_step_obj instanceof EE_SPCO_Reg_Step) { |
|
799 | + // set reg step order based on config |
|
800 | + $reg_step_obj->set_order($order); |
|
801 | + // add instantiated reg step object to the master reg steps array |
|
802 | + $this->checkout->add_reg_step($reg_step_obj); |
|
803 | + } else { |
|
804 | + EE_Error::add_error( |
|
805 | + esc_html__('The current step could not be set.', 'event_espresso'), |
|
806 | + __FILE__, |
|
807 | + __FUNCTION__, |
|
808 | + __LINE__ |
|
809 | + ); |
|
810 | + return false; |
|
811 | + } |
|
812 | + } else { |
|
813 | + if (WP_DEBUG) { |
|
814 | + EE_Error::add_error( |
|
815 | + sprintf( |
|
816 | + esc_html__( |
|
817 | + 'A registration step could not be loaded. One or more of the following data points is invalid:%4$s%5$sFile Path: %1$s%6$s%5$sClass Name: %2$s%6$s%5$sSlug: %3$s%6$s%7$s', |
|
818 | + 'event_espresso' |
|
819 | + ), |
|
820 | + isset($reg_step['file_path']) ? $reg_step['file_path'] : '', |
|
821 | + isset($reg_step['class_name']) ? $reg_step['class_name'] : '', |
|
822 | + isset($reg_step['slug']) ? $reg_step['slug'] : '', |
|
823 | + '<ul>', |
|
824 | + '<li>', |
|
825 | + '</li>', |
|
826 | + '</ul>' |
|
827 | + ), |
|
828 | + __FILE__, |
|
829 | + __FUNCTION__, |
|
830 | + __LINE__ |
|
831 | + ); |
|
832 | + } |
|
833 | + return false; |
|
834 | + } |
|
835 | + return true; |
|
836 | + } |
|
837 | + |
|
838 | + |
|
839 | + /** |
|
840 | + * _verify_transaction_and_get_registrations |
|
841 | + * |
|
842 | + * @access private |
|
843 | + * @return bool |
|
844 | + * @throws InvalidDataTypeException |
|
845 | + * @throws InvalidEntityException |
|
846 | + * @throws EE_Error |
|
847 | + */ |
|
848 | + private function _verify_transaction_and_get_registrations() |
|
849 | + { |
|
850 | + // was there already a valid transaction in the checkout from the session ? |
|
851 | + if (! $this->checkout->transaction instanceof EE_Transaction) { |
|
852 | + // get transaction from db or session |
|
853 | + $this->checkout->transaction = $this->checkout->reg_url_link && ! is_admin() |
|
854 | + ? $this->_get_transaction_and_cart_for_previous_visit() |
|
855 | + : $this->_get_cart_for_current_session_and_setup_new_transaction(); |
|
856 | + if (! $this->checkout->transaction instanceof EE_Transaction) { |
|
857 | + EE_Error::add_error( |
|
858 | + esc_html__( |
|
859 | + 'Your Registration and Transaction information could not be retrieved from the db.', |
|
860 | + 'event_espresso' |
|
861 | + ), |
|
862 | + __FILE__, |
|
863 | + __FUNCTION__, |
|
864 | + __LINE__ |
|
865 | + ); |
|
866 | + $this->checkout->transaction = EE_Transaction::new_instance(); |
|
867 | + // add some style and make it dance |
|
868 | + $this->add_styles_and_scripts($this); |
|
869 | + EED_Single_Page_Checkout::$_initialized = true; |
|
870 | + return false; |
|
871 | + } |
|
872 | + // and the registrations for the transaction |
|
873 | + $this->_get_registrations($this->checkout->transaction); |
|
874 | + } |
|
875 | + return true; |
|
876 | + } |
|
877 | + |
|
878 | + |
|
879 | + /** |
|
880 | + * _get_transaction_and_cart_for_previous_visit |
|
881 | + * |
|
882 | + * @access private |
|
883 | + * @return mixed EE_Transaction|NULL |
|
884 | + */ |
|
885 | + private function _get_transaction_and_cart_for_previous_visit() |
|
886 | + { |
|
887 | + /** @var $TXN_model EEM_Transaction */ |
|
888 | + $TXN_model = EE_Registry::instance()->load_model('Transaction'); |
|
889 | + // because the reg_url_link is present in the request, |
|
890 | + // this is a return visit to SPCO, so we'll get the transaction data from the db |
|
891 | + $transaction = $TXN_model->get_transaction_from_reg_url_link($this->checkout->reg_url_link); |
|
892 | + // verify transaction |
|
893 | + if ($transaction instanceof EE_Transaction) { |
|
894 | + // and get the cart that was used for that transaction |
|
895 | + $this->checkout->cart = $this->_get_cart_for_transaction($transaction); |
|
896 | + return $transaction; |
|
897 | + } |
|
898 | + EE_Error::add_error( |
|
899 | + esc_html__('Your Registration and Transaction information could not be retrieved from the db.', 'event_espresso'), |
|
900 | + __FILE__, |
|
901 | + __FUNCTION__, |
|
902 | + __LINE__ |
|
903 | + ); |
|
904 | + return null; |
|
905 | + } |
|
906 | + |
|
907 | + |
|
908 | + /** |
|
909 | + * _get_cart_for_transaction |
|
910 | + * |
|
911 | + * @access private |
|
912 | + * @param EE_Transaction $transaction |
|
913 | + * @return EE_Cart |
|
914 | + */ |
|
915 | + private function _get_cart_for_transaction($transaction) |
|
916 | + { |
|
917 | + return $this->checkout->get_cart_for_transaction($transaction); |
|
918 | + } |
|
919 | + |
|
920 | + |
|
921 | + /** |
|
922 | + * get_cart_for_transaction |
|
923 | + * |
|
924 | + * @access public |
|
925 | + * @param EE_Transaction $transaction |
|
926 | + * @return EE_Cart |
|
927 | + */ |
|
928 | + public function get_cart_for_transaction(EE_Transaction $transaction) |
|
929 | + { |
|
930 | + return $this->checkout->get_cart_for_transaction($transaction); |
|
931 | + } |
|
932 | + |
|
933 | + |
|
934 | + /** |
|
935 | + * _get_transaction_and_cart_for_current_session |
|
936 | + * generates a new EE_Transaction object and adds it to the $_transaction property. |
|
937 | + * |
|
938 | + * @access private |
|
939 | + * @return EE_Transaction |
|
940 | + * @throws EE_Error |
|
941 | + */ |
|
942 | + private function _get_cart_for_current_session_and_setup_new_transaction() |
|
943 | + { |
|
944 | + // if there's no transaction, then this is the FIRST visit to SPCO |
|
945 | + // so load up the cart ( passing nothing for the TXN because it doesn't exist yet ) |
|
946 | + $this->checkout->cart = $this->_get_cart_for_transaction(null); |
|
947 | + // and then create a new transaction |
|
948 | + $transaction = $this->_initialize_transaction(); |
|
949 | + // verify transaction |
|
950 | + if ($transaction instanceof EE_Transaction) { |
|
951 | + // save it so that we have an ID for other objects to use |
|
952 | + $transaction->save(); |
|
953 | + // and save TXN data to the cart |
|
954 | + $this->checkout->cart->get_grand_total()->save_this_and_descendants_to_txn($transaction->ID()); |
|
955 | + } else { |
|
956 | + EE_Error::add_error( |
|
957 | + esc_html__('A Valid Transaction could not be initialized.', 'event_espresso'), |
|
958 | + __FILE__, |
|
959 | + __FUNCTION__, |
|
960 | + __LINE__ |
|
961 | + ); |
|
962 | + } |
|
963 | + return $transaction; |
|
964 | + } |
|
965 | + |
|
966 | + |
|
967 | + /** |
|
968 | + * generates a new EE_Transaction object and adds it to the $_transaction property. |
|
969 | + * |
|
970 | + * @access private |
|
971 | + * @return mixed EE_Transaction|NULL |
|
972 | + */ |
|
973 | + private function _initialize_transaction() |
|
974 | + { |
|
975 | + try { |
|
976 | + // ensure cart totals have been calculated |
|
977 | + $this->checkout->cart->get_grand_total()->recalculate_total_including_taxes(); |
|
978 | + // grab the cart grand total |
|
979 | + $cart_total = $this->checkout->cart->get_cart_grand_total(); |
|
980 | + // create new TXN |
|
981 | + $transaction = EE_Transaction::new_instance( |
|
982 | + array( |
|
983 | + 'TXN_reg_steps' => $this->checkout->initialize_txn_reg_steps_array(), |
|
984 | + 'TXN_total' => $cart_total > 0 ? $cart_total : 0, |
|
985 | + 'TXN_paid' => 0, |
|
986 | + 'STS_ID' => EEM_Transaction::failed_status_code, |
|
987 | + ) |
|
988 | + ); |
|
989 | + // save it so that we have an ID for other objects to use |
|
990 | + $transaction->save(); |
|
991 | + // set cron job for following up on TXNs after their session has expired |
|
992 | + EE_Cron_Tasks::schedule_expired_transaction_check( |
|
993 | + EE_Registry::instance()->SSN->expiration() + 1, |
|
994 | + $transaction->ID() |
|
995 | + ); |
|
996 | + return $transaction; |
|
997 | + } catch (Exception $e) { |
|
998 | + EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__); |
|
999 | + } |
|
1000 | + return null; |
|
1001 | + } |
|
1002 | + |
|
1003 | + |
|
1004 | + /** |
|
1005 | + * _get_registrations |
|
1006 | + * |
|
1007 | + * @access private |
|
1008 | + * @param EE_Transaction $transaction |
|
1009 | + * @return void |
|
1010 | + * @throws InvalidDataTypeException |
|
1011 | + * @throws InvalidEntityException |
|
1012 | + * @throws EE_Error |
|
1013 | + */ |
|
1014 | + private function _get_registrations(EE_Transaction $transaction) |
|
1015 | + { |
|
1016 | + // first step: grab the registrants { : o |
|
1017 | + $registrations = $transaction->registrations($this->checkout->reg_cache_where_params, false); |
|
1018 | + $this->checkout->total_ticket_count = count($registrations); |
|
1019 | + // verify registrations have been set |
|
1020 | + if (empty($registrations)) { |
|
1021 | + // if no cached registrations, then check the db |
|
1022 | + $registrations = $transaction->registrations($this->checkout->reg_cache_where_params, false); |
|
1023 | + // still nothing ? well as long as this isn't a revisit |
|
1024 | + if (empty($registrations) && ! $this->checkout->revisit) { |
|
1025 | + // generate new registrations from scratch |
|
1026 | + $registrations = $this->_initialize_registrations($transaction); |
|
1027 | + } |
|
1028 | + } |
|
1029 | + // sort by their original registration order |
|
1030 | + usort($registrations, array('EED_Single_Page_Checkout', 'sort_registrations_by_REG_count')); |
|
1031 | + // then loop thru the array |
|
1032 | + foreach ($registrations as $registration) { |
|
1033 | + // verify each registration |
|
1034 | + if ($registration instanceof EE_Registration) { |
|
1035 | + // we display all attendee info for the primary registrant |
|
1036 | + if ($this->checkout->reg_url_link === $registration->reg_url_link() |
|
1037 | + && $registration->is_primary_registrant() |
|
1038 | + ) { |
|
1039 | + $this->checkout->primary_revisit = true; |
|
1040 | + break; |
|
1041 | + } |
|
1042 | + if ($this->checkout->revisit && $this->checkout->reg_url_link !== $registration->reg_url_link()) { |
|
1043 | + // but hide info if it doesn't belong to you |
|
1044 | + $transaction->clear_cache('Registration', $registration->ID()); |
|
1045 | + $this->checkout->total_ticket_count--; |
|
1046 | + } |
|
1047 | + $this->checkout->set_reg_status_updated($registration->ID(), false); |
|
1048 | + } |
|
1049 | + } |
|
1050 | + } |
|
1051 | + |
|
1052 | + |
|
1053 | + /** |
|
1054 | + * adds related EE_Registration objects for each ticket in the cart to the current EE_Transaction object |
|
1055 | + * |
|
1056 | + * @access private |
|
1057 | + * @param EE_Transaction $transaction |
|
1058 | + * @return array |
|
1059 | + * @throws InvalidDataTypeException |
|
1060 | + * @throws InvalidEntityException |
|
1061 | + * @throws EE_Error |
|
1062 | + */ |
|
1063 | + private function _initialize_registrations(EE_Transaction $transaction) |
|
1064 | + { |
|
1065 | + $att_nmbr = 0; |
|
1066 | + $registrations = array(); |
|
1067 | + if ($transaction instanceof EE_Transaction) { |
|
1068 | + /** @type EE_Registration_Processor $registration_processor */ |
|
1069 | + $registration_processor = EE_Registry::instance()->load_class('Registration_Processor'); |
|
1070 | + $this->checkout->total_ticket_count = $this->checkout->cart->all_ticket_quantity_count(); |
|
1071 | + // now let's add the cart items to the $transaction |
|
1072 | + foreach ($this->checkout->cart->get_tickets() as $line_item) { |
|
1073 | + // do the following for each ticket of this type they selected |
|
1074 | + for ($x = 1; $x <= $line_item->quantity(); $x++) { |
|
1075 | + $att_nmbr++; |
|
1076 | + /** @var EventEspresso\core\services\commands\registration\CreateRegistrationCommand $CreateRegistrationCommand */ |
|
1077 | + $CreateRegistrationCommand = EE_Registry::instance()->create( |
|
1078 | + 'EventEspresso\core\services\commands\registration\CreateRegistrationCommand', |
|
1079 | + array( |
|
1080 | + $transaction, |
|
1081 | + $line_item, |
|
1082 | + $att_nmbr, |
|
1083 | + $this->checkout->total_ticket_count, |
|
1084 | + ) |
|
1085 | + ); |
|
1086 | + // override capabilities for frontend registrations |
|
1087 | + if (! is_admin()) { |
|
1088 | + $CreateRegistrationCommand->setCapCheck( |
|
1089 | + new PublicCapabilities('', 'create_new_registration') |
|
1090 | + ); |
|
1091 | + } |
|
1092 | + $registration = EE_Registry::instance()->BUS->execute($CreateRegistrationCommand); |
|
1093 | + if (! $registration instanceof EE_Registration) { |
|
1094 | + throw new InvalidEntityException($registration, 'EE_Registration'); |
|
1095 | + } |
|
1096 | + $registrations[ $registration->ID() ] = $registration; |
|
1097 | + } |
|
1098 | + } |
|
1099 | + $registration_processor->fix_reg_final_price_rounding_issue($transaction); |
|
1100 | + } |
|
1101 | + return $registrations; |
|
1102 | + } |
|
1103 | + |
|
1104 | + |
|
1105 | + /** |
|
1106 | + * sorts registrations by REG_count |
|
1107 | + * |
|
1108 | + * @access public |
|
1109 | + * @param EE_Registration $reg_A |
|
1110 | + * @param EE_Registration $reg_B |
|
1111 | + * @return int |
|
1112 | + */ |
|
1113 | + public static function sort_registrations_by_REG_count(EE_Registration $reg_A, EE_Registration $reg_B) |
|
1114 | + { |
|
1115 | + // this shouldn't ever happen within the same TXN, but oh well |
|
1116 | + if ($reg_A->count() === $reg_B->count()) { |
|
1117 | + return 0; |
|
1118 | + } |
|
1119 | + return ($reg_A->count() > $reg_B->count()) ? 1 : -1; |
|
1120 | + } |
|
1121 | + |
|
1122 | + |
|
1123 | + /** |
|
1124 | + * _final_verifications |
|
1125 | + * just makes sure that everything is set up correctly before proceeding |
|
1126 | + * |
|
1127 | + * @access private |
|
1128 | + * @return bool |
|
1129 | + * @throws EE_Error |
|
1130 | + */ |
|
1131 | + private function _final_verifications() |
|
1132 | + { |
|
1133 | + // filter checkout |
|
1134 | + $this->checkout = apply_filters( |
|
1135 | + 'FHEE__EED_Single_Page_Checkout___final_verifications__checkout', |
|
1136 | + $this->checkout |
|
1137 | + ); |
|
1138 | + // verify that current step is still set correctly |
|
1139 | + if (! $this->checkout->current_step instanceof EE_SPCO_Reg_Step) { |
|
1140 | + EE_Error::add_error( |
|
1141 | + esc_html__( |
|
1142 | + 'We\'re sorry but the registration process can not proceed because one or more registration steps were not setup correctly. Please refresh the page and try again or contact support.', |
|
1143 | + 'event_espresso' |
|
1144 | + ), |
|
1145 | + __FILE__, |
|
1146 | + __FUNCTION__, |
|
1147 | + __LINE__ |
|
1148 | + ); |
|
1149 | + return false; |
|
1150 | + } |
|
1151 | + // if returning to SPCO, then verify that primary registrant is set |
|
1152 | + if (! empty($this->checkout->reg_url_link)) { |
|
1153 | + $valid_registrant = $this->checkout->transaction->primary_registration(); |
|
1154 | + if (! $valid_registrant instanceof EE_Registration) { |
|
1155 | + EE_Error::add_error( |
|
1156 | + esc_html__( |
|
1157 | + 'We\'re sorry but there appears to be an error with the "reg_url_link" or the primary registrant for this transaction. Please refresh the page and try again or contact support.', |
|
1158 | + 'event_espresso' |
|
1159 | + ), |
|
1160 | + __FILE__, |
|
1161 | + __FUNCTION__, |
|
1162 | + __LINE__ |
|
1163 | + ); |
|
1164 | + return false; |
|
1165 | + } |
|
1166 | + $valid_registrant = null; |
|
1167 | + foreach ($this->checkout->transaction->registrations($this->checkout->reg_cache_where_params) as $registration) { |
|
1168 | + if ($registration instanceof EE_Registration |
|
1169 | + && $registration->reg_url_link() === $this->checkout->reg_url_link |
|
1170 | + ) { |
|
1171 | + $valid_registrant = $registration; |
|
1172 | + } |
|
1173 | + } |
|
1174 | + if (! $valid_registrant instanceof EE_Registration) { |
|
1175 | + // hmmm... maybe we have the wrong session because the user is opening multiple tabs ? |
|
1176 | + if (EED_Single_Page_Checkout::$_checkout_verified) { |
|
1177 | + // clear the session, mark the checkout as unverified, and try again |
|
1178 | + EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__); |
|
1179 | + EED_Single_Page_Checkout::$_initialized = false; |
|
1180 | + EED_Single_Page_Checkout::$_checkout_verified = false; |
|
1181 | + $this->_initialize(); |
|
1182 | + EE_Error::reset_notices(); |
|
1183 | + return false; |
|
1184 | + } |
|
1185 | + EE_Error::add_error( |
|
1186 | + esc_html__( |
|
1187 | + 'We\'re sorry but there appears to be an error with the "reg_url_link" or the transaction itself. Please refresh the page and try again or contact support.', |
|
1188 | + 'event_espresso' |
|
1189 | + ), |
|
1190 | + __FILE__, |
|
1191 | + __FUNCTION__, |
|
1192 | + __LINE__ |
|
1193 | + ); |
|
1194 | + return false; |
|
1195 | + } |
|
1196 | + } |
|
1197 | + // now that things have been kinda sufficiently verified, |
|
1198 | + // let's add the checkout to the session so that it's available to other systems |
|
1199 | + EE_Registry::instance()->SSN->set_checkout($this->checkout); |
|
1200 | + return true; |
|
1201 | + } |
|
1202 | + |
|
1203 | + |
|
1204 | + /** |
|
1205 | + * _initialize_reg_steps |
|
1206 | + * first makes sure that EE_Transaction_Processor::set_reg_step_initiated() is called as required |
|
1207 | + * then loops thru all of the active reg steps and calls the initialize_reg_step() method |
|
1208 | + * |
|
1209 | + * @access private |
|
1210 | + * @param bool $reinitializing |
|
1211 | + * @throws EE_Error |
|
1212 | + */ |
|
1213 | + private function _initialize_reg_steps($reinitializing = false) |
|
1214 | + { |
|
1215 | + $this->checkout->set_reg_step_initiated($this->checkout->current_step); |
|
1216 | + // loop thru all steps to call their individual "initialize" methods and set i18n strings for JS |
|
1217 | + foreach ($this->checkout->reg_steps as $reg_step) { |
|
1218 | + if (! $reg_step->initialize_reg_step()) { |
|
1219 | + // if not initialized then maybe this step is being removed... |
|
1220 | + if (! $reinitializing && $reg_step->is_current_step()) { |
|
1221 | + // if it was the current step, then we need to start over here |
|
1222 | + $this->_initialize_reg_steps(true); |
|
1223 | + return; |
|
1224 | + } |
|
1225 | + continue; |
|
1226 | + } |
|
1227 | + // add css and JS for current step |
|
1228 | + $this->add_styles_and_scripts($reg_step); |
|
1229 | + if ($reg_step->is_current_step()) { |
|
1230 | + // the text that appears on the reg step form submit button |
|
1231 | + $reg_step->set_submit_button_text(); |
|
1232 | + } |
|
1233 | + } |
|
1234 | + // dynamically creates hook point like: AHEE__Single_Page_Checkout___initialize_reg_step__attendee_information |
|
1235 | + do_action( |
|
1236 | + "AHEE__Single_Page_Checkout___initialize_reg_step__{$this->checkout->current_step->slug()}", |
|
1237 | + $this->checkout->current_step |
|
1238 | + ); |
|
1239 | + } |
|
1240 | + |
|
1241 | + |
|
1242 | + /** |
|
1243 | + * _check_form_submission |
|
1244 | + * |
|
1245 | + * @access private |
|
1246 | + * @return boolean |
|
1247 | + */ |
|
1248 | + private function _check_form_submission() |
|
1249 | + { |
|
1250 | + // does this request require the reg form to be generated ? |
|
1251 | + if ($this->checkout->generate_reg_form) { |
|
1252 | + // ever heard that song by Blue Rodeo ? |
|
1253 | + try { |
|
1254 | + $this->checkout->current_step->reg_form = $this->checkout->current_step->generate_reg_form(); |
|
1255 | + // if not displaying a form, then check for form submission |
|
1256 | + if ($this->checkout->process_form_submission |
|
1257 | + && $this->checkout->current_step->reg_form->was_submitted() |
|
1258 | + ) { |
|
1259 | + // clear out any old data in case this step is being run again |
|
1260 | + $this->checkout->current_step->set_valid_data(array()); |
|
1261 | + // capture submitted form data |
|
1262 | + $this->checkout->current_step->reg_form->receive_form_submission( |
|
1263 | + apply_filters( |
|
1264 | + 'FHEE__Single_Page_Checkout___check_form_submission__request_params', |
|
1265 | + EE_Registry::instance()->REQ->params(), |
|
1266 | + $this->checkout |
|
1267 | + ) |
|
1268 | + ); |
|
1269 | + // validate submitted form data |
|
1270 | + if (! $this->checkout->continue_reg || ! $this->checkout->current_step->reg_form->is_valid()) { |
|
1271 | + // thou shall not pass !!! |
|
1272 | + $this->checkout->continue_reg = false; |
|
1273 | + // any form validation errors? |
|
1274 | + if ($this->checkout->current_step->reg_form->submission_error_message() !== '') { |
|
1275 | + EE_Error::add_error( |
|
1276 | + $this->checkout->current_step->reg_form->submission_error_message(), |
|
1277 | + __FILE__, |
|
1278 | + __FUNCTION__, |
|
1279 | + __LINE__ |
|
1280 | + ); |
|
1281 | + } |
|
1282 | + // well not really... what will happen is |
|
1283 | + // we'll just get redirected back to redo the current step |
|
1284 | + $this->go_to_next_step(); |
|
1285 | + return false; |
|
1286 | + } |
|
1287 | + } |
|
1288 | + } catch (EE_Error $e) { |
|
1289 | + $e->get_error(); |
|
1290 | + } |
|
1291 | + } |
|
1292 | + return true; |
|
1293 | + } |
|
1294 | + |
|
1295 | + |
|
1296 | + /** |
|
1297 | + * _process_action |
|
1298 | + * |
|
1299 | + * @access private |
|
1300 | + * @return void |
|
1301 | + * @throws EE_Error |
|
1302 | + */ |
|
1303 | + private function _process_form_action() |
|
1304 | + { |
|
1305 | + // what cha wanna do? |
|
1306 | + switch ($this->checkout->action) { |
|
1307 | + // AJAX next step reg form |
|
1308 | + case 'display_spco_reg_step': |
|
1309 | + $this->checkout->redirect = false; |
|
1310 | + if (EE_Registry::instance()->REQ->ajax) { |
|
1311 | + $this->checkout->json_response->set_reg_step_html( |
|
1312 | + $this->checkout->current_step->display_reg_form() |
|
1313 | + ); |
|
1314 | + } |
|
1315 | + break; |
|
1316 | + default: |
|
1317 | + // meh... do one of those other steps first |
|
1318 | + if (! empty($this->checkout->action) |
|
1319 | + && is_callable(array($this->checkout->current_step, $this->checkout->action)) |
|
1320 | + ) { |
|
1321 | + // dynamically creates hook point like: |
|
1322 | + // AHEE__Single_Page_Checkout__before_attendee_information__process_reg_step |
|
1323 | + do_action( |
|
1324 | + "AHEE__Single_Page_Checkout__before_{$this->checkout->current_step->slug()}__{$this->checkout->action}", |
|
1325 | + $this->checkout->current_step |
|
1326 | + ); |
|
1327 | + $process_reg_step = apply_filters( |
|
1328 | + "AHEE__Single_Page_Checkout__process_reg_step__{$this->checkout->current_step->slug()}__{$this->checkout->action}", |
|
1329 | + true, |
|
1330 | + $this->checkout->current_step, |
|
1331 | + $this |
|
1332 | + ); |
|
1333 | + // call action on current step |
|
1334 | + if ($process_reg_step && call_user_func([$this->checkout->current_step, $this->checkout->action])) { |
|
1335 | + // good registrant, you get to proceed |
|
1336 | + if ($this->checkout->current_step->success_message() !== '' |
|
1337 | + && apply_filters( |
|
1338 | + 'FHEE__Single_Page_Checkout___process_form_action__display_success', |
|
1339 | + false |
|
1340 | + ) |
|
1341 | + ) { |
|
1342 | + EE_Error::add_success( |
|
1343 | + $this->checkout->current_step->success_message() |
|
1344 | + . '<br />' . $this->checkout->next_step->_instructions() |
|
1345 | + ); |
|
1346 | + } |
|
1347 | + // pack it up, pack it in... |
|
1348 | + $this->_setup_redirect(); |
|
1349 | + } |
|
1350 | + // dynamically creates hook point like: |
|
1351 | + // AHEE__Single_Page_Checkout__after_payment_options__process_reg_step |
|
1352 | + do_action( |
|
1353 | + "AHEE__Single_Page_Checkout__after_{$this->checkout->current_step->slug()}__{$this->checkout->action}", |
|
1354 | + $this->checkout->current_step |
|
1355 | + ); |
|
1356 | + } else { |
|
1357 | + EE_Error::add_error( |
|
1358 | + sprintf( |
|
1359 | + esc_html__( |
|
1360 | + 'The requested form action "%s" does not exist for the current "%s" registration step.', |
|
1361 | + 'event_espresso' |
|
1362 | + ), |
|
1363 | + $this->checkout->action, |
|
1364 | + $this->checkout->current_step->name() |
|
1365 | + ), |
|
1366 | + __FILE__, |
|
1367 | + __FUNCTION__, |
|
1368 | + __LINE__ |
|
1369 | + ); |
|
1370 | + } |
|
1371 | + // end default |
|
1372 | + } |
|
1373 | + // store our progress so far |
|
1374 | + $this->checkout->stash_transaction_and_checkout(); |
|
1375 | + // advance to the next step! If you pass GO, collect $200 |
|
1376 | + $this->go_to_next_step(); |
|
1377 | + } |
|
1378 | + |
|
1379 | + |
|
1380 | + /** |
|
1381 | + * @param EED_Single_Page_Checkout|EE_SPCO_Reg_Step $target |
|
1382 | + * @param object $target an object with the method `translate_js_strings` and `enqueue_styles_and_scripts`. |
|
1383 | + * @return void |
|
1384 | + */ |
|
1385 | + public function add_styles_and_scripts($target) |
|
1386 | + { |
|
1387 | + // i18n |
|
1388 | + $target->translate_js_strings(); |
|
1389 | + if ($this->checkout->admin_request) { |
|
1390 | + add_action('admin_enqueue_scripts', array($target, 'enqueue_styles_and_scripts'), 10); |
|
1391 | + } else { |
|
1392 | + add_action('wp_enqueue_scripts', array($target, 'enqueue_styles_and_scripts'), 10); |
|
1393 | + } |
|
1394 | + } |
|
1395 | + |
|
1396 | + /** |
|
1397 | + * translate_js_strings |
|
1398 | + * |
|
1399 | + * @access public |
|
1400 | + * @return void |
|
1401 | + */ |
|
1402 | + public function translate_js_strings() |
|
1403 | + { |
|
1404 | + EE_Registry::$i18n_js_strings['revisit'] = $this->checkout->revisit; |
|
1405 | + EE_Registry::$i18n_js_strings['e_reg_url_link'] = $this->checkout->reg_url_link; |
|
1406 | + EE_Registry::$i18n_js_strings['server_error'] = esc_html__( |
|
1407 | + 'An unknown error occurred on the server while attempting to process your request. Please refresh the page and try again or contact support.', |
|
1408 | + 'event_espresso' |
|
1409 | + ); |
|
1410 | + EE_Registry::$i18n_js_strings['invalid_json_response'] = esc_html__( |
|
1411 | + 'An invalid response was returned from the server while attempting to process your request. Please refresh the page and try again or contact support.', |
|
1412 | + 'event_espresso' |
|
1413 | + ); |
|
1414 | + EE_Registry::$i18n_js_strings['validation_error'] = esc_html__( |
|
1415 | + 'There appears to be a problem with the form validation configuration! Please check the admin settings or contact support.', |
|
1416 | + 'event_espresso' |
|
1417 | + ); |
|
1418 | + EE_Registry::$i18n_js_strings['invalid_payment_method'] = esc_html__( |
|
1419 | + 'There appears to be a problem with the payment method configuration! Please refresh the page and try again or contact support.', |
|
1420 | + 'event_espresso' |
|
1421 | + ); |
|
1422 | + EE_Registry::$i18n_js_strings['reg_step_error'] = esc_html__( |
|
1423 | + 'This registration step could not be completed. Please refresh the page and try again.', |
|
1424 | + 'event_espresso' |
|
1425 | + ); |
|
1426 | + EE_Registry::$i18n_js_strings['invalid_coupon'] = esc_html__( |
|
1427 | + 'We\'re sorry but that coupon code does not appear to be valid. If this is incorrect, please contact the site administrator.', |
|
1428 | + 'event_espresso' |
|
1429 | + ); |
|
1430 | + EE_Registry::$i18n_js_strings['process_registration'] = sprintf( |
|
1431 | + esc_html__( |
|
1432 | + 'Please wait while we process your registration.%sDo not refresh the page or navigate away while this is happening.%sThank you for your patience.', |
|
1433 | + 'event_espresso' |
|
1434 | + ), |
|
1435 | + '<br/>', |
|
1436 | + '<br/>' |
|
1437 | + ); |
|
1438 | + EE_Registry::$i18n_js_strings['language'] = get_bloginfo('language'); |
|
1439 | + EE_Registry::$i18n_js_strings['EESID'] = EE_Registry::instance()->SSN->id(); |
|
1440 | + EE_Registry::$i18n_js_strings['currency'] = EE_Registry::instance()->CFG->currency; |
|
1441 | + EE_Registry::$i18n_js_strings['datepicker_yearRange'] = '-150:+20'; |
|
1442 | + EE_Registry::$i18n_js_strings['timer_years'] = esc_html__('years', 'event_espresso'); |
|
1443 | + EE_Registry::$i18n_js_strings['timer_months'] = esc_html__('months', 'event_espresso'); |
|
1444 | + EE_Registry::$i18n_js_strings['timer_weeks'] = esc_html__('weeks', 'event_espresso'); |
|
1445 | + EE_Registry::$i18n_js_strings['timer_days'] = esc_html__('days', 'event_espresso'); |
|
1446 | + EE_Registry::$i18n_js_strings['timer_hours'] = esc_html__('hours', 'event_espresso'); |
|
1447 | + EE_Registry::$i18n_js_strings['timer_minutes'] = esc_html__('minutes', 'event_espresso'); |
|
1448 | + EE_Registry::$i18n_js_strings['timer_seconds'] = esc_html__('seconds', 'event_espresso'); |
|
1449 | + EE_Registry::$i18n_js_strings['timer_year'] = esc_html__('year', 'event_espresso'); |
|
1450 | + EE_Registry::$i18n_js_strings['timer_month'] = esc_html__('month', 'event_espresso'); |
|
1451 | + EE_Registry::$i18n_js_strings['timer_week'] = esc_html__('week', 'event_espresso'); |
|
1452 | + EE_Registry::$i18n_js_strings['timer_day'] = esc_html__('day', 'event_espresso'); |
|
1453 | + EE_Registry::$i18n_js_strings['timer_hour'] = esc_html__('hour', 'event_espresso'); |
|
1454 | + EE_Registry::$i18n_js_strings['timer_minute'] = esc_html__('minute', 'event_espresso'); |
|
1455 | + EE_Registry::$i18n_js_strings['timer_second'] = esc_html__('second', 'event_espresso'); |
|
1456 | + EE_Registry::$i18n_js_strings['registration_expiration_notice'] = EED_Single_Page_Checkout::getRegistrationExpirationNotice( |
|
1457 | + ); |
|
1458 | + EE_Registry::$i18n_js_strings['ajax_submit'] = apply_filters( |
|
1459 | + 'FHEE__Single_Page_Checkout__translate_js_strings__ajax_submit', |
|
1460 | + true |
|
1461 | + ); |
|
1462 | + EE_Registry::$i18n_js_strings['session_extension'] = absint( |
|
1463 | + apply_filters('FHEE__EE_Session__extend_expiration__seconds_added', 10 * MINUTE_IN_SECONDS) |
|
1464 | + ); |
|
1465 | + EE_Registry::$i18n_js_strings['session_expiration'] = gmdate( |
|
1466 | + 'M d, Y H:i:s', |
|
1467 | + EE_Registry::instance()->SSN->expiration() + (get_option('gmt_offset') * HOUR_IN_SECONDS) |
|
1468 | + ); |
|
1469 | + } |
|
1470 | + |
|
1471 | + |
|
1472 | + /** |
|
1473 | + * enqueue_styles_and_scripts |
|
1474 | + * |
|
1475 | + * @access public |
|
1476 | + * @return void |
|
1477 | + * @throws EE_Error |
|
1478 | + */ |
|
1479 | + public function enqueue_styles_and_scripts() |
|
1480 | + { |
|
1481 | + // load css |
|
1482 | + wp_register_style( |
|
1483 | + 'single_page_checkout', |
|
1484 | + SPCO_CSS_URL . 'single_page_checkout.css', |
|
1485 | + array('espresso_default'), |
|
1486 | + EVENT_ESPRESSO_VERSION |
|
1487 | + ); |
|
1488 | + wp_enqueue_style('single_page_checkout'); |
|
1489 | + // load JS |
|
1490 | + wp_register_script( |
|
1491 | + 'jquery_plugin', |
|
1492 | + EE_THIRD_PARTY_URL . 'jquery .plugin.min.js', |
|
1493 | + array('jquery'), |
|
1494 | + '1.0.1', |
|
1495 | + true |
|
1496 | + ); |
|
1497 | + wp_register_script( |
|
1498 | + 'jquery_countdown', |
|
1499 | + EE_THIRD_PARTY_URL . 'jquery .countdown.min.js', |
|
1500 | + array('jquery_plugin'), |
|
1501 | + '2.1.0', |
|
1502 | + true |
|
1503 | + ); |
|
1504 | + wp_register_script( |
|
1505 | + 'single_page_checkout', |
|
1506 | + SPCO_JS_URL . 'single_page_checkout.js', |
|
1507 | + array('espresso_core', 'underscore', 'ee_form_section_validation'), |
|
1508 | + EVENT_ESPRESSO_VERSION, |
|
1509 | + true |
|
1510 | + ); |
|
1511 | + if ($this->checkout->registration_form instanceof EE_Form_Section_Proper) { |
|
1512 | + $this->checkout->registration_form->enqueue_js(); |
|
1513 | + } |
|
1514 | + if ($this->checkout->current_step->reg_form instanceof EE_Form_Section_Proper) { |
|
1515 | + $this->checkout->current_step->reg_form->enqueue_js(); |
|
1516 | + } |
|
1517 | + wp_enqueue_script('single_page_checkout'); |
|
1518 | + if (apply_filters('FHEE__registration_page_wrapper_template__display_time_limit', false)) { |
|
1519 | + wp_enqueue_script('jquery_countdown'); |
|
1520 | + } |
|
1521 | + /** |
|
1522 | + * global action hook for enqueueing styles and scripts with |
|
1523 | + * spco calls. |
|
1524 | + */ |
|
1525 | + do_action('AHEE__EED_Single_Page_Checkout__enqueue_styles_and_scripts', $this); |
|
1526 | + /** |
|
1527 | + * dynamic action hook for enqueueing styles and scripts with spco calls. |
|
1528 | + * The hook will end up being something like: |
|
1529 | + * AHEE__EED_Single_Page_Checkout__enqueue_styles_and_scripts__attendee_information |
|
1530 | + */ |
|
1531 | + do_action( |
|
1532 | + 'AHEE__EED_Single_Page_Checkout__enqueue_styles_and_scripts__' . $this->checkout->current_step->slug(), |
|
1533 | + $this |
|
1534 | + ); |
|
1535 | + } |
|
1536 | + |
|
1537 | + |
|
1538 | + /** |
|
1539 | + * display the Registration Single Page Checkout Form |
|
1540 | + * |
|
1541 | + * @access private |
|
1542 | + * @return void |
|
1543 | + * @throws EE_Error |
|
1544 | + */ |
|
1545 | + private function _display_spco_reg_form() |
|
1546 | + { |
|
1547 | + // if registering via the admin, just display the reg form for the current step |
|
1548 | + if ($this->checkout->admin_request) { |
|
1549 | + EE_Registry::instance()->REQ->add_output($this->checkout->current_step->display_reg_form()); |
|
1550 | + } else { |
|
1551 | + // add powered by EE msg |
|
1552 | + add_action('AHEE__SPCO__reg_form_footer', array('EED_Single_Page_Checkout', 'display_registration_footer')); |
|
1553 | + $empty_cart = count($this->checkout->transaction |
|
1554 | + ->registrations($this->checkout->reg_cache_where_params)) < 1; |
|
1555 | + EE_Registry::$i18n_js_strings['empty_cart'] = $empty_cart; |
|
1556 | + $cookies_not_set_msg = ''; |
|
1557 | + if ($empty_cart) { |
|
1558 | + $cookies_not_set_msg = apply_filters( |
|
1559 | + 'FHEE__Single_Page_Checkout__display_spco_reg_form__cookies_not_set_msg', |
|
1560 | + sprintf( |
|
1561 | + esc_html__( |
|
1562 | + '%1$s%3$sIt appears your browser is not currently set to accept Cookies%4$s%5$sIn order to register for events, you need to enable cookies.%7$sIf you require assistance, then click the following link to learn how to %8$senable cookies%9$s%6$s%2$s', |
|
1563 | + 'event_espresso' |
|
1564 | + ), |
|
1565 | + '<div class="ee-attention hidden" id="ee-cookies-not-set-msg">', |
|
1566 | + '</div>', |
|
1567 | + '<h6 class="important-notice">', |
|
1568 | + '</h6>', |
|
1569 | + '<p>', |
|
1570 | + '</p>', |
|
1571 | + '<br />', |
|
1572 | + '<a href="http://www.whatarecookies.com/enable.asp" target="_blank" rel="noopener noreferrer">', |
|
1573 | + '</a>' |
|
1574 | + ) |
|
1575 | + ); |
|
1576 | + } |
|
1577 | + $this->checkout->registration_form = new EE_Form_Section_Proper( |
|
1578 | + array( |
|
1579 | + 'name' => 'single-page-checkout', |
|
1580 | + 'html_id' => 'ee-single-page-checkout-dv', |
|
1581 | + 'layout_strategy' => |
|
1582 | + new EE_Template_Layout( |
|
1583 | + array( |
|
1584 | + 'layout_template_file' => SPCO_TEMPLATES_PATH . 'registration_page_wrapper.template.php', |
|
1585 | + 'template_args' => array( |
|
1586 | + 'empty_cart' => $empty_cart, |
|
1587 | + 'revisit' => $this->checkout->revisit, |
|
1588 | + 'reg_steps' => $this->checkout->reg_steps, |
|
1589 | + 'next_step' => $this->checkout->next_step instanceof EE_SPCO_Reg_Step |
|
1590 | + ? $this->checkout->next_step->slug() |
|
1591 | + : '', |
|
1592 | + 'empty_msg' => apply_filters( |
|
1593 | + 'FHEE__Single_Page_Checkout__display_spco_reg_form__empty_msg', |
|
1594 | + sprintf( |
|
1595 | + esc_html__( |
|
1596 | + 'You need to %1$sReturn to Events list%2$sselect at least one event%3$s before you can proceed with the registration process.', |
|
1597 | + 'event_espresso' |
|
1598 | + ), |
|
1599 | + '<a href="' |
|
1600 | + . get_post_type_archive_link('espresso_events') |
|
1601 | + . '" title="', |
|
1602 | + '">', |
|
1603 | + '</a>' |
|
1604 | + ) |
|
1605 | + ), |
|
1606 | + 'cookies_not_set_msg' => $cookies_not_set_msg, |
|
1607 | + 'registration_time_limit' => $this->checkout->get_registration_time_limit(), |
|
1608 | + 'session_expiration' => gmdate( |
|
1609 | + 'M d, Y H:i:s', |
|
1610 | + EE_Registry::instance()->SSN->expiration() |
|
1611 | + + (get_option('gmt_offset') * HOUR_IN_SECONDS) |
|
1612 | + ), |
|
1613 | + ), |
|
1614 | + ) |
|
1615 | + ), |
|
1616 | + ) |
|
1617 | + ); |
|
1618 | + // load template and add to output sent that gets filtered into the_content() |
|
1619 | + EE_Registry::instance()->REQ->add_output($this->checkout->registration_form->get_html()); |
|
1620 | + } |
|
1621 | + } |
|
1622 | + |
|
1623 | + |
|
1624 | + /** |
|
1625 | + * add_extra_finalize_registration_inputs |
|
1626 | + * |
|
1627 | + * @access public |
|
1628 | + * @param $next_step |
|
1629 | + * @internal param string $label |
|
1630 | + * @return void |
|
1631 | + */ |
|
1632 | + public function add_extra_finalize_registration_inputs($next_step) |
|
1633 | + { |
|
1634 | + if ($next_step === 'finalize_registration') { |
|
1635 | + echo '<div id="spco-extra-finalize_registration-inputs-dv"></div>'; |
|
1636 | + } |
|
1637 | + } |
|
1638 | + |
|
1639 | + |
|
1640 | + /** |
|
1641 | + * display_registration_footer |
|
1642 | + * |
|
1643 | + * @access public |
|
1644 | + * @return string |
|
1645 | + */ |
|
1646 | + public static function display_registration_footer() |
|
1647 | + { |
|
1648 | + if (apply_filters( |
|
1649 | + 'FHEE__EE_Front__Controller__show_reg_footer', |
|
1650 | + EE_Registry::instance()->CFG->admin->show_reg_footer |
|
1651 | + )) { |
|
1652 | + add_filter( |
|
1653 | + 'FHEE__EEH_Template__powered_by_event_espresso__url', |
|
1654 | + function ($url) { |
|
1655 | + return apply_filters('FHEE__EE_Front_Controller__registration_footer__url', $url); |
|
1656 | + } |
|
1657 | + ); |
|
1658 | + echo apply_filters( |
|
1659 | + 'FHEE__EE_Front_Controller__display_registration_footer', |
|
1660 | + \EEH_Template::powered_by_event_espresso( |
|
1661 | + '', |
|
1662 | + 'espresso-registration-footer-dv', |
|
1663 | + array('utm_content' => 'registration_checkout') |
|
1664 | + ) |
|
1665 | + ); |
|
1666 | + } |
|
1667 | + return ''; |
|
1668 | + } |
|
1669 | + |
|
1670 | + |
|
1671 | + /** |
|
1672 | + * unlock_transaction |
|
1673 | + * |
|
1674 | + * @access public |
|
1675 | + * @return void |
|
1676 | + * @throws EE_Error |
|
1677 | + */ |
|
1678 | + public function unlock_transaction() |
|
1679 | + { |
|
1680 | + if ($this->checkout->transaction instanceof EE_Transaction) { |
|
1681 | + $this->checkout->transaction->unlock(); |
|
1682 | + } |
|
1683 | + } |
|
1684 | + |
|
1685 | + |
|
1686 | + /** |
|
1687 | + * _setup_redirect |
|
1688 | + * |
|
1689 | + * @access private |
|
1690 | + * @return void |
|
1691 | + */ |
|
1692 | + private function _setup_redirect() |
|
1693 | + { |
|
1694 | + if ($this->checkout->continue_reg && $this->checkout->next_step instanceof EE_SPCO_Reg_Step) { |
|
1695 | + $this->checkout->redirect = true; |
|
1696 | + if (empty($this->checkout->redirect_url)) { |
|
1697 | + $this->checkout->redirect_url = $this->checkout->next_step->reg_step_url(); |
|
1698 | + } |
|
1699 | + $this->checkout->redirect_url = apply_filters( |
|
1700 | + 'FHEE__EED_Single_Page_Checkout___setup_redirect__checkout_redirect_url', |
|
1701 | + $this->checkout->redirect_url, |
|
1702 | + $this->checkout |
|
1703 | + ); |
|
1704 | + } |
|
1705 | + } |
|
1706 | + |
|
1707 | + |
|
1708 | + /** |
|
1709 | + * handle ajax message responses and redirects |
|
1710 | + * |
|
1711 | + * @access public |
|
1712 | + * @return void |
|
1713 | + * @throws EE_Error |
|
1714 | + */ |
|
1715 | + public function go_to_next_step() |
|
1716 | + { |
|
1717 | + if (EE_Registry::instance()->REQ->ajax) { |
|
1718 | + // capture contents of output buffer we started earlier in the request, and insert into JSON response |
|
1719 | + $this->checkout->json_response->set_unexpected_errors(ob_get_clean()); |
|
1720 | + } |
|
1721 | + $this->unlock_transaction(); |
|
1722 | + // just return for these conditions |
|
1723 | + if ($this->checkout->admin_request |
|
1724 | + || $this->checkout->action === 'redirect_form' |
|
1725 | + || $this->checkout->action === 'update_checkout' |
|
1726 | + ) { |
|
1727 | + return; |
|
1728 | + } |
|
1729 | + // AJAX response |
|
1730 | + $this->_handle_json_response(); |
|
1731 | + // redirect to next step or the Thank You page |
|
1732 | + $this->_handle_html_redirects(); |
|
1733 | + // hmmm... must be something wrong, so let's just display the form again ! |
|
1734 | + $this->_display_spco_reg_form(); |
|
1735 | + } |
|
1736 | + |
|
1737 | + |
|
1738 | + /** |
|
1739 | + * _handle_json_response |
|
1740 | + * |
|
1741 | + * @access protected |
|
1742 | + * @return void |
|
1743 | + */ |
|
1744 | + protected function _handle_json_response() |
|
1745 | + { |
|
1746 | + // if this is an ajax request |
|
1747 | + if (EE_Registry::instance()->REQ->ajax) { |
|
1748 | + $this->checkout->json_response->set_registration_time_limit( |
|
1749 | + $this->checkout->get_registration_time_limit() |
|
1750 | + ); |
|
1751 | + $this->checkout->json_response->set_payment_amount($this->checkout->amount_owing); |
|
1752 | + // just send the ajax ( |
|
1753 | + $json_response = apply_filters( |
|
1754 | + 'FHEE__EE_Single_Page_Checkout__JSON_response', |
|
1755 | + $this->checkout->json_response |
|
1756 | + ); |
|
1757 | + echo $json_response; |
|
1758 | + exit(); |
|
1759 | + } |
|
1760 | + } |
|
1761 | + |
|
1762 | + |
|
1763 | + /** |
|
1764 | + * _handle_redirects |
|
1765 | + * |
|
1766 | + * @access protected |
|
1767 | + * @return void |
|
1768 | + */ |
|
1769 | + protected function _handle_html_redirects() |
|
1770 | + { |
|
1771 | + // going somewhere ? |
|
1772 | + if ($this->checkout->redirect && ! empty($this->checkout->redirect_url)) { |
|
1773 | + // store notices in a transient |
|
1774 | + EE_Error::get_notices(false, true, true); |
|
1775 | + wp_safe_redirect($this->checkout->redirect_url); |
|
1776 | + exit(); |
|
1777 | + } |
|
1778 | + } |
|
1779 | + |
|
1780 | + |
|
1781 | + /** |
|
1782 | + * set_checkout_anchor |
|
1783 | + * |
|
1784 | + * @access public |
|
1785 | + * @return void |
|
1786 | + */ |
|
1787 | + public function set_checkout_anchor() |
|
1788 | + { |
|
1789 | + echo '<a id="checkout" style="float: left; margin-left: -999em;"></a>'; |
|
1790 | + } |
|
1791 | + |
|
1792 | + /** |
|
1793 | + * getRegistrationExpirationNotice |
|
1794 | + * |
|
1795 | + * @since 4.9.59.p |
|
1796 | + * @access public |
|
1797 | + * @return string |
|
1798 | + */ |
|
1799 | + public static function getRegistrationExpirationNotice() |
|
1800 | + { |
|
1801 | + return sprintf( |
|
1802 | + esc_html__( |
|
1803 | + '%1$sWe\'re sorry, but your registration time has expired.%2$s%3$s%4$sIf you still wish to complete your registration, please return to the %5$sEvent List%6$sEvent List%7$s and reselect your tickets if available. Please accept our apologies for any inconvenience this may have caused.%8$s', |
|
1804 | + 'event_espresso' |
|
1805 | + ), |
|
1806 | + '<h4 class="important-notice">', |
|
1807 | + '</h4>', |
|
1808 | + '<br />', |
|
1809 | + '<p>', |
|
1810 | + '<a href="' . get_post_type_archive_link('espresso_events') . '" title="', |
|
1811 | + '">', |
|
1812 | + '</a>', |
|
1813 | + '</p>' |
|
1814 | + ); |
|
1815 | + } |
|
1816 | 1816 | } |
@@ -17,2072 +17,2072 @@ |
||
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 | } |