@@ -33,725 +33,725 @@ |
||
33 | 33 | class DisplayTicketSelector |
34 | 34 | { |
35 | 35 | |
36 | - /** |
|
37 | - * event that ticket selector is being generated for |
|
38 | - * |
|
39 | - * @access protected |
|
40 | - * @var EE_Event $event |
|
41 | - */ |
|
42 | - protected $event; |
|
43 | - |
|
44 | - /** |
|
45 | - * Used to flag when the ticket selector is being called from an external iframe. |
|
46 | - * |
|
47 | - * @var bool $iframe |
|
48 | - */ |
|
49 | - protected $iframe = false; |
|
50 | - |
|
51 | - /** |
|
52 | - * max attendees that can register for event at one time |
|
53 | - * |
|
54 | - * @var int $max_attendees |
|
55 | - */ |
|
56 | - private $max_attendees = EE_INF; |
|
57 | - |
|
58 | - /** |
|
59 | - * @var string $date_format |
|
60 | - */ |
|
61 | - private $date_format; |
|
62 | - |
|
63 | - /** |
|
64 | - * @var string $time_format |
|
65 | - */ |
|
66 | - private $time_format; |
|
67 | - |
|
68 | - /** |
|
69 | - * @var boolean $display_full_ui |
|
70 | - */ |
|
71 | - private $display_full_ui; |
|
72 | - |
|
73 | - |
|
74 | - /** |
|
75 | - * DisplayTicketSelector constructor. |
|
76 | - * |
|
77 | - * @param bool $iframe |
|
78 | - */ |
|
79 | - public function __construct($iframe = false) |
|
80 | - { |
|
81 | - $this->iframe = $iframe; |
|
82 | - $this->date_format = apply_filters( |
|
83 | - 'FHEE__EED_Ticket_Selector__display_ticket_selector__date_format', |
|
84 | - get_option('date_format') |
|
85 | - ); |
|
86 | - $this->time_format = apply_filters( |
|
87 | - 'FHEE__EED_Ticket_Selector__display_ticket_selector__time_format', |
|
88 | - get_option('time_format') |
|
89 | - ); |
|
90 | - } |
|
91 | - |
|
92 | - |
|
93 | - /** |
|
94 | - * @return bool |
|
95 | - */ |
|
96 | - public function isIframe() |
|
97 | - { |
|
98 | - return $this->iframe; |
|
99 | - } |
|
100 | - |
|
101 | - |
|
102 | - /** |
|
103 | - * @param boolean $iframe |
|
104 | - */ |
|
105 | - public function setIframe($iframe = true) |
|
106 | - { |
|
107 | - $this->iframe = filter_var($iframe, FILTER_VALIDATE_BOOLEAN); |
|
108 | - } |
|
109 | - |
|
110 | - |
|
111 | - /** |
|
112 | - * finds and sets the \EE_Event object for use throughout class |
|
113 | - * |
|
114 | - * @param mixed $event |
|
115 | - * @return bool |
|
116 | - * @throws EE_Error |
|
117 | - * @throws InvalidDataTypeException |
|
118 | - * @throws InvalidInterfaceException |
|
119 | - * @throws InvalidArgumentException |
|
120 | - */ |
|
121 | - protected function setEvent($event = null) |
|
122 | - { |
|
123 | - if ($event === null) { |
|
124 | - global $post; |
|
125 | - $event = $post; |
|
126 | - } |
|
127 | - if ($event instanceof EE_Event) { |
|
128 | - $this->event = $event; |
|
129 | - } elseif ($event instanceof WP_Post) { |
|
130 | - if (isset($event->EE_Event) && $event->EE_Event instanceof EE_Event) { |
|
131 | - $this->event = $event->EE_Event; |
|
132 | - } elseif ($event->post_type === 'espresso_events') { |
|
133 | - $event->EE_Event = EEM_Event::instance()->instantiate_class_from_post_object($event); |
|
134 | - $this->event = $event->EE_Event; |
|
135 | - } |
|
136 | - } else { |
|
137 | - $user_msg = __('No Event object or an invalid Event object was supplied.', 'event_espresso'); |
|
138 | - $dev_msg = $user_msg . __( |
|
139 | - '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.', |
|
140 | - 'event_espresso' |
|
141 | - ); |
|
142 | - EE_Error::add_error($user_msg . '||' . $dev_msg, __FILE__, __FUNCTION__, __LINE__); |
|
143 | - return false; |
|
144 | - } |
|
145 | - return true; |
|
146 | - } |
|
147 | - |
|
148 | - |
|
149 | - /** |
|
150 | - * @return int |
|
151 | - */ |
|
152 | - public function getMaxAttendees() |
|
153 | - { |
|
154 | - return $this->max_attendees; |
|
155 | - } |
|
156 | - |
|
157 | - |
|
158 | - /** |
|
159 | - * @param int $max_attendees |
|
160 | - */ |
|
161 | - public function setMaxAttendees($max_attendees) |
|
162 | - { |
|
163 | - $this->max_attendees = absint( |
|
164 | - apply_filters( |
|
165 | - 'FHEE__EE_Ticket_Selector__display_ticket_selector__max_tickets', |
|
166 | - $max_attendees |
|
167 | - ) |
|
168 | - ); |
|
169 | - } |
|
170 | - |
|
171 | - |
|
172 | - /** |
|
173 | - * Returns whether or not the full ticket selector should be shown or not. |
|
174 | - * Currently, it displays on the frontend (including ajax requests) but not the backend |
|
175 | - * |
|
176 | - * @return bool |
|
177 | - */ |
|
178 | - private function display_full_ui() |
|
179 | - { |
|
180 | - if ($this->display_full_ui === null) { |
|
181 | - $this->display_full_ui = ! is_admin() || (defined('DOING_AJAX') && DOING_AJAX); |
|
182 | - } |
|
183 | - return $this->display_full_ui; |
|
184 | - } |
|
185 | - |
|
186 | - |
|
187 | - /** |
|
188 | - * creates buttons for selecting number of attendees for an event |
|
189 | - * |
|
190 | - * @param WP_Post|int $event |
|
191 | - * @param bool $view_details |
|
192 | - * @return string |
|
193 | - * @throws EE_Error |
|
194 | - * @throws InvalidArgumentException |
|
195 | - * @throws InvalidDataTypeException |
|
196 | - * @throws InvalidInterfaceException |
|
197 | - */ |
|
198 | - public function display($event = null, $view_details = false) |
|
199 | - { |
|
200 | - // reset filter for displaying submit button |
|
201 | - remove_filter('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_true'); |
|
202 | - // poke and prod incoming event till it tells us what it is |
|
203 | - if (! $this->setEvent($event)) { |
|
204 | - return false; |
|
205 | - } |
|
206 | - // begin gathering template arguments by getting event status |
|
207 | - $template_args = array('event_status' => $this->event->get_active_status()); |
|
208 | - if ($this->activeEventAndShowTicketSelector( |
|
209 | - $event, |
|
210 | - $template_args['event_status'], |
|
211 | - $view_details |
|
212 | - )) { |
|
213 | - return ! is_single() ? $this->displayViewDetailsButton() : ''; |
|
214 | - } |
|
215 | - // filter the maximum qty that can appear in the Ticket Selector qty dropdowns |
|
216 | - $this->setMaxAttendees($this->event->additional_limit()); |
|
217 | - if ($this->getMaxAttendees() < 1) { |
|
218 | - return $this->ticketSalesClosedMessage(); |
|
219 | - } |
|
220 | - // is the event expired ? |
|
221 | - $template_args['event_is_expired'] = ! is_admin() ? $this->event->is_expired() : false; |
|
222 | - if ($template_args['event_is_expired']) { |
|
223 | - return $this->expiredEventMessage(); |
|
224 | - } |
|
225 | - // get all tickets for this event ordered by the datetime |
|
226 | - $tickets = $this->getTickets(); |
|
227 | - if (count($tickets) < 1) { |
|
228 | - return $this->noTicketAvailableMessage(); |
|
229 | - } |
|
230 | - // redirecting to another site for registration ?? |
|
231 | - $external_url = (string) $this->event->external_url() |
|
232 | - && $this->event->external_url() !== get_the_permalink() |
|
233 | - ? $this->event->external_url() |
|
234 | - : ''; |
|
235 | - // if redirecting to another site for registration, then we don't load the TS |
|
236 | - $ticket_selector = $external_url |
|
237 | - ? $this->externalEventRegistration() |
|
238 | - : $this->loadTicketSelector($tickets, $template_args); |
|
239 | - // now set up the form (but not for the admin) |
|
240 | - $ticket_selector = $this->display_full_ui() |
|
241 | - ? $this->formOpen($this->event->ID(), $external_url) . $ticket_selector |
|
242 | - : $ticket_selector; |
|
243 | - // submit button and form close tag |
|
244 | - $ticket_selector .= $this->display_full_ui() ? $this->displaySubmitButton($external_url) : ''; |
|
245 | - return $ticket_selector; |
|
246 | - } |
|
247 | - |
|
248 | - |
|
249 | - /** |
|
250 | - * displayTicketSelector |
|
251 | - * examines the event properties and determines whether a Ticket Selector should be displayed |
|
252 | - * |
|
253 | - * @param WP_Post|int $event |
|
254 | - * @param string $_event_active_status |
|
255 | - * @param bool $view_details |
|
256 | - * @return bool |
|
257 | - * @throws EE_Error |
|
258 | - */ |
|
259 | - protected function activeEventAndShowTicketSelector($event, $_event_active_status, $view_details) |
|
260 | - { |
|
261 | - $event_post = $this->event instanceof EE_Event ? $this->event->ID() : $event; |
|
262 | - return $this->display_full_ui() |
|
263 | - && ( |
|
264 | - ! $this->event->display_ticket_selector() |
|
265 | - || $view_details |
|
266 | - || post_password_required($event_post) |
|
267 | - || ( |
|
268 | - $_event_active_status !== EE_Datetime::active |
|
269 | - && $_event_active_status !== EE_Datetime::upcoming |
|
270 | - && $_event_active_status !== EE_Datetime::sold_out |
|
271 | - && ! ( |
|
272 | - $_event_active_status === EE_Datetime::inactive |
|
273 | - && is_user_logged_in() |
|
274 | - ) |
|
275 | - ) |
|
276 | - ); |
|
277 | - } |
|
278 | - |
|
279 | - |
|
280 | - /** |
|
281 | - * noTicketAvailableMessage |
|
282 | - * notice displayed if event is expired |
|
283 | - * |
|
284 | - * @return string |
|
285 | - * @throws EE_Error |
|
286 | - */ |
|
287 | - protected function expiredEventMessage() |
|
288 | - { |
|
289 | - return '<div class="ee-event-expired-notice"><span class="important-notice">' . esc_html__( |
|
290 | - 'We\'re sorry, but all tickets sales have ended because the event is expired.', |
|
291 | - 'event_espresso' |
|
292 | - ) . '</span></div><!-- .ee-event-expired-notice -->'; |
|
293 | - } |
|
294 | - |
|
295 | - |
|
296 | - /** |
|
297 | - * noTicketAvailableMessage |
|
298 | - * notice displayed if event has no more tickets available |
|
299 | - * |
|
300 | - * @return string |
|
301 | - * @throws EE_Error |
|
302 | - */ |
|
303 | - protected function noTicketAvailableMessage() |
|
304 | - { |
|
305 | - $no_ticket_available_msg = esc_html__('We\'re sorry, but all ticket sales have ended.', 'event_espresso'); |
|
306 | - if (current_user_can('edit_post', $this->event->ID())) { |
|
307 | - $no_ticket_available_msg .= sprintf( |
|
308 | - esc_html__( |
|
309 | - '%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', |
|
310 | - 'event_espresso' |
|
311 | - ), |
|
312 | - '<div class="ee-attention" style="text-align: left;"><b>', |
|
313 | - '</b><br />', |
|
314 | - '<span class="edit-link"><a class="post-edit-link" href="' |
|
315 | - . get_edit_post_link($this->event->ID()) |
|
316 | - . '">', |
|
317 | - '</a></span></div><!-- .ee-attention noTicketAvailableMessage -->' |
|
318 | - ); |
|
319 | - } |
|
320 | - return ' |
|
36 | + /** |
|
37 | + * event that ticket selector is being generated for |
|
38 | + * |
|
39 | + * @access protected |
|
40 | + * @var EE_Event $event |
|
41 | + */ |
|
42 | + protected $event; |
|
43 | + |
|
44 | + /** |
|
45 | + * Used to flag when the ticket selector is being called from an external iframe. |
|
46 | + * |
|
47 | + * @var bool $iframe |
|
48 | + */ |
|
49 | + protected $iframe = false; |
|
50 | + |
|
51 | + /** |
|
52 | + * max attendees that can register for event at one time |
|
53 | + * |
|
54 | + * @var int $max_attendees |
|
55 | + */ |
|
56 | + private $max_attendees = EE_INF; |
|
57 | + |
|
58 | + /** |
|
59 | + * @var string $date_format |
|
60 | + */ |
|
61 | + private $date_format; |
|
62 | + |
|
63 | + /** |
|
64 | + * @var string $time_format |
|
65 | + */ |
|
66 | + private $time_format; |
|
67 | + |
|
68 | + /** |
|
69 | + * @var boolean $display_full_ui |
|
70 | + */ |
|
71 | + private $display_full_ui; |
|
72 | + |
|
73 | + |
|
74 | + /** |
|
75 | + * DisplayTicketSelector constructor. |
|
76 | + * |
|
77 | + * @param bool $iframe |
|
78 | + */ |
|
79 | + public function __construct($iframe = false) |
|
80 | + { |
|
81 | + $this->iframe = $iframe; |
|
82 | + $this->date_format = apply_filters( |
|
83 | + 'FHEE__EED_Ticket_Selector__display_ticket_selector__date_format', |
|
84 | + get_option('date_format') |
|
85 | + ); |
|
86 | + $this->time_format = apply_filters( |
|
87 | + 'FHEE__EED_Ticket_Selector__display_ticket_selector__time_format', |
|
88 | + get_option('time_format') |
|
89 | + ); |
|
90 | + } |
|
91 | + |
|
92 | + |
|
93 | + /** |
|
94 | + * @return bool |
|
95 | + */ |
|
96 | + public function isIframe() |
|
97 | + { |
|
98 | + return $this->iframe; |
|
99 | + } |
|
100 | + |
|
101 | + |
|
102 | + /** |
|
103 | + * @param boolean $iframe |
|
104 | + */ |
|
105 | + public function setIframe($iframe = true) |
|
106 | + { |
|
107 | + $this->iframe = filter_var($iframe, FILTER_VALIDATE_BOOLEAN); |
|
108 | + } |
|
109 | + |
|
110 | + |
|
111 | + /** |
|
112 | + * finds and sets the \EE_Event object for use throughout class |
|
113 | + * |
|
114 | + * @param mixed $event |
|
115 | + * @return bool |
|
116 | + * @throws EE_Error |
|
117 | + * @throws InvalidDataTypeException |
|
118 | + * @throws InvalidInterfaceException |
|
119 | + * @throws InvalidArgumentException |
|
120 | + */ |
|
121 | + protected function setEvent($event = null) |
|
122 | + { |
|
123 | + if ($event === null) { |
|
124 | + global $post; |
|
125 | + $event = $post; |
|
126 | + } |
|
127 | + if ($event instanceof EE_Event) { |
|
128 | + $this->event = $event; |
|
129 | + } elseif ($event instanceof WP_Post) { |
|
130 | + if (isset($event->EE_Event) && $event->EE_Event instanceof EE_Event) { |
|
131 | + $this->event = $event->EE_Event; |
|
132 | + } elseif ($event->post_type === 'espresso_events') { |
|
133 | + $event->EE_Event = EEM_Event::instance()->instantiate_class_from_post_object($event); |
|
134 | + $this->event = $event->EE_Event; |
|
135 | + } |
|
136 | + } else { |
|
137 | + $user_msg = __('No Event object or an invalid Event object was supplied.', 'event_espresso'); |
|
138 | + $dev_msg = $user_msg . __( |
|
139 | + '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.', |
|
140 | + 'event_espresso' |
|
141 | + ); |
|
142 | + EE_Error::add_error($user_msg . '||' . $dev_msg, __FILE__, __FUNCTION__, __LINE__); |
|
143 | + return false; |
|
144 | + } |
|
145 | + return true; |
|
146 | + } |
|
147 | + |
|
148 | + |
|
149 | + /** |
|
150 | + * @return int |
|
151 | + */ |
|
152 | + public function getMaxAttendees() |
|
153 | + { |
|
154 | + return $this->max_attendees; |
|
155 | + } |
|
156 | + |
|
157 | + |
|
158 | + /** |
|
159 | + * @param int $max_attendees |
|
160 | + */ |
|
161 | + public function setMaxAttendees($max_attendees) |
|
162 | + { |
|
163 | + $this->max_attendees = absint( |
|
164 | + apply_filters( |
|
165 | + 'FHEE__EE_Ticket_Selector__display_ticket_selector__max_tickets', |
|
166 | + $max_attendees |
|
167 | + ) |
|
168 | + ); |
|
169 | + } |
|
170 | + |
|
171 | + |
|
172 | + /** |
|
173 | + * Returns whether or not the full ticket selector should be shown or not. |
|
174 | + * Currently, it displays on the frontend (including ajax requests) but not the backend |
|
175 | + * |
|
176 | + * @return bool |
|
177 | + */ |
|
178 | + private function display_full_ui() |
|
179 | + { |
|
180 | + if ($this->display_full_ui === null) { |
|
181 | + $this->display_full_ui = ! is_admin() || (defined('DOING_AJAX') && DOING_AJAX); |
|
182 | + } |
|
183 | + return $this->display_full_ui; |
|
184 | + } |
|
185 | + |
|
186 | + |
|
187 | + /** |
|
188 | + * creates buttons for selecting number of attendees for an event |
|
189 | + * |
|
190 | + * @param WP_Post|int $event |
|
191 | + * @param bool $view_details |
|
192 | + * @return string |
|
193 | + * @throws EE_Error |
|
194 | + * @throws InvalidArgumentException |
|
195 | + * @throws InvalidDataTypeException |
|
196 | + * @throws InvalidInterfaceException |
|
197 | + */ |
|
198 | + public function display($event = null, $view_details = false) |
|
199 | + { |
|
200 | + // reset filter for displaying submit button |
|
201 | + remove_filter('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_true'); |
|
202 | + // poke and prod incoming event till it tells us what it is |
|
203 | + if (! $this->setEvent($event)) { |
|
204 | + return false; |
|
205 | + } |
|
206 | + // begin gathering template arguments by getting event status |
|
207 | + $template_args = array('event_status' => $this->event->get_active_status()); |
|
208 | + if ($this->activeEventAndShowTicketSelector( |
|
209 | + $event, |
|
210 | + $template_args['event_status'], |
|
211 | + $view_details |
|
212 | + )) { |
|
213 | + return ! is_single() ? $this->displayViewDetailsButton() : ''; |
|
214 | + } |
|
215 | + // filter the maximum qty that can appear in the Ticket Selector qty dropdowns |
|
216 | + $this->setMaxAttendees($this->event->additional_limit()); |
|
217 | + if ($this->getMaxAttendees() < 1) { |
|
218 | + return $this->ticketSalesClosedMessage(); |
|
219 | + } |
|
220 | + // is the event expired ? |
|
221 | + $template_args['event_is_expired'] = ! is_admin() ? $this->event->is_expired() : false; |
|
222 | + if ($template_args['event_is_expired']) { |
|
223 | + return $this->expiredEventMessage(); |
|
224 | + } |
|
225 | + // get all tickets for this event ordered by the datetime |
|
226 | + $tickets = $this->getTickets(); |
|
227 | + if (count($tickets) < 1) { |
|
228 | + return $this->noTicketAvailableMessage(); |
|
229 | + } |
|
230 | + // redirecting to another site for registration ?? |
|
231 | + $external_url = (string) $this->event->external_url() |
|
232 | + && $this->event->external_url() !== get_the_permalink() |
|
233 | + ? $this->event->external_url() |
|
234 | + : ''; |
|
235 | + // if redirecting to another site for registration, then we don't load the TS |
|
236 | + $ticket_selector = $external_url |
|
237 | + ? $this->externalEventRegistration() |
|
238 | + : $this->loadTicketSelector($tickets, $template_args); |
|
239 | + // now set up the form (but not for the admin) |
|
240 | + $ticket_selector = $this->display_full_ui() |
|
241 | + ? $this->formOpen($this->event->ID(), $external_url) . $ticket_selector |
|
242 | + : $ticket_selector; |
|
243 | + // submit button and form close tag |
|
244 | + $ticket_selector .= $this->display_full_ui() ? $this->displaySubmitButton($external_url) : ''; |
|
245 | + return $ticket_selector; |
|
246 | + } |
|
247 | + |
|
248 | + |
|
249 | + /** |
|
250 | + * displayTicketSelector |
|
251 | + * examines the event properties and determines whether a Ticket Selector should be displayed |
|
252 | + * |
|
253 | + * @param WP_Post|int $event |
|
254 | + * @param string $_event_active_status |
|
255 | + * @param bool $view_details |
|
256 | + * @return bool |
|
257 | + * @throws EE_Error |
|
258 | + */ |
|
259 | + protected function activeEventAndShowTicketSelector($event, $_event_active_status, $view_details) |
|
260 | + { |
|
261 | + $event_post = $this->event instanceof EE_Event ? $this->event->ID() : $event; |
|
262 | + return $this->display_full_ui() |
|
263 | + && ( |
|
264 | + ! $this->event->display_ticket_selector() |
|
265 | + || $view_details |
|
266 | + || post_password_required($event_post) |
|
267 | + || ( |
|
268 | + $_event_active_status !== EE_Datetime::active |
|
269 | + && $_event_active_status !== EE_Datetime::upcoming |
|
270 | + && $_event_active_status !== EE_Datetime::sold_out |
|
271 | + && ! ( |
|
272 | + $_event_active_status === EE_Datetime::inactive |
|
273 | + && is_user_logged_in() |
|
274 | + ) |
|
275 | + ) |
|
276 | + ); |
|
277 | + } |
|
278 | + |
|
279 | + |
|
280 | + /** |
|
281 | + * noTicketAvailableMessage |
|
282 | + * notice displayed if event is expired |
|
283 | + * |
|
284 | + * @return string |
|
285 | + * @throws EE_Error |
|
286 | + */ |
|
287 | + protected function expiredEventMessage() |
|
288 | + { |
|
289 | + return '<div class="ee-event-expired-notice"><span class="important-notice">' . esc_html__( |
|
290 | + 'We\'re sorry, but all tickets sales have ended because the event is expired.', |
|
291 | + 'event_espresso' |
|
292 | + ) . '</span></div><!-- .ee-event-expired-notice -->'; |
|
293 | + } |
|
294 | + |
|
295 | + |
|
296 | + /** |
|
297 | + * noTicketAvailableMessage |
|
298 | + * notice displayed if event has no more tickets available |
|
299 | + * |
|
300 | + * @return string |
|
301 | + * @throws EE_Error |
|
302 | + */ |
|
303 | + protected function noTicketAvailableMessage() |
|
304 | + { |
|
305 | + $no_ticket_available_msg = esc_html__('We\'re sorry, but all ticket sales have ended.', 'event_espresso'); |
|
306 | + if (current_user_can('edit_post', $this->event->ID())) { |
|
307 | + $no_ticket_available_msg .= sprintf( |
|
308 | + esc_html__( |
|
309 | + '%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', |
|
310 | + 'event_espresso' |
|
311 | + ), |
|
312 | + '<div class="ee-attention" style="text-align: left;"><b>', |
|
313 | + '</b><br />', |
|
314 | + '<span class="edit-link"><a class="post-edit-link" href="' |
|
315 | + . get_edit_post_link($this->event->ID()) |
|
316 | + . '">', |
|
317 | + '</a></span></div><!-- .ee-attention noTicketAvailableMessage -->' |
|
318 | + ); |
|
319 | + } |
|
320 | + return ' |
|
321 | 321 | <div class="ee-event-expired-notice"> |
322 | 322 | <span class="important-notice">' . $no_ticket_available_msg . '</span> |
323 | 323 | </div><!-- .ee-event-expired-notice -->'; |
324 | - } |
|
325 | - |
|
326 | - |
|
327 | - /** |
|
328 | - * ticketSalesClosed |
|
329 | - * notice displayed if event ticket sales are turned off |
|
330 | - * |
|
331 | - * @return string |
|
332 | - * @throws EE_Error |
|
333 | - */ |
|
334 | - protected function ticketSalesClosedMessage() |
|
335 | - { |
|
336 | - $sales_closed_msg = esc_html__( |
|
337 | - 'We\'re sorry, but ticket sales have been closed at this time. Please check back again later.', |
|
338 | - 'event_espresso' |
|
339 | - ); |
|
340 | - if (current_user_can('edit_post', $this->event->ID())) { |
|
341 | - $sales_closed_msg .= sprintf( |
|
342 | - esc_html__( |
|
343 | - '%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', |
|
344 | - 'event_espresso' |
|
345 | - ), |
|
346 | - '<div class="ee-attention" style="text-align: left;"><b>', |
|
347 | - '</b><br />', |
|
348 | - '<span class="edit-link"><a class="post-edit-link" href="' |
|
349 | - . get_edit_post_link($this->event->ID()) |
|
350 | - . '">', |
|
351 | - '</a></span></div><!-- .ee-attention ticketSalesClosedMessage -->' |
|
352 | - ); |
|
353 | - } |
|
354 | - return '<p><span class="important-notice">' . $sales_closed_msg . '</span></p>'; |
|
355 | - } |
|
356 | - |
|
357 | - |
|
358 | - /** |
|
359 | - * getTickets |
|
360 | - * |
|
361 | - * @return \EE_Base_Class[]|\EE_Ticket[] |
|
362 | - * @throws EE_Error |
|
363 | - * @throws InvalidDataTypeException |
|
364 | - * @throws InvalidInterfaceException |
|
365 | - * @throws InvalidArgumentException |
|
366 | - */ |
|
367 | - protected function getTickets() |
|
368 | - { |
|
369 | - $show_expired_tickets = is_admin() || ( |
|
370 | - EE_Registry::instance()->CFG->template_settings->EED_Ticket_Selector instanceof EE_Ticket_Selector_Config |
|
371 | - && EE_Registry::instance()->CFG->template_settings->EED_Ticket_Selector->show_expired_tickets |
|
372 | - ); |
|
373 | - |
|
374 | - $ticket_query_args = array( |
|
375 | - array('Datetime.EVT_ID' => $this->event->ID()), |
|
376 | - 'order_by' => array( |
|
377 | - 'TKT_order' => 'ASC', |
|
378 | - 'TKT_required' => 'DESC', |
|
379 | - 'TKT_start_date' => 'ASC', |
|
380 | - 'TKT_end_date' => 'ASC', |
|
381 | - 'Datetime.DTT_EVT_start' => 'DESC', |
|
382 | - ), |
|
383 | - ); |
|
384 | - if (! $show_expired_tickets) { |
|
385 | - // use the correct applicable time query depending on what version of core is being run. |
|
386 | - $current_time = method_exists('EEM_Datetime', 'current_time_for_query') |
|
387 | - ? time() |
|
388 | - : current_time('timestamp'); |
|
389 | - $ticket_query_args[0]['TKT_end_date'] = array('>', $current_time); |
|
390 | - } |
|
391 | - return EEM_Ticket::instance()->get_all($ticket_query_args); |
|
392 | - } |
|
393 | - |
|
394 | - |
|
395 | - /** |
|
396 | - * loadTicketSelector |
|
397 | - * begins to assemble template arguments |
|
398 | - * and decides whether to load a "simple" ticket selector, or the standard |
|
399 | - * |
|
400 | - * @param \EE_Ticket[] $tickets |
|
401 | - * @param array $template_args |
|
402 | - * @return string |
|
403 | - * @throws EE_Error |
|
404 | - */ |
|
405 | - protected function loadTicketSelector(array $tickets, array $template_args) |
|
406 | - { |
|
407 | - $template_args['event'] = $this->event; |
|
408 | - $template_args['EVT_ID'] = $this->event->ID(); |
|
409 | - $template_args['event_is_expired'] = $this->event->is_expired(); |
|
410 | - $template_args['max_atndz'] = $this->getMaxAttendees(); |
|
411 | - $template_args['date_format'] = $this->date_format; |
|
412 | - $template_args['time_format'] = $this->time_format; |
|
413 | - /** |
|
414 | - * Filters the anchor ID used when redirecting to the Ticket Selector if no quantity selected |
|
415 | - * |
|
416 | - * @since 4.9.13 |
|
417 | - * @param string '#tkt-slctr-tbl-' . $EVT_ID The html ID to anchor to |
|
418 | - * @param int $EVT_ID The Event ID |
|
419 | - */ |
|
420 | - $template_args['anchor_id'] = apply_filters( |
|
421 | - 'FHEE__EE_Ticket_Selector__redirect_anchor_id', |
|
422 | - '#tkt-slctr-tbl-' . $this->event->ID(), |
|
423 | - $this->event->ID() |
|
424 | - ); |
|
425 | - $template_args['tickets'] = $tickets; |
|
426 | - $template_args['ticket_count'] = count($tickets); |
|
427 | - $ticket_selector = $this->simpleTicketSelector($tickets, $template_args); |
|
428 | - return $ticket_selector instanceof TicketSelectorSimple |
|
429 | - ? $ticket_selector |
|
430 | - : new TicketSelectorStandard( |
|
431 | - $this->event, |
|
432 | - $tickets, |
|
433 | - $this->getMaxAttendees(), |
|
434 | - $template_args, |
|
435 | - $this->date_format, |
|
436 | - $this->time_format |
|
437 | - ); |
|
438 | - } |
|
439 | - |
|
440 | - |
|
441 | - /** |
|
442 | - * simpleTicketSelector |
|
443 | - * there's one ticket, and max attendees is set to one, |
|
444 | - * so if the event is free, then this is a "simple" ticket selector |
|
445 | - * a.k.a. "Dude Where's my Ticket Selector?" |
|
446 | - * |
|
447 | - * @param \EE_Ticket[] $tickets |
|
448 | - * @param array $template_args |
|
449 | - * @return string |
|
450 | - * @throws EE_Error |
|
451 | - */ |
|
452 | - protected function simpleTicketSelector($tickets, array $template_args) |
|
453 | - { |
|
454 | - // if there is only ONE ticket with a max qty of ONE |
|
455 | - if (count($tickets) > 1 || $this->getMaxAttendees() !== 1) { |
|
456 | - return ''; |
|
457 | - } |
|
458 | - /** @var \EE_Ticket $ticket */ |
|
459 | - $ticket = reset($tickets); |
|
460 | - // if the ticket is free... then not much need for the ticket selector |
|
461 | - if (apply_filters( |
|
462 | - 'FHEE__ticket_selector_chart_template__hide_ticket_selector', |
|
463 | - $ticket->is_free(), |
|
464 | - $this->event->ID() |
|
465 | - )) { |
|
466 | - return new TicketSelectorSimple( |
|
467 | - $this->event, |
|
468 | - $ticket, |
|
469 | - $this->getMaxAttendees(), |
|
470 | - $template_args |
|
471 | - ); |
|
472 | - } |
|
473 | - return ''; |
|
474 | - } |
|
475 | - |
|
476 | - |
|
477 | - /** |
|
478 | - * externalEventRegistration |
|
479 | - * |
|
480 | - * @return string |
|
481 | - */ |
|
482 | - public function externalEventRegistration() |
|
483 | - { |
|
484 | - // if not we still need to trigger the display of the submit button |
|
485 | - add_filter('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_true'); |
|
486 | - // display notice to admin that registration is external |
|
487 | - return $this->display_full_ui() |
|
488 | - ? esc_html__( |
|
489 | - 'Registration is at an external URL for this event.', |
|
490 | - 'event_espresso' |
|
491 | - ) |
|
492 | - : ''; |
|
493 | - } |
|
494 | - |
|
495 | - |
|
496 | - /** |
|
497 | - * formOpen |
|
498 | - * |
|
499 | - * @param int $ID |
|
500 | - * @param string $external_url |
|
501 | - * @return string |
|
502 | - */ |
|
503 | - public function formOpen($ID = 0, $external_url = '') |
|
504 | - { |
|
505 | - // if redirecting, we don't need any anything else |
|
506 | - if ($external_url) { |
|
507 | - $html = '<form method="GET" '; |
|
508 | - $html .= 'action="' . EEH_URL::refactor_url($external_url) . '" '; |
|
509 | - $html .= 'name="ticket-selector-form-' . $ID . '"'; |
|
510 | - // open link in new window ? |
|
511 | - $html .= apply_filters( |
|
512 | - 'FHEE__EventEspresso_modules_ticket_selector_DisplayTicketSelector__formOpen__external_url_target_blank', |
|
513 | - $this->isIframe(), |
|
514 | - $this |
|
515 | - ) |
|
516 | - ? ' target="_blank"' |
|
517 | - : ''; |
|
518 | - $html .= '>'; |
|
519 | - $query_args = EEH_URL::get_query_string($external_url); |
|
520 | - foreach ((array) $query_args as $query_arg => $value) { |
|
521 | - $html .= '<input type="hidden" name="' . $query_arg . '" value="' . $value . '">'; |
|
522 | - } |
|
523 | - return $html; |
|
524 | - } |
|
525 | - // if there is no submit button, then don't start building a form |
|
526 | - // because the "View Details" button will build its own form |
|
527 | - if (! apply_filters('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', false)) { |
|
528 | - return ''; |
|
529 | - } |
|
530 | - $checkout_url = EEH_Event_View::event_link_url($ID); |
|
531 | - if (! $checkout_url) { |
|
532 | - EE_Error::add_error( |
|
533 | - esc_html__('The URL for the Event Details page could not be retrieved.', 'event_espresso'), |
|
534 | - __FILE__, |
|
535 | - __FUNCTION__, |
|
536 | - __LINE__ |
|
537 | - ); |
|
538 | - } |
|
539 | - // set no cache headers and constants |
|
540 | - EE_System::do_not_cache(); |
|
541 | - $html = '<form method="POST" '; |
|
542 | - $html .= 'action="' . $checkout_url . '" '; |
|
543 | - $html .= 'name="ticket-selector-form-' . $ID . '"'; |
|
544 | - $html .= $this->iframe ? ' target="_blank"' : ''; |
|
545 | - $html .= '>'; |
|
546 | - $html .= '<input type="hidden" name="ee" value="process_ticket_selections">'; |
|
547 | - $html = apply_filters('FHEE__EE_Ticket_Selector__ticket_selector_form_open__html', $html, $this->event); |
|
548 | - return $html; |
|
549 | - } |
|
550 | - |
|
551 | - |
|
552 | - /** |
|
553 | - * displaySubmitButton |
|
554 | - * |
|
555 | - * @param string $external_url |
|
556 | - * @return string |
|
557 | - * @throws EE_Error |
|
558 | - */ |
|
559 | - public function displaySubmitButton($external_url = '') |
|
560 | - { |
|
561 | - $html = ''; |
|
562 | - if ($this->display_full_ui()) { |
|
563 | - // standard TS displayed with submit button, ie: "Register Now" |
|
564 | - if (apply_filters('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', false)) { |
|
565 | - $html .= $this->displayRegisterNowButton(); |
|
566 | - $html .= empty($external_url) |
|
567 | - ? $this->ticketSelectorEndDiv() |
|
568 | - : $this->clearTicketSelector(); |
|
569 | - $html .= '<br/>' . $this->formClose(); |
|
570 | - } elseif ($this->getMaxAttendees() === 1) { |
|
571 | - // its a "Dude Where's my Ticket Selector?" (DWMTS) type event (ie: $_max_atndz === 1) |
|
572 | - if ($this->event->is_sold_out()) { |
|
573 | - // then instead of a View Details or Submit button, just display a "Sold Out" message |
|
574 | - $html .= apply_filters( |
|
575 | - 'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__sold_out_msg', |
|
576 | - sprintf( |
|
577 | - __( |
|
578 | - '%1$s"%2$s" is currently sold out.%4$sPlease check back again later, as spots may become available.%3$s', |
|
579 | - 'event_espresso' |
|
580 | - ), |
|
581 | - '<p class="no-ticket-selector-msg clear-float">', |
|
582 | - $this->event->name(), |
|
583 | - '</p>', |
|
584 | - '<br />' |
|
585 | - ), |
|
586 | - $this->event |
|
587 | - ); |
|
588 | - if (apply_filters( |
|
589 | - 'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__no_tickets_but_display_register_now_button', |
|
590 | - false, |
|
591 | - $this->event |
|
592 | - )) { |
|
593 | - $html .= $this->displayRegisterNowButton(); |
|
594 | - } |
|
595 | - // sold out DWMTS event, no TS, no submit or view details button, but has additional content |
|
596 | - $html .= $this->ticketSelectorEndDiv(); |
|
597 | - } elseif (apply_filters('FHEE__EE_Ticket_Selector__hide_ticket_selector', false) |
|
598 | - && ! is_single() |
|
599 | - ) { |
|
600 | - // this is a "Dude Where's my Ticket Selector?" (DWMTS) type event, |
|
601 | - // but no tickets are available, so display event's "View Details" button. |
|
602 | - // it is being viewed via somewhere other than a single post |
|
603 | - $html .= $this->displayViewDetailsButton(true); |
|
604 | - } else { |
|
605 | - $html .= $this->ticketSelectorEndDiv(); |
|
606 | - } |
|
607 | - } elseif (is_archive()) { |
|
608 | - // event list, no tickets available so display event's "View Details" button |
|
609 | - $html .= $this->ticketSelectorEndDiv(); |
|
610 | - $html .= $this->displayViewDetailsButton(); |
|
611 | - } else { |
|
612 | - if (apply_filters( |
|
613 | - 'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__no_tickets_but_display_register_now_button', |
|
614 | - false, |
|
615 | - $this->event |
|
616 | - )) { |
|
617 | - $html .= $this->displayRegisterNowButton(); |
|
618 | - } |
|
619 | - // no submit or view details button, and no additional content |
|
620 | - $html .= $this->ticketSelectorEndDiv(); |
|
621 | - } |
|
622 | - if (! $this->iframe && ! is_archive()) { |
|
623 | - $html .= EEH_Template::powered_by_event_espresso('', '', array('utm_content' => 'ticket_selector')); |
|
624 | - } |
|
625 | - } |
|
626 | - return apply_filters( |
|
627 | - 'FHEE__EventEspresso_modules_ticket_selector_DisplayTicketSelector__displaySubmitButton__html', |
|
628 | - $html, |
|
629 | - $this->event, |
|
630 | - $this |
|
631 | - ); |
|
632 | - } |
|
633 | - |
|
634 | - |
|
635 | - /** |
|
636 | - * @return string |
|
637 | - * @throws EE_Error |
|
638 | - */ |
|
639 | - public function displayRegisterNowButton() |
|
640 | - { |
|
641 | - $btn_text = apply_filters( |
|
642 | - 'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__btn_text', |
|
643 | - __('Register Now', 'event_espresso'), |
|
644 | - $this->event |
|
645 | - ); |
|
646 | - $external_url = (string) $this->event->external_url() |
|
647 | - && $this->event->external_url() !== get_the_permalink() |
|
648 | - ? $this->event->external_url() |
|
649 | - : ''; |
|
650 | - $html = EEH_HTML::div( |
|
651 | - '', |
|
652 | - 'ticket-selector-submit-' . $this->event->ID() . '-btn-wrap', |
|
653 | - 'ticket-selector-submit-btn-wrap' |
|
654 | - ); |
|
655 | - $html .= '<input id="ticket-selector-submit-' . $this->event->ID() . '-btn"'; |
|
656 | - $html .= ' class="ticket-selector-submit-btn '; |
|
657 | - $html .= empty($external_url) ? 'ticket-selector-submit-ajax"' : '"'; |
|
658 | - $html .= ' type="submit" value="' . $btn_text . '" />'; |
|
659 | - $html .= EEH_HTML::divx() . '<!-- .ticket-selector-submit-btn-wrap -->'; |
|
660 | - $html .= apply_filters( |
|
661 | - 'FHEE__EE_Ticket_Selector__after_ticket_selector_submit', |
|
662 | - '', |
|
663 | - $this->event, |
|
664 | - $this->iframe |
|
665 | - ); |
|
666 | - return $html; |
|
667 | - } |
|
668 | - |
|
669 | - |
|
670 | - /** |
|
671 | - * displayViewDetailsButton |
|
672 | - * |
|
673 | - * @param bool $DWMTS indicates a "Dude Where's my Ticket Selector?" (DWMTS) type event |
|
674 | - * (ie: $_max_atndz === 1) where there are no available tickets, |
|
675 | - * either because they are sold out, expired, or not yet on sale. |
|
676 | - * In this case, we need to close the form BEFORE adding any closing divs |
|
677 | - * @return string |
|
678 | - * @throws EE_Error |
|
679 | - */ |
|
680 | - public function displayViewDetailsButton($DWMTS = false) |
|
681 | - { |
|
682 | - if (! $this->event->get_permalink()) { |
|
683 | - EE_Error::add_error( |
|
684 | - esc_html__('The URL for the Event Details page could not be retrieved.', 'event_espresso'), |
|
685 | - __FILE__, |
|
686 | - __FUNCTION__, |
|
687 | - __LINE__ |
|
688 | - ); |
|
689 | - } |
|
690 | - $view_details_btn = '<form method="POST" action="'; |
|
691 | - $view_details_btn .= apply_filters( |
|
692 | - 'FHEE__EE_Ticket_Selector__display_view_details_btn__btn_url', |
|
693 | - $this->event->get_permalink(), |
|
694 | - $this->event |
|
695 | - ); |
|
696 | - $view_details_btn .= '"'; |
|
697 | - // open link in new window ? |
|
698 | - $view_details_btn .= apply_filters( |
|
699 | - 'FHEE__EventEspresso_modules_ticket_selector_DisplayTicketSelector__displayViewDetailsButton__url_target_blank', |
|
700 | - $this->isIframe(), |
|
701 | - $this |
|
702 | - ) |
|
703 | - ? ' target="_blank"' |
|
704 | - : ''; |
|
705 | - $view_details_btn .= '>'; |
|
706 | - $btn_text = apply_filters( |
|
707 | - 'FHEE__EE_Ticket_Selector__display_view_details_btn__btn_text', |
|
708 | - esc_html__('View Details', 'event_espresso'), |
|
709 | - $this->event |
|
710 | - ); |
|
711 | - $view_details_btn .= '<input id="ticket-selector-submit-' |
|
712 | - . $this->event->ID() |
|
713 | - . '-btn" class="ticket-selector-submit-btn view-details-btn" type="submit" value="' |
|
714 | - . $btn_text |
|
715 | - . '" />'; |
|
716 | - $view_details_btn .= apply_filters('FHEE__EE_Ticket_Selector__after_view_details_btn', '', $this->event); |
|
717 | - if ($DWMTS) { |
|
718 | - $view_details_btn .= $this->formClose(); |
|
719 | - $view_details_btn .= $this->ticketSelectorEndDiv(); |
|
720 | - $view_details_btn .= '<br/>'; |
|
721 | - } else { |
|
722 | - $view_details_btn .= $this->clearTicketSelector(); |
|
723 | - $view_details_btn .= '<br/>'; |
|
724 | - $view_details_btn .= $this->formClose(); |
|
725 | - } |
|
726 | - return $view_details_btn; |
|
727 | - } |
|
728 | - |
|
729 | - |
|
730 | - /** |
|
731 | - * @return string |
|
732 | - */ |
|
733 | - public function ticketSelectorEndDiv() |
|
734 | - { |
|
735 | - return $this->clearTicketSelector() . '</div><!-- ticketSelectorEndDiv -->'; |
|
736 | - } |
|
737 | - |
|
738 | - |
|
739 | - /** |
|
740 | - * @return string |
|
741 | - */ |
|
742 | - public function clearTicketSelector() |
|
743 | - { |
|
744 | - // standard TS displayed, appears after a "Register Now" or "view Details" button |
|
745 | - return '<div class="clear"></div><!-- clearTicketSelector -->'; |
|
746 | - } |
|
747 | - |
|
748 | - |
|
749 | - /** |
|
750 | - * @access public |
|
751 | - * @return string |
|
752 | - */ |
|
753 | - public function formClose() |
|
754 | - { |
|
755 | - return '</form>'; |
|
756 | - } |
|
324 | + } |
|
325 | + |
|
326 | + |
|
327 | + /** |
|
328 | + * ticketSalesClosed |
|
329 | + * notice displayed if event ticket sales are turned off |
|
330 | + * |
|
331 | + * @return string |
|
332 | + * @throws EE_Error |
|
333 | + */ |
|
334 | + protected function ticketSalesClosedMessage() |
|
335 | + { |
|
336 | + $sales_closed_msg = esc_html__( |
|
337 | + 'We\'re sorry, but ticket sales have been closed at this time. Please check back again later.', |
|
338 | + 'event_espresso' |
|
339 | + ); |
|
340 | + if (current_user_can('edit_post', $this->event->ID())) { |
|
341 | + $sales_closed_msg .= sprintf( |
|
342 | + esc_html__( |
|
343 | + '%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', |
|
344 | + 'event_espresso' |
|
345 | + ), |
|
346 | + '<div class="ee-attention" style="text-align: left;"><b>', |
|
347 | + '</b><br />', |
|
348 | + '<span class="edit-link"><a class="post-edit-link" href="' |
|
349 | + . get_edit_post_link($this->event->ID()) |
|
350 | + . '">', |
|
351 | + '</a></span></div><!-- .ee-attention ticketSalesClosedMessage -->' |
|
352 | + ); |
|
353 | + } |
|
354 | + return '<p><span class="important-notice">' . $sales_closed_msg . '</span></p>'; |
|
355 | + } |
|
356 | + |
|
357 | + |
|
358 | + /** |
|
359 | + * getTickets |
|
360 | + * |
|
361 | + * @return \EE_Base_Class[]|\EE_Ticket[] |
|
362 | + * @throws EE_Error |
|
363 | + * @throws InvalidDataTypeException |
|
364 | + * @throws InvalidInterfaceException |
|
365 | + * @throws InvalidArgumentException |
|
366 | + */ |
|
367 | + protected function getTickets() |
|
368 | + { |
|
369 | + $show_expired_tickets = is_admin() || ( |
|
370 | + EE_Registry::instance()->CFG->template_settings->EED_Ticket_Selector instanceof EE_Ticket_Selector_Config |
|
371 | + && EE_Registry::instance()->CFG->template_settings->EED_Ticket_Selector->show_expired_tickets |
|
372 | + ); |
|
373 | + |
|
374 | + $ticket_query_args = array( |
|
375 | + array('Datetime.EVT_ID' => $this->event->ID()), |
|
376 | + 'order_by' => array( |
|
377 | + 'TKT_order' => 'ASC', |
|
378 | + 'TKT_required' => 'DESC', |
|
379 | + 'TKT_start_date' => 'ASC', |
|
380 | + 'TKT_end_date' => 'ASC', |
|
381 | + 'Datetime.DTT_EVT_start' => 'DESC', |
|
382 | + ), |
|
383 | + ); |
|
384 | + if (! $show_expired_tickets) { |
|
385 | + // use the correct applicable time query depending on what version of core is being run. |
|
386 | + $current_time = method_exists('EEM_Datetime', 'current_time_for_query') |
|
387 | + ? time() |
|
388 | + : current_time('timestamp'); |
|
389 | + $ticket_query_args[0]['TKT_end_date'] = array('>', $current_time); |
|
390 | + } |
|
391 | + return EEM_Ticket::instance()->get_all($ticket_query_args); |
|
392 | + } |
|
393 | + |
|
394 | + |
|
395 | + /** |
|
396 | + * loadTicketSelector |
|
397 | + * begins to assemble template arguments |
|
398 | + * and decides whether to load a "simple" ticket selector, or the standard |
|
399 | + * |
|
400 | + * @param \EE_Ticket[] $tickets |
|
401 | + * @param array $template_args |
|
402 | + * @return string |
|
403 | + * @throws EE_Error |
|
404 | + */ |
|
405 | + protected function loadTicketSelector(array $tickets, array $template_args) |
|
406 | + { |
|
407 | + $template_args['event'] = $this->event; |
|
408 | + $template_args['EVT_ID'] = $this->event->ID(); |
|
409 | + $template_args['event_is_expired'] = $this->event->is_expired(); |
|
410 | + $template_args['max_atndz'] = $this->getMaxAttendees(); |
|
411 | + $template_args['date_format'] = $this->date_format; |
|
412 | + $template_args['time_format'] = $this->time_format; |
|
413 | + /** |
|
414 | + * Filters the anchor ID used when redirecting to the Ticket Selector if no quantity selected |
|
415 | + * |
|
416 | + * @since 4.9.13 |
|
417 | + * @param string '#tkt-slctr-tbl-' . $EVT_ID The html ID to anchor to |
|
418 | + * @param int $EVT_ID The Event ID |
|
419 | + */ |
|
420 | + $template_args['anchor_id'] = apply_filters( |
|
421 | + 'FHEE__EE_Ticket_Selector__redirect_anchor_id', |
|
422 | + '#tkt-slctr-tbl-' . $this->event->ID(), |
|
423 | + $this->event->ID() |
|
424 | + ); |
|
425 | + $template_args['tickets'] = $tickets; |
|
426 | + $template_args['ticket_count'] = count($tickets); |
|
427 | + $ticket_selector = $this->simpleTicketSelector($tickets, $template_args); |
|
428 | + return $ticket_selector instanceof TicketSelectorSimple |
|
429 | + ? $ticket_selector |
|
430 | + : new TicketSelectorStandard( |
|
431 | + $this->event, |
|
432 | + $tickets, |
|
433 | + $this->getMaxAttendees(), |
|
434 | + $template_args, |
|
435 | + $this->date_format, |
|
436 | + $this->time_format |
|
437 | + ); |
|
438 | + } |
|
439 | + |
|
440 | + |
|
441 | + /** |
|
442 | + * simpleTicketSelector |
|
443 | + * there's one ticket, and max attendees is set to one, |
|
444 | + * so if the event is free, then this is a "simple" ticket selector |
|
445 | + * a.k.a. "Dude Where's my Ticket Selector?" |
|
446 | + * |
|
447 | + * @param \EE_Ticket[] $tickets |
|
448 | + * @param array $template_args |
|
449 | + * @return string |
|
450 | + * @throws EE_Error |
|
451 | + */ |
|
452 | + protected function simpleTicketSelector($tickets, array $template_args) |
|
453 | + { |
|
454 | + // if there is only ONE ticket with a max qty of ONE |
|
455 | + if (count($tickets) > 1 || $this->getMaxAttendees() !== 1) { |
|
456 | + return ''; |
|
457 | + } |
|
458 | + /** @var \EE_Ticket $ticket */ |
|
459 | + $ticket = reset($tickets); |
|
460 | + // if the ticket is free... then not much need for the ticket selector |
|
461 | + if (apply_filters( |
|
462 | + 'FHEE__ticket_selector_chart_template__hide_ticket_selector', |
|
463 | + $ticket->is_free(), |
|
464 | + $this->event->ID() |
|
465 | + )) { |
|
466 | + return new TicketSelectorSimple( |
|
467 | + $this->event, |
|
468 | + $ticket, |
|
469 | + $this->getMaxAttendees(), |
|
470 | + $template_args |
|
471 | + ); |
|
472 | + } |
|
473 | + return ''; |
|
474 | + } |
|
475 | + |
|
476 | + |
|
477 | + /** |
|
478 | + * externalEventRegistration |
|
479 | + * |
|
480 | + * @return string |
|
481 | + */ |
|
482 | + public function externalEventRegistration() |
|
483 | + { |
|
484 | + // if not we still need to trigger the display of the submit button |
|
485 | + add_filter('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_true'); |
|
486 | + // display notice to admin that registration is external |
|
487 | + return $this->display_full_ui() |
|
488 | + ? esc_html__( |
|
489 | + 'Registration is at an external URL for this event.', |
|
490 | + 'event_espresso' |
|
491 | + ) |
|
492 | + : ''; |
|
493 | + } |
|
494 | + |
|
495 | + |
|
496 | + /** |
|
497 | + * formOpen |
|
498 | + * |
|
499 | + * @param int $ID |
|
500 | + * @param string $external_url |
|
501 | + * @return string |
|
502 | + */ |
|
503 | + public function formOpen($ID = 0, $external_url = '') |
|
504 | + { |
|
505 | + // if redirecting, we don't need any anything else |
|
506 | + if ($external_url) { |
|
507 | + $html = '<form method="GET" '; |
|
508 | + $html .= 'action="' . EEH_URL::refactor_url($external_url) . '" '; |
|
509 | + $html .= 'name="ticket-selector-form-' . $ID . '"'; |
|
510 | + // open link in new window ? |
|
511 | + $html .= apply_filters( |
|
512 | + 'FHEE__EventEspresso_modules_ticket_selector_DisplayTicketSelector__formOpen__external_url_target_blank', |
|
513 | + $this->isIframe(), |
|
514 | + $this |
|
515 | + ) |
|
516 | + ? ' target="_blank"' |
|
517 | + : ''; |
|
518 | + $html .= '>'; |
|
519 | + $query_args = EEH_URL::get_query_string($external_url); |
|
520 | + foreach ((array) $query_args as $query_arg => $value) { |
|
521 | + $html .= '<input type="hidden" name="' . $query_arg . '" value="' . $value . '">'; |
|
522 | + } |
|
523 | + return $html; |
|
524 | + } |
|
525 | + // if there is no submit button, then don't start building a form |
|
526 | + // because the "View Details" button will build its own form |
|
527 | + if (! apply_filters('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', false)) { |
|
528 | + return ''; |
|
529 | + } |
|
530 | + $checkout_url = EEH_Event_View::event_link_url($ID); |
|
531 | + if (! $checkout_url) { |
|
532 | + EE_Error::add_error( |
|
533 | + esc_html__('The URL for the Event Details page could not be retrieved.', 'event_espresso'), |
|
534 | + __FILE__, |
|
535 | + __FUNCTION__, |
|
536 | + __LINE__ |
|
537 | + ); |
|
538 | + } |
|
539 | + // set no cache headers and constants |
|
540 | + EE_System::do_not_cache(); |
|
541 | + $html = '<form method="POST" '; |
|
542 | + $html .= 'action="' . $checkout_url . '" '; |
|
543 | + $html .= 'name="ticket-selector-form-' . $ID . '"'; |
|
544 | + $html .= $this->iframe ? ' target="_blank"' : ''; |
|
545 | + $html .= '>'; |
|
546 | + $html .= '<input type="hidden" name="ee" value="process_ticket_selections">'; |
|
547 | + $html = apply_filters('FHEE__EE_Ticket_Selector__ticket_selector_form_open__html', $html, $this->event); |
|
548 | + return $html; |
|
549 | + } |
|
550 | + |
|
551 | + |
|
552 | + /** |
|
553 | + * displaySubmitButton |
|
554 | + * |
|
555 | + * @param string $external_url |
|
556 | + * @return string |
|
557 | + * @throws EE_Error |
|
558 | + */ |
|
559 | + public function displaySubmitButton($external_url = '') |
|
560 | + { |
|
561 | + $html = ''; |
|
562 | + if ($this->display_full_ui()) { |
|
563 | + // standard TS displayed with submit button, ie: "Register Now" |
|
564 | + if (apply_filters('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', false)) { |
|
565 | + $html .= $this->displayRegisterNowButton(); |
|
566 | + $html .= empty($external_url) |
|
567 | + ? $this->ticketSelectorEndDiv() |
|
568 | + : $this->clearTicketSelector(); |
|
569 | + $html .= '<br/>' . $this->formClose(); |
|
570 | + } elseif ($this->getMaxAttendees() === 1) { |
|
571 | + // its a "Dude Where's my Ticket Selector?" (DWMTS) type event (ie: $_max_atndz === 1) |
|
572 | + if ($this->event->is_sold_out()) { |
|
573 | + // then instead of a View Details or Submit button, just display a "Sold Out" message |
|
574 | + $html .= apply_filters( |
|
575 | + 'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__sold_out_msg', |
|
576 | + sprintf( |
|
577 | + __( |
|
578 | + '%1$s"%2$s" is currently sold out.%4$sPlease check back again later, as spots may become available.%3$s', |
|
579 | + 'event_espresso' |
|
580 | + ), |
|
581 | + '<p class="no-ticket-selector-msg clear-float">', |
|
582 | + $this->event->name(), |
|
583 | + '</p>', |
|
584 | + '<br />' |
|
585 | + ), |
|
586 | + $this->event |
|
587 | + ); |
|
588 | + if (apply_filters( |
|
589 | + 'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__no_tickets_but_display_register_now_button', |
|
590 | + false, |
|
591 | + $this->event |
|
592 | + )) { |
|
593 | + $html .= $this->displayRegisterNowButton(); |
|
594 | + } |
|
595 | + // sold out DWMTS event, no TS, no submit or view details button, but has additional content |
|
596 | + $html .= $this->ticketSelectorEndDiv(); |
|
597 | + } elseif (apply_filters('FHEE__EE_Ticket_Selector__hide_ticket_selector', false) |
|
598 | + && ! is_single() |
|
599 | + ) { |
|
600 | + // this is a "Dude Where's my Ticket Selector?" (DWMTS) type event, |
|
601 | + // but no tickets are available, so display event's "View Details" button. |
|
602 | + // it is being viewed via somewhere other than a single post |
|
603 | + $html .= $this->displayViewDetailsButton(true); |
|
604 | + } else { |
|
605 | + $html .= $this->ticketSelectorEndDiv(); |
|
606 | + } |
|
607 | + } elseif (is_archive()) { |
|
608 | + // event list, no tickets available so display event's "View Details" button |
|
609 | + $html .= $this->ticketSelectorEndDiv(); |
|
610 | + $html .= $this->displayViewDetailsButton(); |
|
611 | + } else { |
|
612 | + if (apply_filters( |
|
613 | + 'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__no_tickets_but_display_register_now_button', |
|
614 | + false, |
|
615 | + $this->event |
|
616 | + )) { |
|
617 | + $html .= $this->displayRegisterNowButton(); |
|
618 | + } |
|
619 | + // no submit or view details button, and no additional content |
|
620 | + $html .= $this->ticketSelectorEndDiv(); |
|
621 | + } |
|
622 | + if (! $this->iframe && ! is_archive()) { |
|
623 | + $html .= EEH_Template::powered_by_event_espresso('', '', array('utm_content' => 'ticket_selector')); |
|
624 | + } |
|
625 | + } |
|
626 | + return apply_filters( |
|
627 | + 'FHEE__EventEspresso_modules_ticket_selector_DisplayTicketSelector__displaySubmitButton__html', |
|
628 | + $html, |
|
629 | + $this->event, |
|
630 | + $this |
|
631 | + ); |
|
632 | + } |
|
633 | + |
|
634 | + |
|
635 | + /** |
|
636 | + * @return string |
|
637 | + * @throws EE_Error |
|
638 | + */ |
|
639 | + public function displayRegisterNowButton() |
|
640 | + { |
|
641 | + $btn_text = apply_filters( |
|
642 | + 'FHEE__EE_Ticket_Selector__display_ticket_selector_submit__btn_text', |
|
643 | + __('Register Now', 'event_espresso'), |
|
644 | + $this->event |
|
645 | + ); |
|
646 | + $external_url = (string) $this->event->external_url() |
|
647 | + && $this->event->external_url() !== get_the_permalink() |
|
648 | + ? $this->event->external_url() |
|
649 | + : ''; |
|
650 | + $html = EEH_HTML::div( |
|
651 | + '', |
|
652 | + 'ticket-selector-submit-' . $this->event->ID() . '-btn-wrap', |
|
653 | + 'ticket-selector-submit-btn-wrap' |
|
654 | + ); |
|
655 | + $html .= '<input id="ticket-selector-submit-' . $this->event->ID() . '-btn"'; |
|
656 | + $html .= ' class="ticket-selector-submit-btn '; |
|
657 | + $html .= empty($external_url) ? 'ticket-selector-submit-ajax"' : '"'; |
|
658 | + $html .= ' type="submit" value="' . $btn_text . '" />'; |
|
659 | + $html .= EEH_HTML::divx() . '<!-- .ticket-selector-submit-btn-wrap -->'; |
|
660 | + $html .= apply_filters( |
|
661 | + 'FHEE__EE_Ticket_Selector__after_ticket_selector_submit', |
|
662 | + '', |
|
663 | + $this->event, |
|
664 | + $this->iframe |
|
665 | + ); |
|
666 | + return $html; |
|
667 | + } |
|
668 | + |
|
669 | + |
|
670 | + /** |
|
671 | + * displayViewDetailsButton |
|
672 | + * |
|
673 | + * @param bool $DWMTS indicates a "Dude Where's my Ticket Selector?" (DWMTS) type event |
|
674 | + * (ie: $_max_atndz === 1) where there are no available tickets, |
|
675 | + * either because they are sold out, expired, or not yet on sale. |
|
676 | + * In this case, we need to close the form BEFORE adding any closing divs |
|
677 | + * @return string |
|
678 | + * @throws EE_Error |
|
679 | + */ |
|
680 | + public function displayViewDetailsButton($DWMTS = false) |
|
681 | + { |
|
682 | + if (! $this->event->get_permalink()) { |
|
683 | + EE_Error::add_error( |
|
684 | + esc_html__('The URL for the Event Details page could not be retrieved.', 'event_espresso'), |
|
685 | + __FILE__, |
|
686 | + __FUNCTION__, |
|
687 | + __LINE__ |
|
688 | + ); |
|
689 | + } |
|
690 | + $view_details_btn = '<form method="POST" action="'; |
|
691 | + $view_details_btn .= apply_filters( |
|
692 | + 'FHEE__EE_Ticket_Selector__display_view_details_btn__btn_url', |
|
693 | + $this->event->get_permalink(), |
|
694 | + $this->event |
|
695 | + ); |
|
696 | + $view_details_btn .= '"'; |
|
697 | + // open link in new window ? |
|
698 | + $view_details_btn .= apply_filters( |
|
699 | + 'FHEE__EventEspresso_modules_ticket_selector_DisplayTicketSelector__displayViewDetailsButton__url_target_blank', |
|
700 | + $this->isIframe(), |
|
701 | + $this |
|
702 | + ) |
|
703 | + ? ' target="_blank"' |
|
704 | + : ''; |
|
705 | + $view_details_btn .= '>'; |
|
706 | + $btn_text = apply_filters( |
|
707 | + 'FHEE__EE_Ticket_Selector__display_view_details_btn__btn_text', |
|
708 | + esc_html__('View Details', 'event_espresso'), |
|
709 | + $this->event |
|
710 | + ); |
|
711 | + $view_details_btn .= '<input id="ticket-selector-submit-' |
|
712 | + . $this->event->ID() |
|
713 | + . '-btn" class="ticket-selector-submit-btn view-details-btn" type="submit" value="' |
|
714 | + . $btn_text |
|
715 | + . '" />'; |
|
716 | + $view_details_btn .= apply_filters('FHEE__EE_Ticket_Selector__after_view_details_btn', '', $this->event); |
|
717 | + if ($DWMTS) { |
|
718 | + $view_details_btn .= $this->formClose(); |
|
719 | + $view_details_btn .= $this->ticketSelectorEndDiv(); |
|
720 | + $view_details_btn .= '<br/>'; |
|
721 | + } else { |
|
722 | + $view_details_btn .= $this->clearTicketSelector(); |
|
723 | + $view_details_btn .= '<br/>'; |
|
724 | + $view_details_btn .= $this->formClose(); |
|
725 | + } |
|
726 | + return $view_details_btn; |
|
727 | + } |
|
728 | + |
|
729 | + |
|
730 | + /** |
|
731 | + * @return string |
|
732 | + */ |
|
733 | + public function ticketSelectorEndDiv() |
|
734 | + { |
|
735 | + return $this->clearTicketSelector() . '</div><!-- ticketSelectorEndDiv -->'; |
|
736 | + } |
|
737 | + |
|
738 | + |
|
739 | + /** |
|
740 | + * @return string |
|
741 | + */ |
|
742 | + public function clearTicketSelector() |
|
743 | + { |
|
744 | + // standard TS displayed, appears after a "Register Now" or "view Details" button |
|
745 | + return '<div class="clear"></div><!-- clearTicketSelector -->'; |
|
746 | + } |
|
747 | + |
|
748 | + |
|
749 | + /** |
|
750 | + * @access public |
|
751 | + * @return string |
|
752 | + */ |
|
753 | + public function formClose() |
|
754 | + { |
|
755 | + return '</form>'; |
|
756 | + } |
|
757 | 757 | } |
@@ -135,11 +135,11 @@ discard block |
||
135 | 135 | } |
136 | 136 | } else { |
137 | 137 | $user_msg = __('No Event object or an invalid Event object was supplied.', 'event_espresso'); |
138 | - $dev_msg = $user_msg . __( |
|
138 | + $dev_msg = $user_msg.__( |
|
139 | 139 | '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.', |
140 | 140 | 'event_espresso' |
141 | 141 | ); |
142 | - EE_Error::add_error($user_msg . '||' . $dev_msg, __FILE__, __FUNCTION__, __LINE__); |
|
142 | + EE_Error::add_error($user_msg.'||'.$dev_msg, __FILE__, __FUNCTION__, __LINE__); |
|
143 | 143 | return false; |
144 | 144 | } |
145 | 145 | return true; |
@@ -200,7 +200,7 @@ discard block |
||
200 | 200 | // reset filter for displaying submit button |
201 | 201 | remove_filter('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', '__return_true'); |
202 | 202 | // poke and prod incoming event till it tells us what it is |
203 | - if (! $this->setEvent($event)) { |
|
203 | + if ( ! $this->setEvent($event)) { |
|
204 | 204 | return false; |
205 | 205 | } |
206 | 206 | // begin gathering template arguments by getting event status |
@@ -238,7 +238,7 @@ discard block |
||
238 | 238 | : $this->loadTicketSelector($tickets, $template_args); |
239 | 239 | // now set up the form (but not for the admin) |
240 | 240 | $ticket_selector = $this->display_full_ui() |
241 | - ? $this->formOpen($this->event->ID(), $external_url) . $ticket_selector |
|
241 | + ? $this->formOpen($this->event->ID(), $external_url).$ticket_selector |
|
242 | 242 | : $ticket_selector; |
243 | 243 | // submit button and form close tag |
244 | 244 | $ticket_selector .= $this->display_full_ui() ? $this->displaySubmitButton($external_url) : ''; |
@@ -286,10 +286,10 @@ discard block |
||
286 | 286 | */ |
287 | 287 | protected function expiredEventMessage() |
288 | 288 | { |
289 | - return '<div class="ee-event-expired-notice"><span class="important-notice">' . esc_html__( |
|
289 | + return '<div class="ee-event-expired-notice"><span class="important-notice">'.esc_html__( |
|
290 | 290 | 'We\'re sorry, but all tickets sales have ended because the event is expired.', |
291 | 291 | 'event_espresso' |
292 | - ) . '</span></div><!-- .ee-event-expired-notice -->'; |
|
292 | + ).'</span></div><!-- .ee-event-expired-notice -->'; |
|
293 | 293 | } |
294 | 294 | |
295 | 295 | |
@@ -319,7 +319,7 @@ discard block |
||
319 | 319 | } |
320 | 320 | return ' |
321 | 321 | <div class="ee-event-expired-notice"> |
322 | - <span class="important-notice">' . $no_ticket_available_msg . '</span> |
|
322 | + <span class="important-notice">' . $no_ticket_available_msg.'</span> |
|
323 | 323 | </div><!-- .ee-event-expired-notice -->'; |
324 | 324 | } |
325 | 325 | |
@@ -351,7 +351,7 @@ discard block |
||
351 | 351 | '</a></span></div><!-- .ee-attention ticketSalesClosedMessage -->' |
352 | 352 | ); |
353 | 353 | } |
354 | - return '<p><span class="important-notice">' . $sales_closed_msg . '</span></p>'; |
|
354 | + return '<p><span class="important-notice">'.$sales_closed_msg.'</span></p>'; |
|
355 | 355 | } |
356 | 356 | |
357 | 357 | |
@@ -381,7 +381,7 @@ discard block |
||
381 | 381 | 'Datetime.DTT_EVT_start' => 'DESC', |
382 | 382 | ), |
383 | 383 | ); |
384 | - if (! $show_expired_tickets) { |
|
384 | + if ( ! $show_expired_tickets) { |
|
385 | 385 | // use the correct applicable time query depending on what version of core is being run. |
386 | 386 | $current_time = method_exists('EEM_Datetime', 'current_time_for_query') |
387 | 387 | ? time() |
@@ -419,7 +419,7 @@ discard block |
||
419 | 419 | */ |
420 | 420 | $template_args['anchor_id'] = apply_filters( |
421 | 421 | 'FHEE__EE_Ticket_Selector__redirect_anchor_id', |
422 | - '#tkt-slctr-tbl-' . $this->event->ID(), |
|
422 | + '#tkt-slctr-tbl-'.$this->event->ID(), |
|
423 | 423 | $this->event->ID() |
424 | 424 | ); |
425 | 425 | $template_args['tickets'] = $tickets; |
@@ -505,8 +505,8 @@ discard block |
||
505 | 505 | // if redirecting, we don't need any anything else |
506 | 506 | if ($external_url) { |
507 | 507 | $html = '<form method="GET" '; |
508 | - $html .= 'action="' . EEH_URL::refactor_url($external_url) . '" '; |
|
509 | - $html .= 'name="ticket-selector-form-' . $ID . '"'; |
|
508 | + $html .= 'action="'.EEH_URL::refactor_url($external_url).'" '; |
|
509 | + $html .= 'name="ticket-selector-form-'.$ID.'"'; |
|
510 | 510 | // open link in new window ? |
511 | 511 | $html .= apply_filters( |
512 | 512 | 'FHEE__EventEspresso_modules_ticket_selector_DisplayTicketSelector__formOpen__external_url_target_blank', |
@@ -518,17 +518,17 @@ discard block |
||
518 | 518 | $html .= '>'; |
519 | 519 | $query_args = EEH_URL::get_query_string($external_url); |
520 | 520 | foreach ((array) $query_args as $query_arg => $value) { |
521 | - $html .= '<input type="hidden" name="' . $query_arg . '" value="' . $value . '">'; |
|
521 | + $html .= '<input type="hidden" name="'.$query_arg.'" value="'.$value.'">'; |
|
522 | 522 | } |
523 | 523 | return $html; |
524 | 524 | } |
525 | 525 | // if there is no submit button, then don't start building a form |
526 | 526 | // because the "View Details" button will build its own form |
527 | - if (! apply_filters('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', false)) { |
|
527 | + if ( ! apply_filters('FHEE__EE_Ticket_Selector__display_ticket_selector_submit', false)) { |
|
528 | 528 | return ''; |
529 | 529 | } |
530 | 530 | $checkout_url = EEH_Event_View::event_link_url($ID); |
531 | - if (! $checkout_url) { |
|
531 | + if ( ! $checkout_url) { |
|
532 | 532 | EE_Error::add_error( |
533 | 533 | esc_html__('The URL for the Event Details page could not be retrieved.', 'event_espresso'), |
534 | 534 | __FILE__, |
@@ -539,8 +539,8 @@ discard block |
||
539 | 539 | // set no cache headers and constants |
540 | 540 | EE_System::do_not_cache(); |
541 | 541 | $html = '<form method="POST" '; |
542 | - $html .= 'action="' . $checkout_url . '" '; |
|
543 | - $html .= 'name="ticket-selector-form-' . $ID . '"'; |
|
542 | + $html .= 'action="'.$checkout_url.'" '; |
|
543 | + $html .= 'name="ticket-selector-form-'.$ID.'"'; |
|
544 | 544 | $html .= $this->iframe ? ' target="_blank"' : ''; |
545 | 545 | $html .= '>'; |
546 | 546 | $html .= '<input type="hidden" name="ee" value="process_ticket_selections">'; |
@@ -566,7 +566,7 @@ discard block |
||
566 | 566 | $html .= empty($external_url) |
567 | 567 | ? $this->ticketSelectorEndDiv() |
568 | 568 | : $this->clearTicketSelector(); |
569 | - $html .= '<br/>' . $this->formClose(); |
|
569 | + $html .= '<br/>'.$this->formClose(); |
|
570 | 570 | } elseif ($this->getMaxAttendees() === 1) { |
571 | 571 | // its a "Dude Where's my Ticket Selector?" (DWMTS) type event (ie: $_max_atndz === 1) |
572 | 572 | if ($this->event->is_sold_out()) { |
@@ -619,7 +619,7 @@ discard block |
||
619 | 619 | // no submit or view details button, and no additional content |
620 | 620 | $html .= $this->ticketSelectorEndDiv(); |
621 | 621 | } |
622 | - if (! $this->iframe && ! is_archive()) { |
|
622 | + if ( ! $this->iframe && ! is_archive()) { |
|
623 | 623 | $html .= EEH_Template::powered_by_event_espresso('', '', array('utm_content' => 'ticket_selector')); |
624 | 624 | } |
625 | 625 | } |
@@ -649,14 +649,14 @@ discard block |
||
649 | 649 | : ''; |
650 | 650 | $html = EEH_HTML::div( |
651 | 651 | '', |
652 | - 'ticket-selector-submit-' . $this->event->ID() . '-btn-wrap', |
|
652 | + 'ticket-selector-submit-'.$this->event->ID().'-btn-wrap', |
|
653 | 653 | 'ticket-selector-submit-btn-wrap' |
654 | 654 | ); |
655 | - $html .= '<input id="ticket-selector-submit-' . $this->event->ID() . '-btn"'; |
|
655 | + $html .= '<input id="ticket-selector-submit-'.$this->event->ID().'-btn"'; |
|
656 | 656 | $html .= ' class="ticket-selector-submit-btn '; |
657 | 657 | $html .= empty($external_url) ? 'ticket-selector-submit-ajax"' : '"'; |
658 | - $html .= ' type="submit" value="' . $btn_text . '" />'; |
|
659 | - $html .= EEH_HTML::divx() . '<!-- .ticket-selector-submit-btn-wrap -->'; |
|
658 | + $html .= ' type="submit" value="'.$btn_text.'" />'; |
|
659 | + $html .= EEH_HTML::divx().'<!-- .ticket-selector-submit-btn-wrap -->'; |
|
660 | 660 | $html .= apply_filters( |
661 | 661 | 'FHEE__EE_Ticket_Selector__after_ticket_selector_submit', |
662 | 662 | '', |
@@ -679,7 +679,7 @@ discard block |
||
679 | 679 | */ |
680 | 680 | public function displayViewDetailsButton($DWMTS = false) |
681 | 681 | { |
682 | - if (! $this->event->get_permalink()) { |
|
682 | + if ( ! $this->event->get_permalink()) { |
|
683 | 683 | EE_Error::add_error( |
684 | 684 | esc_html__('The URL for the Event Details page could not be retrieved.', 'event_espresso'), |
685 | 685 | __FILE__, |
@@ -732,7 +732,7 @@ discard block |
||
732 | 732 | */ |
733 | 733 | public function ticketSelectorEndDiv() |
734 | 734 | { |
735 | - return $this->clearTicketSelector() . '</div><!-- ticketSelectorEndDiv -->'; |
|
735 | + return $this->clearTicketSelector().'</div><!-- ticketSelectorEndDiv -->'; |
|
736 | 736 | } |
737 | 737 | |
738 | 738 |
@@ -28,602 +28,602 @@ |
||
28 | 28 | class EEM_Line_Item extends EEM_Base |
29 | 29 | { |
30 | 30 | |
31 | - /** |
|
32 | - * Tax sub-total is just the total of all the taxes, which should be children |
|
33 | - * of this line item. There should only ever be one tax sub-total, and it should |
|
34 | - * be a direct child of. Its quantity and LIN_unit_price = 1. |
|
35 | - */ |
|
36 | - const type_tax_sub_total = 'tax-sub-total'; |
|
37 | - |
|
38 | - /** |
|
39 | - * Tax line items indicate a tax applied to all the taxable line items. |
|
40 | - * Should not have any children line items. Its LIN_unit_price = 0. Its LIN_percent is a percent, not a decimal |
|
41 | - * (eg 10% tax = 10, not 0.1). Its LIN_total = LIN_unit_price * pre-tax-total. Quantity = 1. |
|
42 | - */ |
|
43 | - const type_tax = 'tax'; |
|
44 | - |
|
45 | - /** |
|
46 | - * Indicating individual items purchased, or discounts or surcharges. |
|
47 | - * The sum of all the regular line items plus the tax items should equal the grand total. |
|
48 | - * Possible children are sub-line-items and cancellations. |
|
49 | - * For flat items, LIN_unit_price * LIN_quantity = LIN_total. Its LIN_total is the sum of all the children |
|
50 | - * LIN_totals. Its LIN_percent = 0. |
|
51 | - * For percent items, its LIN_unit_price = 0. Its LIN_percent is a percent, not a decimal (eg 10% = 10, not 0.1). |
|
52 | - * Its LIN_total is LIN_percent / 100 * sum of lower-priority sibling line items. Quantity = 1. |
|
53 | - */ |
|
54 | - const type_line_item = 'line-item'; |
|
55 | - |
|
56 | - /** |
|
57 | - * Line item indicating all the factors that make a single line item. |
|
58 | - * Sub-line items should have NO children line items. |
|
59 | - * For flat sub-items, their quantity should match their parent item, their LIN_unit_price should be this sub-item's |
|
60 | - * contribution towards the price of ONE of their parent items, and its LIN_total should be |
|
61 | - * = LIN_quantity * LIN_unit_price. Its LIN_percent = 0. |
|
62 | - * For percent sub-items, the quantity should be 1, LIN_unit_price should be 0, and its LIN_total should |
|
63 | - * = LIN_percent / 100 * sum of lower-priority sibling line items.. |
|
64 | - */ |
|
65 | - const type_sub_line_item = 'sub-item'; |
|
66 | - |
|
67 | - /** |
|
68 | - * Line item indicating a sub-total (eg total for an event, or pre-tax subtotal). |
|
69 | - * Direct children should be event subtotals. |
|
70 | - * Should have quantity of 1, and a LIN_total and LIN_unit_price of the sum of all its sub-items' LIN_totals. |
|
71 | - */ |
|
72 | - const type_sub_total = 'sub-total'; |
|
73 | - |
|
74 | - /** |
|
75 | - * Line item for the grand total of an order. |
|
76 | - * Its direct children should be tax subtotals and (pre-tax) subtotals, |
|
77 | - * and possibly a regular line item indicating a transaction-wide discount/surcharge. |
|
78 | - * Should have a quantity of 1, a LIN_total and LIN_unit_price of the entire order's amount. |
|
79 | - */ |
|
80 | - const type_total = 'total'; |
|
81 | - |
|
82 | - /** |
|
83 | - * When a line item is cancelled, a sub-line-item of type 'cancellation' |
|
84 | - * should be created, indicating the quantity that were cancelled |
|
85 | - * (because a line item could have a quantity of 1, and its cancellation item |
|
86 | - * could be for 3, indicating that originally 4 were purchased, but 3 have been |
|
87 | - * cancelled, and only one remains). |
|
88 | - * When items are refunded, a cancellation line item should be made, which points |
|
89 | - * to teh payment model object which actually refunded the payment. |
|
90 | - * Cancellations should NOT have any children line items; the should NOT affect |
|
91 | - * any calculations, and are only meant as a record that cancellations have occurred. |
|
92 | - * Their LIN_percent should be 0. |
|
93 | - */ |
|
94 | - const type_cancellation = 'cancellation'; |
|
95 | - |
|
96 | - // various line item object types |
|
97 | - const OBJ_TYPE_EVENT = 'Event'; |
|
98 | - |
|
99 | - const OBJ_TYPE_PRICE = 'Price'; |
|
100 | - |
|
101 | - const OBJ_TYPE_PROMOTION = 'Promotion'; |
|
102 | - |
|
103 | - const OBJ_TYPE_TICKET = 'Ticket'; |
|
104 | - |
|
105 | - const OBJ_TYPE_TRANSACTION = 'Transaction'; |
|
106 | - |
|
107 | - /** |
|
108 | - * @var EEM_Line_Item $_instance |
|
109 | - */ |
|
110 | - protected static $_instance; |
|
111 | - |
|
112 | - |
|
113 | - /** |
|
114 | - * private constructor to prevent direct creation |
|
115 | - * |
|
116 | - * @Constructor |
|
117 | - * @param string $timezone string representing the timezone we want to set for returned Date Time Strings |
|
118 | - * (and any incoming timezone data that gets saved). |
|
119 | - * Note this just sends the timezone info to the date time model field objects. |
|
120 | - * Default is NULL |
|
121 | - * (and will be assumed using the set timezone in the 'timezone_string' wp option) |
|
122 | - * @throws EE_Error |
|
123 | - * @throws InvalidArgumentException |
|
124 | - */ |
|
125 | - protected function __construct($timezone) |
|
126 | - { |
|
127 | - $this->singular_item = esc_html__('Line Item', 'event_espresso'); |
|
128 | - $this->plural_item = esc_html__('Line Items', 'event_espresso'); |
|
129 | - |
|
130 | - $this->_tables = array( |
|
131 | - 'Line_Item' => new EE_Primary_Table('esp_line_item', 'LIN_ID'), |
|
132 | - ); |
|
133 | - $line_items_can_be_for = apply_filters( |
|
134 | - 'FHEE__EEM_Line_Item__line_items_can_be_for', |
|
135 | - array('Ticket', 'Price', 'Event') |
|
136 | - ); |
|
137 | - $this->_fields = array( |
|
138 | - 'Line_Item' => array( |
|
139 | - 'LIN_ID' => new EE_Primary_Key_Int_Field( |
|
140 | - 'LIN_ID', |
|
141 | - esc_html__('ID', 'event_espresso') |
|
142 | - ), |
|
143 | - 'LIN_code' => new EE_Slug_Field( |
|
144 | - 'LIN_code', |
|
145 | - esc_html__('Code for index into Cart', 'event_espresso'), |
|
146 | - true |
|
147 | - ), |
|
148 | - 'TXN_ID' => new EE_Foreign_Key_Int_Field( |
|
149 | - 'TXN_ID', |
|
150 | - esc_html__('Transaction ID', 'event_espresso'), |
|
151 | - true, |
|
152 | - null, |
|
153 | - 'Transaction' |
|
154 | - ), |
|
155 | - 'LIN_name' => new EE_Full_HTML_Field( |
|
156 | - 'LIN_name', |
|
157 | - esc_html__('Line Item Name', 'event_espresso'), |
|
158 | - false, |
|
159 | - '' |
|
160 | - ), |
|
161 | - 'LIN_desc' => new EE_Full_HTML_Field( |
|
162 | - 'LIN_desc', |
|
163 | - esc_html__('Line Item Description', 'event_espresso'), |
|
164 | - true |
|
165 | - ), |
|
166 | - 'LIN_unit_price' => new EE_Money_Field( |
|
167 | - 'LIN_unit_price', |
|
168 | - esc_html__('Unit Price', 'event_espresso'), |
|
169 | - false, |
|
170 | - 0 |
|
171 | - ), |
|
172 | - 'LIN_percent' => new EE_Float_Field( |
|
173 | - 'LIN_percent', |
|
174 | - esc_html__('Percent', 'event_espresso'), |
|
175 | - false, |
|
176 | - 0 |
|
177 | - ), |
|
178 | - 'LIN_is_taxable' => new EE_Boolean_Field( |
|
179 | - 'LIN_is_taxable', |
|
180 | - esc_html__('Taxable', 'event_espresso'), |
|
181 | - false, |
|
182 | - false |
|
183 | - ), |
|
184 | - 'LIN_order' => new EE_Integer_Field( |
|
185 | - 'LIN_order', |
|
186 | - esc_html__('Order of Application towards total of parent', 'event_espresso'), |
|
187 | - false, |
|
188 | - 1 |
|
189 | - ), |
|
190 | - 'LIN_total' => new EE_Money_Field( |
|
191 | - 'LIN_total', |
|
192 | - esc_html__('Total (unit price x quantity)', 'event_espresso'), |
|
193 | - false, |
|
194 | - 0 |
|
195 | - ), |
|
196 | - 'LIN_quantity' => new EE_Integer_Field( |
|
197 | - 'LIN_quantity', |
|
198 | - esc_html__('Quantity', 'event_espresso'), |
|
199 | - true, |
|
200 | - 1 |
|
201 | - ), |
|
202 | - 'LIN_parent' => new EE_Integer_Field( |
|
203 | - 'LIN_parent', |
|
204 | - esc_html__("Parent ID (this item goes towards that Line Item's total)", 'event_espresso'), |
|
205 | - true, |
|
206 | - null |
|
207 | - ), |
|
208 | - 'LIN_type' => new EE_Enum_Text_Field( |
|
209 | - 'LIN_type', |
|
210 | - esc_html__('Type', 'event_espresso'), |
|
211 | - false, |
|
212 | - 'line-item', |
|
213 | - array( |
|
214 | - self::type_line_item => esc_html__('Line Item', 'event_espresso'), |
|
215 | - self::type_sub_line_item => esc_html__('Sub-Item', 'event_espresso'), |
|
216 | - self::type_sub_total => esc_html__('Subtotal', 'event_espresso'), |
|
217 | - self::type_tax_sub_total => esc_html__('Tax Subtotal', 'event_espresso'), |
|
218 | - self::type_tax => esc_html__('Tax', 'event_espresso'), |
|
219 | - self::type_total => esc_html__('Total', 'event_espresso'), |
|
220 | - self::type_cancellation => esc_html__('Cancellation', 'event_espresso'), |
|
221 | - ) |
|
222 | - ), |
|
223 | - 'OBJ_ID' => new EE_Foreign_Key_Int_Field( |
|
224 | - 'OBJ_ID', |
|
225 | - esc_html__('ID of Item purchased.', 'event_espresso'), |
|
226 | - true, |
|
227 | - null, |
|
228 | - $line_items_can_be_for |
|
229 | - ), |
|
230 | - 'OBJ_type' => new EE_Any_Foreign_Model_Name_Field( |
|
231 | - 'OBJ_type', |
|
232 | - esc_html__('Model Name this Line Item is for', 'event_espresso'), |
|
233 | - true, |
|
234 | - null, |
|
235 | - $line_items_can_be_for |
|
236 | - ), |
|
237 | - 'LIN_timestamp' => new EE_Datetime_Field( |
|
238 | - 'LIN_timestamp', |
|
239 | - esc_html__('When the line item was created', 'event_espresso'), |
|
240 | - false, |
|
241 | - EE_Datetime_Field::now, |
|
242 | - $timezone |
|
243 | - ), |
|
244 | - ), |
|
245 | - ); |
|
246 | - $this->_model_relations = array( |
|
247 | - 'Transaction' => new EE_Belongs_To_Relation(), |
|
248 | - 'Ticket' => new EE_Belongs_To_Any_Relation(), |
|
249 | - 'Price' => new EE_Belongs_To_Any_Relation(), |
|
250 | - 'Event' => new EE_Belongs_To_Any_Relation(), |
|
251 | - ); |
|
252 | - $this->_model_chain_to_wp_user = 'Transaction.Registration.Event'; |
|
253 | - $this->_caps_slug = 'transactions'; |
|
254 | - parent::__construct($timezone); |
|
255 | - } |
|
256 | - |
|
257 | - |
|
258 | - /** |
|
259 | - * Gets all the line items for this transaction of the given type |
|
260 | - * |
|
261 | - * @param string $line_item_type like one of EEM_Line_Item::type_* |
|
262 | - * @param EE_Transaction|int $transaction |
|
263 | - * @return EE_Base_Class[]|EE_Line_Item[] |
|
264 | - * @throws EE_Error |
|
265 | - * @throws InvalidArgumentException |
|
266 | - * @throws InvalidDataTypeException |
|
267 | - * @throws InvalidInterfaceException |
|
268 | - */ |
|
269 | - public function get_all_of_type_for_transaction($line_item_type, $transaction) |
|
270 | - { |
|
271 | - $transaction = EEM_Transaction::instance()->ensure_is_ID($transaction); |
|
272 | - return $this->get_all(array( |
|
273 | - array( |
|
274 | - 'LIN_type' => $line_item_type, |
|
275 | - 'TXN_ID' => $transaction, |
|
276 | - ), |
|
277 | - )); |
|
278 | - } |
|
279 | - |
|
280 | - |
|
281 | - /** |
|
282 | - * Gets all line items unrelated to tickets that are normal line items |
|
283 | - * (eg shipping, promotions, and miscellaneous other stuff should probably fit in this category) |
|
284 | - * |
|
285 | - * @param EE_Transaction|int $transaction |
|
286 | - * @return EE_Base_Class[]|EE_Line_Item[] |
|
287 | - * @throws EE_Error |
|
288 | - * @throws InvalidArgumentException |
|
289 | - * @throws InvalidDataTypeException |
|
290 | - * @throws InvalidInterfaceException |
|
291 | - */ |
|
292 | - public function get_all_non_ticket_line_items_for_transaction($transaction) |
|
293 | - { |
|
294 | - $transaction = EEM_Transaction::instance()->ensure_is_ID($transaction); |
|
295 | - return $this->get_all(array( |
|
296 | - array( |
|
297 | - 'LIN_type' => self::type_line_item, |
|
298 | - 'TXN_ID' => $transaction, |
|
299 | - 'OR' => array( |
|
300 | - 'OBJ_type*notticket' => array('!=', EEM_Line_Item::OBJ_TYPE_TICKET), |
|
301 | - 'OBJ_type*null' => array('IS_NULL'), |
|
302 | - ), |
|
303 | - ), |
|
304 | - )); |
|
305 | - } |
|
306 | - |
|
307 | - |
|
308 | - /** |
|
309 | - * Deletes line items with no transaction who have passed the transaction cutoff time. |
|
310 | - * This needs to be very efficient |
|
311 | - * because if there are spam bots afoot there will be LOTS of line items. Also MySQL doesn't allow a limit when |
|
312 | - * deleting and joining tables like this. |
|
313 | - * |
|
314 | - * @return int count of how many deleted |
|
315 | - * @throws EE_Error |
|
316 | - * @throws InvalidArgumentException |
|
317 | - * @throws InvalidDataTypeException |
|
318 | - * @throws InvalidInterfaceException |
|
319 | - */ |
|
320 | - public function delete_line_items_with_no_transaction() |
|
321 | - { |
|
322 | - /** @type WPDB $wpdb */ |
|
323 | - global $wpdb; |
|
324 | - $time_to_leave_alone = apply_filters( |
|
325 | - 'FHEE__EEM_Line_Item__delete_line_items_with_no_transaction__time_to_leave_alone', |
|
326 | - WEEK_IN_SECONDS |
|
327 | - ); |
|
328 | - $query = $wpdb->prepare( |
|
329 | - 'DELETE li |
|
31 | + /** |
|
32 | + * Tax sub-total is just the total of all the taxes, which should be children |
|
33 | + * of this line item. There should only ever be one tax sub-total, and it should |
|
34 | + * be a direct child of. Its quantity and LIN_unit_price = 1. |
|
35 | + */ |
|
36 | + const type_tax_sub_total = 'tax-sub-total'; |
|
37 | + |
|
38 | + /** |
|
39 | + * Tax line items indicate a tax applied to all the taxable line items. |
|
40 | + * Should not have any children line items. Its LIN_unit_price = 0. Its LIN_percent is a percent, not a decimal |
|
41 | + * (eg 10% tax = 10, not 0.1). Its LIN_total = LIN_unit_price * pre-tax-total. Quantity = 1. |
|
42 | + */ |
|
43 | + const type_tax = 'tax'; |
|
44 | + |
|
45 | + /** |
|
46 | + * Indicating individual items purchased, or discounts or surcharges. |
|
47 | + * The sum of all the regular line items plus the tax items should equal the grand total. |
|
48 | + * Possible children are sub-line-items and cancellations. |
|
49 | + * For flat items, LIN_unit_price * LIN_quantity = LIN_total. Its LIN_total is the sum of all the children |
|
50 | + * LIN_totals. Its LIN_percent = 0. |
|
51 | + * For percent items, its LIN_unit_price = 0. Its LIN_percent is a percent, not a decimal (eg 10% = 10, not 0.1). |
|
52 | + * Its LIN_total is LIN_percent / 100 * sum of lower-priority sibling line items. Quantity = 1. |
|
53 | + */ |
|
54 | + const type_line_item = 'line-item'; |
|
55 | + |
|
56 | + /** |
|
57 | + * Line item indicating all the factors that make a single line item. |
|
58 | + * Sub-line items should have NO children line items. |
|
59 | + * For flat sub-items, their quantity should match their parent item, their LIN_unit_price should be this sub-item's |
|
60 | + * contribution towards the price of ONE of their parent items, and its LIN_total should be |
|
61 | + * = LIN_quantity * LIN_unit_price. Its LIN_percent = 0. |
|
62 | + * For percent sub-items, the quantity should be 1, LIN_unit_price should be 0, and its LIN_total should |
|
63 | + * = LIN_percent / 100 * sum of lower-priority sibling line items.. |
|
64 | + */ |
|
65 | + const type_sub_line_item = 'sub-item'; |
|
66 | + |
|
67 | + /** |
|
68 | + * Line item indicating a sub-total (eg total for an event, or pre-tax subtotal). |
|
69 | + * Direct children should be event subtotals. |
|
70 | + * Should have quantity of 1, and a LIN_total and LIN_unit_price of the sum of all its sub-items' LIN_totals. |
|
71 | + */ |
|
72 | + const type_sub_total = 'sub-total'; |
|
73 | + |
|
74 | + /** |
|
75 | + * Line item for the grand total of an order. |
|
76 | + * Its direct children should be tax subtotals and (pre-tax) subtotals, |
|
77 | + * and possibly a regular line item indicating a transaction-wide discount/surcharge. |
|
78 | + * Should have a quantity of 1, a LIN_total and LIN_unit_price of the entire order's amount. |
|
79 | + */ |
|
80 | + const type_total = 'total'; |
|
81 | + |
|
82 | + /** |
|
83 | + * When a line item is cancelled, a sub-line-item of type 'cancellation' |
|
84 | + * should be created, indicating the quantity that were cancelled |
|
85 | + * (because a line item could have a quantity of 1, and its cancellation item |
|
86 | + * could be for 3, indicating that originally 4 were purchased, but 3 have been |
|
87 | + * cancelled, and only one remains). |
|
88 | + * When items are refunded, a cancellation line item should be made, which points |
|
89 | + * to teh payment model object which actually refunded the payment. |
|
90 | + * Cancellations should NOT have any children line items; the should NOT affect |
|
91 | + * any calculations, and are only meant as a record that cancellations have occurred. |
|
92 | + * Their LIN_percent should be 0. |
|
93 | + */ |
|
94 | + const type_cancellation = 'cancellation'; |
|
95 | + |
|
96 | + // various line item object types |
|
97 | + const OBJ_TYPE_EVENT = 'Event'; |
|
98 | + |
|
99 | + const OBJ_TYPE_PRICE = 'Price'; |
|
100 | + |
|
101 | + const OBJ_TYPE_PROMOTION = 'Promotion'; |
|
102 | + |
|
103 | + const OBJ_TYPE_TICKET = 'Ticket'; |
|
104 | + |
|
105 | + const OBJ_TYPE_TRANSACTION = 'Transaction'; |
|
106 | + |
|
107 | + /** |
|
108 | + * @var EEM_Line_Item $_instance |
|
109 | + */ |
|
110 | + protected static $_instance; |
|
111 | + |
|
112 | + |
|
113 | + /** |
|
114 | + * private constructor to prevent direct creation |
|
115 | + * |
|
116 | + * @Constructor |
|
117 | + * @param string $timezone string representing the timezone we want to set for returned Date Time Strings |
|
118 | + * (and any incoming timezone data that gets saved). |
|
119 | + * Note this just sends the timezone info to the date time model field objects. |
|
120 | + * Default is NULL |
|
121 | + * (and will be assumed using the set timezone in the 'timezone_string' wp option) |
|
122 | + * @throws EE_Error |
|
123 | + * @throws InvalidArgumentException |
|
124 | + */ |
|
125 | + protected function __construct($timezone) |
|
126 | + { |
|
127 | + $this->singular_item = esc_html__('Line Item', 'event_espresso'); |
|
128 | + $this->plural_item = esc_html__('Line Items', 'event_espresso'); |
|
129 | + |
|
130 | + $this->_tables = array( |
|
131 | + 'Line_Item' => new EE_Primary_Table('esp_line_item', 'LIN_ID'), |
|
132 | + ); |
|
133 | + $line_items_can_be_for = apply_filters( |
|
134 | + 'FHEE__EEM_Line_Item__line_items_can_be_for', |
|
135 | + array('Ticket', 'Price', 'Event') |
|
136 | + ); |
|
137 | + $this->_fields = array( |
|
138 | + 'Line_Item' => array( |
|
139 | + 'LIN_ID' => new EE_Primary_Key_Int_Field( |
|
140 | + 'LIN_ID', |
|
141 | + esc_html__('ID', 'event_espresso') |
|
142 | + ), |
|
143 | + 'LIN_code' => new EE_Slug_Field( |
|
144 | + 'LIN_code', |
|
145 | + esc_html__('Code for index into Cart', 'event_espresso'), |
|
146 | + true |
|
147 | + ), |
|
148 | + 'TXN_ID' => new EE_Foreign_Key_Int_Field( |
|
149 | + 'TXN_ID', |
|
150 | + esc_html__('Transaction ID', 'event_espresso'), |
|
151 | + true, |
|
152 | + null, |
|
153 | + 'Transaction' |
|
154 | + ), |
|
155 | + 'LIN_name' => new EE_Full_HTML_Field( |
|
156 | + 'LIN_name', |
|
157 | + esc_html__('Line Item Name', 'event_espresso'), |
|
158 | + false, |
|
159 | + '' |
|
160 | + ), |
|
161 | + 'LIN_desc' => new EE_Full_HTML_Field( |
|
162 | + 'LIN_desc', |
|
163 | + esc_html__('Line Item Description', 'event_espresso'), |
|
164 | + true |
|
165 | + ), |
|
166 | + 'LIN_unit_price' => new EE_Money_Field( |
|
167 | + 'LIN_unit_price', |
|
168 | + esc_html__('Unit Price', 'event_espresso'), |
|
169 | + false, |
|
170 | + 0 |
|
171 | + ), |
|
172 | + 'LIN_percent' => new EE_Float_Field( |
|
173 | + 'LIN_percent', |
|
174 | + esc_html__('Percent', 'event_espresso'), |
|
175 | + false, |
|
176 | + 0 |
|
177 | + ), |
|
178 | + 'LIN_is_taxable' => new EE_Boolean_Field( |
|
179 | + 'LIN_is_taxable', |
|
180 | + esc_html__('Taxable', 'event_espresso'), |
|
181 | + false, |
|
182 | + false |
|
183 | + ), |
|
184 | + 'LIN_order' => new EE_Integer_Field( |
|
185 | + 'LIN_order', |
|
186 | + esc_html__('Order of Application towards total of parent', 'event_espresso'), |
|
187 | + false, |
|
188 | + 1 |
|
189 | + ), |
|
190 | + 'LIN_total' => new EE_Money_Field( |
|
191 | + 'LIN_total', |
|
192 | + esc_html__('Total (unit price x quantity)', 'event_espresso'), |
|
193 | + false, |
|
194 | + 0 |
|
195 | + ), |
|
196 | + 'LIN_quantity' => new EE_Integer_Field( |
|
197 | + 'LIN_quantity', |
|
198 | + esc_html__('Quantity', 'event_espresso'), |
|
199 | + true, |
|
200 | + 1 |
|
201 | + ), |
|
202 | + 'LIN_parent' => new EE_Integer_Field( |
|
203 | + 'LIN_parent', |
|
204 | + esc_html__("Parent ID (this item goes towards that Line Item's total)", 'event_espresso'), |
|
205 | + true, |
|
206 | + null |
|
207 | + ), |
|
208 | + 'LIN_type' => new EE_Enum_Text_Field( |
|
209 | + 'LIN_type', |
|
210 | + esc_html__('Type', 'event_espresso'), |
|
211 | + false, |
|
212 | + 'line-item', |
|
213 | + array( |
|
214 | + self::type_line_item => esc_html__('Line Item', 'event_espresso'), |
|
215 | + self::type_sub_line_item => esc_html__('Sub-Item', 'event_espresso'), |
|
216 | + self::type_sub_total => esc_html__('Subtotal', 'event_espresso'), |
|
217 | + self::type_tax_sub_total => esc_html__('Tax Subtotal', 'event_espresso'), |
|
218 | + self::type_tax => esc_html__('Tax', 'event_espresso'), |
|
219 | + self::type_total => esc_html__('Total', 'event_espresso'), |
|
220 | + self::type_cancellation => esc_html__('Cancellation', 'event_espresso'), |
|
221 | + ) |
|
222 | + ), |
|
223 | + 'OBJ_ID' => new EE_Foreign_Key_Int_Field( |
|
224 | + 'OBJ_ID', |
|
225 | + esc_html__('ID of Item purchased.', 'event_espresso'), |
|
226 | + true, |
|
227 | + null, |
|
228 | + $line_items_can_be_for |
|
229 | + ), |
|
230 | + 'OBJ_type' => new EE_Any_Foreign_Model_Name_Field( |
|
231 | + 'OBJ_type', |
|
232 | + esc_html__('Model Name this Line Item is for', 'event_espresso'), |
|
233 | + true, |
|
234 | + null, |
|
235 | + $line_items_can_be_for |
|
236 | + ), |
|
237 | + 'LIN_timestamp' => new EE_Datetime_Field( |
|
238 | + 'LIN_timestamp', |
|
239 | + esc_html__('When the line item was created', 'event_espresso'), |
|
240 | + false, |
|
241 | + EE_Datetime_Field::now, |
|
242 | + $timezone |
|
243 | + ), |
|
244 | + ), |
|
245 | + ); |
|
246 | + $this->_model_relations = array( |
|
247 | + 'Transaction' => new EE_Belongs_To_Relation(), |
|
248 | + 'Ticket' => new EE_Belongs_To_Any_Relation(), |
|
249 | + 'Price' => new EE_Belongs_To_Any_Relation(), |
|
250 | + 'Event' => new EE_Belongs_To_Any_Relation(), |
|
251 | + ); |
|
252 | + $this->_model_chain_to_wp_user = 'Transaction.Registration.Event'; |
|
253 | + $this->_caps_slug = 'transactions'; |
|
254 | + parent::__construct($timezone); |
|
255 | + } |
|
256 | + |
|
257 | + |
|
258 | + /** |
|
259 | + * Gets all the line items for this transaction of the given type |
|
260 | + * |
|
261 | + * @param string $line_item_type like one of EEM_Line_Item::type_* |
|
262 | + * @param EE_Transaction|int $transaction |
|
263 | + * @return EE_Base_Class[]|EE_Line_Item[] |
|
264 | + * @throws EE_Error |
|
265 | + * @throws InvalidArgumentException |
|
266 | + * @throws InvalidDataTypeException |
|
267 | + * @throws InvalidInterfaceException |
|
268 | + */ |
|
269 | + public function get_all_of_type_for_transaction($line_item_type, $transaction) |
|
270 | + { |
|
271 | + $transaction = EEM_Transaction::instance()->ensure_is_ID($transaction); |
|
272 | + return $this->get_all(array( |
|
273 | + array( |
|
274 | + 'LIN_type' => $line_item_type, |
|
275 | + 'TXN_ID' => $transaction, |
|
276 | + ), |
|
277 | + )); |
|
278 | + } |
|
279 | + |
|
280 | + |
|
281 | + /** |
|
282 | + * Gets all line items unrelated to tickets that are normal line items |
|
283 | + * (eg shipping, promotions, and miscellaneous other stuff should probably fit in this category) |
|
284 | + * |
|
285 | + * @param EE_Transaction|int $transaction |
|
286 | + * @return EE_Base_Class[]|EE_Line_Item[] |
|
287 | + * @throws EE_Error |
|
288 | + * @throws InvalidArgumentException |
|
289 | + * @throws InvalidDataTypeException |
|
290 | + * @throws InvalidInterfaceException |
|
291 | + */ |
|
292 | + public function get_all_non_ticket_line_items_for_transaction($transaction) |
|
293 | + { |
|
294 | + $transaction = EEM_Transaction::instance()->ensure_is_ID($transaction); |
|
295 | + return $this->get_all(array( |
|
296 | + array( |
|
297 | + 'LIN_type' => self::type_line_item, |
|
298 | + 'TXN_ID' => $transaction, |
|
299 | + 'OR' => array( |
|
300 | + 'OBJ_type*notticket' => array('!=', EEM_Line_Item::OBJ_TYPE_TICKET), |
|
301 | + 'OBJ_type*null' => array('IS_NULL'), |
|
302 | + ), |
|
303 | + ), |
|
304 | + )); |
|
305 | + } |
|
306 | + |
|
307 | + |
|
308 | + /** |
|
309 | + * Deletes line items with no transaction who have passed the transaction cutoff time. |
|
310 | + * This needs to be very efficient |
|
311 | + * because if there are spam bots afoot there will be LOTS of line items. Also MySQL doesn't allow a limit when |
|
312 | + * deleting and joining tables like this. |
|
313 | + * |
|
314 | + * @return int count of how many deleted |
|
315 | + * @throws EE_Error |
|
316 | + * @throws InvalidArgumentException |
|
317 | + * @throws InvalidDataTypeException |
|
318 | + * @throws InvalidInterfaceException |
|
319 | + */ |
|
320 | + public function delete_line_items_with_no_transaction() |
|
321 | + { |
|
322 | + /** @type WPDB $wpdb */ |
|
323 | + global $wpdb; |
|
324 | + $time_to_leave_alone = apply_filters( |
|
325 | + 'FHEE__EEM_Line_Item__delete_line_items_with_no_transaction__time_to_leave_alone', |
|
326 | + WEEK_IN_SECONDS |
|
327 | + ); |
|
328 | + $query = $wpdb->prepare( |
|
329 | + 'DELETE li |
|
330 | 330 | FROM ' . $this->table() . ' li |
331 | 331 | LEFT JOIN ' . EEM_Transaction::instance()->table() . ' t ON li.TXN_ID = t.TXN_ID |
332 | 332 | WHERE t.TXN_ID IS NULL AND li.LIN_timestamp < %s', |
333 | - // use GMT time because that's what TXN_timestamps are in |
|
334 | - date('Y-m-d H:i:s', time() - $time_to_leave_alone) |
|
335 | - ); |
|
336 | - return $wpdb->query($query); |
|
337 | - } |
|
338 | - |
|
339 | - |
|
340 | - /** |
|
341 | - * get_line_item_for_transaction_object |
|
342 | - * Gets a transaction's line item record for a specific object such as a EE_Event or EE_Ticket |
|
343 | - * |
|
344 | - * @param int $TXN_ID |
|
345 | - * @param EE_Base_Class $object |
|
346 | - * @return EE_Base_Class[]|EE_Line_Item[] |
|
347 | - * @throws EE_Error |
|
348 | - * @throws InvalidArgumentException |
|
349 | - * @throws InvalidDataTypeException |
|
350 | - * @throws InvalidInterfaceException |
|
351 | - * @throws ReflectionException |
|
352 | - */ |
|
353 | - public function get_line_item_for_transaction_object($TXN_ID, EE_Base_Class $object) |
|
354 | - { |
|
355 | - return $this->get_all(array( |
|
356 | - array( |
|
357 | - 'TXN_ID' => $TXN_ID, |
|
358 | - 'OBJ_type' => str_replace('EE_', '', get_class($object)), |
|
359 | - 'OBJ_ID' => $object->ID(), |
|
360 | - ), |
|
361 | - )); |
|
362 | - } |
|
363 | - |
|
364 | - |
|
365 | - /** |
|
366 | - * get_object_line_items_for_transaction |
|
367 | - * Gets all of the the object line items for a transaction, based on an object type plus an array of object IDs |
|
368 | - * |
|
369 | - * @param int $TXN_ID |
|
370 | - * @param string $OBJ_type |
|
371 | - * @param array $OBJ_IDs |
|
372 | - * @return EE_Base_Class[]|EE_Line_Item[] |
|
373 | - * @throws EE_Error |
|
374 | - */ |
|
375 | - public function get_object_line_items_for_transaction( |
|
376 | - $TXN_ID, |
|
377 | - $OBJ_type = EEM_Line_Item::OBJ_TYPE_EVENT, |
|
378 | - $OBJ_IDs = array() |
|
379 | - ) { |
|
380 | - $query_params = array( |
|
381 | - 'OBJ_type' => $OBJ_type, |
|
382 | - // if incoming $OBJ_IDs is an array, then make sure it is formatted correctly for the query |
|
383 | - 'OBJ_ID' => is_array($OBJ_IDs) && ! isset($OBJ_IDs['IN']) ? array('IN', $OBJ_IDs) : $OBJ_IDs, |
|
384 | - ); |
|
385 | - if ($TXN_ID) { |
|
386 | - $query_params['TXN_ID'] = $TXN_ID; |
|
387 | - } |
|
388 | - return $this->get_all(array($query_params)); |
|
389 | - } |
|
390 | - |
|
391 | - |
|
392 | - /** |
|
393 | - * get_all_ticket_line_items_for_transaction |
|
394 | - * |
|
395 | - * @param EE_Transaction $transaction |
|
396 | - * @return EE_Base_Class[]|EE_Line_Item[] |
|
397 | - * @throws EE_Error |
|
398 | - * @throws InvalidArgumentException |
|
399 | - * @throws InvalidDataTypeException |
|
400 | - * @throws InvalidInterfaceException |
|
401 | - * @throws ReflectionException |
|
402 | - */ |
|
403 | - public function get_all_ticket_line_items_for_transaction(EE_Transaction $transaction) |
|
404 | - { |
|
405 | - return $this->get_all(array( |
|
406 | - array( |
|
407 | - 'TXN_ID' => $transaction->ID(), |
|
408 | - 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TICKET, |
|
409 | - ), |
|
410 | - )); |
|
411 | - } |
|
412 | - |
|
413 | - |
|
414 | - /** |
|
415 | - * get_ticket_line_item_for_transaction |
|
416 | - * |
|
417 | - * @param int $TXN_ID |
|
418 | - * @param int $TKT_ID |
|
419 | - * @return EE_Base_Class|EE_Line_Item|EE_Soft_Delete_Base_Class|NULL |
|
420 | - * @throws EE_Error |
|
421 | - * @throws InvalidArgumentException |
|
422 | - * @throws InvalidDataTypeException |
|
423 | - * @throws InvalidInterfaceException |
|
424 | - */ |
|
425 | - public function get_ticket_line_item_for_transaction($TXN_ID, $TKT_ID) |
|
426 | - { |
|
427 | - return $this->get_one(array( |
|
428 | - array( |
|
429 | - 'TXN_ID' => EEM_Transaction::instance()->ensure_is_ID($TXN_ID), |
|
430 | - 'OBJ_ID' => $TKT_ID, |
|
431 | - 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TICKET, |
|
432 | - ), |
|
433 | - )); |
|
434 | - } |
|
435 | - |
|
436 | - |
|
437 | - /** |
|
438 | - * get_existing_promotion_line_item |
|
439 | - * searches the cart for existing line items for the specified promotion |
|
440 | - * |
|
441 | - * @since 1.0.0 |
|
442 | - * @param EE_Line_Item $parent_line_item |
|
443 | - * @param EE_Promotion $promotion |
|
444 | - * @return EE_Base_Class|EE_Line_Item|EE_Soft_Delete_Base_Class|NULL |
|
445 | - * @throws EE_Error |
|
446 | - * @throws InvalidArgumentException |
|
447 | - * @throws InvalidDataTypeException |
|
448 | - * @throws InvalidInterfaceException |
|
449 | - * @throws ReflectionException |
|
450 | - */ |
|
451 | - public function get_existing_promotion_line_item(EE_Line_Item $parent_line_item, EE_Promotion $promotion) |
|
452 | - { |
|
453 | - return $this->get_one(array( |
|
454 | - array( |
|
455 | - 'TXN_ID' => $parent_line_item->TXN_ID(), |
|
456 | - 'LIN_parent' => $parent_line_item->ID(), |
|
457 | - 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_PROMOTION, |
|
458 | - 'OBJ_ID' => $promotion->ID(), |
|
459 | - ), |
|
460 | - )); |
|
461 | - } |
|
462 | - |
|
463 | - |
|
464 | - /** |
|
465 | - * get_all_promotion_line_items |
|
466 | - * searches the cart for any and all existing promotion line items |
|
467 | - * |
|
468 | - * @since 1.0.0 |
|
469 | - * @param EE_Line_Item $parent_line_item |
|
470 | - * @return EE_Base_Class[]|EE_Line_Item[] |
|
471 | - * @throws EE_Error |
|
472 | - * @throws InvalidArgumentException |
|
473 | - * @throws InvalidDataTypeException |
|
474 | - * @throws InvalidInterfaceException |
|
475 | - * @throws ReflectionException |
|
476 | - */ |
|
477 | - public function get_all_promotion_line_items(EE_Line_Item $parent_line_item) |
|
478 | - { |
|
479 | - return $this->get_all(array( |
|
480 | - array( |
|
481 | - 'TXN_ID' => $parent_line_item->TXN_ID(), |
|
482 | - 'LIN_parent' => $parent_line_item->ID(), |
|
483 | - 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_PROMOTION, |
|
484 | - ), |
|
485 | - )); |
|
486 | - } |
|
487 | - |
|
488 | - |
|
489 | - /** |
|
490 | - * Gets the registration's corresponding line item. |
|
491 | - * Note: basically does NOT support having multiple line items for a single ticket, |
|
492 | - * which would happen if some of the registrations had a price modifier while others didn't. |
|
493 | - * In order to support that, we'd probably need a LIN_ID on registrations or something. |
|
494 | - * |
|
495 | - * @param EE_Registration $registration |
|
496 | - * @return EE_Base_Class|EE_Line_ITem|EE_Soft_Delete_Base_Class|NULL |
|
497 | - * @throws EE_Error |
|
498 | - */ |
|
499 | - public function get_line_item_for_registration(EE_Registration $registration) |
|
500 | - { |
|
501 | - return $this->get_one($this->line_item_for_registration_query_params($registration)); |
|
502 | - } |
|
503 | - |
|
504 | - |
|
505 | - /** |
|
506 | - * Gets the query params used to retrieve a specific line item for the given registration |
|
507 | - * |
|
508 | - * @param EE_Registration $registration |
|
509 | - * @param array $original_query_params any extra query params you'd like to be merged with |
|
510 | - * @return array @see |
|
511 | - * https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
512 | - * @throws EE_Error |
|
513 | - */ |
|
514 | - public function line_item_for_registration_query_params( |
|
515 | - EE_Registration $registration, |
|
516 | - $original_query_params = array() |
|
517 | - ) { |
|
518 | - return array_replace_recursive($original_query_params, array( |
|
519 | - array( |
|
520 | - 'OBJ_ID' => $registration->ticket_ID(), |
|
521 | - 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TICKET, |
|
522 | - 'TXN_ID' => $registration->transaction_ID(), |
|
523 | - ), |
|
524 | - )); |
|
525 | - } |
|
526 | - |
|
527 | - |
|
528 | - /** |
|
529 | - * @return EE_Base_Class[]|EE_Line_Item[] |
|
530 | - * @throws InvalidInterfaceException |
|
531 | - * @throws InvalidDataTypeException |
|
532 | - * @throws EE_Error |
|
533 | - * @throws InvalidArgumentException |
|
534 | - */ |
|
535 | - public function get_total_line_items_with_no_transaction() |
|
536 | - { |
|
537 | - return $this->get_total_line_items_for_carts(); |
|
538 | - } |
|
539 | - |
|
540 | - |
|
541 | - /** |
|
542 | - * @return EE_Base_Class[]|EE_Line_Item[] |
|
543 | - * @throws InvalidInterfaceException |
|
544 | - * @throws InvalidDataTypeException |
|
545 | - * @throws EE_Error |
|
546 | - * @throws InvalidArgumentException |
|
547 | - */ |
|
548 | - public function get_total_line_items_for_active_carts() |
|
549 | - { |
|
550 | - return $this->get_total_line_items_for_carts(false); |
|
551 | - } |
|
552 | - |
|
553 | - |
|
554 | - /** |
|
555 | - * @return EE_Base_Class[]|EE_Line_Item[] |
|
556 | - * @throws InvalidInterfaceException |
|
557 | - * @throws InvalidDataTypeException |
|
558 | - * @throws EE_Error |
|
559 | - * @throws InvalidArgumentException |
|
560 | - */ |
|
561 | - public function get_total_line_items_for_expired_carts() |
|
562 | - { |
|
563 | - return $this->get_total_line_items_for_carts(true); |
|
564 | - } |
|
565 | - |
|
566 | - |
|
567 | - /** |
|
568 | - * Returns an array of grand total line items where the TXN_ID is 0. |
|
569 | - * If $expired is set to true, then only line items for expired sessions will be returned. |
|
570 | - * If $expired is set to false, then only line items for active sessions will be returned. |
|
571 | - * |
|
572 | - * @param null $expired |
|
573 | - * @return EE_Base_Class[]|EE_Line_Item[] |
|
574 | - * @throws EE_Error |
|
575 | - * @throws InvalidArgumentException |
|
576 | - * @throws InvalidDataTypeException |
|
577 | - * @throws InvalidInterfaceException |
|
578 | - */ |
|
579 | - private function get_total_line_items_for_carts($expired = null) |
|
580 | - { |
|
581 | - $where_params = array( |
|
582 | - 'TXN_ID' => 0, |
|
583 | - 'LIN_type' => 'total', |
|
584 | - ); |
|
585 | - if ($expired !== null) { |
|
586 | - /** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */ |
|
587 | - $session_lifespan = LoaderFactory::getLoader()->getShared( |
|
588 | - 'EventEspresso\core\domain\values\session\SessionLifespan' |
|
589 | - ); |
|
590 | - $where_params['LIN_timestamp'] = array( |
|
591 | - $expired ? '<=' : '>', |
|
592 | - $session_lifespan->expiration(), |
|
593 | - ); |
|
594 | - } |
|
595 | - return $this->get_all(array($where_params)); |
|
596 | - } |
|
597 | - |
|
598 | - |
|
599 | - /** |
|
600 | - * Returns an array of ticket total line items where the TXN_ID is 0 |
|
601 | - * AND the timestamp is older than the session lifespan. |
|
602 | - * |
|
603 | - * @param int $timestamp |
|
604 | - * @return EE_Base_Class[]|EE_Line_Item[] |
|
605 | - * @throws EE_Error |
|
606 | - * @throws InvalidArgumentException |
|
607 | - * @throws InvalidDataTypeException |
|
608 | - * @throws InvalidInterfaceException |
|
609 | - */ |
|
610 | - public function getTicketLineItemsForExpiredCarts($timestamp = 0) |
|
611 | - { |
|
612 | - if (! absint($timestamp)) { |
|
613 | - /** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */ |
|
614 | - $session_lifespan = LoaderFactory::getLoader()->getShared( |
|
615 | - 'EventEspresso\core\domain\values\session\SessionLifespan' |
|
616 | - ); |
|
617 | - $timestamp = $session_lifespan->expiration(); |
|
618 | - } |
|
619 | - return $this->get_all( |
|
620 | - array( |
|
621 | - array( |
|
622 | - 'TXN_ID' => 0, |
|
623 | - 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TICKET, |
|
624 | - 'LIN_timestamp' => array('<=', $timestamp), |
|
625 | - ), |
|
626 | - ) |
|
627 | - ); |
|
628 | - } |
|
333 | + // use GMT time because that's what TXN_timestamps are in |
|
334 | + date('Y-m-d H:i:s', time() - $time_to_leave_alone) |
|
335 | + ); |
|
336 | + return $wpdb->query($query); |
|
337 | + } |
|
338 | + |
|
339 | + |
|
340 | + /** |
|
341 | + * get_line_item_for_transaction_object |
|
342 | + * Gets a transaction's line item record for a specific object such as a EE_Event or EE_Ticket |
|
343 | + * |
|
344 | + * @param int $TXN_ID |
|
345 | + * @param EE_Base_Class $object |
|
346 | + * @return EE_Base_Class[]|EE_Line_Item[] |
|
347 | + * @throws EE_Error |
|
348 | + * @throws InvalidArgumentException |
|
349 | + * @throws InvalidDataTypeException |
|
350 | + * @throws InvalidInterfaceException |
|
351 | + * @throws ReflectionException |
|
352 | + */ |
|
353 | + public function get_line_item_for_transaction_object($TXN_ID, EE_Base_Class $object) |
|
354 | + { |
|
355 | + return $this->get_all(array( |
|
356 | + array( |
|
357 | + 'TXN_ID' => $TXN_ID, |
|
358 | + 'OBJ_type' => str_replace('EE_', '', get_class($object)), |
|
359 | + 'OBJ_ID' => $object->ID(), |
|
360 | + ), |
|
361 | + )); |
|
362 | + } |
|
363 | + |
|
364 | + |
|
365 | + /** |
|
366 | + * get_object_line_items_for_transaction |
|
367 | + * Gets all of the the object line items for a transaction, based on an object type plus an array of object IDs |
|
368 | + * |
|
369 | + * @param int $TXN_ID |
|
370 | + * @param string $OBJ_type |
|
371 | + * @param array $OBJ_IDs |
|
372 | + * @return EE_Base_Class[]|EE_Line_Item[] |
|
373 | + * @throws EE_Error |
|
374 | + */ |
|
375 | + public function get_object_line_items_for_transaction( |
|
376 | + $TXN_ID, |
|
377 | + $OBJ_type = EEM_Line_Item::OBJ_TYPE_EVENT, |
|
378 | + $OBJ_IDs = array() |
|
379 | + ) { |
|
380 | + $query_params = array( |
|
381 | + 'OBJ_type' => $OBJ_type, |
|
382 | + // if incoming $OBJ_IDs is an array, then make sure it is formatted correctly for the query |
|
383 | + 'OBJ_ID' => is_array($OBJ_IDs) && ! isset($OBJ_IDs['IN']) ? array('IN', $OBJ_IDs) : $OBJ_IDs, |
|
384 | + ); |
|
385 | + if ($TXN_ID) { |
|
386 | + $query_params['TXN_ID'] = $TXN_ID; |
|
387 | + } |
|
388 | + return $this->get_all(array($query_params)); |
|
389 | + } |
|
390 | + |
|
391 | + |
|
392 | + /** |
|
393 | + * get_all_ticket_line_items_for_transaction |
|
394 | + * |
|
395 | + * @param EE_Transaction $transaction |
|
396 | + * @return EE_Base_Class[]|EE_Line_Item[] |
|
397 | + * @throws EE_Error |
|
398 | + * @throws InvalidArgumentException |
|
399 | + * @throws InvalidDataTypeException |
|
400 | + * @throws InvalidInterfaceException |
|
401 | + * @throws ReflectionException |
|
402 | + */ |
|
403 | + public function get_all_ticket_line_items_for_transaction(EE_Transaction $transaction) |
|
404 | + { |
|
405 | + return $this->get_all(array( |
|
406 | + array( |
|
407 | + 'TXN_ID' => $transaction->ID(), |
|
408 | + 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TICKET, |
|
409 | + ), |
|
410 | + )); |
|
411 | + } |
|
412 | + |
|
413 | + |
|
414 | + /** |
|
415 | + * get_ticket_line_item_for_transaction |
|
416 | + * |
|
417 | + * @param int $TXN_ID |
|
418 | + * @param int $TKT_ID |
|
419 | + * @return EE_Base_Class|EE_Line_Item|EE_Soft_Delete_Base_Class|NULL |
|
420 | + * @throws EE_Error |
|
421 | + * @throws InvalidArgumentException |
|
422 | + * @throws InvalidDataTypeException |
|
423 | + * @throws InvalidInterfaceException |
|
424 | + */ |
|
425 | + public function get_ticket_line_item_for_transaction($TXN_ID, $TKT_ID) |
|
426 | + { |
|
427 | + return $this->get_one(array( |
|
428 | + array( |
|
429 | + 'TXN_ID' => EEM_Transaction::instance()->ensure_is_ID($TXN_ID), |
|
430 | + 'OBJ_ID' => $TKT_ID, |
|
431 | + 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TICKET, |
|
432 | + ), |
|
433 | + )); |
|
434 | + } |
|
435 | + |
|
436 | + |
|
437 | + /** |
|
438 | + * get_existing_promotion_line_item |
|
439 | + * searches the cart for existing line items for the specified promotion |
|
440 | + * |
|
441 | + * @since 1.0.0 |
|
442 | + * @param EE_Line_Item $parent_line_item |
|
443 | + * @param EE_Promotion $promotion |
|
444 | + * @return EE_Base_Class|EE_Line_Item|EE_Soft_Delete_Base_Class|NULL |
|
445 | + * @throws EE_Error |
|
446 | + * @throws InvalidArgumentException |
|
447 | + * @throws InvalidDataTypeException |
|
448 | + * @throws InvalidInterfaceException |
|
449 | + * @throws ReflectionException |
|
450 | + */ |
|
451 | + public function get_existing_promotion_line_item(EE_Line_Item $parent_line_item, EE_Promotion $promotion) |
|
452 | + { |
|
453 | + return $this->get_one(array( |
|
454 | + array( |
|
455 | + 'TXN_ID' => $parent_line_item->TXN_ID(), |
|
456 | + 'LIN_parent' => $parent_line_item->ID(), |
|
457 | + 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_PROMOTION, |
|
458 | + 'OBJ_ID' => $promotion->ID(), |
|
459 | + ), |
|
460 | + )); |
|
461 | + } |
|
462 | + |
|
463 | + |
|
464 | + /** |
|
465 | + * get_all_promotion_line_items |
|
466 | + * searches the cart for any and all existing promotion line items |
|
467 | + * |
|
468 | + * @since 1.0.0 |
|
469 | + * @param EE_Line_Item $parent_line_item |
|
470 | + * @return EE_Base_Class[]|EE_Line_Item[] |
|
471 | + * @throws EE_Error |
|
472 | + * @throws InvalidArgumentException |
|
473 | + * @throws InvalidDataTypeException |
|
474 | + * @throws InvalidInterfaceException |
|
475 | + * @throws ReflectionException |
|
476 | + */ |
|
477 | + public function get_all_promotion_line_items(EE_Line_Item $parent_line_item) |
|
478 | + { |
|
479 | + return $this->get_all(array( |
|
480 | + array( |
|
481 | + 'TXN_ID' => $parent_line_item->TXN_ID(), |
|
482 | + 'LIN_parent' => $parent_line_item->ID(), |
|
483 | + 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_PROMOTION, |
|
484 | + ), |
|
485 | + )); |
|
486 | + } |
|
487 | + |
|
488 | + |
|
489 | + /** |
|
490 | + * Gets the registration's corresponding line item. |
|
491 | + * Note: basically does NOT support having multiple line items for a single ticket, |
|
492 | + * which would happen if some of the registrations had a price modifier while others didn't. |
|
493 | + * In order to support that, we'd probably need a LIN_ID on registrations or something. |
|
494 | + * |
|
495 | + * @param EE_Registration $registration |
|
496 | + * @return EE_Base_Class|EE_Line_ITem|EE_Soft_Delete_Base_Class|NULL |
|
497 | + * @throws EE_Error |
|
498 | + */ |
|
499 | + public function get_line_item_for_registration(EE_Registration $registration) |
|
500 | + { |
|
501 | + return $this->get_one($this->line_item_for_registration_query_params($registration)); |
|
502 | + } |
|
503 | + |
|
504 | + |
|
505 | + /** |
|
506 | + * Gets the query params used to retrieve a specific line item for the given registration |
|
507 | + * |
|
508 | + * @param EE_Registration $registration |
|
509 | + * @param array $original_query_params any extra query params you'd like to be merged with |
|
510 | + * @return array @see |
|
511 | + * https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md |
|
512 | + * @throws EE_Error |
|
513 | + */ |
|
514 | + public function line_item_for_registration_query_params( |
|
515 | + EE_Registration $registration, |
|
516 | + $original_query_params = array() |
|
517 | + ) { |
|
518 | + return array_replace_recursive($original_query_params, array( |
|
519 | + array( |
|
520 | + 'OBJ_ID' => $registration->ticket_ID(), |
|
521 | + 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TICKET, |
|
522 | + 'TXN_ID' => $registration->transaction_ID(), |
|
523 | + ), |
|
524 | + )); |
|
525 | + } |
|
526 | + |
|
527 | + |
|
528 | + /** |
|
529 | + * @return EE_Base_Class[]|EE_Line_Item[] |
|
530 | + * @throws InvalidInterfaceException |
|
531 | + * @throws InvalidDataTypeException |
|
532 | + * @throws EE_Error |
|
533 | + * @throws InvalidArgumentException |
|
534 | + */ |
|
535 | + public function get_total_line_items_with_no_transaction() |
|
536 | + { |
|
537 | + return $this->get_total_line_items_for_carts(); |
|
538 | + } |
|
539 | + |
|
540 | + |
|
541 | + /** |
|
542 | + * @return EE_Base_Class[]|EE_Line_Item[] |
|
543 | + * @throws InvalidInterfaceException |
|
544 | + * @throws InvalidDataTypeException |
|
545 | + * @throws EE_Error |
|
546 | + * @throws InvalidArgumentException |
|
547 | + */ |
|
548 | + public function get_total_line_items_for_active_carts() |
|
549 | + { |
|
550 | + return $this->get_total_line_items_for_carts(false); |
|
551 | + } |
|
552 | + |
|
553 | + |
|
554 | + /** |
|
555 | + * @return EE_Base_Class[]|EE_Line_Item[] |
|
556 | + * @throws InvalidInterfaceException |
|
557 | + * @throws InvalidDataTypeException |
|
558 | + * @throws EE_Error |
|
559 | + * @throws InvalidArgumentException |
|
560 | + */ |
|
561 | + public function get_total_line_items_for_expired_carts() |
|
562 | + { |
|
563 | + return $this->get_total_line_items_for_carts(true); |
|
564 | + } |
|
565 | + |
|
566 | + |
|
567 | + /** |
|
568 | + * Returns an array of grand total line items where the TXN_ID is 0. |
|
569 | + * If $expired is set to true, then only line items for expired sessions will be returned. |
|
570 | + * If $expired is set to false, then only line items for active sessions will be returned. |
|
571 | + * |
|
572 | + * @param null $expired |
|
573 | + * @return EE_Base_Class[]|EE_Line_Item[] |
|
574 | + * @throws EE_Error |
|
575 | + * @throws InvalidArgumentException |
|
576 | + * @throws InvalidDataTypeException |
|
577 | + * @throws InvalidInterfaceException |
|
578 | + */ |
|
579 | + private function get_total_line_items_for_carts($expired = null) |
|
580 | + { |
|
581 | + $where_params = array( |
|
582 | + 'TXN_ID' => 0, |
|
583 | + 'LIN_type' => 'total', |
|
584 | + ); |
|
585 | + if ($expired !== null) { |
|
586 | + /** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */ |
|
587 | + $session_lifespan = LoaderFactory::getLoader()->getShared( |
|
588 | + 'EventEspresso\core\domain\values\session\SessionLifespan' |
|
589 | + ); |
|
590 | + $where_params['LIN_timestamp'] = array( |
|
591 | + $expired ? '<=' : '>', |
|
592 | + $session_lifespan->expiration(), |
|
593 | + ); |
|
594 | + } |
|
595 | + return $this->get_all(array($where_params)); |
|
596 | + } |
|
597 | + |
|
598 | + |
|
599 | + /** |
|
600 | + * Returns an array of ticket total line items where the TXN_ID is 0 |
|
601 | + * AND the timestamp is older than the session lifespan. |
|
602 | + * |
|
603 | + * @param int $timestamp |
|
604 | + * @return EE_Base_Class[]|EE_Line_Item[] |
|
605 | + * @throws EE_Error |
|
606 | + * @throws InvalidArgumentException |
|
607 | + * @throws InvalidDataTypeException |
|
608 | + * @throws InvalidInterfaceException |
|
609 | + */ |
|
610 | + public function getTicketLineItemsForExpiredCarts($timestamp = 0) |
|
611 | + { |
|
612 | + if (! absint($timestamp)) { |
|
613 | + /** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */ |
|
614 | + $session_lifespan = LoaderFactory::getLoader()->getShared( |
|
615 | + 'EventEspresso\core\domain\values\session\SessionLifespan' |
|
616 | + ); |
|
617 | + $timestamp = $session_lifespan->expiration(); |
|
618 | + } |
|
619 | + return $this->get_all( |
|
620 | + array( |
|
621 | + array( |
|
622 | + 'TXN_ID' => 0, |
|
623 | + 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TICKET, |
|
624 | + 'LIN_timestamp' => array('<=', $timestamp), |
|
625 | + ), |
|
626 | + ) |
|
627 | + ); |
|
628 | + } |
|
629 | 629 | } |
@@ -13,816 +13,816 @@ discard block |
||
13 | 13 | class EEM_Registration extends EEM_Soft_Delete_Base |
14 | 14 | { |
15 | 15 | |
16 | - /** |
|
17 | - * @var EEM_Registration $_instance |
|
18 | - */ |
|
19 | - protected static $_instance; |
|
20 | - |
|
21 | - /** |
|
22 | - * Keys are the status IDs for registrations (eg, RAP, RCN, etc), and the values |
|
23 | - * are status codes (eg, approved, cancelled, etc) |
|
24 | - * |
|
25 | - * @var array |
|
26 | - */ |
|
27 | - private static $_reg_status; |
|
28 | - |
|
29 | - /** |
|
30 | - * The value of REG_count for a primary registrant |
|
31 | - */ |
|
32 | - const PRIMARY_REGISTRANT_COUNT = 1; |
|
33 | - |
|
34 | - /** |
|
35 | - * Status ID (STS_ID on esp_status table) to indicate an INCOMPLETE registration. |
|
36 | - * Initial status for registrations when they are first created |
|
37 | - * Payments are NOT allowed. |
|
38 | - * Automatically toggled to whatever the default Event registration status is upon completion of the attendee |
|
39 | - * information reg step NO space reserved. Registration is NOT active |
|
40 | - */ |
|
41 | - const status_id_incomplete = 'RIC'; |
|
42 | - |
|
43 | - /** |
|
44 | - * Status ID (STS_ID on esp_status table) to indicate an UNAPPROVED registration. |
|
45 | - * Payments are NOT allowed. |
|
46 | - * Event Admin must manually toggle STS_ID for it to change |
|
47 | - * No space reserved. |
|
48 | - * Registration is active |
|
49 | - */ |
|
50 | - const status_id_not_approved = 'RNA'; |
|
51 | - |
|
52 | - /** |
|
53 | - * Status ID (STS_ID on esp_status table) to indicate registration is PENDING_PAYMENT . |
|
54 | - * Payments are allowed. |
|
55 | - * STS_ID will automatically be toggled to RAP if payment is made in full by the attendee |
|
56 | - * No space reserved. |
|
57 | - * Registration is active |
|
58 | - */ |
|
59 | - const status_id_pending_payment = 'RPP'; |
|
60 | - |
|
61 | - /** |
|
62 | - * Status ID (STS_ID on esp_status table) to indicate registration is on the WAIT_LIST . |
|
63 | - * Payments are allowed. |
|
64 | - * STS_ID will automatically be toggled to RAP if payment is made in full by the attendee |
|
65 | - * No space reserved. |
|
66 | - * Registration is active |
|
67 | - */ |
|
68 | - const status_id_wait_list = 'RWL'; |
|
69 | - |
|
70 | - /** |
|
71 | - * Status ID (STS_ID on esp_status table) to indicate an APPROVED registration. |
|
72 | - * the TXN may or may not be completed ( paid in full ) |
|
73 | - * Payments are allowed. |
|
74 | - * A space IS reserved. |
|
75 | - * Registration is active |
|
76 | - */ |
|
77 | - const status_id_approved = 'RAP'; |
|
78 | - |
|
79 | - /** |
|
80 | - * Status ID (STS_ID on esp_status table) to indicate a registration was CANCELLED by the attendee. |
|
81 | - * Payments are NOT allowed. |
|
82 | - * NO space reserved. |
|
83 | - * Registration is NOT active |
|
84 | - */ |
|
85 | - const status_id_cancelled = 'RCN'; |
|
86 | - |
|
87 | - /** |
|
88 | - * Status ID (STS_ID on esp_status table) to indicate a registration was DECLINED by the Event Admin |
|
89 | - * Payments are NOT allowed. |
|
90 | - * No space reserved. |
|
91 | - * Registration is NOT active |
|
92 | - */ |
|
93 | - const status_id_declined = 'RDC'; |
|
94 | - |
|
95 | - /** |
|
96 | - * @var TableAnalysis $table_analysis |
|
97 | - */ |
|
98 | - protected $_table_analysis; |
|
99 | - |
|
100 | - |
|
101 | - /** |
|
102 | - * private constructor to prevent direct creation |
|
103 | - * |
|
104 | - * @Constructor |
|
105 | - * @access protected |
|
106 | - * @param string $timezone string representing the timezone we want to set for returned Date Time Strings (and any |
|
107 | - * incoming timezone data that gets saved). Note this just sends the timezone info to the |
|
108 | - * date time model field objects. Default is NULL (and will be assumed using the set |
|
109 | - * timezone in the 'timezone_string' wp option) |
|
110 | - * @throws EE_Error |
|
111 | - */ |
|
112 | - protected function __construct($timezone = null) |
|
113 | - { |
|
114 | - $this->_table_analysis = EE_Registry::instance()->create('TableAnalysis', array(), true); |
|
115 | - $this->singular_item = esc_html__('Registration', 'event_espresso'); |
|
116 | - $this->plural_item = esc_html__('Registrations', 'event_espresso'); |
|
117 | - $this->_tables = array( |
|
118 | - 'Registration' => new EE_Primary_Table('esp_registration', 'REG_ID'), |
|
119 | - ); |
|
120 | - $this->_fields = array( |
|
121 | - 'Registration' => array( |
|
122 | - 'REG_ID' => new EE_Primary_Key_Int_Field( |
|
123 | - 'REG_ID', |
|
124 | - esc_html__('Registration ID', 'event_espresso') |
|
125 | - ), |
|
126 | - 'EVT_ID' => new EE_Foreign_Key_Int_Field( |
|
127 | - 'EVT_ID', |
|
128 | - esc_html__('Event ID', 'event_espresso'), |
|
129 | - false, |
|
130 | - 0, |
|
131 | - 'Event' |
|
132 | - ), |
|
133 | - 'ATT_ID' => new EE_Foreign_Key_Int_Field( |
|
134 | - 'ATT_ID', |
|
135 | - esc_html__('Attendee ID', 'event_espresso'), |
|
136 | - false, |
|
137 | - 0, |
|
138 | - 'Attendee' |
|
139 | - ), |
|
140 | - 'TXN_ID' => new EE_Foreign_Key_Int_Field( |
|
141 | - 'TXN_ID', |
|
142 | - esc_html__('Transaction ID', 'event_espresso'), |
|
143 | - false, |
|
144 | - 0, |
|
145 | - 'Transaction' |
|
146 | - ), |
|
147 | - 'TKT_ID' => new EE_Foreign_Key_Int_Field( |
|
148 | - 'TKT_ID', |
|
149 | - esc_html__('Ticket ID', 'event_espresso'), |
|
150 | - false, |
|
151 | - 0, |
|
152 | - 'Ticket' |
|
153 | - ), |
|
154 | - 'STS_ID' => new EE_Foreign_Key_String_Field( |
|
155 | - 'STS_ID', |
|
156 | - esc_html__('Status ID', 'event_espresso'), |
|
157 | - false, |
|
158 | - EEM_Registration::status_id_incomplete, |
|
159 | - 'Status' |
|
160 | - ), |
|
161 | - 'REG_date' => new EE_Datetime_Field( |
|
162 | - 'REG_date', |
|
163 | - esc_html__('Time registration occurred', 'event_espresso'), |
|
164 | - false, |
|
165 | - EE_Datetime_Field::now, |
|
166 | - $timezone |
|
167 | - ), |
|
168 | - 'REG_final_price' => new EE_Money_Field( |
|
169 | - 'REG_final_price', |
|
170 | - esc_html__('Registration\'s share of the transaction total', 'event_espresso'), |
|
171 | - false, |
|
172 | - 0 |
|
173 | - ), |
|
174 | - 'REG_paid' => new EE_Money_Field( |
|
175 | - 'REG_paid', |
|
176 | - esc_html__('Amount paid to date towards registration', 'event_espresso'), |
|
177 | - false, |
|
178 | - 0 |
|
179 | - ), |
|
180 | - 'REG_session' => new EE_Plain_Text_Field( |
|
181 | - 'REG_session', |
|
182 | - esc_html__('Session ID of registration', 'event_espresso'), |
|
183 | - false, |
|
184 | - '' |
|
185 | - ), |
|
186 | - 'REG_code' => new EE_Plain_Text_Field( |
|
187 | - 'REG_code', |
|
188 | - esc_html__('Unique Code for this registration', 'event_espresso'), |
|
189 | - false, |
|
190 | - '' |
|
191 | - ), |
|
192 | - 'REG_url_link' => new EE_Plain_Text_Field( |
|
193 | - 'REG_url_link', |
|
194 | - esc_html__('String to be used in URL for identifying registration', 'event_espresso'), |
|
195 | - false, |
|
196 | - '' |
|
197 | - ), |
|
198 | - 'REG_count' => new EE_Integer_Field( |
|
199 | - 'REG_count', |
|
200 | - esc_html__('Count of this registration in the group registration ', 'event_espresso'), |
|
201 | - true, |
|
202 | - 1 |
|
203 | - ), |
|
204 | - 'REG_group_size' => new EE_Integer_Field( |
|
205 | - 'REG_group_size', |
|
206 | - esc_html__('Number of registrations on this group', 'event_espresso'), |
|
207 | - false, |
|
208 | - 1 |
|
209 | - ), |
|
210 | - 'REG_att_is_going' => new EE_Boolean_Field( |
|
211 | - 'REG_att_is_going', |
|
212 | - esc_html__('Flag indicating the registrant plans on attending', 'event_espresso'), |
|
213 | - false, |
|
214 | - false |
|
215 | - ), |
|
216 | - 'REG_deleted' => new EE_Trashed_Flag_Field( |
|
217 | - 'REG_deleted', |
|
218 | - esc_html__('Flag indicating if registration has been archived or not.', 'event_espresso'), |
|
219 | - false, |
|
220 | - false |
|
221 | - ), |
|
222 | - ), |
|
223 | - ); |
|
224 | - $this->_model_relations = array( |
|
225 | - 'Event' => new EE_Belongs_To_Relation(), |
|
226 | - 'Attendee' => new EE_Belongs_To_Relation(), |
|
227 | - 'Transaction' => new EE_Belongs_To_Relation(), |
|
228 | - 'Ticket' => new EE_Belongs_To_Relation(), |
|
229 | - 'Status' => new EE_Belongs_To_Relation(), |
|
230 | - 'Answer' => new EE_Has_Many_Relation(), |
|
231 | - 'Checkin' => new EE_Has_Many_Relation(), |
|
232 | - 'Registration_Payment' => new EE_Has_Many_Relation(), |
|
233 | - 'Payment' => new EE_HABTM_Relation('Registration_Payment'), |
|
234 | - 'Message' => new EE_Has_Many_Any_Relation(false) |
|
235 | - // allow deletes even if there are messages in the queue related |
|
236 | - ); |
|
237 | - $this->_model_chain_to_wp_user = 'Event'; |
|
238 | - parent::__construct($timezone); |
|
239 | - } |
|
240 | - |
|
241 | - |
|
242 | - /** |
|
243 | - * a list of ALL valid registration statuses currently in use within the system |
|
244 | - * generated by combining the filterable active and inactive reg status arrays |
|
245 | - * |
|
246 | - * @return array |
|
247 | - */ |
|
248 | - public static function reg_statuses() |
|
249 | - { |
|
250 | - return array_unique( |
|
251 | - array_merge( |
|
252 | - EEM_Registration::active_reg_statuses(), |
|
253 | - EEM_Registration::inactive_reg_statuses() |
|
254 | - ) |
|
255 | - ); |
|
256 | - } |
|
257 | - |
|
258 | - |
|
259 | - /** |
|
260 | - * reg_statuses_that_allow_payment |
|
261 | - * a filterable list of registration statuses that allow a registrant to make a payment |
|
262 | - * |
|
263 | - * @access public |
|
264 | - * @return array |
|
265 | - */ |
|
266 | - public static function reg_statuses_that_allow_payment() |
|
267 | - { |
|
268 | - return apply_filters( |
|
269 | - 'FHEE__EEM_Registration__reg_statuses_that_allow_payment', |
|
270 | - array( |
|
271 | - EEM_Registration::status_id_approved, |
|
272 | - EEM_Registration::status_id_pending_payment, |
|
273 | - ) |
|
274 | - ); |
|
275 | - } |
|
276 | - |
|
277 | - |
|
278 | - /** |
|
279 | - * active_reg_statuses |
|
280 | - * a filterable list of registration statuses that are considered active |
|
281 | - * |
|
282 | - * @access public |
|
283 | - * @return array |
|
284 | - */ |
|
285 | - public static function active_reg_statuses() |
|
286 | - { |
|
287 | - return apply_filters( |
|
288 | - 'FHEE__EEM_Registration__active_reg_statuses', |
|
289 | - array( |
|
290 | - EEM_Registration::status_id_approved, |
|
291 | - EEM_Registration::status_id_pending_payment, |
|
292 | - EEM_Registration::status_id_wait_list, |
|
293 | - EEM_Registration::status_id_not_approved, |
|
294 | - ) |
|
295 | - ); |
|
296 | - } |
|
297 | - |
|
298 | - |
|
299 | - /** |
|
300 | - * inactive_reg_statuses |
|
301 | - * a filterable list of registration statuses that are not considered active |
|
302 | - * |
|
303 | - * @access public |
|
304 | - * @return array |
|
305 | - */ |
|
306 | - public static function inactive_reg_statuses() |
|
307 | - { |
|
308 | - return apply_filters( |
|
309 | - 'FHEE__EEM_Registration__inactive_reg_statuses', |
|
310 | - array( |
|
311 | - EEM_Registration::status_id_incomplete, |
|
312 | - EEM_Registration::status_id_cancelled, |
|
313 | - EEM_Registration::status_id_declined, |
|
314 | - ) |
|
315 | - ); |
|
316 | - } |
|
317 | - |
|
318 | - |
|
319 | - /** |
|
320 | - * closed_reg_statuses |
|
321 | - * a filterable list of registration statuses that are considered "closed" |
|
322 | - * meaning they should not be considered in any calculations involving monies owing |
|
323 | - * |
|
324 | - * @access public |
|
325 | - * @return array |
|
326 | - */ |
|
327 | - public static function closed_reg_statuses() |
|
328 | - { |
|
329 | - return apply_filters( |
|
330 | - 'FHEE__EEM_Registration__closed_reg_statuses', |
|
331 | - array( |
|
332 | - EEM_Registration::status_id_cancelled, |
|
333 | - EEM_Registration::status_id_declined, |
|
334 | - EEM_Registration::status_id_wait_list, |
|
335 | - ) |
|
336 | - ); |
|
337 | - } |
|
338 | - |
|
339 | - |
|
340 | - /** |
|
341 | - * get list of registration statuses |
|
342 | - * |
|
343 | - * @access public |
|
344 | - * @param array $exclude The status ids to exclude from the returned results |
|
345 | - * @param bool $translated If true will return the values as singular localized strings |
|
346 | - * @return array |
|
347 | - * @throws EE_Error |
|
348 | - */ |
|
349 | - public static function reg_status_array($exclude = array(), $translated = false) |
|
350 | - { |
|
351 | - EEM_Registration::instance()->_get_registration_status_array($exclude); |
|
352 | - return $translated |
|
353 | - ? EEM_Status::instance()->localized_status(self::$_reg_status, false, 'sentence') |
|
354 | - : self::$_reg_status; |
|
355 | - } |
|
356 | - |
|
357 | - |
|
358 | - /** |
|
359 | - * get list of registration statuses |
|
360 | - * |
|
361 | - * @access private |
|
362 | - * @param array $exclude |
|
363 | - * @return void |
|
364 | - * @throws EE_Error |
|
365 | - */ |
|
366 | - private function _get_registration_status_array($exclude = array()) |
|
367 | - { |
|
368 | - // in the very rare circumstance that we are deleting a model's table's data |
|
369 | - // and the table hasn't actually been created, this could have an error |
|
370 | - /** @type WPDB $wpdb */ |
|
371 | - global $wpdb; |
|
372 | - if ($this->_get_table_analysis()->tableExists($wpdb->prefix . 'esp_status')) { |
|
373 | - $results = $wpdb->get_results( |
|
374 | - "SELECT STS_ID, STS_code FROM {$wpdb->prefix}esp_status WHERE STS_type = 'registration'" |
|
375 | - ); |
|
376 | - self::$_reg_status = array(); |
|
377 | - foreach ($results as $status) { |
|
378 | - if (!in_array($status->STS_ID, $exclude, true)) { |
|
379 | - self::$_reg_status[ $status->STS_ID ] = $status->STS_code; |
|
380 | - } |
|
381 | - } |
|
382 | - } |
|
383 | - } |
|
384 | - |
|
385 | - |
|
386 | - /** |
|
387 | - * Gets the injected table analyzer, or throws an exception |
|
388 | - * |
|
389 | - * @return TableAnalysis |
|
390 | - * @throws EE_Error |
|
391 | - */ |
|
392 | - protected function _get_table_analysis() |
|
393 | - { |
|
394 | - if ($this->_table_analysis instanceof TableAnalysis) { |
|
395 | - return $this->_table_analysis; |
|
396 | - } |
|
397 | - throw new EE_Error( |
|
398 | - sprintf( |
|
399 | - esc_html__('Table analysis class on class %1$s is not set properly.', 'event_espresso'), |
|
400 | - get_class($this) |
|
401 | - ) |
|
402 | - ); |
|
403 | - } |
|
404 | - |
|
405 | - |
|
406 | - /** |
|
407 | - * This returns a wpdb->results array of all registration date month and years matching the incoming query params |
|
408 | - * and grouped by month and year. |
|
409 | - * |
|
410 | - * @param array $where_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions |
|
411 | - * @return array |
|
412 | - * @throws EE_Error |
|
413 | - */ |
|
414 | - public function get_reg_months_and_years($where_params) |
|
415 | - { |
|
416 | - $query_params[0] = $where_params; |
|
417 | - $query_params['group_by'] = array('reg_year', 'reg_month'); |
|
418 | - $query_params['order_by'] = array('REG_date' => 'DESC'); |
|
419 | - $columns_to_select = array( |
|
420 | - 'reg_year' => array('YEAR(REG_date)', '%s'), |
|
421 | - 'reg_month' => array('MONTHNAME(REG_date)', '%s'), |
|
422 | - ); |
|
423 | - return $this->_get_all_wpdb_results($query_params, OBJECT, $columns_to_select); |
|
424 | - } |
|
425 | - |
|
426 | - |
|
427 | - /** |
|
428 | - * retrieve ALL registrations for a particular Attendee from db |
|
429 | - * |
|
430 | - * @param int $ATT_ID |
|
431 | - * @return EE_Base_Class[]|EE_Registration[]|null |
|
432 | - * @throws EE_Error |
|
433 | - */ |
|
434 | - public function get_all_registrations_for_attendee($ATT_ID = 0) |
|
435 | - { |
|
436 | - if (!$ATT_ID) { |
|
437 | - return null; |
|
438 | - } |
|
439 | - return $this->get_all(array(array('ATT_ID' => $ATT_ID))); |
|
440 | - } |
|
441 | - |
|
442 | - |
|
443 | - /** |
|
444 | - * Gets a registration given their REG_url_link. Yes, this should usually |
|
445 | - * be passed via a GET parameter. |
|
446 | - * |
|
447 | - * @param string $REG_url_link |
|
448 | - * @return EE_Base_Class|EE_Registration|null |
|
449 | - * @throws EE_Error |
|
450 | - */ |
|
451 | - public function get_registration_for_reg_url_link($REG_url_link) |
|
452 | - { |
|
453 | - if (!$REG_url_link) { |
|
454 | - return null; |
|
455 | - } |
|
456 | - return $this->get_one(array(array('REG_url_link' => $REG_url_link))); |
|
457 | - } |
|
458 | - |
|
459 | - |
|
460 | - /** |
|
461 | - * retrieve registration for a specific transaction attendee from db |
|
462 | - * |
|
463 | - * @access public |
|
464 | - * @param int $TXN_ID |
|
465 | - * @param int $ATT_ID |
|
466 | - * @param int $att_nmbr in case the ATT_ID is the same for multiple registrations (same details used) then the |
|
467 | - * attendee number is required |
|
468 | - * @return mixed array on success, FALSE on fail |
|
469 | - * @throws EE_Error |
|
470 | - */ |
|
471 | - public function get_registration_for_transaction_attendee($TXN_ID = 0, $ATT_ID = 0, $att_nmbr = 0) |
|
472 | - { |
|
473 | - return $this->get_one(array( |
|
474 | - array( |
|
475 | - 'TXN_ID' => $TXN_ID, |
|
476 | - 'ATT_ID' => $ATT_ID, |
|
477 | - ), |
|
478 | - 'limit' => array(min($att_nmbr - 1, 0), 1), |
|
479 | - )); |
|
480 | - } |
|
481 | - |
|
482 | - |
|
483 | - /** |
|
484 | - * get the number of registrations per day for the Registration Admin page Reports Tab. |
|
485 | - * (doesn't utilize models because it's a fairly specialized query) |
|
486 | - * |
|
487 | - * @access public |
|
488 | - * @param $period string which can be passed to php's strtotime function (eg "-1 month") |
|
489 | - * @return stdClass[] with properties regDate and total |
|
490 | - * @throws EE_Error |
|
491 | - */ |
|
492 | - public function get_registrations_per_day_report($period = '-1 month') |
|
493 | - { |
|
494 | - $sql_date = $this->convert_datetime_for_query( |
|
495 | - 'REG_date', |
|
496 | - date('Y-m-d H:i:s', strtotime($period)), |
|
497 | - 'Y-m-d H:i:s', |
|
498 | - 'UTC' |
|
499 | - ); |
|
500 | - $where = array( |
|
501 | - 'REG_date' => array('>=', $sql_date), |
|
502 | - 'STS_ID' => array('!=', EEM_Registration::status_id_incomplete), |
|
503 | - ); |
|
504 | - if (!EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_day_report')) { |
|
505 | - $where['Event.EVT_wp_user'] = get_current_user_id(); |
|
506 | - } |
|
507 | - $query_interval = EEH_DTT_Helper::get_sql_query_interval_for_offset($this->get_timezone(), 'REG_date'); |
|
508 | - $results = $this->_get_all_wpdb_results( |
|
509 | - array( |
|
510 | - $where, |
|
511 | - 'group_by' => 'regDate', |
|
512 | - 'order_by' => array('REG_date' => 'ASC'), |
|
513 | - ), |
|
514 | - OBJECT, |
|
515 | - array( |
|
516 | - 'regDate' => array('DATE(' . $query_interval . ')', '%s'), |
|
517 | - 'total' => array('count(REG_ID)', '%d'), |
|
518 | - ) |
|
519 | - ); |
|
520 | - return $results; |
|
521 | - } |
|
522 | - |
|
523 | - |
|
524 | - /** |
|
525 | - * Get the number of registrations per day including the count of registrations for each Registration Status. |
|
526 | - * Note: EEM_Registration::status_id_incomplete registrations are excluded from the results. |
|
527 | - * |
|
528 | - * @param string $period |
|
529 | - * @return stdClass[] with properties Registration_REG_date and a column for each registration status as the STS_ID |
|
530 | - * @throws EE_Error |
|
531 | - * (i.e. RAP) |
|
532 | - */ |
|
533 | - public function get_registrations_per_day_and_per_status_report($period = '-1 month') |
|
534 | - { |
|
535 | - global $wpdb; |
|
536 | - $registration_table = $wpdb->prefix . 'esp_registration'; |
|
537 | - $event_table = $wpdb->posts; |
|
538 | - $sql_date = date('Y-m-d H:i:s', strtotime($period)); |
|
539 | - // prepare the query interval for displaying offset |
|
540 | - $query_interval = EEH_DTT_Helper::get_sql_query_interval_for_offset($this->get_timezone(), 'dates.REG_date'); |
|
541 | - // inner date query |
|
542 | - $inner_date_query = "SELECT DISTINCT REG_date from {$registration_table} "; |
|
543 | - $inner_where = ' WHERE'; |
|
544 | - // exclude events not authored by user if permissions in effect |
|
545 | - if (!EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_event_report')) { |
|
546 | - $inner_date_query .= "LEFT JOIN {$event_table} ON ID = EVT_ID"; |
|
547 | - $inner_where .= ' post_author = ' . get_current_user_id() . ' AND'; |
|
548 | - } |
|
549 | - $inner_where .= " REG_date >= '{$sql_date}'"; |
|
550 | - $inner_date_query .= $inner_where; |
|
551 | - // start main query |
|
552 | - $select = "SELECT DATE({$query_interval}) as Registration_REG_date, "; |
|
553 | - $join = ''; |
|
554 | - $join_parts = array(); |
|
555 | - $select_parts = array(); |
|
556 | - // loop through registration stati to do parts for each status. |
|
557 | - foreach (EEM_Registration::reg_status_array() as $STS_ID => $STS_code) { |
|
558 | - if ($STS_ID === EEM_Registration::status_id_incomplete) { |
|
559 | - continue; |
|
560 | - } |
|
561 | - $select_parts[] = "COUNT({$STS_code}.REG_ID) as {$STS_ID}"; |
|
562 | - $join_parts[] = "{$registration_table} AS {$STS_code} ON {$STS_code}.REG_date = dates.REG_date AND {$STS_code}.STS_ID = '{$STS_ID}'"; |
|
563 | - } |
|
564 | - // setup the selects |
|
565 | - $select .= implode(', ', $select_parts); |
|
566 | - $select .= " FROM ($inner_date_query) AS dates LEFT JOIN "; |
|
567 | - // setup the joins |
|
568 | - $join .= implode(' LEFT JOIN ', $join_parts); |
|
569 | - // now let's put it all together |
|
570 | - $query = $select . $join . ' GROUP BY Registration_REG_date'; |
|
571 | - // and execute it |
|
572 | - return $wpdb->get_results($query, ARRAY_A); |
|
573 | - } |
|
574 | - |
|
575 | - |
|
576 | - /** |
|
577 | - * get the number of registrations per event for the Registration Admin page Reports Tab |
|
578 | - * |
|
579 | - * @access public |
|
580 | - * @param $period string which can be passed to php's strtotime function (eg "-1 month") |
|
581 | - * @return stdClass[] each with properties event_name, reg_limit, and total |
|
582 | - * @throws EE_Error |
|
583 | - */ |
|
584 | - public function get_registrations_per_event_report($period = '-1 month') |
|
585 | - { |
|
586 | - $date_sql = $this->convert_datetime_for_query( |
|
587 | - 'REG_date', |
|
588 | - date('Y-m-d H:i:s', strtotime($period)), |
|
589 | - 'Y-m-d H:i:s', |
|
590 | - 'UTC' |
|
591 | - ); |
|
592 | - $where = array( |
|
593 | - 'REG_date' => array('>=', $date_sql), |
|
594 | - 'STS_ID' => array('!=', EEM_Registration::status_id_incomplete), |
|
595 | - ); |
|
596 | - if (!EE_Registry::instance()->CAP->current_user_can( |
|
597 | - 'ee_read_others_registrations', |
|
598 | - 'reg_per_event_report' |
|
599 | - ) |
|
600 | - ) { |
|
601 | - $where['Event.EVT_wp_user'] = get_current_user_id(); |
|
602 | - } |
|
603 | - $results = $this->_get_all_wpdb_results( |
|
604 | - array( |
|
605 | - $where, |
|
606 | - 'group_by' => 'Event.EVT_name', |
|
607 | - 'order_by' => 'Event.EVT_name', |
|
608 | - 'limit' => array(0, 24), |
|
609 | - ), |
|
610 | - OBJECT, |
|
611 | - array( |
|
612 | - 'event_name' => array('Event_CPT.post_title', '%s'), |
|
613 | - 'total' => array('COUNT(REG_ID)', '%s'), |
|
614 | - ) |
|
615 | - ); |
|
616 | - return $results; |
|
617 | - } |
|
618 | - |
|
619 | - |
|
620 | - /** |
|
621 | - * Get the number of registrations per event grouped by registration status. |
|
622 | - * Note: EEM_Registration::status_id_incomplete registrations are excluded from the results. |
|
623 | - * |
|
624 | - * @param string $period |
|
625 | - * @return stdClass[] with properties `Registration_Event` and a column for each registration status as the STS_ID |
|
626 | - * @throws EE_Error |
|
627 | - * (i.e. RAP) |
|
628 | - */ |
|
629 | - public function get_registrations_per_event_and_per_status_report($period = '-1 month') |
|
630 | - { |
|
631 | - global $wpdb; |
|
632 | - $registration_table = $wpdb->prefix . 'esp_registration'; |
|
633 | - $event_table = $wpdb->posts; |
|
634 | - $sql_date = date('Y-m-d H:i:s', strtotime($period)); |
|
635 | - // inner date query |
|
636 | - $inner_date_query = "SELECT DISTINCT EVT_ID, REG_date from $registration_table "; |
|
637 | - $inner_where = ' WHERE'; |
|
638 | - // exclude events not authored by user if permissions in effect |
|
639 | - if (!EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_event_report')) { |
|
640 | - $inner_date_query .= "LEFT JOIN {$event_table} ON ID = EVT_ID"; |
|
641 | - $inner_where .= ' post_author = ' . get_current_user_id() . ' AND'; |
|
642 | - } |
|
643 | - $inner_where .= " REG_date >= '{$sql_date}'"; |
|
644 | - $inner_date_query .= $inner_where; |
|
645 | - // build main query |
|
646 | - $select = 'SELECT Event.post_title as Registration_Event, '; |
|
647 | - $join = ''; |
|
648 | - $join_parts = array(); |
|
649 | - $select_parts = array(); |
|
650 | - // loop through registration stati to do parts for each status. |
|
651 | - foreach (EEM_Registration::reg_status_array() as $STS_ID => $STS_code) { |
|
652 | - if ($STS_ID === EEM_Registration::status_id_incomplete) { |
|
653 | - continue; |
|
654 | - } |
|
655 | - $select_parts[] = "COUNT({$STS_code}.REG_ID) as {$STS_ID}"; |
|
656 | - $join_parts[] = "{$registration_table} AS {$STS_code} ON {$STS_code}.EVT_ID = dates.EVT_ID AND {$STS_code}.STS_ID = '{$STS_ID}' AND {$STS_code}.REG_date = dates.REG_date"; |
|
657 | - } |
|
658 | - // setup the selects |
|
659 | - $select .= implode(', ', $select_parts); |
|
660 | - $select .= " FROM ($inner_date_query) AS dates LEFT JOIN $event_table as Event ON Event.ID = dates.EVT_ID LEFT JOIN "; |
|
661 | - // setup remaining joins |
|
662 | - $join .= implode(' LEFT JOIN ', $join_parts); |
|
663 | - // now put it all together |
|
664 | - $query = $select . $join . ' GROUP BY Registration_Event'; |
|
665 | - // and execute |
|
666 | - return $wpdb->get_results($query, ARRAY_A); |
|
667 | - } |
|
668 | - |
|
669 | - |
|
670 | - /** |
|
671 | - * Returns the EE_Registration of the primary attendee on the transaction id provided |
|
672 | - * |
|
673 | - * @param int $TXN_ID |
|
674 | - * @return EE_Base_Class|EE_Registration|null |
|
675 | - * @throws EE_Error |
|
676 | - */ |
|
677 | - public function get_primary_registration_for_transaction_ID($TXN_ID = 0) |
|
678 | - { |
|
679 | - if (!$TXN_ID) { |
|
680 | - return null; |
|
681 | - } |
|
682 | - return $this->get_one(array( |
|
683 | - array( |
|
684 | - 'TXN_ID' => $TXN_ID, |
|
685 | - 'REG_count' => EEM_Registration::PRIMARY_REGISTRANT_COUNT, |
|
686 | - ), |
|
687 | - )); |
|
688 | - } |
|
689 | - |
|
690 | - |
|
691 | - /** |
|
692 | - * get_event_registration_count |
|
693 | - * |
|
694 | - * @access public |
|
695 | - * @param int $EVT_ID |
|
696 | - * @param boolean $for_incomplete_payments |
|
697 | - * @return int |
|
698 | - * @throws EE_Error |
|
699 | - */ |
|
700 | - public function get_event_registration_count($EVT_ID, $for_incomplete_payments = false) |
|
701 | - { |
|
702 | - // we only count approved registrations towards registration limits |
|
703 | - $query_params = array(array('EVT_ID' => $EVT_ID, 'STS_ID' => self::status_id_approved)); |
|
704 | - if ($for_incomplete_payments) { |
|
705 | - $query_params[0]['Transaction.STS_ID'] = array('!=', EEM_Transaction::complete_status_code); |
|
706 | - } |
|
707 | - return $this->count($query_params); |
|
708 | - } |
|
709 | - |
|
710 | - |
|
711 | - /** |
|
712 | - * Deletes all registrations with no transactions. Note that this needs to be very efficient |
|
713 | - * and so it uses wpdb directly. Also, we can't put a limit on this because MySQL doesn't allow a limit on a delete |
|
714 | - * when joining tables like this. |
|
715 | - * |
|
716 | - * @global WPDB $wpdb |
|
717 | - * @return int number deleted |
|
718 | - * @throws EE_Error |
|
719 | - */ |
|
720 | - public function delete_registrations_with_no_transaction() |
|
721 | - { |
|
722 | - /** @type WPDB $wpdb */ |
|
723 | - global $wpdb; |
|
724 | - return $wpdb->query( |
|
725 | - 'DELETE r FROM ' |
|
726 | - . $this->table() |
|
727 | - . ' r LEFT JOIN ' |
|
728 | - . EEM_Transaction::instance()->table() |
|
729 | - . ' t ON r.TXN_ID = t.TXN_ID WHERE t.TXN_ID IS NULL' |
|
730 | - ); |
|
731 | - } |
|
732 | - |
|
733 | - |
|
734 | - /** |
|
735 | - * Count registrations checked into (or out of) a datetime |
|
736 | - * |
|
737 | - * @param int $DTT_ID datetime ID |
|
738 | - * @param boolean $checked_in whether to count registrations checked IN or OUT |
|
739 | - * @return int |
|
740 | - * @throws EE_Error |
|
741 | - */ |
|
742 | - public function count_registrations_checked_into_datetime($DTT_ID, $checked_in = true) |
|
743 | - { |
|
744 | - global $wpdb; |
|
745 | - // subquery to get latest checkin |
|
746 | - $query = $wpdb->prepare( |
|
747 | - 'SELECT ' |
|
748 | - . 'COUNT( DISTINCT checkins.REG_ID ) ' |
|
749 | - . 'FROM ' . EEM_Checkin::instance()->table() . ' AS checkins INNER JOIN' |
|
750 | - . '( SELECT ' |
|
751 | - . 'max( CHK_timestamp ) AS latest_checkin, ' |
|
752 | - . 'REG_ID AS REG_ID ' |
|
753 | - . 'FROM ' . EEM_Checkin::instance()->table() . ' ' |
|
754 | - . 'WHERE DTT_ID=%d ' |
|
755 | - . 'GROUP BY REG_ID' |
|
756 | - . ') AS most_recent_checkin_per_reg ' |
|
757 | - . 'ON checkins.REG_ID=most_recent_checkin_per_reg.REG_ID ' |
|
758 | - . 'AND checkins.CHK_timestamp = most_recent_checkin_per_reg.latest_checkin ' |
|
759 | - . 'WHERE ' |
|
760 | - . 'checkins.CHK_in=%d', |
|
761 | - $DTT_ID, |
|
762 | - $checked_in |
|
763 | - ); |
|
764 | - return (int) $wpdb->get_var($query); |
|
765 | - } |
|
766 | - |
|
767 | - |
|
768 | - /** |
|
769 | - * Count registrations checked into (or out of) an event. |
|
770 | - * |
|
771 | - * @param int $EVT_ID event ID |
|
772 | - * @param boolean $checked_in whether to count registrations checked IN or OUT |
|
773 | - * @return int |
|
774 | - * @throws EE_Error |
|
775 | - */ |
|
776 | - public function count_registrations_checked_into_event($EVT_ID, $checked_in = true) |
|
777 | - { |
|
778 | - global $wpdb; |
|
779 | - // subquery to get latest checkin |
|
780 | - $query = $wpdb->prepare( |
|
781 | - 'SELECT ' |
|
782 | - . 'COUNT( DISTINCT checkins.REG_ID ) ' |
|
783 | - . 'FROM ' . EEM_Checkin::instance()->table() . ' AS checkins INNER JOIN' |
|
784 | - . '( SELECT ' |
|
785 | - . 'max( CHK_timestamp ) AS latest_checkin, ' |
|
786 | - . 'REG_ID AS REG_ID ' |
|
787 | - . 'FROM ' . EEM_Checkin::instance()->table() . ' AS c ' |
|
788 | - . 'INNER JOIN ' . EEM_Datetime::instance()->table() . ' AS d ' |
|
789 | - . 'ON c.DTT_ID=d.DTT_ID ' |
|
790 | - . 'WHERE d.EVT_ID=%d ' |
|
791 | - . 'GROUP BY REG_ID' |
|
792 | - . ') AS most_recent_checkin_per_reg ' |
|
793 | - . 'ON checkins.REG_ID=most_recent_checkin_per_reg.REG_ID ' |
|
794 | - . 'AND checkins.CHK_timestamp = most_recent_checkin_per_reg.latest_checkin ' |
|
795 | - . 'WHERE ' |
|
796 | - . 'checkins.CHK_in=%d', |
|
797 | - $EVT_ID, |
|
798 | - $checked_in |
|
799 | - ); |
|
800 | - return (int) $wpdb->get_var($query); |
|
801 | - } |
|
802 | - |
|
803 | - |
|
804 | - /** |
|
805 | - * The purpose of this method is to retrieve an array of |
|
806 | - * EE_Registration objects that represent the latest registration |
|
807 | - * for each ATT_ID given in the function argument. |
|
808 | - * |
|
809 | - * @param array $attendee_ids |
|
810 | - * @return EE_Base_Class[]|EE_Registration[] |
|
811 | - * @throws EE_Error |
|
812 | - */ |
|
813 | - public function get_latest_registration_for_each_of_given_contacts($attendee_ids = array()) |
|
814 | - { |
|
815 | - // first do a native wp_query to get the latest REG_ID's matching these attendees. |
|
816 | - global $wpdb; |
|
817 | - $registration_table = $wpdb->prefix . 'esp_registration'; |
|
818 | - $attendee_table = $wpdb->posts; |
|
819 | - $attendee_ids = is_array($attendee_ids) |
|
820 | - ? array_map('absint', $attendee_ids) |
|
821 | - : array((int) $attendee_ids); |
|
822 | - $ATT_IDs = implode(',', $attendee_ids); |
|
823 | - // first we do a query to get the registration ids |
|
824 | - // (because a group by before order by causes the order by to be ignored.) |
|
825 | - $registration_id_query = " |
|
16 | + /** |
|
17 | + * @var EEM_Registration $_instance |
|
18 | + */ |
|
19 | + protected static $_instance; |
|
20 | + |
|
21 | + /** |
|
22 | + * Keys are the status IDs for registrations (eg, RAP, RCN, etc), and the values |
|
23 | + * are status codes (eg, approved, cancelled, etc) |
|
24 | + * |
|
25 | + * @var array |
|
26 | + */ |
|
27 | + private static $_reg_status; |
|
28 | + |
|
29 | + /** |
|
30 | + * The value of REG_count for a primary registrant |
|
31 | + */ |
|
32 | + const PRIMARY_REGISTRANT_COUNT = 1; |
|
33 | + |
|
34 | + /** |
|
35 | + * Status ID (STS_ID on esp_status table) to indicate an INCOMPLETE registration. |
|
36 | + * Initial status for registrations when they are first created |
|
37 | + * Payments are NOT allowed. |
|
38 | + * Automatically toggled to whatever the default Event registration status is upon completion of the attendee |
|
39 | + * information reg step NO space reserved. Registration is NOT active |
|
40 | + */ |
|
41 | + const status_id_incomplete = 'RIC'; |
|
42 | + |
|
43 | + /** |
|
44 | + * Status ID (STS_ID on esp_status table) to indicate an UNAPPROVED registration. |
|
45 | + * Payments are NOT allowed. |
|
46 | + * Event Admin must manually toggle STS_ID for it to change |
|
47 | + * No space reserved. |
|
48 | + * Registration is active |
|
49 | + */ |
|
50 | + const status_id_not_approved = 'RNA'; |
|
51 | + |
|
52 | + /** |
|
53 | + * Status ID (STS_ID on esp_status table) to indicate registration is PENDING_PAYMENT . |
|
54 | + * Payments are allowed. |
|
55 | + * STS_ID will automatically be toggled to RAP if payment is made in full by the attendee |
|
56 | + * No space reserved. |
|
57 | + * Registration is active |
|
58 | + */ |
|
59 | + const status_id_pending_payment = 'RPP'; |
|
60 | + |
|
61 | + /** |
|
62 | + * Status ID (STS_ID on esp_status table) to indicate registration is on the WAIT_LIST . |
|
63 | + * Payments are allowed. |
|
64 | + * STS_ID will automatically be toggled to RAP if payment is made in full by the attendee |
|
65 | + * No space reserved. |
|
66 | + * Registration is active |
|
67 | + */ |
|
68 | + const status_id_wait_list = 'RWL'; |
|
69 | + |
|
70 | + /** |
|
71 | + * Status ID (STS_ID on esp_status table) to indicate an APPROVED registration. |
|
72 | + * the TXN may or may not be completed ( paid in full ) |
|
73 | + * Payments are allowed. |
|
74 | + * A space IS reserved. |
|
75 | + * Registration is active |
|
76 | + */ |
|
77 | + const status_id_approved = 'RAP'; |
|
78 | + |
|
79 | + /** |
|
80 | + * Status ID (STS_ID on esp_status table) to indicate a registration was CANCELLED by the attendee. |
|
81 | + * Payments are NOT allowed. |
|
82 | + * NO space reserved. |
|
83 | + * Registration is NOT active |
|
84 | + */ |
|
85 | + const status_id_cancelled = 'RCN'; |
|
86 | + |
|
87 | + /** |
|
88 | + * Status ID (STS_ID on esp_status table) to indicate a registration was DECLINED by the Event Admin |
|
89 | + * Payments are NOT allowed. |
|
90 | + * No space reserved. |
|
91 | + * Registration is NOT active |
|
92 | + */ |
|
93 | + const status_id_declined = 'RDC'; |
|
94 | + |
|
95 | + /** |
|
96 | + * @var TableAnalysis $table_analysis |
|
97 | + */ |
|
98 | + protected $_table_analysis; |
|
99 | + |
|
100 | + |
|
101 | + /** |
|
102 | + * private constructor to prevent direct creation |
|
103 | + * |
|
104 | + * @Constructor |
|
105 | + * @access protected |
|
106 | + * @param string $timezone string representing the timezone we want to set for returned Date Time Strings (and any |
|
107 | + * incoming timezone data that gets saved). Note this just sends the timezone info to the |
|
108 | + * date time model field objects. Default is NULL (and will be assumed using the set |
|
109 | + * timezone in the 'timezone_string' wp option) |
|
110 | + * @throws EE_Error |
|
111 | + */ |
|
112 | + protected function __construct($timezone = null) |
|
113 | + { |
|
114 | + $this->_table_analysis = EE_Registry::instance()->create('TableAnalysis', array(), true); |
|
115 | + $this->singular_item = esc_html__('Registration', 'event_espresso'); |
|
116 | + $this->plural_item = esc_html__('Registrations', 'event_espresso'); |
|
117 | + $this->_tables = array( |
|
118 | + 'Registration' => new EE_Primary_Table('esp_registration', 'REG_ID'), |
|
119 | + ); |
|
120 | + $this->_fields = array( |
|
121 | + 'Registration' => array( |
|
122 | + 'REG_ID' => new EE_Primary_Key_Int_Field( |
|
123 | + 'REG_ID', |
|
124 | + esc_html__('Registration ID', 'event_espresso') |
|
125 | + ), |
|
126 | + 'EVT_ID' => new EE_Foreign_Key_Int_Field( |
|
127 | + 'EVT_ID', |
|
128 | + esc_html__('Event ID', 'event_espresso'), |
|
129 | + false, |
|
130 | + 0, |
|
131 | + 'Event' |
|
132 | + ), |
|
133 | + 'ATT_ID' => new EE_Foreign_Key_Int_Field( |
|
134 | + 'ATT_ID', |
|
135 | + esc_html__('Attendee ID', 'event_espresso'), |
|
136 | + false, |
|
137 | + 0, |
|
138 | + 'Attendee' |
|
139 | + ), |
|
140 | + 'TXN_ID' => new EE_Foreign_Key_Int_Field( |
|
141 | + 'TXN_ID', |
|
142 | + esc_html__('Transaction ID', 'event_espresso'), |
|
143 | + false, |
|
144 | + 0, |
|
145 | + 'Transaction' |
|
146 | + ), |
|
147 | + 'TKT_ID' => new EE_Foreign_Key_Int_Field( |
|
148 | + 'TKT_ID', |
|
149 | + esc_html__('Ticket ID', 'event_espresso'), |
|
150 | + false, |
|
151 | + 0, |
|
152 | + 'Ticket' |
|
153 | + ), |
|
154 | + 'STS_ID' => new EE_Foreign_Key_String_Field( |
|
155 | + 'STS_ID', |
|
156 | + esc_html__('Status ID', 'event_espresso'), |
|
157 | + false, |
|
158 | + EEM_Registration::status_id_incomplete, |
|
159 | + 'Status' |
|
160 | + ), |
|
161 | + 'REG_date' => new EE_Datetime_Field( |
|
162 | + 'REG_date', |
|
163 | + esc_html__('Time registration occurred', 'event_espresso'), |
|
164 | + false, |
|
165 | + EE_Datetime_Field::now, |
|
166 | + $timezone |
|
167 | + ), |
|
168 | + 'REG_final_price' => new EE_Money_Field( |
|
169 | + 'REG_final_price', |
|
170 | + esc_html__('Registration\'s share of the transaction total', 'event_espresso'), |
|
171 | + false, |
|
172 | + 0 |
|
173 | + ), |
|
174 | + 'REG_paid' => new EE_Money_Field( |
|
175 | + 'REG_paid', |
|
176 | + esc_html__('Amount paid to date towards registration', 'event_espresso'), |
|
177 | + false, |
|
178 | + 0 |
|
179 | + ), |
|
180 | + 'REG_session' => new EE_Plain_Text_Field( |
|
181 | + 'REG_session', |
|
182 | + esc_html__('Session ID of registration', 'event_espresso'), |
|
183 | + false, |
|
184 | + '' |
|
185 | + ), |
|
186 | + 'REG_code' => new EE_Plain_Text_Field( |
|
187 | + 'REG_code', |
|
188 | + esc_html__('Unique Code for this registration', 'event_espresso'), |
|
189 | + false, |
|
190 | + '' |
|
191 | + ), |
|
192 | + 'REG_url_link' => new EE_Plain_Text_Field( |
|
193 | + 'REG_url_link', |
|
194 | + esc_html__('String to be used in URL for identifying registration', 'event_espresso'), |
|
195 | + false, |
|
196 | + '' |
|
197 | + ), |
|
198 | + 'REG_count' => new EE_Integer_Field( |
|
199 | + 'REG_count', |
|
200 | + esc_html__('Count of this registration in the group registration ', 'event_espresso'), |
|
201 | + true, |
|
202 | + 1 |
|
203 | + ), |
|
204 | + 'REG_group_size' => new EE_Integer_Field( |
|
205 | + 'REG_group_size', |
|
206 | + esc_html__('Number of registrations on this group', 'event_espresso'), |
|
207 | + false, |
|
208 | + 1 |
|
209 | + ), |
|
210 | + 'REG_att_is_going' => new EE_Boolean_Field( |
|
211 | + 'REG_att_is_going', |
|
212 | + esc_html__('Flag indicating the registrant plans on attending', 'event_espresso'), |
|
213 | + false, |
|
214 | + false |
|
215 | + ), |
|
216 | + 'REG_deleted' => new EE_Trashed_Flag_Field( |
|
217 | + 'REG_deleted', |
|
218 | + esc_html__('Flag indicating if registration has been archived or not.', 'event_espresso'), |
|
219 | + false, |
|
220 | + false |
|
221 | + ), |
|
222 | + ), |
|
223 | + ); |
|
224 | + $this->_model_relations = array( |
|
225 | + 'Event' => new EE_Belongs_To_Relation(), |
|
226 | + 'Attendee' => new EE_Belongs_To_Relation(), |
|
227 | + 'Transaction' => new EE_Belongs_To_Relation(), |
|
228 | + 'Ticket' => new EE_Belongs_To_Relation(), |
|
229 | + 'Status' => new EE_Belongs_To_Relation(), |
|
230 | + 'Answer' => new EE_Has_Many_Relation(), |
|
231 | + 'Checkin' => new EE_Has_Many_Relation(), |
|
232 | + 'Registration_Payment' => new EE_Has_Many_Relation(), |
|
233 | + 'Payment' => new EE_HABTM_Relation('Registration_Payment'), |
|
234 | + 'Message' => new EE_Has_Many_Any_Relation(false) |
|
235 | + // allow deletes even if there are messages in the queue related |
|
236 | + ); |
|
237 | + $this->_model_chain_to_wp_user = 'Event'; |
|
238 | + parent::__construct($timezone); |
|
239 | + } |
|
240 | + |
|
241 | + |
|
242 | + /** |
|
243 | + * a list of ALL valid registration statuses currently in use within the system |
|
244 | + * generated by combining the filterable active and inactive reg status arrays |
|
245 | + * |
|
246 | + * @return array |
|
247 | + */ |
|
248 | + public static function reg_statuses() |
|
249 | + { |
|
250 | + return array_unique( |
|
251 | + array_merge( |
|
252 | + EEM_Registration::active_reg_statuses(), |
|
253 | + EEM_Registration::inactive_reg_statuses() |
|
254 | + ) |
|
255 | + ); |
|
256 | + } |
|
257 | + |
|
258 | + |
|
259 | + /** |
|
260 | + * reg_statuses_that_allow_payment |
|
261 | + * a filterable list of registration statuses that allow a registrant to make a payment |
|
262 | + * |
|
263 | + * @access public |
|
264 | + * @return array |
|
265 | + */ |
|
266 | + public static function reg_statuses_that_allow_payment() |
|
267 | + { |
|
268 | + return apply_filters( |
|
269 | + 'FHEE__EEM_Registration__reg_statuses_that_allow_payment', |
|
270 | + array( |
|
271 | + EEM_Registration::status_id_approved, |
|
272 | + EEM_Registration::status_id_pending_payment, |
|
273 | + ) |
|
274 | + ); |
|
275 | + } |
|
276 | + |
|
277 | + |
|
278 | + /** |
|
279 | + * active_reg_statuses |
|
280 | + * a filterable list of registration statuses that are considered active |
|
281 | + * |
|
282 | + * @access public |
|
283 | + * @return array |
|
284 | + */ |
|
285 | + public static function active_reg_statuses() |
|
286 | + { |
|
287 | + return apply_filters( |
|
288 | + 'FHEE__EEM_Registration__active_reg_statuses', |
|
289 | + array( |
|
290 | + EEM_Registration::status_id_approved, |
|
291 | + EEM_Registration::status_id_pending_payment, |
|
292 | + EEM_Registration::status_id_wait_list, |
|
293 | + EEM_Registration::status_id_not_approved, |
|
294 | + ) |
|
295 | + ); |
|
296 | + } |
|
297 | + |
|
298 | + |
|
299 | + /** |
|
300 | + * inactive_reg_statuses |
|
301 | + * a filterable list of registration statuses that are not considered active |
|
302 | + * |
|
303 | + * @access public |
|
304 | + * @return array |
|
305 | + */ |
|
306 | + public static function inactive_reg_statuses() |
|
307 | + { |
|
308 | + return apply_filters( |
|
309 | + 'FHEE__EEM_Registration__inactive_reg_statuses', |
|
310 | + array( |
|
311 | + EEM_Registration::status_id_incomplete, |
|
312 | + EEM_Registration::status_id_cancelled, |
|
313 | + EEM_Registration::status_id_declined, |
|
314 | + ) |
|
315 | + ); |
|
316 | + } |
|
317 | + |
|
318 | + |
|
319 | + /** |
|
320 | + * closed_reg_statuses |
|
321 | + * a filterable list of registration statuses that are considered "closed" |
|
322 | + * meaning they should not be considered in any calculations involving monies owing |
|
323 | + * |
|
324 | + * @access public |
|
325 | + * @return array |
|
326 | + */ |
|
327 | + public static function closed_reg_statuses() |
|
328 | + { |
|
329 | + return apply_filters( |
|
330 | + 'FHEE__EEM_Registration__closed_reg_statuses', |
|
331 | + array( |
|
332 | + EEM_Registration::status_id_cancelled, |
|
333 | + EEM_Registration::status_id_declined, |
|
334 | + EEM_Registration::status_id_wait_list, |
|
335 | + ) |
|
336 | + ); |
|
337 | + } |
|
338 | + |
|
339 | + |
|
340 | + /** |
|
341 | + * get list of registration statuses |
|
342 | + * |
|
343 | + * @access public |
|
344 | + * @param array $exclude The status ids to exclude from the returned results |
|
345 | + * @param bool $translated If true will return the values as singular localized strings |
|
346 | + * @return array |
|
347 | + * @throws EE_Error |
|
348 | + */ |
|
349 | + public static function reg_status_array($exclude = array(), $translated = false) |
|
350 | + { |
|
351 | + EEM_Registration::instance()->_get_registration_status_array($exclude); |
|
352 | + return $translated |
|
353 | + ? EEM_Status::instance()->localized_status(self::$_reg_status, false, 'sentence') |
|
354 | + : self::$_reg_status; |
|
355 | + } |
|
356 | + |
|
357 | + |
|
358 | + /** |
|
359 | + * get list of registration statuses |
|
360 | + * |
|
361 | + * @access private |
|
362 | + * @param array $exclude |
|
363 | + * @return void |
|
364 | + * @throws EE_Error |
|
365 | + */ |
|
366 | + private function _get_registration_status_array($exclude = array()) |
|
367 | + { |
|
368 | + // in the very rare circumstance that we are deleting a model's table's data |
|
369 | + // and the table hasn't actually been created, this could have an error |
|
370 | + /** @type WPDB $wpdb */ |
|
371 | + global $wpdb; |
|
372 | + if ($this->_get_table_analysis()->tableExists($wpdb->prefix . 'esp_status')) { |
|
373 | + $results = $wpdb->get_results( |
|
374 | + "SELECT STS_ID, STS_code FROM {$wpdb->prefix}esp_status WHERE STS_type = 'registration'" |
|
375 | + ); |
|
376 | + self::$_reg_status = array(); |
|
377 | + foreach ($results as $status) { |
|
378 | + if (!in_array($status->STS_ID, $exclude, true)) { |
|
379 | + self::$_reg_status[ $status->STS_ID ] = $status->STS_code; |
|
380 | + } |
|
381 | + } |
|
382 | + } |
|
383 | + } |
|
384 | + |
|
385 | + |
|
386 | + /** |
|
387 | + * Gets the injected table analyzer, or throws an exception |
|
388 | + * |
|
389 | + * @return TableAnalysis |
|
390 | + * @throws EE_Error |
|
391 | + */ |
|
392 | + protected function _get_table_analysis() |
|
393 | + { |
|
394 | + if ($this->_table_analysis instanceof TableAnalysis) { |
|
395 | + return $this->_table_analysis; |
|
396 | + } |
|
397 | + throw new EE_Error( |
|
398 | + sprintf( |
|
399 | + esc_html__('Table analysis class on class %1$s is not set properly.', 'event_espresso'), |
|
400 | + get_class($this) |
|
401 | + ) |
|
402 | + ); |
|
403 | + } |
|
404 | + |
|
405 | + |
|
406 | + /** |
|
407 | + * This returns a wpdb->results array of all registration date month and years matching the incoming query params |
|
408 | + * and grouped by month and year. |
|
409 | + * |
|
410 | + * @param array $where_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md#0-where-conditions |
|
411 | + * @return array |
|
412 | + * @throws EE_Error |
|
413 | + */ |
|
414 | + public function get_reg_months_and_years($where_params) |
|
415 | + { |
|
416 | + $query_params[0] = $where_params; |
|
417 | + $query_params['group_by'] = array('reg_year', 'reg_month'); |
|
418 | + $query_params['order_by'] = array('REG_date' => 'DESC'); |
|
419 | + $columns_to_select = array( |
|
420 | + 'reg_year' => array('YEAR(REG_date)', '%s'), |
|
421 | + 'reg_month' => array('MONTHNAME(REG_date)', '%s'), |
|
422 | + ); |
|
423 | + return $this->_get_all_wpdb_results($query_params, OBJECT, $columns_to_select); |
|
424 | + } |
|
425 | + |
|
426 | + |
|
427 | + /** |
|
428 | + * retrieve ALL registrations for a particular Attendee from db |
|
429 | + * |
|
430 | + * @param int $ATT_ID |
|
431 | + * @return EE_Base_Class[]|EE_Registration[]|null |
|
432 | + * @throws EE_Error |
|
433 | + */ |
|
434 | + public function get_all_registrations_for_attendee($ATT_ID = 0) |
|
435 | + { |
|
436 | + if (!$ATT_ID) { |
|
437 | + return null; |
|
438 | + } |
|
439 | + return $this->get_all(array(array('ATT_ID' => $ATT_ID))); |
|
440 | + } |
|
441 | + |
|
442 | + |
|
443 | + /** |
|
444 | + * Gets a registration given their REG_url_link. Yes, this should usually |
|
445 | + * be passed via a GET parameter. |
|
446 | + * |
|
447 | + * @param string $REG_url_link |
|
448 | + * @return EE_Base_Class|EE_Registration|null |
|
449 | + * @throws EE_Error |
|
450 | + */ |
|
451 | + public function get_registration_for_reg_url_link($REG_url_link) |
|
452 | + { |
|
453 | + if (!$REG_url_link) { |
|
454 | + return null; |
|
455 | + } |
|
456 | + return $this->get_one(array(array('REG_url_link' => $REG_url_link))); |
|
457 | + } |
|
458 | + |
|
459 | + |
|
460 | + /** |
|
461 | + * retrieve registration for a specific transaction attendee from db |
|
462 | + * |
|
463 | + * @access public |
|
464 | + * @param int $TXN_ID |
|
465 | + * @param int $ATT_ID |
|
466 | + * @param int $att_nmbr in case the ATT_ID is the same for multiple registrations (same details used) then the |
|
467 | + * attendee number is required |
|
468 | + * @return mixed array on success, FALSE on fail |
|
469 | + * @throws EE_Error |
|
470 | + */ |
|
471 | + public function get_registration_for_transaction_attendee($TXN_ID = 0, $ATT_ID = 0, $att_nmbr = 0) |
|
472 | + { |
|
473 | + return $this->get_one(array( |
|
474 | + array( |
|
475 | + 'TXN_ID' => $TXN_ID, |
|
476 | + 'ATT_ID' => $ATT_ID, |
|
477 | + ), |
|
478 | + 'limit' => array(min($att_nmbr - 1, 0), 1), |
|
479 | + )); |
|
480 | + } |
|
481 | + |
|
482 | + |
|
483 | + /** |
|
484 | + * get the number of registrations per day for the Registration Admin page Reports Tab. |
|
485 | + * (doesn't utilize models because it's a fairly specialized query) |
|
486 | + * |
|
487 | + * @access public |
|
488 | + * @param $period string which can be passed to php's strtotime function (eg "-1 month") |
|
489 | + * @return stdClass[] with properties regDate and total |
|
490 | + * @throws EE_Error |
|
491 | + */ |
|
492 | + public function get_registrations_per_day_report($period = '-1 month') |
|
493 | + { |
|
494 | + $sql_date = $this->convert_datetime_for_query( |
|
495 | + 'REG_date', |
|
496 | + date('Y-m-d H:i:s', strtotime($period)), |
|
497 | + 'Y-m-d H:i:s', |
|
498 | + 'UTC' |
|
499 | + ); |
|
500 | + $where = array( |
|
501 | + 'REG_date' => array('>=', $sql_date), |
|
502 | + 'STS_ID' => array('!=', EEM_Registration::status_id_incomplete), |
|
503 | + ); |
|
504 | + if (!EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_day_report')) { |
|
505 | + $where['Event.EVT_wp_user'] = get_current_user_id(); |
|
506 | + } |
|
507 | + $query_interval = EEH_DTT_Helper::get_sql_query_interval_for_offset($this->get_timezone(), 'REG_date'); |
|
508 | + $results = $this->_get_all_wpdb_results( |
|
509 | + array( |
|
510 | + $where, |
|
511 | + 'group_by' => 'regDate', |
|
512 | + 'order_by' => array('REG_date' => 'ASC'), |
|
513 | + ), |
|
514 | + OBJECT, |
|
515 | + array( |
|
516 | + 'regDate' => array('DATE(' . $query_interval . ')', '%s'), |
|
517 | + 'total' => array('count(REG_ID)', '%d'), |
|
518 | + ) |
|
519 | + ); |
|
520 | + return $results; |
|
521 | + } |
|
522 | + |
|
523 | + |
|
524 | + /** |
|
525 | + * Get the number of registrations per day including the count of registrations for each Registration Status. |
|
526 | + * Note: EEM_Registration::status_id_incomplete registrations are excluded from the results. |
|
527 | + * |
|
528 | + * @param string $period |
|
529 | + * @return stdClass[] with properties Registration_REG_date and a column for each registration status as the STS_ID |
|
530 | + * @throws EE_Error |
|
531 | + * (i.e. RAP) |
|
532 | + */ |
|
533 | + public function get_registrations_per_day_and_per_status_report($period = '-1 month') |
|
534 | + { |
|
535 | + global $wpdb; |
|
536 | + $registration_table = $wpdb->prefix . 'esp_registration'; |
|
537 | + $event_table = $wpdb->posts; |
|
538 | + $sql_date = date('Y-m-d H:i:s', strtotime($period)); |
|
539 | + // prepare the query interval for displaying offset |
|
540 | + $query_interval = EEH_DTT_Helper::get_sql_query_interval_for_offset($this->get_timezone(), 'dates.REG_date'); |
|
541 | + // inner date query |
|
542 | + $inner_date_query = "SELECT DISTINCT REG_date from {$registration_table} "; |
|
543 | + $inner_where = ' WHERE'; |
|
544 | + // exclude events not authored by user if permissions in effect |
|
545 | + if (!EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_event_report')) { |
|
546 | + $inner_date_query .= "LEFT JOIN {$event_table} ON ID = EVT_ID"; |
|
547 | + $inner_where .= ' post_author = ' . get_current_user_id() . ' AND'; |
|
548 | + } |
|
549 | + $inner_where .= " REG_date >= '{$sql_date}'"; |
|
550 | + $inner_date_query .= $inner_where; |
|
551 | + // start main query |
|
552 | + $select = "SELECT DATE({$query_interval}) as Registration_REG_date, "; |
|
553 | + $join = ''; |
|
554 | + $join_parts = array(); |
|
555 | + $select_parts = array(); |
|
556 | + // loop through registration stati to do parts for each status. |
|
557 | + foreach (EEM_Registration::reg_status_array() as $STS_ID => $STS_code) { |
|
558 | + if ($STS_ID === EEM_Registration::status_id_incomplete) { |
|
559 | + continue; |
|
560 | + } |
|
561 | + $select_parts[] = "COUNT({$STS_code}.REG_ID) as {$STS_ID}"; |
|
562 | + $join_parts[] = "{$registration_table} AS {$STS_code} ON {$STS_code}.REG_date = dates.REG_date AND {$STS_code}.STS_ID = '{$STS_ID}'"; |
|
563 | + } |
|
564 | + // setup the selects |
|
565 | + $select .= implode(', ', $select_parts); |
|
566 | + $select .= " FROM ($inner_date_query) AS dates LEFT JOIN "; |
|
567 | + // setup the joins |
|
568 | + $join .= implode(' LEFT JOIN ', $join_parts); |
|
569 | + // now let's put it all together |
|
570 | + $query = $select . $join . ' GROUP BY Registration_REG_date'; |
|
571 | + // and execute it |
|
572 | + return $wpdb->get_results($query, ARRAY_A); |
|
573 | + } |
|
574 | + |
|
575 | + |
|
576 | + /** |
|
577 | + * get the number of registrations per event for the Registration Admin page Reports Tab |
|
578 | + * |
|
579 | + * @access public |
|
580 | + * @param $period string which can be passed to php's strtotime function (eg "-1 month") |
|
581 | + * @return stdClass[] each with properties event_name, reg_limit, and total |
|
582 | + * @throws EE_Error |
|
583 | + */ |
|
584 | + public function get_registrations_per_event_report($period = '-1 month') |
|
585 | + { |
|
586 | + $date_sql = $this->convert_datetime_for_query( |
|
587 | + 'REG_date', |
|
588 | + date('Y-m-d H:i:s', strtotime($period)), |
|
589 | + 'Y-m-d H:i:s', |
|
590 | + 'UTC' |
|
591 | + ); |
|
592 | + $where = array( |
|
593 | + 'REG_date' => array('>=', $date_sql), |
|
594 | + 'STS_ID' => array('!=', EEM_Registration::status_id_incomplete), |
|
595 | + ); |
|
596 | + if (!EE_Registry::instance()->CAP->current_user_can( |
|
597 | + 'ee_read_others_registrations', |
|
598 | + 'reg_per_event_report' |
|
599 | + ) |
|
600 | + ) { |
|
601 | + $where['Event.EVT_wp_user'] = get_current_user_id(); |
|
602 | + } |
|
603 | + $results = $this->_get_all_wpdb_results( |
|
604 | + array( |
|
605 | + $where, |
|
606 | + 'group_by' => 'Event.EVT_name', |
|
607 | + 'order_by' => 'Event.EVT_name', |
|
608 | + 'limit' => array(0, 24), |
|
609 | + ), |
|
610 | + OBJECT, |
|
611 | + array( |
|
612 | + 'event_name' => array('Event_CPT.post_title', '%s'), |
|
613 | + 'total' => array('COUNT(REG_ID)', '%s'), |
|
614 | + ) |
|
615 | + ); |
|
616 | + return $results; |
|
617 | + } |
|
618 | + |
|
619 | + |
|
620 | + /** |
|
621 | + * Get the number of registrations per event grouped by registration status. |
|
622 | + * Note: EEM_Registration::status_id_incomplete registrations are excluded from the results. |
|
623 | + * |
|
624 | + * @param string $period |
|
625 | + * @return stdClass[] with properties `Registration_Event` and a column for each registration status as the STS_ID |
|
626 | + * @throws EE_Error |
|
627 | + * (i.e. RAP) |
|
628 | + */ |
|
629 | + public function get_registrations_per_event_and_per_status_report($period = '-1 month') |
|
630 | + { |
|
631 | + global $wpdb; |
|
632 | + $registration_table = $wpdb->prefix . 'esp_registration'; |
|
633 | + $event_table = $wpdb->posts; |
|
634 | + $sql_date = date('Y-m-d H:i:s', strtotime($period)); |
|
635 | + // inner date query |
|
636 | + $inner_date_query = "SELECT DISTINCT EVT_ID, REG_date from $registration_table "; |
|
637 | + $inner_where = ' WHERE'; |
|
638 | + // exclude events not authored by user if permissions in effect |
|
639 | + if (!EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_event_report')) { |
|
640 | + $inner_date_query .= "LEFT JOIN {$event_table} ON ID = EVT_ID"; |
|
641 | + $inner_where .= ' post_author = ' . get_current_user_id() . ' AND'; |
|
642 | + } |
|
643 | + $inner_where .= " REG_date >= '{$sql_date}'"; |
|
644 | + $inner_date_query .= $inner_where; |
|
645 | + // build main query |
|
646 | + $select = 'SELECT Event.post_title as Registration_Event, '; |
|
647 | + $join = ''; |
|
648 | + $join_parts = array(); |
|
649 | + $select_parts = array(); |
|
650 | + // loop through registration stati to do parts for each status. |
|
651 | + foreach (EEM_Registration::reg_status_array() as $STS_ID => $STS_code) { |
|
652 | + if ($STS_ID === EEM_Registration::status_id_incomplete) { |
|
653 | + continue; |
|
654 | + } |
|
655 | + $select_parts[] = "COUNT({$STS_code}.REG_ID) as {$STS_ID}"; |
|
656 | + $join_parts[] = "{$registration_table} AS {$STS_code} ON {$STS_code}.EVT_ID = dates.EVT_ID AND {$STS_code}.STS_ID = '{$STS_ID}' AND {$STS_code}.REG_date = dates.REG_date"; |
|
657 | + } |
|
658 | + // setup the selects |
|
659 | + $select .= implode(', ', $select_parts); |
|
660 | + $select .= " FROM ($inner_date_query) AS dates LEFT JOIN $event_table as Event ON Event.ID = dates.EVT_ID LEFT JOIN "; |
|
661 | + // setup remaining joins |
|
662 | + $join .= implode(' LEFT JOIN ', $join_parts); |
|
663 | + // now put it all together |
|
664 | + $query = $select . $join . ' GROUP BY Registration_Event'; |
|
665 | + // and execute |
|
666 | + return $wpdb->get_results($query, ARRAY_A); |
|
667 | + } |
|
668 | + |
|
669 | + |
|
670 | + /** |
|
671 | + * Returns the EE_Registration of the primary attendee on the transaction id provided |
|
672 | + * |
|
673 | + * @param int $TXN_ID |
|
674 | + * @return EE_Base_Class|EE_Registration|null |
|
675 | + * @throws EE_Error |
|
676 | + */ |
|
677 | + public function get_primary_registration_for_transaction_ID($TXN_ID = 0) |
|
678 | + { |
|
679 | + if (!$TXN_ID) { |
|
680 | + return null; |
|
681 | + } |
|
682 | + return $this->get_one(array( |
|
683 | + array( |
|
684 | + 'TXN_ID' => $TXN_ID, |
|
685 | + 'REG_count' => EEM_Registration::PRIMARY_REGISTRANT_COUNT, |
|
686 | + ), |
|
687 | + )); |
|
688 | + } |
|
689 | + |
|
690 | + |
|
691 | + /** |
|
692 | + * get_event_registration_count |
|
693 | + * |
|
694 | + * @access public |
|
695 | + * @param int $EVT_ID |
|
696 | + * @param boolean $for_incomplete_payments |
|
697 | + * @return int |
|
698 | + * @throws EE_Error |
|
699 | + */ |
|
700 | + public function get_event_registration_count($EVT_ID, $for_incomplete_payments = false) |
|
701 | + { |
|
702 | + // we only count approved registrations towards registration limits |
|
703 | + $query_params = array(array('EVT_ID' => $EVT_ID, 'STS_ID' => self::status_id_approved)); |
|
704 | + if ($for_incomplete_payments) { |
|
705 | + $query_params[0]['Transaction.STS_ID'] = array('!=', EEM_Transaction::complete_status_code); |
|
706 | + } |
|
707 | + return $this->count($query_params); |
|
708 | + } |
|
709 | + |
|
710 | + |
|
711 | + /** |
|
712 | + * Deletes all registrations with no transactions. Note that this needs to be very efficient |
|
713 | + * and so it uses wpdb directly. Also, we can't put a limit on this because MySQL doesn't allow a limit on a delete |
|
714 | + * when joining tables like this. |
|
715 | + * |
|
716 | + * @global WPDB $wpdb |
|
717 | + * @return int number deleted |
|
718 | + * @throws EE_Error |
|
719 | + */ |
|
720 | + public function delete_registrations_with_no_transaction() |
|
721 | + { |
|
722 | + /** @type WPDB $wpdb */ |
|
723 | + global $wpdb; |
|
724 | + return $wpdb->query( |
|
725 | + 'DELETE r FROM ' |
|
726 | + . $this->table() |
|
727 | + . ' r LEFT JOIN ' |
|
728 | + . EEM_Transaction::instance()->table() |
|
729 | + . ' t ON r.TXN_ID = t.TXN_ID WHERE t.TXN_ID IS NULL' |
|
730 | + ); |
|
731 | + } |
|
732 | + |
|
733 | + |
|
734 | + /** |
|
735 | + * Count registrations checked into (or out of) a datetime |
|
736 | + * |
|
737 | + * @param int $DTT_ID datetime ID |
|
738 | + * @param boolean $checked_in whether to count registrations checked IN or OUT |
|
739 | + * @return int |
|
740 | + * @throws EE_Error |
|
741 | + */ |
|
742 | + public function count_registrations_checked_into_datetime($DTT_ID, $checked_in = true) |
|
743 | + { |
|
744 | + global $wpdb; |
|
745 | + // subquery to get latest checkin |
|
746 | + $query = $wpdb->prepare( |
|
747 | + 'SELECT ' |
|
748 | + . 'COUNT( DISTINCT checkins.REG_ID ) ' |
|
749 | + . 'FROM ' . EEM_Checkin::instance()->table() . ' AS checkins INNER JOIN' |
|
750 | + . '( SELECT ' |
|
751 | + . 'max( CHK_timestamp ) AS latest_checkin, ' |
|
752 | + . 'REG_ID AS REG_ID ' |
|
753 | + . 'FROM ' . EEM_Checkin::instance()->table() . ' ' |
|
754 | + . 'WHERE DTT_ID=%d ' |
|
755 | + . 'GROUP BY REG_ID' |
|
756 | + . ') AS most_recent_checkin_per_reg ' |
|
757 | + . 'ON checkins.REG_ID=most_recent_checkin_per_reg.REG_ID ' |
|
758 | + . 'AND checkins.CHK_timestamp = most_recent_checkin_per_reg.latest_checkin ' |
|
759 | + . 'WHERE ' |
|
760 | + . 'checkins.CHK_in=%d', |
|
761 | + $DTT_ID, |
|
762 | + $checked_in |
|
763 | + ); |
|
764 | + return (int) $wpdb->get_var($query); |
|
765 | + } |
|
766 | + |
|
767 | + |
|
768 | + /** |
|
769 | + * Count registrations checked into (or out of) an event. |
|
770 | + * |
|
771 | + * @param int $EVT_ID event ID |
|
772 | + * @param boolean $checked_in whether to count registrations checked IN or OUT |
|
773 | + * @return int |
|
774 | + * @throws EE_Error |
|
775 | + */ |
|
776 | + public function count_registrations_checked_into_event($EVT_ID, $checked_in = true) |
|
777 | + { |
|
778 | + global $wpdb; |
|
779 | + // subquery to get latest checkin |
|
780 | + $query = $wpdb->prepare( |
|
781 | + 'SELECT ' |
|
782 | + . 'COUNT( DISTINCT checkins.REG_ID ) ' |
|
783 | + . 'FROM ' . EEM_Checkin::instance()->table() . ' AS checkins INNER JOIN' |
|
784 | + . '( SELECT ' |
|
785 | + . 'max( CHK_timestamp ) AS latest_checkin, ' |
|
786 | + . 'REG_ID AS REG_ID ' |
|
787 | + . 'FROM ' . EEM_Checkin::instance()->table() . ' AS c ' |
|
788 | + . 'INNER JOIN ' . EEM_Datetime::instance()->table() . ' AS d ' |
|
789 | + . 'ON c.DTT_ID=d.DTT_ID ' |
|
790 | + . 'WHERE d.EVT_ID=%d ' |
|
791 | + . 'GROUP BY REG_ID' |
|
792 | + . ') AS most_recent_checkin_per_reg ' |
|
793 | + . 'ON checkins.REG_ID=most_recent_checkin_per_reg.REG_ID ' |
|
794 | + . 'AND checkins.CHK_timestamp = most_recent_checkin_per_reg.latest_checkin ' |
|
795 | + . 'WHERE ' |
|
796 | + . 'checkins.CHK_in=%d', |
|
797 | + $EVT_ID, |
|
798 | + $checked_in |
|
799 | + ); |
|
800 | + return (int) $wpdb->get_var($query); |
|
801 | + } |
|
802 | + |
|
803 | + |
|
804 | + /** |
|
805 | + * The purpose of this method is to retrieve an array of |
|
806 | + * EE_Registration objects that represent the latest registration |
|
807 | + * for each ATT_ID given in the function argument. |
|
808 | + * |
|
809 | + * @param array $attendee_ids |
|
810 | + * @return EE_Base_Class[]|EE_Registration[] |
|
811 | + * @throws EE_Error |
|
812 | + */ |
|
813 | + public function get_latest_registration_for_each_of_given_contacts($attendee_ids = array()) |
|
814 | + { |
|
815 | + // first do a native wp_query to get the latest REG_ID's matching these attendees. |
|
816 | + global $wpdb; |
|
817 | + $registration_table = $wpdb->prefix . 'esp_registration'; |
|
818 | + $attendee_table = $wpdb->posts; |
|
819 | + $attendee_ids = is_array($attendee_ids) |
|
820 | + ? array_map('absint', $attendee_ids) |
|
821 | + : array((int) $attendee_ids); |
|
822 | + $ATT_IDs = implode(',', $attendee_ids); |
|
823 | + // first we do a query to get the registration ids |
|
824 | + // (because a group by before order by causes the order by to be ignored.) |
|
825 | + $registration_id_query = " |
|
826 | 826 | SELECT registrations.registration_ids as registration_id |
827 | 827 | FROM ( |
828 | 828 | SELECT |
@@ -836,61 +836,61 @@ discard block |
||
836 | 836 | ) AS registrations |
837 | 837 | GROUP BY registrations.attendee_ids |
838 | 838 | "; |
839 | - $registration_ids = $wpdb->get_results($registration_id_query, ARRAY_A); |
|
840 | - if (empty($registration_ids)) { |
|
841 | - return array(); |
|
842 | - } |
|
843 | - $ids_for_model_query = array(); |
|
844 | - // let's flatten the ids so they can be used in the model query. |
|
845 | - foreach ($registration_ids as $registration_id) { |
|
846 | - if (isset($registration_id['registration_id'])) { |
|
847 | - $ids_for_model_query[] = $registration_id['registration_id']; |
|
848 | - } |
|
849 | - } |
|
850 | - // construct query |
|
851 | - $_where = array( |
|
852 | - 'REG_ID' => array('IN', $ids_for_model_query), |
|
853 | - ); |
|
854 | - return $this->get_all(array($_where)); |
|
855 | - } |
|
856 | - |
|
857 | - |
|
858 | - |
|
859 | - /** |
|
860 | - * returns a count of registrations for the supplied event having the status as specified |
|
861 | - * |
|
862 | - * @param int $EVT_ID |
|
863 | - * @param array $statuses |
|
864 | - * @return int |
|
865 | - * @throws InvalidArgumentException |
|
866 | - * @throws InvalidStatusException |
|
867 | - * @throws EE_Error |
|
868 | - */ |
|
869 | - public function event_reg_count_for_statuses($EVT_ID, $statuses = array()) |
|
870 | - { |
|
871 | - $EVT_ID = absint($EVT_ID); |
|
872 | - if (! $EVT_ID) { |
|
873 | - throw new InvalidArgumentException( |
|
874 | - esc_html__('An invalid Event ID was supplied.', 'event_espresso') |
|
875 | - ); |
|
876 | - } |
|
877 | - $statuses = is_array($statuses) ? $statuses : array($statuses); |
|
878 | - $statuses = ! empty($statuses) ? $statuses : array(EEM_Registration::status_id_approved); |
|
879 | - $valid_reg_statuses = EEM_Registration::reg_statuses(); |
|
880 | - foreach ($statuses as $status) { |
|
881 | - if (! in_array($status, $valid_reg_statuses, true)) { |
|
882 | - throw new InvalidStatusException($status, esc_html__('Registration', 'event_espresso')); |
|
883 | - } |
|
884 | - } |
|
885 | - return $this->count( |
|
886 | - array( |
|
887 | - array( |
|
888 | - 'EVT_ID' => $EVT_ID, |
|
889 | - 'STS_ID' => array('IN', $statuses), |
|
890 | - ), |
|
891 | - ), |
|
892 | - 'REG_ID', |
|
893 | - true |
|
894 | - ); |
|
895 | - } |
|
839 | + $registration_ids = $wpdb->get_results($registration_id_query, ARRAY_A); |
|
840 | + if (empty($registration_ids)) { |
|
841 | + return array(); |
|
842 | + } |
|
843 | + $ids_for_model_query = array(); |
|
844 | + // let's flatten the ids so they can be used in the model query. |
|
845 | + foreach ($registration_ids as $registration_id) { |
|
846 | + if (isset($registration_id['registration_id'])) { |
|
847 | + $ids_for_model_query[] = $registration_id['registration_id']; |
|
848 | + } |
|
849 | + } |
|
850 | + // construct query |
|
851 | + $_where = array( |
|
852 | + 'REG_ID' => array('IN', $ids_for_model_query), |
|
853 | + ); |
|
854 | + return $this->get_all(array($_where)); |
|
855 | + } |
|
856 | + |
|
857 | + |
|
858 | + |
|
859 | + /** |
|
860 | + * returns a count of registrations for the supplied event having the status as specified |
|
861 | + * |
|
862 | + * @param int $EVT_ID |
|
863 | + * @param array $statuses |
|
864 | + * @return int |
|
865 | + * @throws InvalidArgumentException |
|
866 | + * @throws InvalidStatusException |
|
867 | + * @throws EE_Error |
|
868 | + */ |
|
869 | + public function event_reg_count_for_statuses($EVT_ID, $statuses = array()) |
|
870 | + { |
|
871 | + $EVT_ID = absint($EVT_ID); |
|
872 | + if (! $EVT_ID) { |
|
873 | + throw new InvalidArgumentException( |
|
874 | + esc_html__('An invalid Event ID was supplied.', 'event_espresso') |
|
875 | + ); |
|
876 | + } |
|
877 | + $statuses = is_array($statuses) ? $statuses : array($statuses); |
|
878 | + $statuses = ! empty($statuses) ? $statuses : array(EEM_Registration::status_id_approved); |
|
879 | + $valid_reg_statuses = EEM_Registration::reg_statuses(); |
|
880 | + foreach ($statuses as $status) { |
|
881 | + if (! in_array($status, $valid_reg_statuses, true)) { |
|
882 | + throw new InvalidStatusException($status, esc_html__('Registration', 'event_espresso')); |
|
883 | + } |
|
884 | + } |
|
885 | + return $this->count( |
|
886 | + array( |
|
887 | + array( |
|
888 | + 'EVT_ID' => $EVT_ID, |
|
889 | + 'STS_ID' => array('IN', $statuses), |
|
890 | + ), |
|
891 | + ), |
|
892 | + 'REG_ID', |
|
893 | + true |
|
894 | + ); |
|
895 | + } |
|
896 | 896 | } |
@@ -16,230 +16,230 @@ discard block |
||
16 | 16 | class EEM_Transaction extends EEM_Base |
17 | 17 | { |
18 | 18 | |
19 | - // private instance of the Transaction object |
|
20 | - protected static $_instance; |
|
21 | - |
|
22 | - /** |
|
23 | - * Status ID(STS_ID on esp_status table) to indicate the transaction is complete, |
|
24 | - * but payment is pending. This is the state for transactions where payment is promised |
|
25 | - * from an offline gateway. |
|
26 | - */ |
|
27 | - // const open_status_code = 'TPN'; |
|
28 | - |
|
29 | - /** |
|
30 | - * Status ID(STS_ID on esp_status table) to indicate the transaction failed, |
|
31 | - * either due to a technical reason (server or computer crash during registration), |
|
32 | - * or some other reason that prevent the collection of any useful contact information from any of the registrants |
|
33 | - */ |
|
34 | - const failed_status_code = 'TFL'; |
|
35 | - |
|
36 | - /** |
|
37 | - * Status ID(STS_ID on esp_status table) to indicate the transaction was abandoned, |
|
38 | - * either due to a technical reason (server or computer crash during registration), |
|
39 | - * or due to an abandoned cart after registrant chose not to complete the registration process |
|
40 | - * HOWEVER... |
|
41 | - * an abandoned TXN differs from a failed TXN in that it was able to capture contact information for at least one |
|
42 | - * registrant |
|
43 | - */ |
|
44 | - const abandoned_status_code = 'TAB'; |
|
45 | - |
|
46 | - /** |
|
47 | - * Status ID(STS_ID on esp_status table) to indicate an incomplete transaction, |
|
48 | - * meaning that monies are still owing: TXN_paid < TXN_total |
|
49 | - */ |
|
50 | - const incomplete_status_code = 'TIN'; |
|
51 | - |
|
52 | - /** |
|
53 | - * Status ID (STS_ID on esp_status table) to indicate a complete transaction. |
|
54 | - * meaning that NO monies are owing: TXN_paid == TXN_total |
|
55 | - */ |
|
56 | - const complete_status_code = 'TCM'; |
|
57 | - |
|
58 | - /** |
|
59 | - * Status ID(STS_ID on esp_status table) to indicate the transaction is overpaid. |
|
60 | - * This is the same as complete, but site admins actually owe clients the moneys! TXN_paid > TXN_total |
|
61 | - */ |
|
62 | - const overpaid_status_code = 'TOP'; |
|
63 | - |
|
64 | - |
|
65 | - /** |
|
66 | - * private constructor to prevent direct creation |
|
67 | - * |
|
68 | - * @Constructor |
|
69 | - * @access protected |
|
70 | - * |
|
71 | - * @param string $timezone string representing the timezone we want to set for returned Date Time Strings (and any |
|
72 | - * incoming timezone data that gets saved). Note this just sends the timezone info to the |
|
73 | - * date time model field objects. Default is NULL (and will be assumed using the set |
|
74 | - * timezone in the 'timezone_string' wp option) |
|
75 | - * |
|
76 | - * @return EEM_Transaction |
|
77 | - * @throws \EE_Error |
|
78 | - */ |
|
79 | - protected function __construct($timezone) |
|
80 | - { |
|
81 | - $this->singular_item = __('Transaction', 'event_espresso'); |
|
82 | - $this->plural_item = __('Transactions', 'event_espresso'); |
|
83 | - |
|
84 | - $this->_tables = array( |
|
85 | - 'TransactionTable' => new EE_Primary_Table('esp_transaction', 'TXN_ID') |
|
86 | - ); |
|
87 | - $this->_fields = array( |
|
88 | - 'TransactionTable' => array( |
|
89 | - 'TXN_ID' => new EE_Primary_Key_Int_Field('TXN_ID', __('Transaction ID', 'event_espresso')), |
|
90 | - 'TXN_timestamp' => new EE_Datetime_Field( |
|
91 | - 'TXN_timestamp', |
|
92 | - __('date when transaction was created', 'event_espresso'), |
|
93 | - false, |
|
94 | - EE_Datetime_Field::now, |
|
95 | - $timezone |
|
96 | - ), |
|
97 | - 'TXN_total' => new EE_Money_Field( |
|
98 | - 'TXN_total', |
|
99 | - __('Total value of Transaction', 'event_espresso'), |
|
100 | - false, |
|
101 | - 0 |
|
102 | - ), |
|
103 | - 'TXN_paid' => new EE_Money_Field( |
|
104 | - 'TXN_paid', |
|
105 | - __('Amount paid towards transaction to date', 'event_espresso'), |
|
106 | - false, |
|
107 | - 0 |
|
108 | - ), |
|
109 | - 'STS_ID' => new EE_Foreign_Key_String_Field( |
|
110 | - 'STS_ID', |
|
111 | - __('Status ID', 'event_espresso'), |
|
112 | - false, |
|
113 | - EEM_Transaction::failed_status_code, |
|
114 | - 'Status' |
|
115 | - ), |
|
116 | - 'TXN_session_data' => new EE_Serialized_Text_Field( |
|
117 | - 'TXN_session_data', |
|
118 | - __('Serialized session data', 'event_espresso'), |
|
119 | - true, |
|
120 | - '' |
|
121 | - ), |
|
122 | - 'TXN_hash_salt' => new EE_Plain_Text_Field( |
|
123 | - 'TXN_hash_salt', |
|
124 | - __('Transaction Hash Salt', 'event_espresso'), |
|
125 | - true, |
|
126 | - '' |
|
127 | - ), |
|
128 | - 'PMD_ID' => new EE_Foreign_Key_Int_Field( |
|
129 | - 'PMD_ID', |
|
130 | - __("Last Used Payment Method", 'event_espresso'), |
|
131 | - true, |
|
132 | - null, |
|
133 | - 'Payment_Method' |
|
134 | - ), |
|
135 | - 'TXN_reg_steps' => new EE_Serialized_Text_Field( |
|
136 | - 'TXN_reg_steps', |
|
137 | - __('Registration Steps', 'event_espresso'), |
|
138 | - false, |
|
139 | - array() |
|
140 | - ), |
|
141 | - ) |
|
142 | - ); |
|
143 | - $this->_model_relations = array( |
|
144 | - 'Registration' => new EE_Has_Many_Relation(), |
|
145 | - 'Payment' => new EE_Has_Many_Relation(), |
|
146 | - 'Status' => new EE_Belongs_To_Relation(), |
|
147 | - 'Line_Item' => new EE_Has_Many_Relation(false), |
|
148 | - // you can delete a transaction without needing to delete its line items |
|
149 | - 'Payment_Method' => new EE_Belongs_To_Relation(), |
|
150 | - 'Message' => new EE_Has_Many_Relation() |
|
151 | - ); |
|
152 | - $this->_model_chain_to_wp_user = 'Registration.Event'; |
|
153 | - parent::__construct($timezone); |
|
154 | - } |
|
155 | - |
|
156 | - |
|
157 | - /** |
|
158 | - * txn_status_array |
|
159 | - * get list of transaction statuses |
|
160 | - * |
|
161 | - * @access public |
|
162 | - * @return array |
|
163 | - */ |
|
164 | - public static function txn_status_array() |
|
165 | - { |
|
166 | - return apply_filters( |
|
167 | - 'FHEE__EEM_Transaction__txn_status_array', |
|
168 | - array( |
|
169 | - EEM_Transaction::overpaid_status_code, |
|
170 | - EEM_Transaction::complete_status_code, |
|
171 | - EEM_Transaction::incomplete_status_code, |
|
172 | - EEM_Transaction::abandoned_status_code, |
|
173 | - EEM_Transaction::failed_status_code, |
|
174 | - ) |
|
175 | - ); |
|
176 | - } |
|
177 | - |
|
178 | - /** |
|
179 | - * get the revenue per day for the Transaction Admin page Reports Tab |
|
180 | - * |
|
181 | - * @access public |
|
182 | - * |
|
183 | - * @param string $period |
|
184 | - * |
|
185 | - * @return \stdClass[] |
|
186 | - */ |
|
187 | - public function get_revenue_per_day_report($period = '-1 month') |
|
188 | - { |
|
189 | - $sql_date = $this->convert_datetime_for_query( |
|
190 | - 'TXN_timestamp', |
|
191 | - date('Y-m-d H:i:s', strtotime($period)), |
|
192 | - 'Y-m-d H:i:s', |
|
193 | - 'UTC' |
|
194 | - ); |
|
195 | - |
|
196 | - $query_interval = EEH_DTT_Helper::get_sql_query_interval_for_offset($this->get_timezone(), 'TXN_timestamp'); |
|
197 | - |
|
198 | - return $this->_get_all_wpdb_results( |
|
199 | - array( |
|
200 | - array( |
|
201 | - 'TXN_timestamp' => array('>=', $sql_date) |
|
202 | - ), |
|
203 | - 'group_by' => 'txnDate', |
|
204 | - 'order_by' => array('TXN_timestamp' => 'ASC') |
|
205 | - ), |
|
206 | - OBJECT, |
|
207 | - array( |
|
208 | - 'txnDate' => array('DATE(' . $query_interval . ')', '%s'), |
|
209 | - 'revenue' => array('SUM(TransactionTable.TXN_paid)', '%d') |
|
210 | - ) |
|
211 | - ); |
|
212 | - } |
|
213 | - |
|
214 | - |
|
215 | - /** |
|
216 | - * get the revenue per event for the Transaction Admin page Reports Tab |
|
217 | - * |
|
218 | - * @access public |
|
219 | - * |
|
220 | - * @param string $period |
|
221 | - * |
|
222 | - * @throws \EE_Error |
|
223 | - * @return mixed |
|
224 | - */ |
|
225 | - public function get_revenue_per_event_report($period = '-1 month') |
|
226 | - { |
|
227 | - global $wpdb; |
|
228 | - $transaction_table = $wpdb->prefix . 'esp_transaction'; |
|
229 | - $registration_table = $wpdb->prefix . 'esp_registration'; |
|
230 | - $registration_payment_table = $wpdb->prefix . 'esp_registration_payment'; |
|
231 | - $event_table = $wpdb->posts; |
|
232 | - $payment_table = $wpdb->prefix . 'esp_payment'; |
|
233 | - $sql_date = date('Y-m-d H:i:s', strtotime($period)); |
|
234 | - $approved_payment_status = EEM_Payment::status_id_approved; |
|
235 | - $extra_event_on_join = ''; |
|
236 | - // exclude events not authored by user if permissions in effect |
|
237 | - if (! EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_event_report')) { |
|
238 | - $extra_event_on_join = ' AND Event.post_author = ' . get_current_user_id(); |
|
239 | - } |
|
240 | - |
|
241 | - return $wpdb->get_results( |
|
242 | - "SELECT |
|
19 | + // private instance of the Transaction object |
|
20 | + protected static $_instance; |
|
21 | + |
|
22 | + /** |
|
23 | + * Status ID(STS_ID on esp_status table) to indicate the transaction is complete, |
|
24 | + * but payment is pending. This is the state for transactions where payment is promised |
|
25 | + * from an offline gateway. |
|
26 | + */ |
|
27 | + // const open_status_code = 'TPN'; |
|
28 | + |
|
29 | + /** |
|
30 | + * Status ID(STS_ID on esp_status table) to indicate the transaction failed, |
|
31 | + * either due to a technical reason (server or computer crash during registration), |
|
32 | + * or some other reason that prevent the collection of any useful contact information from any of the registrants |
|
33 | + */ |
|
34 | + const failed_status_code = 'TFL'; |
|
35 | + |
|
36 | + /** |
|
37 | + * Status ID(STS_ID on esp_status table) to indicate the transaction was abandoned, |
|
38 | + * either due to a technical reason (server or computer crash during registration), |
|
39 | + * or due to an abandoned cart after registrant chose not to complete the registration process |
|
40 | + * HOWEVER... |
|
41 | + * an abandoned TXN differs from a failed TXN in that it was able to capture contact information for at least one |
|
42 | + * registrant |
|
43 | + */ |
|
44 | + const abandoned_status_code = 'TAB'; |
|
45 | + |
|
46 | + /** |
|
47 | + * Status ID(STS_ID on esp_status table) to indicate an incomplete transaction, |
|
48 | + * meaning that monies are still owing: TXN_paid < TXN_total |
|
49 | + */ |
|
50 | + const incomplete_status_code = 'TIN'; |
|
51 | + |
|
52 | + /** |
|
53 | + * Status ID (STS_ID on esp_status table) to indicate a complete transaction. |
|
54 | + * meaning that NO monies are owing: TXN_paid == TXN_total |
|
55 | + */ |
|
56 | + const complete_status_code = 'TCM'; |
|
57 | + |
|
58 | + /** |
|
59 | + * Status ID(STS_ID on esp_status table) to indicate the transaction is overpaid. |
|
60 | + * This is the same as complete, but site admins actually owe clients the moneys! TXN_paid > TXN_total |
|
61 | + */ |
|
62 | + const overpaid_status_code = 'TOP'; |
|
63 | + |
|
64 | + |
|
65 | + /** |
|
66 | + * private constructor to prevent direct creation |
|
67 | + * |
|
68 | + * @Constructor |
|
69 | + * @access protected |
|
70 | + * |
|
71 | + * @param string $timezone string representing the timezone we want to set for returned Date Time Strings (and any |
|
72 | + * incoming timezone data that gets saved). Note this just sends the timezone info to the |
|
73 | + * date time model field objects. Default is NULL (and will be assumed using the set |
|
74 | + * timezone in the 'timezone_string' wp option) |
|
75 | + * |
|
76 | + * @return EEM_Transaction |
|
77 | + * @throws \EE_Error |
|
78 | + */ |
|
79 | + protected function __construct($timezone) |
|
80 | + { |
|
81 | + $this->singular_item = __('Transaction', 'event_espresso'); |
|
82 | + $this->plural_item = __('Transactions', 'event_espresso'); |
|
83 | + |
|
84 | + $this->_tables = array( |
|
85 | + 'TransactionTable' => new EE_Primary_Table('esp_transaction', 'TXN_ID') |
|
86 | + ); |
|
87 | + $this->_fields = array( |
|
88 | + 'TransactionTable' => array( |
|
89 | + 'TXN_ID' => new EE_Primary_Key_Int_Field('TXN_ID', __('Transaction ID', 'event_espresso')), |
|
90 | + 'TXN_timestamp' => new EE_Datetime_Field( |
|
91 | + 'TXN_timestamp', |
|
92 | + __('date when transaction was created', 'event_espresso'), |
|
93 | + false, |
|
94 | + EE_Datetime_Field::now, |
|
95 | + $timezone |
|
96 | + ), |
|
97 | + 'TXN_total' => new EE_Money_Field( |
|
98 | + 'TXN_total', |
|
99 | + __('Total value of Transaction', 'event_espresso'), |
|
100 | + false, |
|
101 | + 0 |
|
102 | + ), |
|
103 | + 'TXN_paid' => new EE_Money_Field( |
|
104 | + 'TXN_paid', |
|
105 | + __('Amount paid towards transaction to date', 'event_espresso'), |
|
106 | + false, |
|
107 | + 0 |
|
108 | + ), |
|
109 | + 'STS_ID' => new EE_Foreign_Key_String_Field( |
|
110 | + 'STS_ID', |
|
111 | + __('Status ID', 'event_espresso'), |
|
112 | + false, |
|
113 | + EEM_Transaction::failed_status_code, |
|
114 | + 'Status' |
|
115 | + ), |
|
116 | + 'TXN_session_data' => new EE_Serialized_Text_Field( |
|
117 | + 'TXN_session_data', |
|
118 | + __('Serialized session data', 'event_espresso'), |
|
119 | + true, |
|
120 | + '' |
|
121 | + ), |
|
122 | + 'TXN_hash_salt' => new EE_Plain_Text_Field( |
|
123 | + 'TXN_hash_salt', |
|
124 | + __('Transaction Hash Salt', 'event_espresso'), |
|
125 | + true, |
|
126 | + '' |
|
127 | + ), |
|
128 | + 'PMD_ID' => new EE_Foreign_Key_Int_Field( |
|
129 | + 'PMD_ID', |
|
130 | + __("Last Used Payment Method", 'event_espresso'), |
|
131 | + true, |
|
132 | + null, |
|
133 | + 'Payment_Method' |
|
134 | + ), |
|
135 | + 'TXN_reg_steps' => new EE_Serialized_Text_Field( |
|
136 | + 'TXN_reg_steps', |
|
137 | + __('Registration Steps', 'event_espresso'), |
|
138 | + false, |
|
139 | + array() |
|
140 | + ), |
|
141 | + ) |
|
142 | + ); |
|
143 | + $this->_model_relations = array( |
|
144 | + 'Registration' => new EE_Has_Many_Relation(), |
|
145 | + 'Payment' => new EE_Has_Many_Relation(), |
|
146 | + 'Status' => new EE_Belongs_To_Relation(), |
|
147 | + 'Line_Item' => new EE_Has_Many_Relation(false), |
|
148 | + // you can delete a transaction without needing to delete its line items |
|
149 | + 'Payment_Method' => new EE_Belongs_To_Relation(), |
|
150 | + 'Message' => new EE_Has_Many_Relation() |
|
151 | + ); |
|
152 | + $this->_model_chain_to_wp_user = 'Registration.Event'; |
|
153 | + parent::__construct($timezone); |
|
154 | + } |
|
155 | + |
|
156 | + |
|
157 | + /** |
|
158 | + * txn_status_array |
|
159 | + * get list of transaction statuses |
|
160 | + * |
|
161 | + * @access public |
|
162 | + * @return array |
|
163 | + */ |
|
164 | + public static function txn_status_array() |
|
165 | + { |
|
166 | + return apply_filters( |
|
167 | + 'FHEE__EEM_Transaction__txn_status_array', |
|
168 | + array( |
|
169 | + EEM_Transaction::overpaid_status_code, |
|
170 | + EEM_Transaction::complete_status_code, |
|
171 | + EEM_Transaction::incomplete_status_code, |
|
172 | + EEM_Transaction::abandoned_status_code, |
|
173 | + EEM_Transaction::failed_status_code, |
|
174 | + ) |
|
175 | + ); |
|
176 | + } |
|
177 | + |
|
178 | + /** |
|
179 | + * get the revenue per day for the Transaction Admin page Reports Tab |
|
180 | + * |
|
181 | + * @access public |
|
182 | + * |
|
183 | + * @param string $period |
|
184 | + * |
|
185 | + * @return \stdClass[] |
|
186 | + */ |
|
187 | + public function get_revenue_per_day_report($period = '-1 month') |
|
188 | + { |
|
189 | + $sql_date = $this->convert_datetime_for_query( |
|
190 | + 'TXN_timestamp', |
|
191 | + date('Y-m-d H:i:s', strtotime($period)), |
|
192 | + 'Y-m-d H:i:s', |
|
193 | + 'UTC' |
|
194 | + ); |
|
195 | + |
|
196 | + $query_interval = EEH_DTT_Helper::get_sql_query_interval_for_offset($this->get_timezone(), 'TXN_timestamp'); |
|
197 | + |
|
198 | + return $this->_get_all_wpdb_results( |
|
199 | + array( |
|
200 | + array( |
|
201 | + 'TXN_timestamp' => array('>=', $sql_date) |
|
202 | + ), |
|
203 | + 'group_by' => 'txnDate', |
|
204 | + 'order_by' => array('TXN_timestamp' => 'ASC') |
|
205 | + ), |
|
206 | + OBJECT, |
|
207 | + array( |
|
208 | + 'txnDate' => array('DATE(' . $query_interval . ')', '%s'), |
|
209 | + 'revenue' => array('SUM(TransactionTable.TXN_paid)', '%d') |
|
210 | + ) |
|
211 | + ); |
|
212 | + } |
|
213 | + |
|
214 | + |
|
215 | + /** |
|
216 | + * get the revenue per event for the Transaction Admin page Reports Tab |
|
217 | + * |
|
218 | + * @access public |
|
219 | + * |
|
220 | + * @param string $period |
|
221 | + * |
|
222 | + * @throws \EE_Error |
|
223 | + * @return mixed |
|
224 | + */ |
|
225 | + public function get_revenue_per_event_report($period = '-1 month') |
|
226 | + { |
|
227 | + global $wpdb; |
|
228 | + $transaction_table = $wpdb->prefix . 'esp_transaction'; |
|
229 | + $registration_table = $wpdb->prefix . 'esp_registration'; |
|
230 | + $registration_payment_table = $wpdb->prefix . 'esp_registration_payment'; |
|
231 | + $event_table = $wpdb->posts; |
|
232 | + $payment_table = $wpdb->prefix . 'esp_payment'; |
|
233 | + $sql_date = date('Y-m-d H:i:s', strtotime($period)); |
|
234 | + $approved_payment_status = EEM_Payment::status_id_approved; |
|
235 | + $extra_event_on_join = ''; |
|
236 | + // exclude events not authored by user if permissions in effect |
|
237 | + if (! EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_event_report')) { |
|
238 | + $extra_event_on_join = ' AND Event.post_author = ' . get_current_user_id(); |
|
239 | + } |
|
240 | + |
|
241 | + return $wpdb->get_results( |
|
242 | + "SELECT |
|
243 | 243 | Transaction_Event.event_name AS event_name, |
244 | 244 | SUM(Transaction_Event.paid) AS revenue |
245 | 245 | FROM |
@@ -267,239 +267,239 @@ discard block |
||
267 | 267 | $extra_event_on_join |
268 | 268 | ) AS Transaction_Event |
269 | 269 | GROUP BY event_name", |
270 | - OBJECT |
|
271 | - ); |
|
272 | - } |
|
273 | - |
|
274 | - |
|
275 | - /** |
|
276 | - * Gets the current transaction given the reg_url_link, or assumes the reg_url_link is in the |
|
277 | - * $_REQUEST global variable. Either way, tries to find the current transaction (through |
|
278 | - * the registration pointed to by reg_url_link), if not returns null |
|
279 | - * |
|
280 | - * @param string $reg_url_link |
|
281 | - * |
|
282 | - * @return EE_Transaction |
|
283 | - */ |
|
284 | - public function get_transaction_from_reg_url_link($reg_url_link = '') |
|
285 | - { |
|
286 | - return $this->get_one(array( |
|
287 | - array( |
|
288 | - 'Registration.REG_url_link' => ! empty($reg_url_link) ? $reg_url_link : EE_Registry::instance()->REQ->get( |
|
289 | - 'e_reg_url_link', |
|
290 | - '' |
|
291 | - ) |
|
292 | - ) |
|
293 | - )); |
|
294 | - } |
|
295 | - |
|
296 | - |
|
297 | - /** |
|
298 | - * Updates the provided EE_Transaction with all the applicable payments |
|
299 | - * (or fetch the EE_Transaction from its ID) |
|
300 | - * |
|
301 | - * @deprecated |
|
302 | - * |
|
303 | - * @param EE_Transaction|int $transaction_obj_or_id |
|
304 | - * @param boolean $save_txn whether or not to save the transaction during this function call |
|
305 | - * |
|
306 | - * @return boolean |
|
307 | - * @throws \EE_Error |
|
308 | - */ |
|
309 | - public function update_based_on_payments($transaction_obj_or_id, $save_txn = true) |
|
310 | - { |
|
311 | - EE_Error::doing_it_wrong( |
|
312 | - __CLASS__ . '::' . __FUNCTION__, |
|
313 | - sprintf( |
|
314 | - __('This method is deprecated. Please use "%s" instead', 'event_espresso'), |
|
315 | - 'EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()' |
|
316 | - ), |
|
317 | - '4.6.0' |
|
318 | - ); |
|
319 | - /** @type EE_Transaction_Processor $transaction_processor */ |
|
320 | - $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor'); |
|
321 | - |
|
322 | - return $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment( |
|
323 | - $this->ensure_is_obj($transaction_obj_or_id) |
|
324 | - ); |
|
325 | - } |
|
326 | - |
|
327 | - /** |
|
328 | - * Deletes "junk" transactions that were probably added by bots. There might be TONS |
|
329 | - * of these, so we are very careful to NOT select (which the models do even when deleting), |
|
330 | - * and so we only use wpdb directly and only do minimal joins. |
|
331 | - * Transactions are considered "junk" if they're failed for longer than a week. |
|
332 | - * Also, there is an extra check for payments related to the transaction, because if a transaction has a payment on |
|
333 | - * it, it's probably not junk (regardless of what status it has). |
|
334 | - * The downside to this approach is that is addons are listening for object deletions |
|
335 | - * on EEM_Base::delete() they won't be notified of this. However, there is an action that plugins can hook into |
|
336 | - * to catch these types of deletions. |
|
337 | - * |
|
338 | - * @global WPDB $wpdb |
|
339 | - * @return mixed |
|
340 | - */ |
|
341 | - public function delete_junk_transactions() |
|
342 | - { |
|
343 | - /** @type WPDB $wpdb */ |
|
344 | - global $wpdb; |
|
345 | - $deleted = false; |
|
346 | - $time_to_leave_alone = apply_filters( |
|
347 | - 'FHEE__EEM_Transaction__delete_junk_transactions__time_to_leave_alone', |
|
348 | - WEEK_IN_SECONDS |
|
349 | - ); |
|
350 | - |
|
351 | - |
|
352 | - /** |
|
353 | - * This allows code to filter the query arguments used for retrieving the transaction IDs to delete. |
|
354 | - * Useful for plugins that want to exclude transactions matching certain query parameters. |
|
355 | - * The query parameters should be in the format accepted by the EEM_Base model queries. |
|
356 | - */ |
|
357 | - $ids_query = apply_filters( |
|
358 | - 'FHEE__EEM_Transaction__delete_junk_transactions__initial_query_args', |
|
359 | - array( |
|
360 | - 0 => array( |
|
361 | - 'STS_ID' => EEM_Transaction::failed_status_code, |
|
362 | - 'Payment.PAY_ID' => array( 'IS NULL' ), |
|
363 | - 'TXN_timestamp' => array('<', time() - $time_to_leave_alone) |
|
364 | - ), |
|
365 | - 'order_by' => ['TXN_timestamp' => 'DESC'], |
|
366 | - 'limit' => 1000 |
|
367 | - ), |
|
368 | - $time_to_leave_alone |
|
369 | - ); |
|
370 | - |
|
371 | - |
|
372 | - /** |
|
373 | - * This filter is for when code needs to filter the list of transaction ids that represent transactions |
|
374 | - * about to be deleted based on some other criteria that isn't easily done via the query args filter. |
|
375 | - */ |
|
376 | - $txn_ids = apply_filters( |
|
377 | - 'FHEE__EEM_Transaction__delete_junk_transactions__transaction_ids_to_delete', |
|
378 | - EEM_Transaction::instance()->get_col($ids_query, 'TXN_ID'), |
|
379 | - $time_to_leave_alone |
|
380 | - ); |
|
381 | - // now that we have the ids to delete |
|
382 | - if (! empty($txn_ids) && is_array($txn_ids)) { |
|
383 | - // first, make sure these TXN's are removed the "ee_locked_transactions" array |
|
384 | - EEM_Transaction::unset_locked_transactions($txn_ids); |
|
385 | - |
|
386 | - // Create IDs placeholder. |
|
387 | - $placeholders = array_fill(0, count($txn_ids), '%d'); |
|
270 | + OBJECT |
|
271 | + ); |
|
272 | + } |
|
273 | + |
|
274 | + |
|
275 | + /** |
|
276 | + * Gets the current transaction given the reg_url_link, or assumes the reg_url_link is in the |
|
277 | + * $_REQUEST global variable. Either way, tries to find the current transaction (through |
|
278 | + * the registration pointed to by reg_url_link), if not returns null |
|
279 | + * |
|
280 | + * @param string $reg_url_link |
|
281 | + * |
|
282 | + * @return EE_Transaction |
|
283 | + */ |
|
284 | + public function get_transaction_from_reg_url_link($reg_url_link = '') |
|
285 | + { |
|
286 | + return $this->get_one(array( |
|
287 | + array( |
|
288 | + 'Registration.REG_url_link' => ! empty($reg_url_link) ? $reg_url_link : EE_Registry::instance()->REQ->get( |
|
289 | + 'e_reg_url_link', |
|
290 | + '' |
|
291 | + ) |
|
292 | + ) |
|
293 | + )); |
|
294 | + } |
|
295 | + |
|
296 | + |
|
297 | + /** |
|
298 | + * Updates the provided EE_Transaction with all the applicable payments |
|
299 | + * (or fetch the EE_Transaction from its ID) |
|
300 | + * |
|
301 | + * @deprecated |
|
302 | + * |
|
303 | + * @param EE_Transaction|int $transaction_obj_or_id |
|
304 | + * @param boolean $save_txn whether or not to save the transaction during this function call |
|
305 | + * |
|
306 | + * @return boolean |
|
307 | + * @throws \EE_Error |
|
308 | + */ |
|
309 | + public function update_based_on_payments($transaction_obj_or_id, $save_txn = true) |
|
310 | + { |
|
311 | + EE_Error::doing_it_wrong( |
|
312 | + __CLASS__ . '::' . __FUNCTION__, |
|
313 | + sprintf( |
|
314 | + __('This method is deprecated. Please use "%s" instead', 'event_espresso'), |
|
315 | + 'EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()' |
|
316 | + ), |
|
317 | + '4.6.0' |
|
318 | + ); |
|
319 | + /** @type EE_Transaction_Processor $transaction_processor */ |
|
320 | + $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor'); |
|
321 | + |
|
322 | + return $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment( |
|
323 | + $this->ensure_is_obj($transaction_obj_or_id) |
|
324 | + ); |
|
325 | + } |
|
326 | + |
|
327 | + /** |
|
328 | + * Deletes "junk" transactions that were probably added by bots. There might be TONS |
|
329 | + * of these, so we are very careful to NOT select (which the models do even when deleting), |
|
330 | + * and so we only use wpdb directly and only do minimal joins. |
|
331 | + * Transactions are considered "junk" if they're failed for longer than a week. |
|
332 | + * Also, there is an extra check for payments related to the transaction, because if a transaction has a payment on |
|
333 | + * it, it's probably not junk (regardless of what status it has). |
|
334 | + * The downside to this approach is that is addons are listening for object deletions |
|
335 | + * on EEM_Base::delete() they won't be notified of this. However, there is an action that plugins can hook into |
|
336 | + * to catch these types of deletions. |
|
337 | + * |
|
338 | + * @global WPDB $wpdb |
|
339 | + * @return mixed |
|
340 | + */ |
|
341 | + public function delete_junk_transactions() |
|
342 | + { |
|
343 | + /** @type WPDB $wpdb */ |
|
344 | + global $wpdb; |
|
345 | + $deleted = false; |
|
346 | + $time_to_leave_alone = apply_filters( |
|
347 | + 'FHEE__EEM_Transaction__delete_junk_transactions__time_to_leave_alone', |
|
348 | + WEEK_IN_SECONDS |
|
349 | + ); |
|
350 | + |
|
351 | + |
|
352 | + /** |
|
353 | + * This allows code to filter the query arguments used for retrieving the transaction IDs to delete. |
|
354 | + * Useful for plugins that want to exclude transactions matching certain query parameters. |
|
355 | + * The query parameters should be in the format accepted by the EEM_Base model queries. |
|
356 | + */ |
|
357 | + $ids_query = apply_filters( |
|
358 | + 'FHEE__EEM_Transaction__delete_junk_transactions__initial_query_args', |
|
359 | + array( |
|
360 | + 0 => array( |
|
361 | + 'STS_ID' => EEM_Transaction::failed_status_code, |
|
362 | + 'Payment.PAY_ID' => array( 'IS NULL' ), |
|
363 | + 'TXN_timestamp' => array('<', time() - $time_to_leave_alone) |
|
364 | + ), |
|
365 | + 'order_by' => ['TXN_timestamp' => 'DESC'], |
|
366 | + 'limit' => 1000 |
|
367 | + ), |
|
368 | + $time_to_leave_alone |
|
369 | + ); |
|
370 | + |
|
371 | + |
|
372 | + /** |
|
373 | + * This filter is for when code needs to filter the list of transaction ids that represent transactions |
|
374 | + * about to be deleted based on some other criteria that isn't easily done via the query args filter. |
|
375 | + */ |
|
376 | + $txn_ids = apply_filters( |
|
377 | + 'FHEE__EEM_Transaction__delete_junk_transactions__transaction_ids_to_delete', |
|
378 | + EEM_Transaction::instance()->get_col($ids_query, 'TXN_ID'), |
|
379 | + $time_to_leave_alone |
|
380 | + ); |
|
381 | + // now that we have the ids to delete |
|
382 | + if (! empty($txn_ids) && is_array($txn_ids)) { |
|
383 | + // first, make sure these TXN's are removed the "ee_locked_transactions" array |
|
384 | + EEM_Transaction::unset_locked_transactions($txn_ids); |
|
385 | + |
|
386 | + // Create IDs placeholder. |
|
387 | + $placeholders = array_fill(0, count($txn_ids), '%d'); |
|
388 | 388 | |
389 | - // Glue it together to use inside $wpdb->prepare. |
|
390 | - $format = implode(', ', $placeholders); |
|
391 | - |
|
392 | - // let's get deletin'... |
|
393 | - // We got the ids from the original query to get them FROM |
|
394 | - // the db (which is sanitized) so no need to prepare them again. |
|
395 | - $query = $wpdb->prepare("DELETE FROM " . $this->table() . " WHERE TXN_ID IN ( $format )", $txn_ids); |
|
396 | - $deleted = $wpdb->query($query); |
|
397 | - } |
|
398 | - if ($deleted) { |
|
399 | - /** |
|
400 | - * Allows code to do something after the transactions have been deleted. |
|
401 | - */ |
|
402 | - do_action('AHEE__EEM_Transaction__delete_junk_transactions__successful_deletion', $txn_ids); |
|
403 | - } |
|
404 | - |
|
405 | - return $deleted; |
|
406 | - } |
|
407 | - |
|
408 | - |
|
409 | - /** |
|
410 | - * @param array $transaction_IDs |
|
411 | - * |
|
412 | - * @return bool |
|
413 | - */ |
|
414 | - public static function unset_locked_transactions(array $transaction_IDs) |
|
415 | - { |
|
416 | - $locked_transactions = get_option('ee_locked_transactions', array()); |
|
417 | - $update = false; |
|
418 | - foreach ($transaction_IDs as $TXN_ID) { |
|
419 | - if (isset($locked_transactions[ $TXN_ID ])) { |
|
420 | - unset($locked_transactions[ $TXN_ID ]); |
|
421 | - $update = true; |
|
422 | - } |
|
423 | - } |
|
424 | - if ($update) { |
|
425 | - update_option('ee_locked_transactions', $locked_transactions); |
|
426 | - } |
|
427 | - |
|
428 | - return $update; |
|
429 | - } |
|
430 | - |
|
431 | - |
|
432 | - |
|
433 | - /** |
|
434 | - * returns an array of EE_Transaction objects whose timestamp is greater than |
|
435 | - * the current time minus the session lifespan, which defaults to 60 minutes |
|
436 | - * |
|
437 | - * @return EE_Base_Class[]|EE_Transaction[] |
|
438 | - * @throws EE_Error |
|
439 | - * @throws InvalidArgumentException |
|
440 | - * @throws InvalidDataTypeException |
|
441 | - * @throws InvalidInterfaceException |
|
442 | - */ |
|
443 | - public function get_transactions_in_progress() |
|
444 | - { |
|
445 | - return $this->_get_transactions_in_progress(); |
|
446 | - } |
|
447 | - |
|
448 | - |
|
449 | - |
|
450 | - /** |
|
451 | - * returns an array of EE_Transaction objects whose timestamp is less than |
|
452 | - * the current time minus the session lifespan, which defaults to 60 minutes |
|
453 | - * |
|
454 | - * @return EE_Base_Class[]|EE_Transaction[] |
|
455 | - * @throws EE_Error |
|
456 | - * @throws InvalidArgumentException |
|
457 | - * @throws InvalidDataTypeException |
|
458 | - * @throws InvalidInterfaceException |
|
459 | - */ |
|
460 | - public function get_transactions_not_in_progress() |
|
461 | - { |
|
462 | - return $this->_get_transactions_in_progress('<='); |
|
463 | - } |
|
464 | - |
|
465 | - |
|
466 | - |
|
467 | - /** |
|
468 | - * @param string $comparison |
|
469 | - * @return EE_Base_Class[]|EE_Transaction[] |
|
470 | - * @throws EE_Error |
|
471 | - * @throws InvalidArgumentException |
|
472 | - * @throws InvalidDataTypeException |
|
473 | - * @throws InvalidInterfaceException |
|
474 | - */ |
|
475 | - private function _get_transactions_in_progress($comparison = '>=') |
|
476 | - { |
|
477 | - $comparison = $comparison === '>=' || $comparison === '<=' |
|
478 | - ? $comparison |
|
479 | - : '>='; |
|
480 | - /** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */ |
|
481 | - $session_lifespan = LoaderFactory::getLoader()->getShared( |
|
482 | - 'EventEspresso\core\domain\values\session\SessionLifespan' |
|
483 | - ); |
|
484 | - return $this->get_all( |
|
485 | - array( |
|
486 | - array( |
|
487 | - 'TXN_timestamp' => array( |
|
488 | - $comparison, |
|
489 | - $session_lifespan->expiration() |
|
490 | - ), |
|
491 | - 'STS_ID' => array( |
|
492 | - '!=', |
|
493 | - EEM_Transaction::complete_status_code |
|
494 | - ), |
|
495 | - ), |
|
496 | - 'order_by' => ['TXN_timestamp' => 'DESC'], |
|
497 | - 'limit' => apply_filters( |
|
498 | - 'FHEE__EEM_Transaction___get_transactions_in_progress__limit', |
|
499 | - 1000, |
|
500 | - $comparison |
|
501 | - ) |
|
502 | - ) |
|
503 | - ); |
|
504 | - } |
|
389 | + // Glue it together to use inside $wpdb->prepare. |
|
390 | + $format = implode(', ', $placeholders); |
|
391 | + |
|
392 | + // let's get deletin'... |
|
393 | + // We got the ids from the original query to get them FROM |
|
394 | + // the db (which is sanitized) so no need to prepare them again. |
|
395 | + $query = $wpdb->prepare("DELETE FROM " . $this->table() . " WHERE TXN_ID IN ( $format )", $txn_ids); |
|
396 | + $deleted = $wpdb->query($query); |
|
397 | + } |
|
398 | + if ($deleted) { |
|
399 | + /** |
|
400 | + * Allows code to do something after the transactions have been deleted. |
|
401 | + */ |
|
402 | + do_action('AHEE__EEM_Transaction__delete_junk_transactions__successful_deletion', $txn_ids); |
|
403 | + } |
|
404 | + |
|
405 | + return $deleted; |
|
406 | + } |
|
407 | + |
|
408 | + |
|
409 | + /** |
|
410 | + * @param array $transaction_IDs |
|
411 | + * |
|
412 | + * @return bool |
|
413 | + */ |
|
414 | + public static function unset_locked_transactions(array $transaction_IDs) |
|
415 | + { |
|
416 | + $locked_transactions = get_option('ee_locked_transactions', array()); |
|
417 | + $update = false; |
|
418 | + foreach ($transaction_IDs as $TXN_ID) { |
|
419 | + if (isset($locked_transactions[ $TXN_ID ])) { |
|
420 | + unset($locked_transactions[ $TXN_ID ]); |
|
421 | + $update = true; |
|
422 | + } |
|
423 | + } |
|
424 | + if ($update) { |
|
425 | + update_option('ee_locked_transactions', $locked_transactions); |
|
426 | + } |
|
427 | + |
|
428 | + return $update; |
|
429 | + } |
|
430 | + |
|
431 | + |
|
432 | + |
|
433 | + /** |
|
434 | + * returns an array of EE_Transaction objects whose timestamp is greater than |
|
435 | + * the current time minus the session lifespan, which defaults to 60 minutes |
|
436 | + * |
|
437 | + * @return EE_Base_Class[]|EE_Transaction[] |
|
438 | + * @throws EE_Error |
|
439 | + * @throws InvalidArgumentException |
|
440 | + * @throws InvalidDataTypeException |
|
441 | + * @throws InvalidInterfaceException |
|
442 | + */ |
|
443 | + public function get_transactions_in_progress() |
|
444 | + { |
|
445 | + return $this->_get_transactions_in_progress(); |
|
446 | + } |
|
447 | + |
|
448 | + |
|
449 | + |
|
450 | + /** |
|
451 | + * returns an array of EE_Transaction objects whose timestamp is less than |
|
452 | + * the current time minus the session lifespan, which defaults to 60 minutes |
|
453 | + * |
|
454 | + * @return EE_Base_Class[]|EE_Transaction[] |
|
455 | + * @throws EE_Error |
|
456 | + * @throws InvalidArgumentException |
|
457 | + * @throws InvalidDataTypeException |
|
458 | + * @throws InvalidInterfaceException |
|
459 | + */ |
|
460 | + public function get_transactions_not_in_progress() |
|
461 | + { |
|
462 | + return $this->_get_transactions_in_progress('<='); |
|
463 | + } |
|
464 | + |
|
465 | + |
|
466 | + |
|
467 | + /** |
|
468 | + * @param string $comparison |
|
469 | + * @return EE_Base_Class[]|EE_Transaction[] |
|
470 | + * @throws EE_Error |
|
471 | + * @throws InvalidArgumentException |
|
472 | + * @throws InvalidDataTypeException |
|
473 | + * @throws InvalidInterfaceException |
|
474 | + */ |
|
475 | + private function _get_transactions_in_progress($comparison = '>=') |
|
476 | + { |
|
477 | + $comparison = $comparison === '>=' || $comparison === '<=' |
|
478 | + ? $comparison |
|
479 | + : '>='; |
|
480 | + /** @var EventEspresso\core\domain\values\session\SessionLifespan $session_lifespan */ |
|
481 | + $session_lifespan = LoaderFactory::getLoader()->getShared( |
|
482 | + 'EventEspresso\core\domain\values\session\SessionLifespan' |
|
483 | + ); |
|
484 | + return $this->get_all( |
|
485 | + array( |
|
486 | + array( |
|
487 | + 'TXN_timestamp' => array( |
|
488 | + $comparison, |
|
489 | + $session_lifespan->expiration() |
|
490 | + ), |
|
491 | + 'STS_ID' => array( |
|
492 | + '!=', |
|
493 | + EEM_Transaction::complete_status_code |
|
494 | + ), |
|
495 | + ), |
|
496 | + 'order_by' => ['TXN_timestamp' => 'DESC'], |
|
497 | + 'limit' => apply_filters( |
|
498 | + 'FHEE__EEM_Transaction___get_transactions_in_progress__limit', |
|
499 | + 1000, |
|
500 | + $comparison |
|
501 | + ) |
|
502 | + ) |
|
503 | + ); |
|
504 | + } |
|
505 | 505 | } |
@@ -140,7 +140,7 @@ discard block |
||
140 | 140 | ), |
141 | 141 | ) |
142 | 142 | ); |
143 | - $this->_model_relations = array( |
|
143 | + $this->_model_relations = array( |
|
144 | 144 | 'Registration' => new EE_Has_Many_Relation(), |
145 | 145 | 'Payment' => new EE_Has_Many_Relation(), |
146 | 146 | 'Status' => new EE_Belongs_To_Relation(), |
@@ -205,7 +205,7 @@ discard block |
||
205 | 205 | ), |
206 | 206 | OBJECT, |
207 | 207 | array( |
208 | - 'txnDate' => array('DATE(' . $query_interval . ')', '%s'), |
|
208 | + 'txnDate' => array('DATE('.$query_interval.')', '%s'), |
|
209 | 209 | 'revenue' => array('SUM(TransactionTable.TXN_paid)', '%d') |
210 | 210 | ) |
211 | 211 | ); |
@@ -225,17 +225,17 @@ discard block |
||
225 | 225 | public function get_revenue_per_event_report($period = '-1 month') |
226 | 226 | { |
227 | 227 | global $wpdb; |
228 | - $transaction_table = $wpdb->prefix . 'esp_transaction'; |
|
229 | - $registration_table = $wpdb->prefix . 'esp_registration'; |
|
230 | - $registration_payment_table = $wpdb->prefix . 'esp_registration_payment'; |
|
228 | + $transaction_table = $wpdb->prefix.'esp_transaction'; |
|
229 | + $registration_table = $wpdb->prefix.'esp_registration'; |
|
230 | + $registration_payment_table = $wpdb->prefix.'esp_registration_payment'; |
|
231 | 231 | $event_table = $wpdb->posts; |
232 | - $payment_table = $wpdb->prefix . 'esp_payment'; |
|
232 | + $payment_table = $wpdb->prefix.'esp_payment'; |
|
233 | 233 | $sql_date = date('Y-m-d H:i:s', strtotime($period)); |
234 | 234 | $approved_payment_status = EEM_Payment::status_id_approved; |
235 | 235 | $extra_event_on_join = ''; |
236 | 236 | // exclude events not authored by user if permissions in effect |
237 | - if (! EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_event_report')) { |
|
238 | - $extra_event_on_join = ' AND Event.post_author = ' . get_current_user_id(); |
|
237 | + if ( ! EE_Registry::instance()->CAP->current_user_can('ee_read_others_registrations', 'reg_per_event_report')) { |
|
238 | + $extra_event_on_join = ' AND Event.post_author = '.get_current_user_id(); |
|
239 | 239 | } |
240 | 240 | |
241 | 241 | return $wpdb->get_results( |
@@ -309,7 +309,7 @@ discard block |
||
309 | 309 | public function update_based_on_payments($transaction_obj_or_id, $save_txn = true) |
310 | 310 | { |
311 | 311 | EE_Error::doing_it_wrong( |
312 | - __CLASS__ . '::' . __FUNCTION__, |
|
312 | + __CLASS__.'::'.__FUNCTION__, |
|
313 | 313 | sprintf( |
314 | 314 | __('This method is deprecated. Please use "%s" instead', 'event_espresso'), |
315 | 315 | 'EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()' |
@@ -359,7 +359,7 @@ discard block |
||
359 | 359 | array( |
360 | 360 | 0 => array( |
361 | 361 | 'STS_ID' => EEM_Transaction::failed_status_code, |
362 | - 'Payment.PAY_ID' => array( 'IS NULL' ), |
|
362 | + 'Payment.PAY_ID' => array('IS NULL'), |
|
363 | 363 | 'TXN_timestamp' => array('<', time() - $time_to_leave_alone) |
364 | 364 | ), |
365 | 365 | 'order_by' => ['TXN_timestamp' => 'DESC'], |
@@ -379,7 +379,7 @@ discard block |
||
379 | 379 | $time_to_leave_alone |
380 | 380 | ); |
381 | 381 | // now that we have the ids to delete |
382 | - if (! empty($txn_ids) && is_array($txn_ids)) { |
|
382 | + if ( ! empty($txn_ids) && is_array($txn_ids)) { |
|
383 | 383 | // first, make sure these TXN's are removed the "ee_locked_transactions" array |
384 | 384 | EEM_Transaction::unset_locked_transactions($txn_ids); |
385 | 385 | |
@@ -392,7 +392,7 @@ discard block |
||
392 | 392 | // let's get deletin'... |
393 | 393 | // We got the ids from the original query to get them FROM |
394 | 394 | // the db (which is sanitized) so no need to prepare them again. |
395 | - $query = $wpdb->prepare("DELETE FROM " . $this->table() . " WHERE TXN_ID IN ( $format )", $txn_ids); |
|
395 | + $query = $wpdb->prepare("DELETE FROM ".$this->table()." WHERE TXN_ID IN ( $format )", $txn_ids); |
|
396 | 396 | $deleted = $wpdb->query($query); |
397 | 397 | } |
398 | 398 | if ($deleted) { |
@@ -416,8 +416,8 @@ discard block |
||
416 | 416 | $locked_transactions = get_option('ee_locked_transactions', array()); |
417 | 417 | $update = false; |
418 | 418 | foreach ($transaction_IDs as $TXN_ID) { |
419 | - if (isset($locked_transactions[ $TXN_ID ])) { |
|
420 | - unset($locked_transactions[ $TXN_ID ]); |
|
419 | + if (isset($locked_transactions[$TXN_ID])) { |
|
420 | + unset($locked_transactions[$TXN_ID]); |
|
421 | 421 | $update = true; |
422 | 422 | } |
423 | 423 | } |
@@ -38,103 +38,103 @@ |
||
38 | 38 | * @since 4.0 |
39 | 39 | */ |
40 | 40 | if (function_exists('espresso_version')) { |
41 | - if (! function_exists('espresso_duplicate_plugin_error')) { |
|
42 | - /** |
|
43 | - * espresso_duplicate_plugin_error |
|
44 | - * displays if more than one version of EE is activated at the same time |
|
45 | - */ |
|
46 | - function espresso_duplicate_plugin_error() |
|
47 | - { |
|
48 | - ?> |
|
41 | + if (! function_exists('espresso_duplicate_plugin_error')) { |
|
42 | + /** |
|
43 | + * espresso_duplicate_plugin_error |
|
44 | + * displays if more than one version of EE is activated at the same time |
|
45 | + */ |
|
46 | + function espresso_duplicate_plugin_error() |
|
47 | + { |
|
48 | + ?> |
|
49 | 49 | <div class="error"> |
50 | 50 | <p> |
51 | 51 | <?php |
52 | - echo esc_html__( |
|
53 | - 'Can not run multiple versions of Event Espresso! One version has been automatically deactivated. Please verify that you have the correct version you want still active.', |
|
54 | - 'event_espresso' |
|
55 | - ); ?> |
|
52 | + echo esc_html__( |
|
53 | + 'Can not run multiple versions of Event Espresso! One version has been automatically deactivated. Please verify that you have the correct version you want still active.', |
|
54 | + 'event_espresso' |
|
55 | + ); ?> |
|
56 | 56 | </p> |
57 | 57 | </div> |
58 | 58 | <?php |
59 | - espresso_deactivate_plugin(plugin_basename(__FILE__)); |
|
60 | - } |
|
61 | - } |
|
62 | - add_action('admin_notices', 'espresso_duplicate_plugin_error', 1); |
|
59 | + espresso_deactivate_plugin(plugin_basename(__FILE__)); |
|
60 | + } |
|
61 | + } |
|
62 | + add_action('admin_notices', 'espresso_duplicate_plugin_error', 1); |
|
63 | 63 | } else { |
64 | - define('EE_MIN_PHP_VER_REQUIRED', '5.4.0'); |
|
65 | - if (! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) { |
|
66 | - /** |
|
67 | - * espresso_minimum_php_version_error |
|
68 | - * |
|
69 | - * @return void |
|
70 | - */ |
|
71 | - function espresso_minimum_php_version_error() |
|
72 | - { |
|
73 | - ?> |
|
64 | + define('EE_MIN_PHP_VER_REQUIRED', '5.4.0'); |
|
65 | + if (! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) { |
|
66 | + /** |
|
67 | + * espresso_minimum_php_version_error |
|
68 | + * |
|
69 | + * @return void |
|
70 | + */ |
|
71 | + function espresso_minimum_php_version_error() |
|
72 | + { |
|
73 | + ?> |
|
74 | 74 | <div class="error"> |
75 | 75 | <p> |
76 | 76 | <?php |
77 | - printf( |
|
78 | - esc_html__( |
|
79 | - 'We\'re sorry, but Event Espresso requires PHP version %1$s or greater in order to operate. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.', |
|
80 | - 'event_espresso' |
|
81 | - ), |
|
82 | - EE_MIN_PHP_VER_REQUIRED, |
|
83 | - PHP_VERSION, |
|
84 | - '<br/>', |
|
85 | - '<a href="http://php.net/downloads.php">http://php.net/downloads.php</a>' |
|
86 | - ); |
|
87 | - ?> |
|
77 | + printf( |
|
78 | + esc_html__( |
|
79 | + 'We\'re sorry, but Event Espresso requires PHP version %1$s or greater in order to operate. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.', |
|
80 | + 'event_espresso' |
|
81 | + ), |
|
82 | + EE_MIN_PHP_VER_REQUIRED, |
|
83 | + PHP_VERSION, |
|
84 | + '<br/>', |
|
85 | + '<a href="http://php.net/downloads.php">http://php.net/downloads.php</a>' |
|
86 | + ); |
|
87 | + ?> |
|
88 | 88 | </p> |
89 | 89 | </div> |
90 | 90 | <?php |
91 | - espresso_deactivate_plugin(plugin_basename(__FILE__)); |
|
92 | - } |
|
91 | + espresso_deactivate_plugin(plugin_basename(__FILE__)); |
|
92 | + } |
|
93 | 93 | |
94 | - add_action('admin_notices', 'espresso_minimum_php_version_error', 1); |
|
95 | - } else { |
|
96 | - define('EVENT_ESPRESSO_MAIN_FILE', __FILE__); |
|
97 | - /** |
|
98 | - * espresso_version |
|
99 | - * Returns the plugin version |
|
100 | - * |
|
101 | - * @return string |
|
102 | - */ |
|
103 | - function espresso_version() |
|
104 | - { |
|
105 | - return apply_filters('FHEE__espresso__espresso_version', '4.10.3.rc.003'); |
|
106 | - } |
|
94 | + add_action('admin_notices', 'espresso_minimum_php_version_error', 1); |
|
95 | + } else { |
|
96 | + define('EVENT_ESPRESSO_MAIN_FILE', __FILE__); |
|
97 | + /** |
|
98 | + * espresso_version |
|
99 | + * Returns the plugin version |
|
100 | + * |
|
101 | + * @return string |
|
102 | + */ |
|
103 | + function espresso_version() |
|
104 | + { |
|
105 | + return apply_filters('FHEE__espresso__espresso_version', '4.10.3.rc.003'); |
|
106 | + } |
|
107 | 107 | |
108 | - /** |
|
109 | - * espresso_plugin_activation |
|
110 | - * adds a wp-option to indicate that EE has been activated via the WP admin plugins page |
|
111 | - */ |
|
112 | - function espresso_plugin_activation() |
|
113 | - { |
|
114 | - update_option('ee_espresso_activation', true); |
|
115 | - } |
|
108 | + /** |
|
109 | + * espresso_plugin_activation |
|
110 | + * adds a wp-option to indicate that EE has been activated via the WP admin plugins page |
|
111 | + */ |
|
112 | + function espresso_plugin_activation() |
|
113 | + { |
|
114 | + update_option('ee_espresso_activation', true); |
|
115 | + } |
|
116 | 116 | |
117 | - register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation'); |
|
117 | + register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation'); |
|
118 | 118 | |
119 | - require_once __DIR__ . '/core/bootstrap_espresso.php'; |
|
120 | - bootstrap_espresso(); |
|
121 | - } |
|
119 | + require_once __DIR__ . '/core/bootstrap_espresso.php'; |
|
120 | + bootstrap_espresso(); |
|
121 | + } |
|
122 | 122 | } |
123 | 123 | if (! function_exists('espresso_deactivate_plugin')) { |
124 | - /** |
|
125 | - * deactivate_plugin |
|
126 | - * usage: espresso_deactivate_plugin( plugin_basename( __FILE__ )); |
|
127 | - * |
|
128 | - * @access public |
|
129 | - * @param string $plugin_basename - the results of plugin_basename( __FILE__ ) for the plugin's main file |
|
130 | - * @return void |
|
131 | - */ |
|
132 | - function espresso_deactivate_plugin($plugin_basename = '') |
|
133 | - { |
|
134 | - if (! function_exists('deactivate_plugins')) { |
|
135 | - require_once ABSPATH . 'wp-admin/includes/plugin.php'; |
|
136 | - } |
|
137 | - unset($_GET['activate'], $_REQUEST['activate']); |
|
138 | - deactivate_plugins($plugin_basename); |
|
139 | - } |
|
124 | + /** |
|
125 | + * deactivate_plugin |
|
126 | + * usage: espresso_deactivate_plugin( plugin_basename( __FILE__ )); |
|
127 | + * |
|
128 | + * @access public |
|
129 | + * @param string $plugin_basename - the results of plugin_basename( __FILE__ ) for the plugin's main file |
|
130 | + * @return void |
|
131 | + */ |
|
132 | + function espresso_deactivate_plugin($plugin_basename = '') |
|
133 | + { |
|
134 | + if (! function_exists('deactivate_plugins')) { |
|
135 | + require_once ABSPATH . 'wp-admin/includes/plugin.php'; |
|
136 | + } |
|
137 | + unset($_GET['activate'], $_REQUEST['activate']); |
|
138 | + deactivate_plugins($plugin_basename); |
|
139 | + } |
|
140 | 140 | } |