@@ -15,1800 +15,1800 @@ |
||
15 | 15 | class EED_Single_Page_Checkout extends EED_Module |
16 | 16 | { |
17 | 17 | |
18 | - /** |
|
19 | - * $_initialized - has the SPCO controller already been initialized ? |
|
20 | - * |
|
21 | - * @access private |
|
22 | - * @var bool $_initialized |
|
23 | - */ |
|
24 | - private static $_initialized = false; |
|
25 | - |
|
26 | - |
|
27 | - /** |
|
28 | - * $_checkout_verified - is the EE_Checkout verified as correct for this request ? |
|
29 | - * |
|
30 | - * @access private |
|
31 | - * @var bool $_valid_checkout |
|
32 | - */ |
|
33 | - private static $_checkout_verified = true; |
|
34 | - |
|
35 | - /** |
|
36 | - * $_reg_steps_array - holds initial array of reg steps |
|
37 | - * |
|
38 | - * @access private |
|
39 | - * @var array $_reg_steps_array |
|
40 | - */ |
|
41 | - private static $_reg_steps_array = array(); |
|
42 | - |
|
43 | - /** |
|
44 | - * $checkout - EE_Checkout object for handling the properties of the current checkout process |
|
45 | - * |
|
46 | - * @access public |
|
47 | - * @var EE_Checkout $checkout |
|
48 | - */ |
|
49 | - public $checkout; |
|
50 | - |
|
51 | - |
|
52 | - /** |
|
53 | - * @return EED_Module|EED_Single_Page_Checkout |
|
54 | - */ |
|
55 | - public static function instance() |
|
56 | - { |
|
57 | - add_filter('EED_Single_Page_Checkout__SPCO_active', '__return_true'); |
|
58 | - return parent::get_instance(__CLASS__); |
|
59 | - } |
|
60 | - |
|
61 | - |
|
62 | - /** |
|
63 | - * @return EE_CART |
|
64 | - */ |
|
65 | - public function cart() |
|
66 | - { |
|
67 | - return $this->checkout->cart; |
|
68 | - } |
|
69 | - |
|
70 | - |
|
71 | - /** |
|
72 | - * @return EE_Transaction |
|
73 | - */ |
|
74 | - public function transaction() |
|
75 | - { |
|
76 | - return $this->checkout->transaction; |
|
77 | - } |
|
78 | - |
|
79 | - |
|
80 | - /** |
|
81 | - * set_hooks - for hooking into EE Core, other modules, etc |
|
82 | - * |
|
83 | - * @access public |
|
84 | - * @return void |
|
85 | - * @throws EE_Error |
|
86 | - */ |
|
87 | - public static function set_hooks() |
|
88 | - { |
|
89 | - EED_Single_Page_Checkout::set_definitions(); |
|
90 | - } |
|
91 | - |
|
92 | - |
|
93 | - /** |
|
94 | - * set_hooks_admin - for hooking into EE Admin Core, other modules, etc |
|
95 | - * |
|
96 | - * @access public |
|
97 | - * @return void |
|
98 | - * @throws EE_Error |
|
99 | - */ |
|
100 | - public static function set_hooks_admin() |
|
101 | - { |
|
102 | - EED_Single_Page_Checkout::set_definitions(); |
|
103 | - if (! (defined('DOING_AJAX') && DOING_AJAX)) { |
|
104 | - return; |
|
105 | - } |
|
106 | - // going to start an output buffer in case anything gets accidentally output |
|
107 | - // that might disrupt our JSON response |
|
108 | - ob_start(); |
|
109 | - EED_Single_Page_Checkout::load_request_handler(); |
|
110 | - EED_Single_Page_Checkout::load_reg_steps(); |
|
111 | - // set ajax hooks |
|
112 | - add_action('wp_ajax_process_reg_step', array('EED_Single_Page_Checkout', 'process_reg_step')); |
|
113 | - add_action('wp_ajax_nopriv_process_reg_step', array('EED_Single_Page_Checkout', 'process_reg_step')); |
|
114 | - add_action('wp_ajax_display_spco_reg_step', array('EED_Single_Page_Checkout', 'display_reg_step')); |
|
115 | - add_action('wp_ajax_nopriv_display_spco_reg_step', array('EED_Single_Page_Checkout', 'display_reg_step')); |
|
116 | - add_action('wp_ajax_update_reg_step', array('EED_Single_Page_Checkout', 'update_reg_step')); |
|
117 | - add_action('wp_ajax_nopriv_update_reg_step', array('EED_Single_Page_Checkout', 'update_reg_step')); |
|
118 | - } |
|
119 | - |
|
120 | - |
|
121 | - /** |
|
122 | - * process ajax request |
|
123 | - * |
|
124 | - * @param string $ajax_action |
|
125 | - * @throws EE_Error |
|
126 | - */ |
|
127 | - public static function process_ajax_request($ajax_action) |
|
128 | - { |
|
129 | - EE_Registry::instance()->REQ->set('action', $ajax_action); |
|
130 | - EED_Single_Page_Checkout::instance()->_initialize(); |
|
131 | - } |
|
132 | - |
|
133 | - |
|
134 | - /** |
|
135 | - * ajax display registration step |
|
136 | - * |
|
137 | - * @throws EE_Error |
|
138 | - */ |
|
139 | - public static function display_reg_step() |
|
140 | - { |
|
141 | - EED_Single_Page_Checkout::process_ajax_request('display_spco_reg_step'); |
|
142 | - } |
|
143 | - |
|
144 | - |
|
145 | - /** |
|
146 | - * ajax process registration step |
|
147 | - * |
|
148 | - * @throws EE_Error |
|
149 | - */ |
|
150 | - public static function process_reg_step() |
|
151 | - { |
|
152 | - EED_Single_Page_Checkout::process_ajax_request('process_reg_step'); |
|
153 | - } |
|
154 | - |
|
155 | - |
|
156 | - /** |
|
157 | - * ajax process registration step |
|
158 | - * |
|
159 | - * @throws EE_Error |
|
160 | - */ |
|
161 | - public static function update_reg_step() |
|
162 | - { |
|
163 | - EED_Single_Page_Checkout::process_ajax_request('update_reg_step'); |
|
164 | - } |
|
165 | - |
|
166 | - |
|
167 | - /** |
|
168 | - * update_checkout |
|
169 | - * |
|
170 | - * @access public |
|
171 | - * @return void |
|
172 | - * @throws EE_Error |
|
173 | - */ |
|
174 | - public static function update_checkout() |
|
175 | - { |
|
176 | - EED_Single_Page_Checkout::process_ajax_request('update_checkout'); |
|
177 | - } |
|
178 | - |
|
179 | - |
|
180 | - /** |
|
181 | - * load_request_handler |
|
182 | - * |
|
183 | - * @access public |
|
184 | - * @return void |
|
185 | - */ |
|
186 | - public static function load_request_handler() |
|
187 | - { |
|
188 | - // load core Request_Handler class |
|
189 | - if (EE_Registry::instance()->REQ !== null) { |
|
190 | - EE_Registry::instance()->load_core('Request_Handler'); |
|
191 | - } |
|
192 | - } |
|
193 | - |
|
194 | - |
|
195 | - /** |
|
196 | - * set_definitions |
|
197 | - * |
|
198 | - * @access public |
|
199 | - * @return void |
|
200 | - * @throws EE_Error |
|
201 | - */ |
|
202 | - public static function set_definitions() |
|
203 | - { |
|
204 | - if (defined('SPCO_BASE_PATH')) { |
|
205 | - return; |
|
206 | - } |
|
207 | - define( |
|
208 | - 'SPCO_BASE_PATH', |
|
209 | - rtrim(str_replace(array('\\', '/'), DS, plugin_dir_path(__FILE__)), DS) . DS |
|
210 | - ); |
|
211 | - define('SPCO_CSS_URL', plugin_dir_url(__FILE__) . 'css' . DS); |
|
212 | - define('SPCO_IMG_URL', plugin_dir_url(__FILE__) . 'img' . DS); |
|
213 | - define('SPCO_JS_URL', plugin_dir_url(__FILE__) . 'js' . DS); |
|
214 | - define('SPCO_INC_PATH', SPCO_BASE_PATH . 'inc' . DS); |
|
215 | - define('SPCO_REG_STEPS_PATH', SPCO_BASE_PATH . 'reg_steps' . DS); |
|
216 | - define('SPCO_TEMPLATES_PATH', SPCO_BASE_PATH . 'templates' . DS); |
|
217 | - EEH_Autoloader::register_autoloaders_for_each_file_in_folder(SPCO_BASE_PATH, true); |
|
218 | - EE_Registry::$i18n_js_strings['registration_expiration_notice'] = EED_Single_Page_Checkout::getRegistrationExpirationNotice( |
|
219 | - ); |
|
220 | - } |
|
221 | - |
|
222 | - |
|
223 | - /** |
|
224 | - * load_reg_steps |
|
225 | - * loads and instantiates each reg step based on the EE_Registry::instance()->CFG->registration->reg_steps array |
|
226 | - * |
|
227 | - * @access private |
|
228 | - * @throws EE_Error |
|
229 | - */ |
|
230 | - public static function load_reg_steps() |
|
231 | - { |
|
232 | - static $reg_steps_loaded = false; |
|
233 | - if ($reg_steps_loaded) { |
|
234 | - return; |
|
235 | - } |
|
236 | - // filter list of reg_steps |
|
237 | - $reg_steps_to_load = (array) apply_filters( |
|
238 | - 'AHEE__SPCO__load_reg_steps__reg_steps_to_load', |
|
239 | - EED_Single_Page_Checkout::get_reg_steps() |
|
240 | - ); |
|
241 | - // sort by key (order) |
|
242 | - ksort($reg_steps_to_load); |
|
243 | - // loop through folders |
|
244 | - foreach ($reg_steps_to_load as $order => $reg_step) { |
|
245 | - // we need a |
|
246 | - if (isset($reg_step['file_path'], $reg_step['class_name'], $reg_step['slug'])) { |
|
247 | - // copy over to the reg_steps_array |
|
248 | - EED_Single_Page_Checkout::$_reg_steps_array[ $order ] = $reg_step; |
|
249 | - // register custom key route for each reg step |
|
250 | - // ie: step=>"slug" - this is the entire reason we load the reg steps array now |
|
251 | - EE_Config::register_route( |
|
252 | - $reg_step['slug'], |
|
253 | - 'EED_Single_Page_Checkout', |
|
254 | - 'run', |
|
255 | - 'step' |
|
256 | - ); |
|
257 | - // add AJAX or other hooks |
|
258 | - if (isset($reg_step['has_hooks']) && $reg_step['has_hooks']) { |
|
259 | - // setup autoloaders if necessary |
|
260 | - if (! class_exists($reg_step['class_name'])) { |
|
261 | - EEH_Autoloader::register_autoloaders_for_each_file_in_folder( |
|
262 | - $reg_step['file_path'], |
|
263 | - true |
|
264 | - ); |
|
265 | - } |
|
266 | - if (is_callable($reg_step['class_name'], 'set_hooks')) { |
|
267 | - call_user_func(array($reg_step['class_name'], 'set_hooks')); |
|
268 | - } |
|
269 | - } |
|
270 | - } |
|
271 | - } |
|
272 | - $reg_steps_loaded = true; |
|
273 | - } |
|
274 | - |
|
275 | - |
|
276 | - /** |
|
277 | - * get_reg_steps |
|
278 | - * |
|
279 | - * @access public |
|
280 | - * @return array |
|
281 | - */ |
|
282 | - public static function get_reg_steps() |
|
283 | - { |
|
284 | - $reg_steps = EE_Registry::instance()->CFG->registration->reg_steps; |
|
285 | - if (empty($reg_steps)) { |
|
286 | - $reg_steps = array( |
|
287 | - 10 => array( |
|
288 | - 'file_path' => SPCO_REG_STEPS_PATH . 'attendee_information', |
|
289 | - 'class_name' => 'EE_SPCO_Reg_Step_Attendee_Information', |
|
290 | - 'slug' => 'attendee_information', |
|
291 | - 'has_hooks' => false, |
|
292 | - ), |
|
293 | - 30 => array( |
|
294 | - 'file_path' => SPCO_REG_STEPS_PATH . 'payment_options', |
|
295 | - 'class_name' => 'EE_SPCO_Reg_Step_Payment_Options', |
|
296 | - 'slug' => 'payment_options', |
|
297 | - 'has_hooks' => true, |
|
298 | - ), |
|
299 | - 999 => array( |
|
300 | - 'file_path' => SPCO_REG_STEPS_PATH . 'finalize_registration', |
|
301 | - 'class_name' => 'EE_SPCO_Reg_Step_Finalize_Registration', |
|
302 | - 'slug' => 'finalize_registration', |
|
303 | - 'has_hooks' => false, |
|
304 | - ), |
|
305 | - ); |
|
306 | - } |
|
307 | - return $reg_steps; |
|
308 | - } |
|
309 | - |
|
310 | - |
|
311 | - /** |
|
312 | - * registration_checkout_for_admin |
|
313 | - * |
|
314 | - * @access public |
|
315 | - * @return string |
|
316 | - * @throws EE_Error |
|
317 | - */ |
|
318 | - public static function registration_checkout_for_admin() |
|
319 | - { |
|
320 | - EED_Single_Page_Checkout::load_request_handler(); |
|
321 | - EE_Registry::instance()->REQ->set('step', 'attendee_information'); |
|
322 | - EE_Registry::instance()->REQ->set('action', 'display_spco_reg_step'); |
|
323 | - EE_Registry::instance()->REQ->set('process_form_submission', false); |
|
324 | - EED_Single_Page_Checkout::instance()->_initialize(); |
|
325 | - EED_Single_Page_Checkout::instance()->_display_spco_reg_form(); |
|
326 | - return EE_Registry::instance()->REQ->get_output(); |
|
327 | - } |
|
328 | - |
|
329 | - |
|
330 | - /** |
|
331 | - * process_registration_from_admin |
|
332 | - * |
|
333 | - * @access public |
|
334 | - * @return \EE_Transaction |
|
335 | - * @throws EE_Error |
|
336 | - */ |
|
337 | - public static function process_registration_from_admin() |
|
338 | - { |
|
339 | - EED_Single_Page_Checkout::load_request_handler(); |
|
340 | - EE_Registry::instance()->REQ->set('step', 'attendee_information'); |
|
341 | - EE_Registry::instance()->REQ->set('action', 'process_reg_step'); |
|
342 | - EE_Registry::instance()->REQ->set('process_form_submission', true); |
|
343 | - EED_Single_Page_Checkout::instance()->_initialize(); |
|
344 | - if (EED_Single_Page_Checkout::instance()->checkout->current_step->completed()) { |
|
345 | - $final_reg_step = end(EED_Single_Page_Checkout::instance()->checkout->reg_steps); |
|
346 | - if ($final_reg_step instanceof EE_SPCO_Reg_Step_Finalize_Registration) { |
|
347 | - EED_Single_Page_Checkout::instance()->checkout->set_reg_step_initiated($final_reg_step); |
|
348 | - if ($final_reg_step->process_reg_step()) { |
|
349 | - $final_reg_step->set_completed(); |
|
350 | - EED_Single_Page_Checkout::instance()->checkout->update_txn_reg_steps_array(); |
|
351 | - return EED_Single_Page_Checkout::instance()->checkout->transaction; |
|
352 | - } |
|
353 | - } |
|
354 | - } |
|
355 | - return null; |
|
356 | - } |
|
357 | - |
|
358 | - |
|
359 | - /** |
|
360 | - * run |
|
361 | - * |
|
362 | - * @access public |
|
363 | - * @param WP_Query $WP_Query |
|
364 | - * @return void |
|
365 | - * @throws EE_Error |
|
366 | - */ |
|
367 | - public function run($WP_Query) |
|
368 | - { |
|
369 | - if ($WP_Query instanceof WP_Query |
|
370 | - && $WP_Query->is_main_query() |
|
371 | - && apply_filters('FHEE__EED_Single_Page_Checkout__run', true) |
|
372 | - && $this->_is_reg_checkout() |
|
373 | - ) { |
|
374 | - $this->_initialize(); |
|
375 | - } |
|
376 | - } |
|
377 | - |
|
378 | - |
|
379 | - /** |
|
380 | - * determines whether current url matches reg page url |
|
381 | - * |
|
382 | - * @return bool |
|
383 | - */ |
|
384 | - protected function _is_reg_checkout() |
|
385 | - { |
|
386 | - // get current permalink for reg page without any extra query args |
|
387 | - $reg_page_url = \get_permalink(EE_Config::instance()->core->reg_page_id); |
|
388 | - // get request URI for current request, but without the scheme or host |
|
389 | - $current_request_uri = \EEH_URL::filter_input_server_url('REQUEST_URI'); |
|
390 | - $current_request_uri = html_entity_decode($current_request_uri); |
|
391 | - // get array of query args from the current request URI |
|
392 | - $query_args = \EEH_URL::get_query_string($current_request_uri); |
|
393 | - // grab page id if it is set |
|
394 | - $page_id = isset($query_args['page_id']) ? absint($query_args['page_id']) : 0; |
|
395 | - // and remove the page id from the query args (we will re-add it later) |
|
396 | - unset($query_args['page_id']); |
|
397 | - // now strip all query args from current request URI |
|
398 | - $current_request_uri = remove_query_arg(array_keys($query_args), $current_request_uri); |
|
399 | - // and re-add the page id if it was set |
|
400 | - if ($page_id) { |
|
401 | - $current_request_uri = add_query_arg('page_id', $page_id, $current_request_uri); |
|
402 | - } |
|
403 | - // remove slashes and ? |
|
404 | - $current_request_uri = trim($current_request_uri, '?/'); |
|
405 | - // is current request URI part of the known full reg page URL ? |
|
406 | - return ! empty($current_request_uri) && strpos($reg_page_url, $current_request_uri) !== false; |
|
407 | - } |
|
408 | - |
|
409 | - |
|
410 | - /** |
|
411 | - * @param WP_Query $wp_query |
|
412 | - * @return void |
|
413 | - * @throws EE_Error |
|
414 | - */ |
|
415 | - public static function init($wp_query) |
|
416 | - { |
|
417 | - EED_Single_Page_Checkout::instance()->run($wp_query); |
|
418 | - } |
|
419 | - |
|
420 | - |
|
421 | - /** |
|
422 | - * _initialize - initial module setup |
|
423 | - * |
|
424 | - * @access private |
|
425 | - * @throws EE_Error |
|
426 | - * @return void |
|
427 | - */ |
|
428 | - private function _initialize() |
|
429 | - { |
|
430 | - // ensure SPCO doesn't run twice |
|
431 | - if (EED_Single_Page_Checkout::$_initialized) { |
|
432 | - return; |
|
433 | - } |
|
434 | - try { |
|
435 | - EED_Single_Page_Checkout::load_reg_steps(); |
|
436 | - $this->_verify_session(); |
|
437 | - // setup the EE_Checkout object |
|
438 | - $this->checkout = $this->_initialize_checkout(); |
|
439 | - // filter checkout |
|
440 | - $this->checkout = apply_filters('FHEE__EED_Single_Page_Checkout___initialize__checkout', $this->checkout); |
|
441 | - // get the $_GET |
|
442 | - $this->_get_request_vars(); |
|
443 | - if ($this->_block_bots()) { |
|
444 | - return; |
|
445 | - } |
|
446 | - // filter continue_reg |
|
447 | - $this->checkout->continue_reg = apply_filters( |
|
448 | - 'FHEE__EED_Single_Page_Checkout__init___continue_reg', |
|
449 | - true, |
|
450 | - $this->checkout |
|
451 | - ); |
|
452 | - // load the reg steps array |
|
453 | - if (! $this->_load_and_instantiate_reg_steps()) { |
|
454 | - EED_Single_Page_Checkout::$_initialized = true; |
|
455 | - return; |
|
456 | - } |
|
457 | - // set the current step |
|
458 | - $this->checkout->set_current_step($this->checkout->step); |
|
459 | - // and the next step |
|
460 | - $this->checkout->set_next_step(); |
|
461 | - // verify that everything has been setup correctly |
|
462 | - if (! ($this->_verify_transaction_and_get_registrations() && $this->_final_verifications())) { |
|
463 | - EED_Single_Page_Checkout::$_initialized = true; |
|
464 | - return; |
|
465 | - } |
|
466 | - // lock the transaction |
|
467 | - $this->checkout->transaction->lock(); |
|
468 | - // make sure all of our cached objects are added to their respective model entity mappers |
|
469 | - $this->checkout->refresh_all_entities(); |
|
470 | - // set amount owing |
|
471 | - $this->checkout->amount_owing = $this->checkout->transaction->remaining(); |
|
472 | - // initialize each reg step, which gives them the chance to potentially alter the process |
|
473 | - $this->_initialize_reg_steps(); |
|
474 | - // DEBUG LOG |
|
475 | - // $this->checkout->log( __CLASS__, __FUNCTION__, __LINE__ ); |
|
476 | - // get reg form |
|
477 | - if (! $this->_check_form_submission()) { |
|
478 | - EED_Single_Page_Checkout::$_initialized = true; |
|
479 | - return; |
|
480 | - } |
|
481 | - // checkout the action!!! |
|
482 | - $this->_process_form_action(); |
|
483 | - // add some style and make it dance |
|
484 | - $this->add_styles_and_scripts(); |
|
485 | - // kk... SPCO has successfully run |
|
486 | - EED_Single_Page_Checkout::$_initialized = true; |
|
487 | - // set no cache headers and constants |
|
488 | - EE_System::do_not_cache(); |
|
489 | - // add anchor |
|
490 | - add_action('loop_start', array($this, 'set_checkout_anchor'), 1); |
|
491 | - // remove transaction lock |
|
492 | - add_action('shutdown', array($this, 'unlock_transaction'), 1); |
|
493 | - } catch (Exception $e) { |
|
494 | - EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__); |
|
495 | - } |
|
496 | - } |
|
497 | - |
|
498 | - |
|
499 | - /** |
|
500 | - * _verify_session |
|
501 | - * checks that the session is valid and not expired |
|
502 | - * |
|
503 | - * @access private |
|
504 | - * @throws EE_Error |
|
505 | - */ |
|
506 | - private function _verify_session() |
|
507 | - { |
|
508 | - if (! EE_Registry::instance()->SSN instanceof EE_Session) { |
|
509 | - throw new EE_Error(esc_html__('The EE_Session class could not be loaded.', 'event_espresso')); |
|
510 | - } |
|
511 | - $clear_session_requested = filter_var( |
|
512 | - EE_Registry::instance()->REQ->get('clear_session', false), |
|
513 | - FILTER_VALIDATE_BOOLEAN |
|
514 | - ); |
|
515 | - // is session still valid ? |
|
516 | - if ($clear_session_requested |
|
517 | - || (EE_Registry::instance()->SSN->expired() |
|
518 | - && EE_Registry::instance()->REQ->get('e_reg_url_link', '') === '' |
|
519 | - ) |
|
520 | - ) { |
|
521 | - $this->checkout = new EE_Checkout(); |
|
522 | - EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__); |
|
523 | - // EE_Registry::instance()->SSN->reset_cart(); |
|
524 | - // EE_Registry::instance()->SSN->reset_checkout(); |
|
525 | - // EE_Registry::instance()->SSN->reset_transaction(); |
|
526 | - if (! $clear_session_requested) { |
|
527 | - EE_Error::add_attention( |
|
528 | - EE_Registry::$i18n_js_strings['registration_expiration_notice'], |
|
529 | - __FILE__, |
|
530 | - __FUNCTION__, |
|
531 | - __LINE__ |
|
532 | - ); |
|
533 | - } |
|
534 | - // EE_Registry::instance()->SSN->reset_expired(); |
|
535 | - } |
|
536 | - } |
|
537 | - |
|
538 | - |
|
539 | - /** |
|
540 | - * _initialize_checkout |
|
541 | - * loads and instantiates EE_Checkout |
|
542 | - * |
|
543 | - * @access private |
|
544 | - * @throws EE_Error |
|
545 | - * @return EE_Checkout |
|
546 | - */ |
|
547 | - private function _initialize_checkout() |
|
548 | - { |
|
549 | - // look in session for existing checkout |
|
550 | - /** @type EE_Checkout $checkout */ |
|
551 | - $checkout = EE_Registry::instance()->SSN->checkout(); |
|
552 | - // verify |
|
553 | - if (! $checkout instanceof EE_Checkout) { |
|
554 | - // instantiate EE_Checkout object for handling the properties of the current checkout process |
|
555 | - $checkout = EE_Registry::instance()->load_file( |
|
556 | - SPCO_INC_PATH, |
|
557 | - 'EE_Checkout', |
|
558 | - 'class', |
|
559 | - array(), |
|
560 | - false |
|
561 | - ); |
|
562 | - } else { |
|
563 | - if ($checkout->current_step->is_final_step() && $checkout->exit_spco() === true) { |
|
564 | - $this->unlock_transaction(); |
|
565 | - wp_safe_redirect($checkout->redirect_url); |
|
566 | - exit(); |
|
567 | - } |
|
568 | - } |
|
569 | - $checkout = apply_filters('FHEE__EED_Single_Page_Checkout___initialize_checkout__checkout', $checkout); |
|
570 | - // verify again |
|
571 | - if (! $checkout instanceof EE_Checkout) { |
|
572 | - throw new EE_Error(esc_html__('The EE_Checkout class could not be loaded.', 'event_espresso')); |
|
573 | - } |
|
574 | - // reset anything that needs a clean slate for each request |
|
575 | - $checkout->reset_for_current_request(); |
|
576 | - return $checkout; |
|
577 | - } |
|
578 | - |
|
579 | - |
|
580 | - /** |
|
581 | - * _get_request_vars |
|
582 | - * |
|
583 | - * @access private |
|
584 | - * @return void |
|
585 | - * @throws EE_Error |
|
586 | - */ |
|
587 | - private function _get_request_vars() |
|
588 | - { |
|
589 | - // load classes |
|
590 | - EED_Single_Page_Checkout::load_request_handler(); |
|
591 | - // make sure this request is marked as belonging to EE |
|
592 | - EE_Registry::instance()->REQ->set_espresso_page(true); |
|
593 | - // which step is being requested ? |
|
594 | - $this->checkout->step = EE_Registry::instance()->REQ->get('step', $this->_get_first_step()); |
|
595 | - // which step is being edited ? |
|
596 | - $this->checkout->edit_step = EE_Registry::instance()->REQ->get('edit_step', ''); |
|
597 | - // and what we're doing on the current step |
|
598 | - $this->checkout->action = EE_Registry::instance()->REQ->get('action', 'display_spco_reg_step'); |
|
599 | - // timestamp |
|
600 | - $this->checkout->uts = EE_Registry::instance()->REQ->get('uts', 0); |
|
601 | - // returning to edit ? |
|
602 | - $this->checkout->reg_url_link = EE_Registry::instance()->REQ->get('e_reg_url_link', ''); |
|
603 | - // add reg url link to registration query params |
|
604 | - if ($this->checkout->reg_url_link && strpos($this->checkout->reg_url_link, '1-') !== 0) { |
|
605 | - $this->checkout->reg_cache_where_params[0]['REG_url_link'] = $this->checkout->reg_url_link; |
|
606 | - } |
|
607 | - // or some other kind of revisit ? |
|
608 | - $this->checkout->revisit = filter_var( |
|
609 | - EE_Registry::instance()->REQ->get('revisit', false), |
|
610 | - FILTER_VALIDATE_BOOLEAN |
|
611 | - ); |
|
612 | - // and whether or not to generate a reg form for this request |
|
613 | - $this->checkout->generate_reg_form = filter_var( |
|
614 | - EE_Registry::instance()->REQ->get('generate_reg_form', true), |
|
615 | - FILTER_VALIDATE_BOOLEAN |
|
616 | - ); |
|
617 | - // and whether or not to process a reg form submission for this request |
|
618 | - $this->checkout->process_form_submission = filter_var( |
|
619 | - EE_Registry::instance()->REQ->get( |
|
620 | - 'process_form_submission', |
|
621 | - $this->checkout->action === 'process_reg_step' |
|
622 | - ), |
|
623 | - FILTER_VALIDATE_BOOLEAN |
|
624 | - ); |
|
625 | - $this->checkout->process_form_submission = filter_var( |
|
626 | - $this->checkout->action !== 'display_spco_reg_step' |
|
627 | - ? $this->checkout->process_form_submission |
|
628 | - : false, |
|
629 | - FILTER_VALIDATE_BOOLEAN |
|
630 | - ); |
|
631 | - // $this->_display_request_vars(); |
|
632 | - } |
|
633 | - |
|
634 | - |
|
635 | - /** |
|
636 | - * _display_request_vars |
|
637 | - * |
|
638 | - * @access protected |
|
639 | - * @return void |
|
640 | - */ |
|
641 | - protected function _display_request_vars() |
|
642 | - { |
|
643 | - if (! WP_DEBUG) { |
|
644 | - return; |
|
645 | - } |
|
646 | - EEH_Debug_Tools::printr($_REQUEST, '$_REQUEST', __FILE__, __LINE__); |
|
647 | - EEH_Debug_Tools::printr($this->checkout->step, '$this->checkout->step', __FILE__, __LINE__); |
|
648 | - EEH_Debug_Tools::printr($this->checkout->edit_step, '$this->checkout->edit_step', __FILE__, __LINE__); |
|
649 | - EEH_Debug_Tools::printr($this->checkout->action, '$this->checkout->action', __FILE__, __LINE__); |
|
650 | - EEH_Debug_Tools::printr($this->checkout->reg_url_link, '$this->checkout->reg_url_link', __FILE__, __LINE__); |
|
651 | - EEH_Debug_Tools::printr($this->checkout->revisit, '$this->checkout->revisit', __FILE__, __LINE__); |
|
652 | - EEH_Debug_Tools::printr( |
|
653 | - $this->checkout->generate_reg_form, |
|
654 | - '$this->checkout->generate_reg_form', |
|
655 | - __FILE__, |
|
656 | - __LINE__ |
|
657 | - ); |
|
658 | - EEH_Debug_Tools::printr( |
|
659 | - $this->checkout->process_form_submission, |
|
660 | - '$this->checkout->process_form_submission', |
|
661 | - __FILE__, |
|
662 | - __LINE__ |
|
663 | - ); |
|
664 | - } |
|
665 | - |
|
666 | - |
|
667 | - /** |
|
668 | - * _block_bots |
|
669 | - * checks that the incoming request has either of the following set: |
|
670 | - * a uts (unix timestamp) which indicates that the request was redirected from the Ticket Selector |
|
671 | - * a REG URL Link, which indicates that the request is a return visit to SPCO for a valid TXN |
|
672 | - * so if you're not coming from the Ticket Selector nor returning for a valid IP... |
|
673 | - * then where you coming from man? |
|
674 | - * |
|
675 | - * @return boolean |
|
676 | - */ |
|
677 | - private function _block_bots() |
|
678 | - { |
|
679 | - $invalid_checkout_access = EED_Invalid_Checkout_Access::getInvalidCheckoutAccess(); |
|
680 | - if ($invalid_checkout_access->checkoutAccessIsInvalid($this->checkout)) { |
|
681 | - return true; |
|
682 | - } |
|
683 | - return false; |
|
684 | - } |
|
685 | - |
|
686 | - |
|
687 | - /** |
|
688 | - * _get_first_step |
|
689 | - * gets slug for first step in $_reg_steps_array |
|
690 | - * |
|
691 | - * @access private |
|
692 | - * @throws EE_Error |
|
693 | - * @return string |
|
694 | - */ |
|
695 | - private function _get_first_step() |
|
696 | - { |
|
697 | - $first_step = reset(EED_Single_Page_Checkout::$_reg_steps_array); |
|
698 | - return isset($first_step['slug']) ? $first_step['slug'] : 'attendee_information'; |
|
699 | - } |
|
700 | - |
|
701 | - |
|
702 | - /** |
|
703 | - * instantiates each reg step based on the loaded reg_steps array |
|
704 | - * |
|
705 | - * @return bool |
|
706 | - * @throws EE_Error |
|
707 | - * @throws InvalidArgumentException |
|
708 | - * @throws InvalidDataTypeException |
|
709 | - * @throws InvalidInterfaceException |
|
710 | - */ |
|
711 | - private function _load_and_instantiate_reg_steps() |
|
712 | - { |
|
713 | - do_action('AHEE__Single_Page_Checkout___load_and_instantiate_reg_steps__start', $this->checkout); |
|
714 | - // have reg_steps already been instantiated ? |
|
715 | - if (empty($this->checkout->reg_steps) |
|
716 | - || apply_filters('FHEE__Single_Page_Checkout__load_reg_steps__reload_reg_steps', false, $this->checkout) |
|
717 | - ) { |
|
718 | - // if not, then loop through raw reg steps array |
|
719 | - foreach (EED_Single_Page_Checkout::$_reg_steps_array as $order => $reg_step) { |
|
720 | - if (! $this->_load_and_instantiate_reg_step($reg_step, $order)) { |
|
721 | - return false; |
|
722 | - } |
|
723 | - } |
|
724 | - if (isset($this->checkout->reg_steps['registration_confirmation'])) { |
|
725 | - // skip the registration_confirmation page ? |
|
726 | - if (EE_Registry::instance()->CFG->registration->skip_reg_confirmation) { |
|
727 | - // just remove it from the reg steps array |
|
728 | - $this->checkout->remove_reg_step('registration_confirmation', false); |
|
729 | - } elseif (EE_Registry::instance()->CFG->registration->reg_confirmation_last |
|
730 | - ) { |
|
731 | - // set the order to something big like 100 |
|
732 | - $this->checkout->set_reg_step_order('registration_confirmation', 100); |
|
733 | - } |
|
734 | - } |
|
735 | - // filter the array for good luck |
|
736 | - $this->checkout->reg_steps = apply_filters( |
|
737 | - 'FHEE__Single_Page_Checkout__load_reg_steps__reg_steps', |
|
738 | - $this->checkout->reg_steps |
|
739 | - ); |
|
740 | - // finally re-sort based on the reg step class order properties |
|
741 | - $this->checkout->sort_reg_steps(); |
|
742 | - } else { |
|
743 | - foreach ($this->checkout->reg_steps as $reg_step) { |
|
744 | - // set all current step stati to FALSE |
|
745 | - $reg_step->set_is_current_step(false); |
|
746 | - } |
|
747 | - } |
|
748 | - if (empty($this->checkout->reg_steps)) { |
|
749 | - EE_Error::add_error( |
|
750 | - esc_html__('No Reg Steps were loaded..', 'event_espresso'), |
|
751 | - __FILE__, |
|
752 | - __FUNCTION__, |
|
753 | - __LINE__ |
|
754 | - ); |
|
755 | - return false; |
|
756 | - } |
|
757 | - // make reg step details available to JS |
|
758 | - $this->checkout->set_reg_step_JSON_info(); |
|
759 | - return true; |
|
760 | - } |
|
761 | - |
|
762 | - |
|
763 | - /** |
|
764 | - * _load_and_instantiate_reg_step |
|
765 | - * |
|
766 | - * @access private |
|
767 | - * @param array $reg_step |
|
768 | - * @param int $order |
|
769 | - * @return bool |
|
770 | - */ |
|
771 | - private function _load_and_instantiate_reg_step($reg_step = array(), $order = 0) |
|
772 | - { |
|
773 | - // we need a file_path, class_name, and slug to add a reg step |
|
774 | - if (isset($reg_step['file_path'], $reg_step['class_name'], $reg_step['slug'])) { |
|
775 | - // if editing a specific step, but this is NOT that step... (and it's not the 'finalize_registration' step) |
|
776 | - if ($this->checkout->reg_url_link |
|
777 | - && $this->checkout->step !== $reg_step['slug'] |
|
778 | - && $reg_step['slug'] !== 'finalize_registration' |
|
779 | - // normally at this point we would NOT load the reg step, but this filter can change that |
|
780 | - && apply_filters( |
|
781 | - 'FHEE__Single_Page_Checkout___load_and_instantiate_reg_step__bypass_reg_step', |
|
782 | - true, |
|
783 | - $reg_step, |
|
784 | - $this->checkout |
|
785 | - ) |
|
786 | - ) { |
|
787 | - return true; |
|
788 | - } |
|
789 | - // instantiate step class using file path and class name |
|
790 | - $reg_step_obj = EE_Registry::instance()->load_file( |
|
791 | - $reg_step['file_path'], |
|
792 | - $reg_step['class_name'], |
|
793 | - 'class', |
|
794 | - $this->checkout, |
|
795 | - false |
|
796 | - ); |
|
797 | - // did we gets the goods ? |
|
798 | - if ($reg_step_obj instanceof EE_SPCO_Reg_Step) { |
|
799 | - // set reg step order based on config |
|
800 | - $reg_step_obj->set_order($order); |
|
801 | - // add instantiated reg step object to the master reg steps array |
|
802 | - $this->checkout->add_reg_step($reg_step_obj); |
|
803 | - } else { |
|
804 | - EE_Error::add_error( |
|
805 | - esc_html__('The current step could not be set.', 'event_espresso'), |
|
806 | - __FILE__, |
|
807 | - __FUNCTION__, |
|
808 | - __LINE__ |
|
809 | - ); |
|
810 | - return false; |
|
811 | - } |
|
812 | - } else { |
|
813 | - if (WP_DEBUG) { |
|
814 | - EE_Error::add_error( |
|
815 | - sprintf( |
|
816 | - esc_html__( |
|
817 | - 'A registration step could not be loaded. One or more of the following data points is invalid:%4$s%5$sFile Path: %1$s%6$s%5$sClass Name: %2$s%6$s%5$sSlug: %3$s%6$s%7$s', |
|
818 | - 'event_espresso' |
|
819 | - ), |
|
820 | - isset($reg_step['file_path']) ? $reg_step['file_path'] : '', |
|
821 | - isset($reg_step['class_name']) ? $reg_step['class_name'] : '', |
|
822 | - isset($reg_step['slug']) ? $reg_step['slug'] : '', |
|
823 | - '<ul>', |
|
824 | - '<li>', |
|
825 | - '</li>', |
|
826 | - '</ul>' |
|
827 | - ), |
|
828 | - __FILE__, |
|
829 | - __FUNCTION__, |
|
830 | - __LINE__ |
|
831 | - ); |
|
832 | - } |
|
833 | - return false; |
|
834 | - } |
|
835 | - return true; |
|
836 | - } |
|
837 | - |
|
838 | - |
|
839 | - /** |
|
840 | - * _verify_transaction_and_get_registrations |
|
841 | - * |
|
842 | - * @access private |
|
843 | - * @return bool |
|
844 | - * @throws InvalidDataTypeException |
|
845 | - * @throws InvalidEntityException |
|
846 | - * @throws EE_Error |
|
847 | - */ |
|
848 | - private function _verify_transaction_and_get_registrations() |
|
849 | - { |
|
850 | - // was there already a valid transaction in the checkout from the session ? |
|
851 | - if (! $this->checkout->transaction instanceof EE_Transaction) { |
|
852 | - // get transaction from db or session |
|
853 | - $this->checkout->transaction = $this->checkout->reg_url_link && ! is_admin() |
|
854 | - ? $this->_get_transaction_and_cart_for_previous_visit() |
|
855 | - : $this->_get_cart_for_current_session_and_setup_new_transaction(); |
|
856 | - if (! $this->checkout->transaction instanceof EE_Transaction) { |
|
857 | - EE_Error::add_error( |
|
858 | - esc_html__( |
|
859 | - 'Your Registration and Transaction information could not be retrieved from the db.', |
|
860 | - 'event_espresso' |
|
861 | - ), |
|
862 | - __FILE__, |
|
863 | - __FUNCTION__, |
|
864 | - __LINE__ |
|
865 | - ); |
|
866 | - $this->checkout->transaction = EE_Transaction::new_instance(); |
|
867 | - // add some style and make it dance |
|
868 | - $this->add_styles_and_scripts(); |
|
869 | - EED_Single_Page_Checkout::$_initialized = true; |
|
870 | - return false; |
|
871 | - } |
|
872 | - // and the registrations for the transaction |
|
873 | - $this->_get_registrations($this->checkout->transaction); |
|
874 | - } |
|
875 | - return true; |
|
876 | - } |
|
877 | - |
|
878 | - |
|
879 | - /** |
|
880 | - * _get_transaction_and_cart_for_previous_visit |
|
881 | - * |
|
882 | - * @access private |
|
883 | - * @return mixed EE_Transaction|NULL |
|
884 | - */ |
|
885 | - private function _get_transaction_and_cart_for_previous_visit() |
|
886 | - { |
|
887 | - /** @var $TXN_model EEM_Transaction */ |
|
888 | - $TXN_model = EE_Registry::instance()->load_model('Transaction'); |
|
889 | - // because the reg_url_link is present in the request, |
|
890 | - // this is a return visit to SPCO, so we'll get the transaction data from the db |
|
891 | - $transaction = $TXN_model->get_transaction_from_reg_url_link($this->checkout->reg_url_link); |
|
892 | - // verify transaction |
|
893 | - if ($transaction instanceof EE_Transaction) { |
|
894 | - // and get the cart that was used for that transaction |
|
895 | - $this->checkout->cart = $this->_get_cart_for_transaction($transaction); |
|
896 | - return $transaction; |
|
897 | - } |
|
898 | - EE_Error::add_error( |
|
899 | - esc_html__('Your Registration and Transaction information could not be retrieved from the db.', 'event_espresso'), |
|
900 | - __FILE__, |
|
901 | - __FUNCTION__, |
|
902 | - __LINE__ |
|
903 | - ); |
|
904 | - return null; |
|
905 | - } |
|
906 | - |
|
907 | - |
|
908 | - /** |
|
909 | - * _get_cart_for_transaction |
|
910 | - * |
|
911 | - * @access private |
|
912 | - * @param EE_Transaction $transaction |
|
913 | - * @return EE_Cart |
|
914 | - */ |
|
915 | - private function _get_cart_for_transaction($transaction) |
|
916 | - { |
|
917 | - return $this->checkout->get_cart_for_transaction($transaction); |
|
918 | - } |
|
919 | - |
|
920 | - |
|
921 | - /** |
|
922 | - * get_cart_for_transaction |
|
923 | - * |
|
924 | - * @access public |
|
925 | - * @param EE_Transaction $transaction |
|
926 | - * @return EE_Cart |
|
927 | - */ |
|
928 | - public function get_cart_for_transaction(EE_Transaction $transaction) |
|
929 | - { |
|
930 | - return $this->checkout->get_cart_for_transaction($transaction); |
|
931 | - } |
|
932 | - |
|
933 | - |
|
934 | - /** |
|
935 | - * _get_transaction_and_cart_for_current_session |
|
936 | - * generates a new EE_Transaction object and adds it to the $_transaction property. |
|
937 | - * |
|
938 | - * @access private |
|
939 | - * @return EE_Transaction |
|
940 | - * @throws EE_Error |
|
941 | - */ |
|
942 | - private function _get_cart_for_current_session_and_setup_new_transaction() |
|
943 | - { |
|
944 | - // if there's no transaction, then this is the FIRST visit to SPCO |
|
945 | - // so load up the cart ( passing nothing for the TXN because it doesn't exist yet ) |
|
946 | - $this->checkout->cart = $this->_get_cart_for_transaction(null); |
|
947 | - // and then create a new transaction |
|
948 | - $transaction = $this->_initialize_transaction(); |
|
949 | - // verify transaction |
|
950 | - if ($transaction instanceof EE_Transaction) { |
|
951 | - // save it so that we have an ID for other objects to use |
|
952 | - $transaction->save(); |
|
953 | - // and save TXN data to the cart |
|
954 | - $this->checkout->cart->get_grand_total()->save_this_and_descendants_to_txn($transaction->ID()); |
|
955 | - } else { |
|
956 | - EE_Error::add_error( |
|
957 | - esc_html__('A Valid Transaction could not be initialized.', 'event_espresso'), |
|
958 | - __FILE__, |
|
959 | - __FUNCTION__, |
|
960 | - __LINE__ |
|
961 | - ); |
|
962 | - } |
|
963 | - return $transaction; |
|
964 | - } |
|
965 | - |
|
966 | - |
|
967 | - /** |
|
968 | - * generates a new EE_Transaction object and adds it to the $_transaction property. |
|
969 | - * |
|
970 | - * @access private |
|
971 | - * @return mixed EE_Transaction|NULL |
|
972 | - */ |
|
973 | - private function _initialize_transaction() |
|
974 | - { |
|
975 | - try { |
|
976 | - // ensure cart totals have been calculated |
|
977 | - $this->checkout->cart->get_grand_total()->recalculate_total_including_taxes(); |
|
978 | - // grab the cart grand total |
|
979 | - $cart_total = $this->checkout->cart->get_cart_grand_total(); |
|
980 | - // create new TXN |
|
981 | - $transaction = EE_Transaction::new_instance( |
|
982 | - array( |
|
983 | - 'TXN_reg_steps' => $this->checkout->initialize_txn_reg_steps_array(), |
|
984 | - 'TXN_total' => $cart_total > 0 ? $cart_total : 0, |
|
985 | - 'TXN_paid' => 0, |
|
986 | - 'STS_ID' => EEM_Transaction::failed_status_code, |
|
987 | - ) |
|
988 | - ); |
|
989 | - // save it so that we have an ID for other objects to use |
|
990 | - $transaction->save(); |
|
991 | - // set cron job for following up on TXNs after their session has expired |
|
992 | - EE_Cron_Tasks::schedule_expired_transaction_check( |
|
993 | - EE_Registry::instance()->SSN->expiration() + 1, |
|
994 | - $transaction->ID() |
|
995 | - ); |
|
996 | - return $transaction; |
|
997 | - } catch (Exception $e) { |
|
998 | - EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__); |
|
999 | - } |
|
1000 | - return null; |
|
1001 | - } |
|
1002 | - |
|
1003 | - |
|
1004 | - /** |
|
1005 | - * _get_registrations |
|
1006 | - * |
|
1007 | - * @access private |
|
1008 | - * @param EE_Transaction $transaction |
|
1009 | - * @return void |
|
1010 | - * @throws InvalidDataTypeException |
|
1011 | - * @throws InvalidEntityException |
|
1012 | - * @throws EE_Error |
|
1013 | - */ |
|
1014 | - private function _get_registrations(EE_Transaction $transaction) |
|
1015 | - { |
|
1016 | - // first step: grab the registrants { : o |
|
1017 | - $registrations = $transaction->registrations($this->checkout->reg_cache_where_params, false); |
|
1018 | - $this->checkout->total_ticket_count = count($registrations); |
|
1019 | - // verify registrations have been set |
|
1020 | - if (empty($registrations)) { |
|
1021 | - // if no cached registrations, then check the db |
|
1022 | - $registrations = $transaction->registrations($this->checkout->reg_cache_where_params, false); |
|
1023 | - // still nothing ? well as long as this isn't a revisit |
|
1024 | - if (empty($registrations) && ! $this->checkout->revisit) { |
|
1025 | - // generate new registrations from scratch |
|
1026 | - $registrations = $this->_initialize_registrations($transaction); |
|
1027 | - } |
|
1028 | - } |
|
1029 | - // sort by their original registration order |
|
1030 | - usort($registrations, array('EED_Single_Page_Checkout', 'sort_registrations_by_REG_count')); |
|
1031 | - // then loop thru the array |
|
1032 | - foreach ($registrations as $registration) { |
|
1033 | - // verify each registration |
|
1034 | - if ($registration instanceof EE_Registration) { |
|
1035 | - // we display all attendee info for the primary registrant |
|
1036 | - if ($this->checkout->reg_url_link === $registration->reg_url_link() |
|
1037 | - && $registration->is_primary_registrant() |
|
1038 | - ) { |
|
1039 | - $this->checkout->primary_revisit = true; |
|
1040 | - break; |
|
1041 | - } |
|
1042 | - if ($this->checkout->revisit && $this->checkout->reg_url_link !== $registration->reg_url_link()) { |
|
1043 | - // but hide info if it doesn't belong to you |
|
1044 | - $transaction->clear_cache('Registration', $registration->ID()); |
|
1045 | - $this->checkout->total_ticket_count--; |
|
1046 | - } |
|
1047 | - $this->checkout->set_reg_status_updated($registration->ID(), false); |
|
1048 | - } |
|
1049 | - } |
|
1050 | - } |
|
1051 | - |
|
1052 | - |
|
1053 | - /** |
|
1054 | - * adds related EE_Registration objects for each ticket in the cart to the current EE_Transaction object |
|
1055 | - * |
|
1056 | - * @access private |
|
1057 | - * @param EE_Transaction $transaction |
|
1058 | - * @return array |
|
1059 | - * @throws InvalidDataTypeException |
|
1060 | - * @throws InvalidEntityException |
|
1061 | - * @throws EE_Error |
|
1062 | - */ |
|
1063 | - private function _initialize_registrations(EE_Transaction $transaction) |
|
1064 | - { |
|
1065 | - $att_nmbr = 0; |
|
1066 | - $registrations = array(); |
|
1067 | - if ($transaction instanceof EE_Transaction) { |
|
1068 | - /** @type EE_Registration_Processor $registration_processor */ |
|
1069 | - $registration_processor = EE_Registry::instance()->load_class('Registration_Processor'); |
|
1070 | - $this->checkout->total_ticket_count = $this->checkout->cart->all_ticket_quantity_count(); |
|
1071 | - // now let's add the cart items to the $transaction |
|
1072 | - foreach ($this->checkout->cart->get_tickets() as $line_item) { |
|
1073 | - // do the following for each ticket of this type they selected |
|
1074 | - for ($x = 1; $x <= $line_item->quantity(); $x++) { |
|
1075 | - $att_nmbr++; |
|
1076 | - /** @var EventEspresso\core\services\commands\registration\CreateRegistrationCommand $CreateRegistrationCommand */ |
|
1077 | - $CreateRegistrationCommand = EE_Registry::instance()->create( |
|
1078 | - 'EventEspresso\core\services\commands\registration\CreateRegistrationCommand', |
|
1079 | - array( |
|
1080 | - $transaction, |
|
1081 | - $line_item, |
|
1082 | - $att_nmbr, |
|
1083 | - $this->checkout->total_ticket_count, |
|
1084 | - ) |
|
1085 | - ); |
|
1086 | - // override capabilities for frontend registrations |
|
1087 | - if (! is_admin()) { |
|
1088 | - $CreateRegistrationCommand->setCapCheck( |
|
1089 | - new PublicCapabilities('', 'create_new_registration') |
|
1090 | - ); |
|
1091 | - } |
|
1092 | - $registration = EE_Registry::instance()->BUS->execute($CreateRegistrationCommand); |
|
1093 | - if (! $registration instanceof EE_Registration) { |
|
1094 | - throw new InvalidEntityException($registration, 'EE_Registration'); |
|
1095 | - } |
|
1096 | - $registrations[ $registration->ID() ] = $registration; |
|
1097 | - } |
|
1098 | - } |
|
1099 | - $registration_processor->fix_reg_final_price_rounding_issue($transaction); |
|
1100 | - } |
|
1101 | - return $registrations; |
|
1102 | - } |
|
1103 | - |
|
1104 | - |
|
1105 | - /** |
|
1106 | - * sorts registrations by REG_count |
|
1107 | - * |
|
1108 | - * @access public |
|
1109 | - * @param EE_Registration $reg_A |
|
1110 | - * @param EE_Registration $reg_B |
|
1111 | - * @return int |
|
1112 | - */ |
|
1113 | - public static function sort_registrations_by_REG_count(EE_Registration $reg_A, EE_Registration $reg_B) |
|
1114 | - { |
|
1115 | - // this shouldn't ever happen within the same TXN, but oh well |
|
1116 | - if ($reg_A->count() === $reg_B->count()) { |
|
1117 | - return 0; |
|
1118 | - } |
|
1119 | - return ($reg_A->count() > $reg_B->count()) ? 1 : -1; |
|
1120 | - } |
|
1121 | - |
|
1122 | - |
|
1123 | - /** |
|
1124 | - * _final_verifications |
|
1125 | - * just makes sure that everything is set up correctly before proceeding |
|
1126 | - * |
|
1127 | - * @access private |
|
1128 | - * @return bool |
|
1129 | - * @throws EE_Error |
|
1130 | - */ |
|
1131 | - private function _final_verifications() |
|
1132 | - { |
|
1133 | - // filter checkout |
|
1134 | - $this->checkout = apply_filters( |
|
1135 | - 'FHEE__EED_Single_Page_Checkout___final_verifications__checkout', |
|
1136 | - $this->checkout |
|
1137 | - ); |
|
1138 | - // verify that current step is still set correctly |
|
1139 | - if (! $this->checkout->current_step instanceof EE_SPCO_Reg_Step) { |
|
1140 | - EE_Error::add_error( |
|
1141 | - esc_html__( |
|
1142 | - 'We\'re sorry but the registration process can not proceed because one or more registration steps were not setup correctly. Please refresh the page and try again or contact support.', |
|
1143 | - 'event_espresso' |
|
1144 | - ), |
|
1145 | - __FILE__, |
|
1146 | - __FUNCTION__, |
|
1147 | - __LINE__ |
|
1148 | - ); |
|
1149 | - return false; |
|
1150 | - } |
|
1151 | - // if returning to SPCO, then verify that primary registrant is set |
|
1152 | - if (! empty($this->checkout->reg_url_link)) { |
|
1153 | - $valid_registrant = $this->checkout->transaction->primary_registration(); |
|
1154 | - if (! $valid_registrant instanceof EE_Registration) { |
|
1155 | - EE_Error::add_error( |
|
1156 | - esc_html__( |
|
1157 | - 'We\'re sorry but there appears to be an error with the "reg_url_link" or the primary registrant for this transaction. Please refresh the page and try again or contact support.', |
|
1158 | - 'event_espresso' |
|
1159 | - ), |
|
1160 | - __FILE__, |
|
1161 | - __FUNCTION__, |
|
1162 | - __LINE__ |
|
1163 | - ); |
|
1164 | - return false; |
|
1165 | - } |
|
1166 | - $valid_registrant = null; |
|
1167 | - foreach ($this->checkout->transaction->registrations($this->checkout->reg_cache_where_params) as $registration) { |
|
1168 | - if ($registration instanceof EE_Registration |
|
1169 | - && $registration->reg_url_link() === $this->checkout->reg_url_link |
|
1170 | - ) { |
|
1171 | - $valid_registrant = $registration; |
|
1172 | - } |
|
1173 | - } |
|
1174 | - if (! $valid_registrant instanceof EE_Registration) { |
|
1175 | - // hmmm... maybe we have the wrong session because the user is opening multiple tabs ? |
|
1176 | - if (EED_Single_Page_Checkout::$_checkout_verified) { |
|
1177 | - // clear the session, mark the checkout as unverified, and try again |
|
1178 | - EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__); |
|
1179 | - EED_Single_Page_Checkout::$_initialized = false; |
|
1180 | - EED_Single_Page_Checkout::$_checkout_verified = false; |
|
1181 | - $this->_initialize(); |
|
1182 | - EE_Error::reset_notices(); |
|
1183 | - return false; |
|
1184 | - } |
|
1185 | - EE_Error::add_error( |
|
1186 | - esc_html__( |
|
1187 | - 'We\'re sorry but there appears to be an error with the "reg_url_link" or the transaction itself. Please refresh the page and try again or contact support.', |
|
1188 | - 'event_espresso' |
|
1189 | - ), |
|
1190 | - __FILE__, |
|
1191 | - __FUNCTION__, |
|
1192 | - __LINE__ |
|
1193 | - ); |
|
1194 | - return false; |
|
1195 | - } |
|
1196 | - } |
|
1197 | - // now that things have been kinda sufficiently verified, |
|
1198 | - // let's add the checkout to the session so that it's available to other systems |
|
1199 | - EE_Registry::instance()->SSN->set_checkout($this->checkout); |
|
1200 | - return true; |
|
1201 | - } |
|
1202 | - |
|
1203 | - |
|
1204 | - /** |
|
1205 | - * _initialize_reg_steps |
|
1206 | - * first makes sure that EE_Transaction_Processor::set_reg_step_initiated() is called as required |
|
1207 | - * then loops thru all of the active reg steps and calls the initialize_reg_step() method |
|
1208 | - * |
|
1209 | - * @access private |
|
1210 | - * @param bool $reinitializing |
|
1211 | - * @throws EE_Error |
|
1212 | - */ |
|
1213 | - private function _initialize_reg_steps($reinitializing = false) |
|
1214 | - { |
|
1215 | - $this->checkout->set_reg_step_initiated($this->checkout->current_step); |
|
1216 | - // loop thru all steps to call their individual "initialize" methods and set i18n strings for JS |
|
1217 | - foreach ($this->checkout->reg_steps as $reg_step) { |
|
1218 | - if (! $reg_step->initialize_reg_step()) { |
|
1219 | - // if not initialized then maybe this step is being removed... |
|
1220 | - if (! $reinitializing && $reg_step->is_current_step()) { |
|
1221 | - // if it was the current step, then we need to start over here |
|
1222 | - $this->_initialize_reg_steps(true); |
|
1223 | - return; |
|
1224 | - } |
|
1225 | - continue; |
|
1226 | - } |
|
1227 | - // add css and JS for current step |
|
1228 | - $reg_step->enqueue_styles_and_scripts(); |
|
1229 | - // i18n |
|
1230 | - $reg_step->translate_js_strings(); |
|
1231 | - if ($reg_step->is_current_step()) { |
|
1232 | - // the text that appears on the reg step form submit button |
|
1233 | - $reg_step->set_submit_button_text(); |
|
1234 | - } |
|
1235 | - } |
|
1236 | - // dynamically creates hook point like: AHEE__Single_Page_Checkout___initialize_reg_step__attendee_information |
|
1237 | - do_action( |
|
1238 | - "AHEE__Single_Page_Checkout___initialize_reg_step__{$this->checkout->current_step->slug()}", |
|
1239 | - $this->checkout->current_step |
|
1240 | - ); |
|
1241 | - } |
|
1242 | - |
|
1243 | - |
|
1244 | - /** |
|
1245 | - * _check_form_submission |
|
1246 | - * |
|
1247 | - * @access private |
|
1248 | - * @return boolean |
|
1249 | - */ |
|
1250 | - private function _check_form_submission() |
|
1251 | - { |
|
1252 | - // does this request require the reg form to be generated ? |
|
1253 | - if ($this->checkout->generate_reg_form) { |
|
1254 | - // ever heard that song by Blue Rodeo ? |
|
1255 | - try { |
|
1256 | - $this->checkout->current_step->reg_form = $this->checkout->current_step->generate_reg_form(); |
|
1257 | - // if not displaying a form, then check for form submission |
|
1258 | - if ($this->checkout->process_form_submission |
|
1259 | - && $this->checkout->current_step->reg_form->was_submitted() |
|
1260 | - ) { |
|
1261 | - // clear out any old data in case this step is being run again |
|
1262 | - $this->checkout->current_step->set_valid_data(array()); |
|
1263 | - // capture submitted form data |
|
1264 | - $this->checkout->current_step->reg_form->receive_form_submission( |
|
1265 | - apply_filters( |
|
1266 | - 'FHEE__Single_Page_Checkout___check_form_submission__request_params', |
|
1267 | - EE_Registry::instance()->REQ->params(), |
|
1268 | - $this->checkout |
|
1269 | - ) |
|
1270 | - ); |
|
1271 | - // validate submitted form data |
|
1272 | - if (! $this->checkout->continue_reg || ! $this->checkout->current_step->reg_form->is_valid()) { |
|
1273 | - // thou shall not pass !!! |
|
1274 | - $this->checkout->continue_reg = false; |
|
1275 | - // any form validation errors? |
|
1276 | - if ($this->checkout->current_step->reg_form->submission_error_message() !== '') { |
|
1277 | - EE_Error::add_error( |
|
1278 | - $this->checkout->current_step->reg_form->submission_error_message(), |
|
1279 | - __FILE__, |
|
1280 | - __FUNCTION__, |
|
1281 | - __LINE__ |
|
1282 | - ); |
|
1283 | - } |
|
1284 | - // well not really... what will happen is |
|
1285 | - // we'll just get redirected back to redo the current step |
|
1286 | - $this->go_to_next_step(); |
|
1287 | - return false; |
|
1288 | - } |
|
1289 | - } |
|
1290 | - } catch (EE_Error $e) { |
|
1291 | - $e->get_error(); |
|
1292 | - } |
|
1293 | - } |
|
1294 | - return true; |
|
1295 | - } |
|
1296 | - |
|
1297 | - |
|
1298 | - /** |
|
1299 | - * _process_action |
|
1300 | - * |
|
1301 | - * @access private |
|
1302 | - * @return void |
|
1303 | - * @throws EE_Error |
|
1304 | - */ |
|
1305 | - private function _process_form_action() |
|
1306 | - { |
|
1307 | - // what cha wanna do? |
|
1308 | - switch ($this->checkout->action) { |
|
1309 | - // AJAX next step reg form |
|
1310 | - case 'display_spco_reg_step': |
|
1311 | - $this->checkout->redirect = false; |
|
1312 | - if (EE_Registry::instance()->REQ->ajax) { |
|
1313 | - $this->checkout->json_response->set_reg_step_html( |
|
1314 | - $this->checkout->current_step->display_reg_form() |
|
1315 | - ); |
|
1316 | - } |
|
1317 | - break; |
|
1318 | - default: |
|
1319 | - // meh... do one of those other steps first |
|
1320 | - if (! empty($this->checkout->action) |
|
1321 | - && is_callable(array($this->checkout->current_step, $this->checkout->action)) |
|
1322 | - ) { |
|
1323 | - // dynamically creates hook point like: |
|
1324 | - // AHEE__Single_Page_Checkout__before_attendee_information__process_reg_step |
|
1325 | - do_action( |
|
1326 | - "AHEE__Single_Page_Checkout__before_{$this->checkout->current_step->slug()}__{$this->checkout->action}", |
|
1327 | - $this->checkout->current_step |
|
1328 | - ); |
|
1329 | - // call action on current step |
|
1330 | - if (call_user_func(array($this->checkout->current_step, $this->checkout->action))) { |
|
1331 | - // good registrant, you get to proceed |
|
1332 | - if ($this->checkout->current_step->success_message() !== '' |
|
1333 | - && apply_filters( |
|
1334 | - 'FHEE__Single_Page_Checkout___process_form_action__display_success', |
|
1335 | - false |
|
1336 | - ) |
|
1337 | - ) { |
|
1338 | - EE_Error::add_success( |
|
1339 | - $this->checkout->current_step->success_message() |
|
1340 | - . '<br />' . $this->checkout->next_step->_instructions() |
|
1341 | - ); |
|
1342 | - } |
|
1343 | - // pack it up, pack it in... |
|
1344 | - $this->_setup_redirect(); |
|
1345 | - } |
|
1346 | - // dynamically creates hook point like: |
|
1347 | - // AHEE__Single_Page_Checkout__after_payment_options__process_reg_step |
|
1348 | - do_action( |
|
1349 | - "AHEE__Single_Page_Checkout__after_{$this->checkout->current_step->slug()}__{$this->checkout->action}", |
|
1350 | - $this->checkout->current_step |
|
1351 | - ); |
|
1352 | - } else { |
|
1353 | - EE_Error::add_error( |
|
1354 | - sprintf( |
|
1355 | - esc_html__( |
|
1356 | - 'The requested form action "%s" does not exist for the current "%s" registration step.', |
|
1357 | - 'event_espresso' |
|
1358 | - ), |
|
1359 | - $this->checkout->action, |
|
1360 | - $this->checkout->current_step->name() |
|
1361 | - ), |
|
1362 | - __FILE__, |
|
1363 | - __FUNCTION__, |
|
1364 | - __LINE__ |
|
1365 | - ); |
|
1366 | - } |
|
1367 | - // end default |
|
1368 | - } |
|
1369 | - // store our progress so far |
|
1370 | - $this->checkout->stash_transaction_and_checkout(); |
|
1371 | - // advance to the next step! If you pass GO, collect $200 |
|
1372 | - $this->go_to_next_step(); |
|
1373 | - } |
|
1374 | - |
|
1375 | - |
|
1376 | - /** |
|
1377 | - * add_styles_and_scripts |
|
1378 | - * |
|
1379 | - * @access public |
|
1380 | - * @return void |
|
1381 | - */ |
|
1382 | - public function add_styles_and_scripts() |
|
1383 | - { |
|
1384 | - // i18n |
|
1385 | - $this->translate_js_strings(); |
|
1386 | - if ($this->checkout->admin_request) { |
|
1387 | - add_action('admin_enqueue_scripts', array($this, 'enqueue_styles_and_scripts'), 10); |
|
1388 | - } else { |
|
1389 | - add_action('wp_enqueue_scripts', array($this, 'enqueue_styles_and_scripts'), 10); |
|
1390 | - } |
|
1391 | - } |
|
1392 | - |
|
1393 | - |
|
1394 | - /** |
|
1395 | - * translate_js_strings |
|
1396 | - * |
|
1397 | - * @access public |
|
1398 | - * @return void |
|
1399 | - */ |
|
1400 | - public function translate_js_strings() |
|
1401 | - { |
|
1402 | - EE_Registry::$i18n_js_strings['revisit'] = $this->checkout->revisit; |
|
1403 | - EE_Registry::$i18n_js_strings['e_reg_url_link'] = $this->checkout->reg_url_link; |
|
1404 | - EE_Registry::$i18n_js_strings['server_error'] = esc_html__( |
|
1405 | - 'An unknown error occurred on the server while attempting to process your request. Please refresh the page and try again or contact support.', |
|
1406 | - 'event_espresso' |
|
1407 | - ); |
|
1408 | - EE_Registry::$i18n_js_strings['invalid_json_response'] = esc_html__( |
|
1409 | - 'An invalid response was returned from the server while attempting to process your request. Please refresh the page and try again or contact support.', |
|
1410 | - 'event_espresso' |
|
1411 | - ); |
|
1412 | - EE_Registry::$i18n_js_strings['validation_error'] = esc_html__( |
|
1413 | - 'There appears to be a problem with the form validation configuration! Please check the admin settings or contact support.', |
|
1414 | - 'event_espresso' |
|
1415 | - ); |
|
1416 | - EE_Registry::$i18n_js_strings['invalid_payment_method'] = esc_html__( |
|
1417 | - 'There appears to be a problem with the payment method configuration! Please refresh the page and try again or contact support.', |
|
1418 | - 'event_espresso' |
|
1419 | - ); |
|
1420 | - EE_Registry::$i18n_js_strings['reg_step_error'] = esc_html__( |
|
1421 | - 'This registration step could not be completed. Please refresh the page and try again.', |
|
1422 | - 'event_espresso' |
|
1423 | - ); |
|
1424 | - EE_Registry::$i18n_js_strings['invalid_coupon'] = esc_html__( |
|
1425 | - 'We\'re sorry but that coupon code does not appear to be valid. If this is incorrect, please contact the site administrator.', |
|
1426 | - 'event_espresso' |
|
1427 | - ); |
|
1428 | - EE_Registry::$i18n_js_strings['process_registration'] = sprintf( |
|
1429 | - esc_html__( |
|
1430 | - 'Please wait while we process your registration.%sDo not refresh the page or navigate away while this is happening.%sThank you for your patience.', |
|
1431 | - 'event_espresso' |
|
1432 | - ), |
|
1433 | - '<br/>', |
|
1434 | - '<br/>' |
|
1435 | - ); |
|
1436 | - EE_Registry::$i18n_js_strings['language'] = get_bloginfo('language'); |
|
1437 | - EE_Registry::$i18n_js_strings['EESID'] = EE_Registry::instance()->SSN->id(); |
|
1438 | - EE_Registry::$i18n_js_strings['currency'] = EE_Registry::instance()->CFG->currency; |
|
1439 | - EE_Registry::$i18n_js_strings['datepicker_yearRange'] = '-150:+20'; |
|
1440 | - EE_Registry::$i18n_js_strings['timer_years'] = esc_html__('years', 'event_espresso'); |
|
1441 | - EE_Registry::$i18n_js_strings['timer_months'] = esc_html__('months', 'event_espresso'); |
|
1442 | - EE_Registry::$i18n_js_strings['timer_weeks'] = esc_html__('weeks', 'event_espresso'); |
|
1443 | - EE_Registry::$i18n_js_strings['timer_days'] = esc_html__('days', 'event_espresso'); |
|
1444 | - EE_Registry::$i18n_js_strings['timer_hours'] = esc_html__('hours', 'event_espresso'); |
|
1445 | - EE_Registry::$i18n_js_strings['timer_minutes'] = esc_html__('minutes', 'event_espresso'); |
|
1446 | - EE_Registry::$i18n_js_strings['timer_seconds'] = esc_html__('seconds', 'event_espresso'); |
|
1447 | - EE_Registry::$i18n_js_strings['timer_year'] = esc_html__('year', 'event_espresso'); |
|
1448 | - EE_Registry::$i18n_js_strings['timer_month'] = esc_html__('month', 'event_espresso'); |
|
1449 | - EE_Registry::$i18n_js_strings['timer_week'] = esc_html__('week', 'event_espresso'); |
|
1450 | - EE_Registry::$i18n_js_strings['timer_day'] = esc_html__('day', 'event_espresso'); |
|
1451 | - EE_Registry::$i18n_js_strings['timer_hour'] = esc_html__('hour', 'event_espresso'); |
|
1452 | - EE_Registry::$i18n_js_strings['timer_minute'] = esc_html__('minute', 'event_espresso'); |
|
1453 | - EE_Registry::$i18n_js_strings['timer_second'] = esc_html__('second', 'event_espresso'); |
|
1454 | - EE_Registry::$i18n_js_strings['registration_expiration_notice'] = EED_Single_Page_Checkout::getRegistrationExpirationNotice( |
|
1455 | - ); |
|
1456 | - EE_Registry::$i18n_js_strings['ajax_submit'] = apply_filters( |
|
1457 | - 'FHEE__Single_Page_Checkout__translate_js_strings__ajax_submit', |
|
1458 | - true |
|
1459 | - ); |
|
1460 | - EE_Registry::$i18n_js_strings['session_extension'] = absint( |
|
1461 | - apply_filters('FHEE__EE_Session__extend_expiration__seconds_added', 10 * MINUTE_IN_SECONDS) |
|
1462 | - ); |
|
1463 | - EE_Registry::$i18n_js_strings['session_expiration'] = gmdate( |
|
1464 | - 'M d, Y H:i:s', |
|
1465 | - EE_Registry::instance()->SSN->expiration() + (get_option('gmt_offset') * HOUR_IN_SECONDS) |
|
1466 | - ); |
|
1467 | - } |
|
1468 | - |
|
1469 | - |
|
1470 | - /** |
|
1471 | - * enqueue_styles_and_scripts |
|
1472 | - * |
|
1473 | - * @access public |
|
1474 | - * @return void |
|
1475 | - * @throws EE_Error |
|
1476 | - */ |
|
1477 | - public function enqueue_styles_and_scripts() |
|
1478 | - { |
|
1479 | - // load css |
|
1480 | - wp_register_style( |
|
1481 | - 'single_page_checkout', |
|
1482 | - SPCO_CSS_URL . 'single_page_checkout.css', |
|
1483 | - array('espresso_default'), |
|
1484 | - EVENT_ESPRESSO_VERSION |
|
1485 | - ); |
|
1486 | - wp_enqueue_style('single_page_checkout'); |
|
1487 | - // load JS |
|
1488 | - wp_register_script( |
|
1489 | - 'jquery_plugin', |
|
1490 | - EE_THIRD_PARTY_URL . 'jquery .plugin.min.js', |
|
1491 | - array('jquery'), |
|
1492 | - '1.0.1', |
|
1493 | - true |
|
1494 | - ); |
|
1495 | - wp_register_script( |
|
1496 | - 'jquery_countdown', |
|
1497 | - EE_THIRD_PARTY_URL . 'jquery .countdown.min.js', |
|
1498 | - array('jquery_plugin'), |
|
1499 | - '2.1.0', |
|
1500 | - true |
|
1501 | - ); |
|
1502 | - wp_register_script( |
|
1503 | - 'single_page_checkout', |
|
1504 | - SPCO_JS_URL . 'single_page_checkout.js', |
|
1505 | - array('espresso_core', 'underscore', 'ee_form_section_validation'), |
|
1506 | - EVENT_ESPRESSO_VERSION, |
|
1507 | - true |
|
1508 | - ); |
|
1509 | - if ($this->checkout->registration_form instanceof EE_Form_Section_Proper) { |
|
1510 | - $this->checkout->registration_form->enqueue_js(); |
|
1511 | - } |
|
1512 | - if ($this->checkout->current_step->reg_form instanceof EE_Form_Section_Proper) { |
|
1513 | - $this->checkout->current_step->reg_form->enqueue_js(); |
|
1514 | - } |
|
1515 | - wp_enqueue_script('single_page_checkout'); |
|
1516 | - if (apply_filters('FHEE__registration_page_wrapper_template__display_time_limit', false)) { |
|
1517 | - wp_enqueue_script('jquery_countdown'); |
|
1518 | - } |
|
1519 | - /** |
|
1520 | - * global action hook for enqueueing styles and scripts with |
|
1521 | - * spco calls. |
|
1522 | - */ |
|
1523 | - do_action('AHEE__EED_Single_Page_Checkout__enqueue_styles_and_scripts', $this); |
|
1524 | - /** |
|
1525 | - * dynamic action hook for enqueueing styles and scripts with spco calls. |
|
1526 | - * The hook will end up being something like: |
|
1527 | - * AHEE__EED_Single_Page_Checkout__enqueue_styles_and_scripts__attendee_information |
|
1528 | - */ |
|
1529 | - do_action( |
|
1530 | - 'AHEE__EED_Single_Page_Checkout__enqueue_styles_and_scripts__' . $this->checkout->current_step->slug(), |
|
1531 | - $this |
|
1532 | - ); |
|
1533 | - } |
|
1534 | - |
|
1535 | - |
|
1536 | - /** |
|
1537 | - * display the Registration Single Page Checkout Form |
|
1538 | - * |
|
1539 | - * @access private |
|
1540 | - * @return void |
|
1541 | - * @throws EE_Error |
|
1542 | - */ |
|
1543 | - private function _display_spco_reg_form() |
|
1544 | - { |
|
1545 | - // if registering via the admin, just display the reg form for the current step |
|
1546 | - if ($this->checkout->admin_request) { |
|
1547 | - EE_Registry::instance()->REQ->add_output($this->checkout->current_step->display_reg_form()); |
|
1548 | - } else { |
|
1549 | - // add powered by EE msg |
|
1550 | - add_action('AHEE__SPCO__reg_form_footer', array('EED_Single_Page_Checkout', 'display_registration_footer')); |
|
1551 | - $empty_cart = count($this->checkout->transaction |
|
1552 | - ->registrations($this->checkout->reg_cache_where_params)) < 1; |
|
1553 | - EE_Registry::$i18n_js_strings['empty_cart'] = $empty_cart; |
|
1554 | - $cookies_not_set_msg = ''; |
|
1555 | - if ($empty_cart) { |
|
1556 | - $cookies_not_set_msg = apply_filters( |
|
1557 | - 'FHEE__Single_Page_Checkout__display_spco_reg_form__cookies_not_set_msg', |
|
1558 | - sprintf( |
|
1559 | - esc_html__( |
|
1560 | - '%1$s%3$sIt appears your browser is not currently set to accept Cookies%4$s%5$sIn order to register for events, you need to enable cookies.%7$sIf you require assistance, then click the following link to learn how to %8$senable cookies%9$s%6$s%2$s', |
|
1561 | - 'event_espresso' |
|
1562 | - ), |
|
1563 | - '<div class="ee-attention hidden" id="ee-cookies-not-set-msg">', |
|
1564 | - '</div>', |
|
1565 | - '<h6 class="important-notice">', |
|
1566 | - '</h6>', |
|
1567 | - '<p>', |
|
1568 | - '</p>', |
|
1569 | - '<br />', |
|
1570 | - '<a href="http://www.whatarecookies.com/enable.asp" target="_blank" rel="noopener noreferrer">', |
|
1571 | - '</a>' |
|
1572 | - ) |
|
1573 | - ); |
|
1574 | - } |
|
1575 | - $this->checkout->registration_form = new EE_Form_Section_Proper( |
|
1576 | - array( |
|
1577 | - 'name' => 'single-page-checkout', |
|
1578 | - 'html_id' => 'ee-single-page-checkout-dv', |
|
1579 | - 'layout_strategy' => |
|
1580 | - new EE_Template_Layout( |
|
1581 | - array( |
|
1582 | - 'layout_template_file' => SPCO_TEMPLATES_PATH . 'registration_page_wrapper.template.php', |
|
1583 | - 'template_args' => array( |
|
1584 | - 'empty_cart' => $empty_cart, |
|
1585 | - 'revisit' => $this->checkout->revisit, |
|
1586 | - 'reg_steps' => $this->checkout->reg_steps, |
|
1587 | - 'next_step' => $this->checkout->next_step instanceof EE_SPCO_Reg_Step |
|
1588 | - ? $this->checkout->next_step->slug() |
|
1589 | - : '', |
|
1590 | - 'empty_msg' => apply_filters( |
|
1591 | - 'FHEE__Single_Page_Checkout__display_spco_reg_form__empty_msg', |
|
1592 | - sprintf( |
|
1593 | - esc_html__( |
|
1594 | - 'You need to %1$sReturn to Events list%2$sselect at least one event%3$s before you can proceed with the registration process.', |
|
1595 | - 'event_espresso' |
|
1596 | - ), |
|
1597 | - '<a href="' |
|
1598 | - . get_post_type_archive_link('espresso_events') |
|
1599 | - . '" title="', |
|
1600 | - '">', |
|
1601 | - '</a>' |
|
1602 | - ) |
|
1603 | - ), |
|
1604 | - 'cookies_not_set_msg' => $cookies_not_set_msg, |
|
1605 | - 'registration_time_limit' => $this->checkout->get_registration_time_limit(), |
|
1606 | - 'session_expiration' => gmdate( |
|
1607 | - 'M d, Y H:i:s', |
|
1608 | - EE_Registry::instance()->SSN->expiration() |
|
1609 | - + (get_option('gmt_offset') * HOUR_IN_SECONDS) |
|
1610 | - ), |
|
1611 | - ), |
|
1612 | - ) |
|
1613 | - ), |
|
1614 | - ) |
|
1615 | - ); |
|
1616 | - // load template and add to output sent that gets filtered into the_content() |
|
1617 | - EE_Registry::instance()->REQ->add_output($this->checkout->registration_form->get_html()); |
|
1618 | - } |
|
1619 | - } |
|
1620 | - |
|
1621 | - |
|
1622 | - /** |
|
1623 | - * add_extra_finalize_registration_inputs |
|
1624 | - * |
|
1625 | - * @access public |
|
1626 | - * @param $next_step |
|
1627 | - * @internal param string $label |
|
1628 | - * @return void |
|
1629 | - */ |
|
1630 | - public function add_extra_finalize_registration_inputs($next_step) |
|
1631 | - { |
|
1632 | - if ($next_step === 'finalize_registration') { |
|
1633 | - echo '<div id="spco-extra-finalize_registration-inputs-dv"></div>'; |
|
1634 | - } |
|
1635 | - } |
|
1636 | - |
|
1637 | - |
|
1638 | - /** |
|
1639 | - * display_registration_footer |
|
1640 | - * |
|
1641 | - * @access public |
|
1642 | - * @return string |
|
1643 | - */ |
|
1644 | - public static function display_registration_footer() |
|
1645 | - { |
|
1646 | - if (apply_filters( |
|
1647 | - 'FHEE__EE_Front__Controller__show_reg_footer', |
|
1648 | - EE_Registry::instance()->CFG->admin->show_reg_footer |
|
1649 | - )) { |
|
1650 | - add_filter( |
|
1651 | - 'FHEE__EEH_Template__powered_by_event_espresso__url', |
|
1652 | - function ($url) { |
|
1653 | - return apply_filters('FHEE__EE_Front_Controller__registration_footer__url', $url); |
|
1654 | - } |
|
1655 | - ); |
|
1656 | - echo apply_filters( |
|
1657 | - 'FHEE__EE_Front_Controller__display_registration_footer', |
|
1658 | - \EEH_Template::powered_by_event_espresso( |
|
1659 | - '', |
|
1660 | - 'espresso-registration-footer-dv', |
|
1661 | - array('utm_content' => 'registration_checkout') |
|
1662 | - ) |
|
1663 | - ); |
|
1664 | - } |
|
1665 | - return ''; |
|
1666 | - } |
|
1667 | - |
|
1668 | - |
|
1669 | - /** |
|
1670 | - * unlock_transaction |
|
1671 | - * |
|
1672 | - * @access public |
|
1673 | - * @return void |
|
1674 | - * @throws EE_Error |
|
1675 | - */ |
|
1676 | - public function unlock_transaction() |
|
1677 | - { |
|
1678 | - if ($this->checkout->transaction instanceof EE_Transaction) { |
|
1679 | - $this->checkout->transaction->unlock(); |
|
1680 | - } |
|
1681 | - } |
|
1682 | - |
|
1683 | - |
|
1684 | - /** |
|
1685 | - * _setup_redirect |
|
1686 | - * |
|
1687 | - * @access private |
|
1688 | - * @return void |
|
1689 | - */ |
|
1690 | - private function _setup_redirect() |
|
1691 | - { |
|
1692 | - if ($this->checkout->continue_reg && $this->checkout->next_step instanceof EE_SPCO_Reg_Step) { |
|
1693 | - $this->checkout->redirect = true; |
|
1694 | - if (empty($this->checkout->redirect_url)) { |
|
1695 | - $this->checkout->redirect_url = $this->checkout->next_step->reg_step_url(); |
|
1696 | - } |
|
1697 | - $this->checkout->redirect_url = apply_filters( |
|
1698 | - 'FHEE__EED_Single_Page_Checkout___setup_redirect__checkout_redirect_url', |
|
1699 | - $this->checkout->redirect_url, |
|
1700 | - $this->checkout |
|
1701 | - ); |
|
1702 | - } |
|
1703 | - } |
|
1704 | - |
|
1705 | - |
|
1706 | - /** |
|
1707 | - * handle ajax message responses and redirects |
|
1708 | - * |
|
1709 | - * @access public |
|
1710 | - * @return void |
|
1711 | - * @throws EE_Error |
|
1712 | - */ |
|
1713 | - public function go_to_next_step() |
|
1714 | - { |
|
1715 | - if (EE_Registry::instance()->REQ->ajax) { |
|
1716 | - // capture contents of output buffer we started earlier in the request, and insert into JSON response |
|
1717 | - $this->checkout->json_response->set_unexpected_errors(ob_get_clean()); |
|
1718 | - } |
|
1719 | - $this->unlock_transaction(); |
|
1720 | - // just return for these conditions |
|
1721 | - if ($this->checkout->admin_request |
|
1722 | - || $this->checkout->action === 'redirect_form' |
|
1723 | - || $this->checkout->action === 'update_checkout' |
|
1724 | - ) { |
|
1725 | - return; |
|
1726 | - } |
|
1727 | - // AJAX response |
|
1728 | - $this->_handle_json_response(); |
|
1729 | - // redirect to next step or the Thank You page |
|
1730 | - $this->_handle_html_redirects(); |
|
1731 | - // hmmm... must be something wrong, so let's just display the form again ! |
|
1732 | - $this->_display_spco_reg_form(); |
|
1733 | - } |
|
1734 | - |
|
1735 | - |
|
1736 | - /** |
|
1737 | - * _handle_json_response |
|
1738 | - * |
|
1739 | - * @access protected |
|
1740 | - * @return void |
|
1741 | - */ |
|
1742 | - protected function _handle_json_response() |
|
1743 | - { |
|
1744 | - // if this is an ajax request |
|
1745 | - if (EE_Registry::instance()->REQ->ajax) { |
|
1746 | - $this->checkout->json_response->set_registration_time_limit( |
|
1747 | - $this->checkout->get_registration_time_limit() |
|
1748 | - ); |
|
1749 | - $this->checkout->json_response->set_payment_amount($this->checkout->amount_owing); |
|
1750 | - // just send the ajax ( |
|
1751 | - $json_response = apply_filters( |
|
1752 | - 'FHEE__EE_Single_Page_Checkout__JSON_response', |
|
1753 | - $this->checkout->json_response |
|
1754 | - ); |
|
1755 | - echo $json_response; |
|
1756 | - exit(); |
|
1757 | - } |
|
1758 | - } |
|
1759 | - |
|
1760 | - |
|
1761 | - /** |
|
1762 | - * _handle_redirects |
|
1763 | - * |
|
1764 | - * @access protected |
|
1765 | - * @return void |
|
1766 | - */ |
|
1767 | - protected function _handle_html_redirects() |
|
1768 | - { |
|
1769 | - // going somewhere ? |
|
1770 | - if ($this->checkout->redirect && ! empty($this->checkout->redirect_url)) { |
|
1771 | - // store notices in a transient |
|
1772 | - EE_Error::get_notices(false, true, true); |
|
1773 | - wp_safe_redirect($this->checkout->redirect_url); |
|
1774 | - exit(); |
|
1775 | - } |
|
1776 | - } |
|
1777 | - |
|
1778 | - |
|
1779 | - /** |
|
1780 | - * set_checkout_anchor |
|
1781 | - * |
|
1782 | - * @access public |
|
1783 | - * @return void |
|
1784 | - */ |
|
1785 | - public function set_checkout_anchor() |
|
1786 | - { |
|
1787 | - echo '<a id="checkout" style="float: left; margin-left: -999em;"></a>'; |
|
1788 | - } |
|
1789 | - |
|
1790 | - /** |
|
1791 | - * getRegistrationExpirationNotice |
|
1792 | - * |
|
1793 | - * @since 4.9.59.p |
|
1794 | - * @access public |
|
1795 | - * @return string |
|
1796 | - */ |
|
1797 | - public static function getRegistrationExpirationNotice() |
|
1798 | - { |
|
1799 | - return sprintf( |
|
1800 | - esc_html__( |
|
1801 | - '%1$sWe\'re sorry, but your registration time has expired.%2$s%3$s%4$sIf you still wish to complete your registration, please return to the %5$sEvent List%6$sEvent List%7$s and reselect your tickets if available. Please accept our apologies for any inconvenience this may have caused.%8$s', |
|
1802 | - 'event_espresso' |
|
1803 | - ), |
|
1804 | - '<h4 class="important-notice">', |
|
1805 | - '</h4>', |
|
1806 | - '<br />', |
|
1807 | - '<p>', |
|
1808 | - '<a href="' . get_post_type_archive_link('espresso_events') . '" title="', |
|
1809 | - '">', |
|
1810 | - '</a>', |
|
1811 | - '</p>' |
|
1812 | - ); |
|
1813 | - } |
|
18 | + /** |
|
19 | + * $_initialized - has the SPCO controller already been initialized ? |
|
20 | + * |
|
21 | + * @access private |
|
22 | + * @var bool $_initialized |
|
23 | + */ |
|
24 | + private static $_initialized = false; |
|
25 | + |
|
26 | + |
|
27 | + /** |
|
28 | + * $_checkout_verified - is the EE_Checkout verified as correct for this request ? |
|
29 | + * |
|
30 | + * @access private |
|
31 | + * @var bool $_valid_checkout |
|
32 | + */ |
|
33 | + private static $_checkout_verified = true; |
|
34 | + |
|
35 | + /** |
|
36 | + * $_reg_steps_array - holds initial array of reg steps |
|
37 | + * |
|
38 | + * @access private |
|
39 | + * @var array $_reg_steps_array |
|
40 | + */ |
|
41 | + private static $_reg_steps_array = array(); |
|
42 | + |
|
43 | + /** |
|
44 | + * $checkout - EE_Checkout object for handling the properties of the current checkout process |
|
45 | + * |
|
46 | + * @access public |
|
47 | + * @var EE_Checkout $checkout |
|
48 | + */ |
|
49 | + public $checkout; |
|
50 | + |
|
51 | + |
|
52 | + /** |
|
53 | + * @return EED_Module|EED_Single_Page_Checkout |
|
54 | + */ |
|
55 | + public static function instance() |
|
56 | + { |
|
57 | + add_filter('EED_Single_Page_Checkout__SPCO_active', '__return_true'); |
|
58 | + return parent::get_instance(__CLASS__); |
|
59 | + } |
|
60 | + |
|
61 | + |
|
62 | + /** |
|
63 | + * @return EE_CART |
|
64 | + */ |
|
65 | + public function cart() |
|
66 | + { |
|
67 | + return $this->checkout->cart; |
|
68 | + } |
|
69 | + |
|
70 | + |
|
71 | + /** |
|
72 | + * @return EE_Transaction |
|
73 | + */ |
|
74 | + public function transaction() |
|
75 | + { |
|
76 | + return $this->checkout->transaction; |
|
77 | + } |
|
78 | + |
|
79 | + |
|
80 | + /** |
|
81 | + * set_hooks - for hooking into EE Core, other modules, etc |
|
82 | + * |
|
83 | + * @access public |
|
84 | + * @return void |
|
85 | + * @throws EE_Error |
|
86 | + */ |
|
87 | + public static function set_hooks() |
|
88 | + { |
|
89 | + EED_Single_Page_Checkout::set_definitions(); |
|
90 | + } |
|
91 | + |
|
92 | + |
|
93 | + /** |
|
94 | + * set_hooks_admin - for hooking into EE Admin Core, other modules, etc |
|
95 | + * |
|
96 | + * @access public |
|
97 | + * @return void |
|
98 | + * @throws EE_Error |
|
99 | + */ |
|
100 | + public static function set_hooks_admin() |
|
101 | + { |
|
102 | + EED_Single_Page_Checkout::set_definitions(); |
|
103 | + if (! (defined('DOING_AJAX') && DOING_AJAX)) { |
|
104 | + return; |
|
105 | + } |
|
106 | + // going to start an output buffer in case anything gets accidentally output |
|
107 | + // that might disrupt our JSON response |
|
108 | + ob_start(); |
|
109 | + EED_Single_Page_Checkout::load_request_handler(); |
|
110 | + EED_Single_Page_Checkout::load_reg_steps(); |
|
111 | + // set ajax hooks |
|
112 | + add_action('wp_ajax_process_reg_step', array('EED_Single_Page_Checkout', 'process_reg_step')); |
|
113 | + add_action('wp_ajax_nopriv_process_reg_step', array('EED_Single_Page_Checkout', 'process_reg_step')); |
|
114 | + add_action('wp_ajax_display_spco_reg_step', array('EED_Single_Page_Checkout', 'display_reg_step')); |
|
115 | + add_action('wp_ajax_nopriv_display_spco_reg_step', array('EED_Single_Page_Checkout', 'display_reg_step')); |
|
116 | + add_action('wp_ajax_update_reg_step', array('EED_Single_Page_Checkout', 'update_reg_step')); |
|
117 | + add_action('wp_ajax_nopriv_update_reg_step', array('EED_Single_Page_Checkout', 'update_reg_step')); |
|
118 | + } |
|
119 | + |
|
120 | + |
|
121 | + /** |
|
122 | + * process ajax request |
|
123 | + * |
|
124 | + * @param string $ajax_action |
|
125 | + * @throws EE_Error |
|
126 | + */ |
|
127 | + public static function process_ajax_request($ajax_action) |
|
128 | + { |
|
129 | + EE_Registry::instance()->REQ->set('action', $ajax_action); |
|
130 | + EED_Single_Page_Checkout::instance()->_initialize(); |
|
131 | + } |
|
132 | + |
|
133 | + |
|
134 | + /** |
|
135 | + * ajax display registration step |
|
136 | + * |
|
137 | + * @throws EE_Error |
|
138 | + */ |
|
139 | + public static function display_reg_step() |
|
140 | + { |
|
141 | + EED_Single_Page_Checkout::process_ajax_request('display_spco_reg_step'); |
|
142 | + } |
|
143 | + |
|
144 | + |
|
145 | + /** |
|
146 | + * ajax process registration step |
|
147 | + * |
|
148 | + * @throws EE_Error |
|
149 | + */ |
|
150 | + public static function process_reg_step() |
|
151 | + { |
|
152 | + EED_Single_Page_Checkout::process_ajax_request('process_reg_step'); |
|
153 | + } |
|
154 | + |
|
155 | + |
|
156 | + /** |
|
157 | + * ajax process registration step |
|
158 | + * |
|
159 | + * @throws EE_Error |
|
160 | + */ |
|
161 | + public static function update_reg_step() |
|
162 | + { |
|
163 | + EED_Single_Page_Checkout::process_ajax_request('update_reg_step'); |
|
164 | + } |
|
165 | + |
|
166 | + |
|
167 | + /** |
|
168 | + * update_checkout |
|
169 | + * |
|
170 | + * @access public |
|
171 | + * @return void |
|
172 | + * @throws EE_Error |
|
173 | + */ |
|
174 | + public static function update_checkout() |
|
175 | + { |
|
176 | + EED_Single_Page_Checkout::process_ajax_request('update_checkout'); |
|
177 | + } |
|
178 | + |
|
179 | + |
|
180 | + /** |
|
181 | + * load_request_handler |
|
182 | + * |
|
183 | + * @access public |
|
184 | + * @return void |
|
185 | + */ |
|
186 | + public static function load_request_handler() |
|
187 | + { |
|
188 | + // load core Request_Handler class |
|
189 | + if (EE_Registry::instance()->REQ !== null) { |
|
190 | + EE_Registry::instance()->load_core('Request_Handler'); |
|
191 | + } |
|
192 | + } |
|
193 | + |
|
194 | + |
|
195 | + /** |
|
196 | + * set_definitions |
|
197 | + * |
|
198 | + * @access public |
|
199 | + * @return void |
|
200 | + * @throws EE_Error |
|
201 | + */ |
|
202 | + public static function set_definitions() |
|
203 | + { |
|
204 | + if (defined('SPCO_BASE_PATH')) { |
|
205 | + return; |
|
206 | + } |
|
207 | + define( |
|
208 | + 'SPCO_BASE_PATH', |
|
209 | + rtrim(str_replace(array('\\', '/'), DS, plugin_dir_path(__FILE__)), DS) . DS |
|
210 | + ); |
|
211 | + define('SPCO_CSS_URL', plugin_dir_url(__FILE__) . 'css' . DS); |
|
212 | + define('SPCO_IMG_URL', plugin_dir_url(__FILE__) . 'img' . DS); |
|
213 | + define('SPCO_JS_URL', plugin_dir_url(__FILE__) . 'js' . DS); |
|
214 | + define('SPCO_INC_PATH', SPCO_BASE_PATH . 'inc' . DS); |
|
215 | + define('SPCO_REG_STEPS_PATH', SPCO_BASE_PATH . 'reg_steps' . DS); |
|
216 | + define('SPCO_TEMPLATES_PATH', SPCO_BASE_PATH . 'templates' . DS); |
|
217 | + EEH_Autoloader::register_autoloaders_for_each_file_in_folder(SPCO_BASE_PATH, true); |
|
218 | + EE_Registry::$i18n_js_strings['registration_expiration_notice'] = EED_Single_Page_Checkout::getRegistrationExpirationNotice( |
|
219 | + ); |
|
220 | + } |
|
221 | + |
|
222 | + |
|
223 | + /** |
|
224 | + * load_reg_steps |
|
225 | + * loads and instantiates each reg step based on the EE_Registry::instance()->CFG->registration->reg_steps array |
|
226 | + * |
|
227 | + * @access private |
|
228 | + * @throws EE_Error |
|
229 | + */ |
|
230 | + public static function load_reg_steps() |
|
231 | + { |
|
232 | + static $reg_steps_loaded = false; |
|
233 | + if ($reg_steps_loaded) { |
|
234 | + return; |
|
235 | + } |
|
236 | + // filter list of reg_steps |
|
237 | + $reg_steps_to_load = (array) apply_filters( |
|
238 | + 'AHEE__SPCO__load_reg_steps__reg_steps_to_load', |
|
239 | + EED_Single_Page_Checkout::get_reg_steps() |
|
240 | + ); |
|
241 | + // sort by key (order) |
|
242 | + ksort($reg_steps_to_load); |
|
243 | + // loop through folders |
|
244 | + foreach ($reg_steps_to_load as $order => $reg_step) { |
|
245 | + // we need a |
|
246 | + if (isset($reg_step['file_path'], $reg_step['class_name'], $reg_step['slug'])) { |
|
247 | + // copy over to the reg_steps_array |
|
248 | + EED_Single_Page_Checkout::$_reg_steps_array[ $order ] = $reg_step; |
|
249 | + // register custom key route for each reg step |
|
250 | + // ie: step=>"slug" - this is the entire reason we load the reg steps array now |
|
251 | + EE_Config::register_route( |
|
252 | + $reg_step['slug'], |
|
253 | + 'EED_Single_Page_Checkout', |
|
254 | + 'run', |
|
255 | + 'step' |
|
256 | + ); |
|
257 | + // add AJAX or other hooks |
|
258 | + if (isset($reg_step['has_hooks']) && $reg_step['has_hooks']) { |
|
259 | + // setup autoloaders if necessary |
|
260 | + if (! class_exists($reg_step['class_name'])) { |
|
261 | + EEH_Autoloader::register_autoloaders_for_each_file_in_folder( |
|
262 | + $reg_step['file_path'], |
|
263 | + true |
|
264 | + ); |
|
265 | + } |
|
266 | + if (is_callable($reg_step['class_name'], 'set_hooks')) { |
|
267 | + call_user_func(array($reg_step['class_name'], 'set_hooks')); |
|
268 | + } |
|
269 | + } |
|
270 | + } |
|
271 | + } |
|
272 | + $reg_steps_loaded = true; |
|
273 | + } |
|
274 | + |
|
275 | + |
|
276 | + /** |
|
277 | + * get_reg_steps |
|
278 | + * |
|
279 | + * @access public |
|
280 | + * @return array |
|
281 | + */ |
|
282 | + public static function get_reg_steps() |
|
283 | + { |
|
284 | + $reg_steps = EE_Registry::instance()->CFG->registration->reg_steps; |
|
285 | + if (empty($reg_steps)) { |
|
286 | + $reg_steps = array( |
|
287 | + 10 => array( |
|
288 | + 'file_path' => SPCO_REG_STEPS_PATH . 'attendee_information', |
|
289 | + 'class_name' => 'EE_SPCO_Reg_Step_Attendee_Information', |
|
290 | + 'slug' => 'attendee_information', |
|
291 | + 'has_hooks' => false, |
|
292 | + ), |
|
293 | + 30 => array( |
|
294 | + 'file_path' => SPCO_REG_STEPS_PATH . 'payment_options', |
|
295 | + 'class_name' => 'EE_SPCO_Reg_Step_Payment_Options', |
|
296 | + 'slug' => 'payment_options', |
|
297 | + 'has_hooks' => true, |
|
298 | + ), |
|
299 | + 999 => array( |
|
300 | + 'file_path' => SPCO_REG_STEPS_PATH . 'finalize_registration', |
|
301 | + 'class_name' => 'EE_SPCO_Reg_Step_Finalize_Registration', |
|
302 | + 'slug' => 'finalize_registration', |
|
303 | + 'has_hooks' => false, |
|
304 | + ), |
|
305 | + ); |
|
306 | + } |
|
307 | + return $reg_steps; |
|
308 | + } |
|
309 | + |
|
310 | + |
|
311 | + /** |
|
312 | + * registration_checkout_for_admin |
|
313 | + * |
|
314 | + * @access public |
|
315 | + * @return string |
|
316 | + * @throws EE_Error |
|
317 | + */ |
|
318 | + public static function registration_checkout_for_admin() |
|
319 | + { |
|
320 | + EED_Single_Page_Checkout::load_request_handler(); |
|
321 | + EE_Registry::instance()->REQ->set('step', 'attendee_information'); |
|
322 | + EE_Registry::instance()->REQ->set('action', 'display_spco_reg_step'); |
|
323 | + EE_Registry::instance()->REQ->set('process_form_submission', false); |
|
324 | + EED_Single_Page_Checkout::instance()->_initialize(); |
|
325 | + EED_Single_Page_Checkout::instance()->_display_spco_reg_form(); |
|
326 | + return EE_Registry::instance()->REQ->get_output(); |
|
327 | + } |
|
328 | + |
|
329 | + |
|
330 | + /** |
|
331 | + * process_registration_from_admin |
|
332 | + * |
|
333 | + * @access public |
|
334 | + * @return \EE_Transaction |
|
335 | + * @throws EE_Error |
|
336 | + */ |
|
337 | + public static function process_registration_from_admin() |
|
338 | + { |
|
339 | + EED_Single_Page_Checkout::load_request_handler(); |
|
340 | + EE_Registry::instance()->REQ->set('step', 'attendee_information'); |
|
341 | + EE_Registry::instance()->REQ->set('action', 'process_reg_step'); |
|
342 | + EE_Registry::instance()->REQ->set('process_form_submission', true); |
|
343 | + EED_Single_Page_Checkout::instance()->_initialize(); |
|
344 | + if (EED_Single_Page_Checkout::instance()->checkout->current_step->completed()) { |
|
345 | + $final_reg_step = end(EED_Single_Page_Checkout::instance()->checkout->reg_steps); |
|
346 | + if ($final_reg_step instanceof EE_SPCO_Reg_Step_Finalize_Registration) { |
|
347 | + EED_Single_Page_Checkout::instance()->checkout->set_reg_step_initiated($final_reg_step); |
|
348 | + if ($final_reg_step->process_reg_step()) { |
|
349 | + $final_reg_step->set_completed(); |
|
350 | + EED_Single_Page_Checkout::instance()->checkout->update_txn_reg_steps_array(); |
|
351 | + return EED_Single_Page_Checkout::instance()->checkout->transaction; |
|
352 | + } |
|
353 | + } |
|
354 | + } |
|
355 | + return null; |
|
356 | + } |
|
357 | + |
|
358 | + |
|
359 | + /** |
|
360 | + * run |
|
361 | + * |
|
362 | + * @access public |
|
363 | + * @param WP_Query $WP_Query |
|
364 | + * @return void |
|
365 | + * @throws EE_Error |
|
366 | + */ |
|
367 | + public function run($WP_Query) |
|
368 | + { |
|
369 | + if ($WP_Query instanceof WP_Query |
|
370 | + && $WP_Query->is_main_query() |
|
371 | + && apply_filters('FHEE__EED_Single_Page_Checkout__run', true) |
|
372 | + && $this->_is_reg_checkout() |
|
373 | + ) { |
|
374 | + $this->_initialize(); |
|
375 | + } |
|
376 | + } |
|
377 | + |
|
378 | + |
|
379 | + /** |
|
380 | + * determines whether current url matches reg page url |
|
381 | + * |
|
382 | + * @return bool |
|
383 | + */ |
|
384 | + protected function _is_reg_checkout() |
|
385 | + { |
|
386 | + // get current permalink for reg page without any extra query args |
|
387 | + $reg_page_url = \get_permalink(EE_Config::instance()->core->reg_page_id); |
|
388 | + // get request URI for current request, but without the scheme or host |
|
389 | + $current_request_uri = \EEH_URL::filter_input_server_url('REQUEST_URI'); |
|
390 | + $current_request_uri = html_entity_decode($current_request_uri); |
|
391 | + // get array of query args from the current request URI |
|
392 | + $query_args = \EEH_URL::get_query_string($current_request_uri); |
|
393 | + // grab page id if it is set |
|
394 | + $page_id = isset($query_args['page_id']) ? absint($query_args['page_id']) : 0; |
|
395 | + // and remove the page id from the query args (we will re-add it later) |
|
396 | + unset($query_args['page_id']); |
|
397 | + // now strip all query args from current request URI |
|
398 | + $current_request_uri = remove_query_arg(array_keys($query_args), $current_request_uri); |
|
399 | + // and re-add the page id if it was set |
|
400 | + if ($page_id) { |
|
401 | + $current_request_uri = add_query_arg('page_id', $page_id, $current_request_uri); |
|
402 | + } |
|
403 | + // remove slashes and ? |
|
404 | + $current_request_uri = trim($current_request_uri, '?/'); |
|
405 | + // is current request URI part of the known full reg page URL ? |
|
406 | + return ! empty($current_request_uri) && strpos($reg_page_url, $current_request_uri) !== false; |
|
407 | + } |
|
408 | + |
|
409 | + |
|
410 | + /** |
|
411 | + * @param WP_Query $wp_query |
|
412 | + * @return void |
|
413 | + * @throws EE_Error |
|
414 | + */ |
|
415 | + public static function init($wp_query) |
|
416 | + { |
|
417 | + EED_Single_Page_Checkout::instance()->run($wp_query); |
|
418 | + } |
|
419 | + |
|
420 | + |
|
421 | + /** |
|
422 | + * _initialize - initial module setup |
|
423 | + * |
|
424 | + * @access private |
|
425 | + * @throws EE_Error |
|
426 | + * @return void |
|
427 | + */ |
|
428 | + private function _initialize() |
|
429 | + { |
|
430 | + // ensure SPCO doesn't run twice |
|
431 | + if (EED_Single_Page_Checkout::$_initialized) { |
|
432 | + return; |
|
433 | + } |
|
434 | + try { |
|
435 | + EED_Single_Page_Checkout::load_reg_steps(); |
|
436 | + $this->_verify_session(); |
|
437 | + // setup the EE_Checkout object |
|
438 | + $this->checkout = $this->_initialize_checkout(); |
|
439 | + // filter checkout |
|
440 | + $this->checkout = apply_filters('FHEE__EED_Single_Page_Checkout___initialize__checkout', $this->checkout); |
|
441 | + // get the $_GET |
|
442 | + $this->_get_request_vars(); |
|
443 | + if ($this->_block_bots()) { |
|
444 | + return; |
|
445 | + } |
|
446 | + // filter continue_reg |
|
447 | + $this->checkout->continue_reg = apply_filters( |
|
448 | + 'FHEE__EED_Single_Page_Checkout__init___continue_reg', |
|
449 | + true, |
|
450 | + $this->checkout |
|
451 | + ); |
|
452 | + // load the reg steps array |
|
453 | + if (! $this->_load_and_instantiate_reg_steps()) { |
|
454 | + EED_Single_Page_Checkout::$_initialized = true; |
|
455 | + return; |
|
456 | + } |
|
457 | + // set the current step |
|
458 | + $this->checkout->set_current_step($this->checkout->step); |
|
459 | + // and the next step |
|
460 | + $this->checkout->set_next_step(); |
|
461 | + // verify that everything has been setup correctly |
|
462 | + if (! ($this->_verify_transaction_and_get_registrations() && $this->_final_verifications())) { |
|
463 | + EED_Single_Page_Checkout::$_initialized = true; |
|
464 | + return; |
|
465 | + } |
|
466 | + // lock the transaction |
|
467 | + $this->checkout->transaction->lock(); |
|
468 | + // make sure all of our cached objects are added to their respective model entity mappers |
|
469 | + $this->checkout->refresh_all_entities(); |
|
470 | + // set amount owing |
|
471 | + $this->checkout->amount_owing = $this->checkout->transaction->remaining(); |
|
472 | + // initialize each reg step, which gives them the chance to potentially alter the process |
|
473 | + $this->_initialize_reg_steps(); |
|
474 | + // DEBUG LOG |
|
475 | + // $this->checkout->log( __CLASS__, __FUNCTION__, __LINE__ ); |
|
476 | + // get reg form |
|
477 | + if (! $this->_check_form_submission()) { |
|
478 | + EED_Single_Page_Checkout::$_initialized = true; |
|
479 | + return; |
|
480 | + } |
|
481 | + // checkout the action!!! |
|
482 | + $this->_process_form_action(); |
|
483 | + // add some style and make it dance |
|
484 | + $this->add_styles_and_scripts(); |
|
485 | + // kk... SPCO has successfully run |
|
486 | + EED_Single_Page_Checkout::$_initialized = true; |
|
487 | + // set no cache headers and constants |
|
488 | + EE_System::do_not_cache(); |
|
489 | + // add anchor |
|
490 | + add_action('loop_start', array($this, 'set_checkout_anchor'), 1); |
|
491 | + // remove transaction lock |
|
492 | + add_action('shutdown', array($this, 'unlock_transaction'), 1); |
|
493 | + } catch (Exception $e) { |
|
494 | + EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__); |
|
495 | + } |
|
496 | + } |
|
497 | + |
|
498 | + |
|
499 | + /** |
|
500 | + * _verify_session |
|
501 | + * checks that the session is valid and not expired |
|
502 | + * |
|
503 | + * @access private |
|
504 | + * @throws EE_Error |
|
505 | + */ |
|
506 | + private function _verify_session() |
|
507 | + { |
|
508 | + if (! EE_Registry::instance()->SSN instanceof EE_Session) { |
|
509 | + throw new EE_Error(esc_html__('The EE_Session class could not be loaded.', 'event_espresso')); |
|
510 | + } |
|
511 | + $clear_session_requested = filter_var( |
|
512 | + EE_Registry::instance()->REQ->get('clear_session', false), |
|
513 | + FILTER_VALIDATE_BOOLEAN |
|
514 | + ); |
|
515 | + // is session still valid ? |
|
516 | + if ($clear_session_requested |
|
517 | + || (EE_Registry::instance()->SSN->expired() |
|
518 | + && EE_Registry::instance()->REQ->get('e_reg_url_link', '') === '' |
|
519 | + ) |
|
520 | + ) { |
|
521 | + $this->checkout = new EE_Checkout(); |
|
522 | + EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__); |
|
523 | + // EE_Registry::instance()->SSN->reset_cart(); |
|
524 | + // EE_Registry::instance()->SSN->reset_checkout(); |
|
525 | + // EE_Registry::instance()->SSN->reset_transaction(); |
|
526 | + if (! $clear_session_requested) { |
|
527 | + EE_Error::add_attention( |
|
528 | + EE_Registry::$i18n_js_strings['registration_expiration_notice'], |
|
529 | + __FILE__, |
|
530 | + __FUNCTION__, |
|
531 | + __LINE__ |
|
532 | + ); |
|
533 | + } |
|
534 | + // EE_Registry::instance()->SSN->reset_expired(); |
|
535 | + } |
|
536 | + } |
|
537 | + |
|
538 | + |
|
539 | + /** |
|
540 | + * _initialize_checkout |
|
541 | + * loads and instantiates EE_Checkout |
|
542 | + * |
|
543 | + * @access private |
|
544 | + * @throws EE_Error |
|
545 | + * @return EE_Checkout |
|
546 | + */ |
|
547 | + private function _initialize_checkout() |
|
548 | + { |
|
549 | + // look in session for existing checkout |
|
550 | + /** @type EE_Checkout $checkout */ |
|
551 | + $checkout = EE_Registry::instance()->SSN->checkout(); |
|
552 | + // verify |
|
553 | + if (! $checkout instanceof EE_Checkout) { |
|
554 | + // instantiate EE_Checkout object for handling the properties of the current checkout process |
|
555 | + $checkout = EE_Registry::instance()->load_file( |
|
556 | + SPCO_INC_PATH, |
|
557 | + 'EE_Checkout', |
|
558 | + 'class', |
|
559 | + array(), |
|
560 | + false |
|
561 | + ); |
|
562 | + } else { |
|
563 | + if ($checkout->current_step->is_final_step() && $checkout->exit_spco() === true) { |
|
564 | + $this->unlock_transaction(); |
|
565 | + wp_safe_redirect($checkout->redirect_url); |
|
566 | + exit(); |
|
567 | + } |
|
568 | + } |
|
569 | + $checkout = apply_filters('FHEE__EED_Single_Page_Checkout___initialize_checkout__checkout', $checkout); |
|
570 | + // verify again |
|
571 | + if (! $checkout instanceof EE_Checkout) { |
|
572 | + throw new EE_Error(esc_html__('The EE_Checkout class could not be loaded.', 'event_espresso')); |
|
573 | + } |
|
574 | + // reset anything that needs a clean slate for each request |
|
575 | + $checkout->reset_for_current_request(); |
|
576 | + return $checkout; |
|
577 | + } |
|
578 | + |
|
579 | + |
|
580 | + /** |
|
581 | + * _get_request_vars |
|
582 | + * |
|
583 | + * @access private |
|
584 | + * @return void |
|
585 | + * @throws EE_Error |
|
586 | + */ |
|
587 | + private function _get_request_vars() |
|
588 | + { |
|
589 | + // load classes |
|
590 | + EED_Single_Page_Checkout::load_request_handler(); |
|
591 | + // make sure this request is marked as belonging to EE |
|
592 | + EE_Registry::instance()->REQ->set_espresso_page(true); |
|
593 | + // which step is being requested ? |
|
594 | + $this->checkout->step = EE_Registry::instance()->REQ->get('step', $this->_get_first_step()); |
|
595 | + // which step is being edited ? |
|
596 | + $this->checkout->edit_step = EE_Registry::instance()->REQ->get('edit_step', ''); |
|
597 | + // and what we're doing on the current step |
|
598 | + $this->checkout->action = EE_Registry::instance()->REQ->get('action', 'display_spco_reg_step'); |
|
599 | + // timestamp |
|
600 | + $this->checkout->uts = EE_Registry::instance()->REQ->get('uts', 0); |
|
601 | + // returning to edit ? |
|
602 | + $this->checkout->reg_url_link = EE_Registry::instance()->REQ->get('e_reg_url_link', ''); |
|
603 | + // add reg url link to registration query params |
|
604 | + if ($this->checkout->reg_url_link && strpos($this->checkout->reg_url_link, '1-') !== 0) { |
|
605 | + $this->checkout->reg_cache_where_params[0]['REG_url_link'] = $this->checkout->reg_url_link; |
|
606 | + } |
|
607 | + // or some other kind of revisit ? |
|
608 | + $this->checkout->revisit = filter_var( |
|
609 | + EE_Registry::instance()->REQ->get('revisit', false), |
|
610 | + FILTER_VALIDATE_BOOLEAN |
|
611 | + ); |
|
612 | + // and whether or not to generate a reg form for this request |
|
613 | + $this->checkout->generate_reg_form = filter_var( |
|
614 | + EE_Registry::instance()->REQ->get('generate_reg_form', true), |
|
615 | + FILTER_VALIDATE_BOOLEAN |
|
616 | + ); |
|
617 | + // and whether or not to process a reg form submission for this request |
|
618 | + $this->checkout->process_form_submission = filter_var( |
|
619 | + EE_Registry::instance()->REQ->get( |
|
620 | + 'process_form_submission', |
|
621 | + $this->checkout->action === 'process_reg_step' |
|
622 | + ), |
|
623 | + FILTER_VALIDATE_BOOLEAN |
|
624 | + ); |
|
625 | + $this->checkout->process_form_submission = filter_var( |
|
626 | + $this->checkout->action !== 'display_spco_reg_step' |
|
627 | + ? $this->checkout->process_form_submission |
|
628 | + : false, |
|
629 | + FILTER_VALIDATE_BOOLEAN |
|
630 | + ); |
|
631 | + // $this->_display_request_vars(); |
|
632 | + } |
|
633 | + |
|
634 | + |
|
635 | + /** |
|
636 | + * _display_request_vars |
|
637 | + * |
|
638 | + * @access protected |
|
639 | + * @return void |
|
640 | + */ |
|
641 | + protected function _display_request_vars() |
|
642 | + { |
|
643 | + if (! WP_DEBUG) { |
|
644 | + return; |
|
645 | + } |
|
646 | + EEH_Debug_Tools::printr($_REQUEST, '$_REQUEST', __FILE__, __LINE__); |
|
647 | + EEH_Debug_Tools::printr($this->checkout->step, '$this->checkout->step', __FILE__, __LINE__); |
|
648 | + EEH_Debug_Tools::printr($this->checkout->edit_step, '$this->checkout->edit_step', __FILE__, __LINE__); |
|
649 | + EEH_Debug_Tools::printr($this->checkout->action, '$this->checkout->action', __FILE__, __LINE__); |
|
650 | + EEH_Debug_Tools::printr($this->checkout->reg_url_link, '$this->checkout->reg_url_link', __FILE__, __LINE__); |
|
651 | + EEH_Debug_Tools::printr($this->checkout->revisit, '$this->checkout->revisit', __FILE__, __LINE__); |
|
652 | + EEH_Debug_Tools::printr( |
|
653 | + $this->checkout->generate_reg_form, |
|
654 | + '$this->checkout->generate_reg_form', |
|
655 | + __FILE__, |
|
656 | + __LINE__ |
|
657 | + ); |
|
658 | + EEH_Debug_Tools::printr( |
|
659 | + $this->checkout->process_form_submission, |
|
660 | + '$this->checkout->process_form_submission', |
|
661 | + __FILE__, |
|
662 | + __LINE__ |
|
663 | + ); |
|
664 | + } |
|
665 | + |
|
666 | + |
|
667 | + /** |
|
668 | + * _block_bots |
|
669 | + * checks that the incoming request has either of the following set: |
|
670 | + * a uts (unix timestamp) which indicates that the request was redirected from the Ticket Selector |
|
671 | + * a REG URL Link, which indicates that the request is a return visit to SPCO for a valid TXN |
|
672 | + * so if you're not coming from the Ticket Selector nor returning for a valid IP... |
|
673 | + * then where you coming from man? |
|
674 | + * |
|
675 | + * @return boolean |
|
676 | + */ |
|
677 | + private function _block_bots() |
|
678 | + { |
|
679 | + $invalid_checkout_access = EED_Invalid_Checkout_Access::getInvalidCheckoutAccess(); |
|
680 | + if ($invalid_checkout_access->checkoutAccessIsInvalid($this->checkout)) { |
|
681 | + return true; |
|
682 | + } |
|
683 | + return false; |
|
684 | + } |
|
685 | + |
|
686 | + |
|
687 | + /** |
|
688 | + * _get_first_step |
|
689 | + * gets slug for first step in $_reg_steps_array |
|
690 | + * |
|
691 | + * @access private |
|
692 | + * @throws EE_Error |
|
693 | + * @return string |
|
694 | + */ |
|
695 | + private function _get_first_step() |
|
696 | + { |
|
697 | + $first_step = reset(EED_Single_Page_Checkout::$_reg_steps_array); |
|
698 | + return isset($first_step['slug']) ? $first_step['slug'] : 'attendee_information'; |
|
699 | + } |
|
700 | + |
|
701 | + |
|
702 | + /** |
|
703 | + * instantiates each reg step based on the loaded reg_steps array |
|
704 | + * |
|
705 | + * @return bool |
|
706 | + * @throws EE_Error |
|
707 | + * @throws InvalidArgumentException |
|
708 | + * @throws InvalidDataTypeException |
|
709 | + * @throws InvalidInterfaceException |
|
710 | + */ |
|
711 | + private function _load_and_instantiate_reg_steps() |
|
712 | + { |
|
713 | + do_action('AHEE__Single_Page_Checkout___load_and_instantiate_reg_steps__start', $this->checkout); |
|
714 | + // have reg_steps already been instantiated ? |
|
715 | + if (empty($this->checkout->reg_steps) |
|
716 | + || apply_filters('FHEE__Single_Page_Checkout__load_reg_steps__reload_reg_steps', false, $this->checkout) |
|
717 | + ) { |
|
718 | + // if not, then loop through raw reg steps array |
|
719 | + foreach (EED_Single_Page_Checkout::$_reg_steps_array as $order => $reg_step) { |
|
720 | + if (! $this->_load_and_instantiate_reg_step($reg_step, $order)) { |
|
721 | + return false; |
|
722 | + } |
|
723 | + } |
|
724 | + if (isset($this->checkout->reg_steps['registration_confirmation'])) { |
|
725 | + // skip the registration_confirmation page ? |
|
726 | + if (EE_Registry::instance()->CFG->registration->skip_reg_confirmation) { |
|
727 | + // just remove it from the reg steps array |
|
728 | + $this->checkout->remove_reg_step('registration_confirmation', false); |
|
729 | + } elseif (EE_Registry::instance()->CFG->registration->reg_confirmation_last |
|
730 | + ) { |
|
731 | + // set the order to something big like 100 |
|
732 | + $this->checkout->set_reg_step_order('registration_confirmation', 100); |
|
733 | + } |
|
734 | + } |
|
735 | + // filter the array for good luck |
|
736 | + $this->checkout->reg_steps = apply_filters( |
|
737 | + 'FHEE__Single_Page_Checkout__load_reg_steps__reg_steps', |
|
738 | + $this->checkout->reg_steps |
|
739 | + ); |
|
740 | + // finally re-sort based on the reg step class order properties |
|
741 | + $this->checkout->sort_reg_steps(); |
|
742 | + } else { |
|
743 | + foreach ($this->checkout->reg_steps as $reg_step) { |
|
744 | + // set all current step stati to FALSE |
|
745 | + $reg_step->set_is_current_step(false); |
|
746 | + } |
|
747 | + } |
|
748 | + if (empty($this->checkout->reg_steps)) { |
|
749 | + EE_Error::add_error( |
|
750 | + esc_html__('No Reg Steps were loaded..', 'event_espresso'), |
|
751 | + __FILE__, |
|
752 | + __FUNCTION__, |
|
753 | + __LINE__ |
|
754 | + ); |
|
755 | + return false; |
|
756 | + } |
|
757 | + // make reg step details available to JS |
|
758 | + $this->checkout->set_reg_step_JSON_info(); |
|
759 | + return true; |
|
760 | + } |
|
761 | + |
|
762 | + |
|
763 | + /** |
|
764 | + * _load_and_instantiate_reg_step |
|
765 | + * |
|
766 | + * @access private |
|
767 | + * @param array $reg_step |
|
768 | + * @param int $order |
|
769 | + * @return bool |
|
770 | + */ |
|
771 | + private function _load_and_instantiate_reg_step($reg_step = array(), $order = 0) |
|
772 | + { |
|
773 | + // we need a file_path, class_name, and slug to add a reg step |
|
774 | + if (isset($reg_step['file_path'], $reg_step['class_name'], $reg_step['slug'])) { |
|
775 | + // if editing a specific step, but this is NOT that step... (and it's not the 'finalize_registration' step) |
|
776 | + if ($this->checkout->reg_url_link |
|
777 | + && $this->checkout->step !== $reg_step['slug'] |
|
778 | + && $reg_step['slug'] !== 'finalize_registration' |
|
779 | + // normally at this point we would NOT load the reg step, but this filter can change that |
|
780 | + && apply_filters( |
|
781 | + 'FHEE__Single_Page_Checkout___load_and_instantiate_reg_step__bypass_reg_step', |
|
782 | + true, |
|
783 | + $reg_step, |
|
784 | + $this->checkout |
|
785 | + ) |
|
786 | + ) { |
|
787 | + return true; |
|
788 | + } |
|
789 | + // instantiate step class using file path and class name |
|
790 | + $reg_step_obj = EE_Registry::instance()->load_file( |
|
791 | + $reg_step['file_path'], |
|
792 | + $reg_step['class_name'], |
|
793 | + 'class', |
|
794 | + $this->checkout, |
|
795 | + false |
|
796 | + ); |
|
797 | + // did we gets the goods ? |
|
798 | + if ($reg_step_obj instanceof EE_SPCO_Reg_Step) { |
|
799 | + // set reg step order based on config |
|
800 | + $reg_step_obj->set_order($order); |
|
801 | + // add instantiated reg step object to the master reg steps array |
|
802 | + $this->checkout->add_reg_step($reg_step_obj); |
|
803 | + } else { |
|
804 | + EE_Error::add_error( |
|
805 | + esc_html__('The current step could not be set.', 'event_espresso'), |
|
806 | + __FILE__, |
|
807 | + __FUNCTION__, |
|
808 | + __LINE__ |
|
809 | + ); |
|
810 | + return false; |
|
811 | + } |
|
812 | + } else { |
|
813 | + if (WP_DEBUG) { |
|
814 | + EE_Error::add_error( |
|
815 | + sprintf( |
|
816 | + esc_html__( |
|
817 | + 'A registration step could not be loaded. One or more of the following data points is invalid:%4$s%5$sFile Path: %1$s%6$s%5$sClass Name: %2$s%6$s%5$sSlug: %3$s%6$s%7$s', |
|
818 | + 'event_espresso' |
|
819 | + ), |
|
820 | + isset($reg_step['file_path']) ? $reg_step['file_path'] : '', |
|
821 | + isset($reg_step['class_name']) ? $reg_step['class_name'] : '', |
|
822 | + isset($reg_step['slug']) ? $reg_step['slug'] : '', |
|
823 | + '<ul>', |
|
824 | + '<li>', |
|
825 | + '</li>', |
|
826 | + '</ul>' |
|
827 | + ), |
|
828 | + __FILE__, |
|
829 | + __FUNCTION__, |
|
830 | + __LINE__ |
|
831 | + ); |
|
832 | + } |
|
833 | + return false; |
|
834 | + } |
|
835 | + return true; |
|
836 | + } |
|
837 | + |
|
838 | + |
|
839 | + /** |
|
840 | + * _verify_transaction_and_get_registrations |
|
841 | + * |
|
842 | + * @access private |
|
843 | + * @return bool |
|
844 | + * @throws InvalidDataTypeException |
|
845 | + * @throws InvalidEntityException |
|
846 | + * @throws EE_Error |
|
847 | + */ |
|
848 | + private function _verify_transaction_and_get_registrations() |
|
849 | + { |
|
850 | + // was there already a valid transaction in the checkout from the session ? |
|
851 | + if (! $this->checkout->transaction instanceof EE_Transaction) { |
|
852 | + // get transaction from db or session |
|
853 | + $this->checkout->transaction = $this->checkout->reg_url_link && ! is_admin() |
|
854 | + ? $this->_get_transaction_and_cart_for_previous_visit() |
|
855 | + : $this->_get_cart_for_current_session_and_setup_new_transaction(); |
|
856 | + if (! $this->checkout->transaction instanceof EE_Transaction) { |
|
857 | + EE_Error::add_error( |
|
858 | + esc_html__( |
|
859 | + 'Your Registration and Transaction information could not be retrieved from the db.', |
|
860 | + 'event_espresso' |
|
861 | + ), |
|
862 | + __FILE__, |
|
863 | + __FUNCTION__, |
|
864 | + __LINE__ |
|
865 | + ); |
|
866 | + $this->checkout->transaction = EE_Transaction::new_instance(); |
|
867 | + // add some style and make it dance |
|
868 | + $this->add_styles_and_scripts(); |
|
869 | + EED_Single_Page_Checkout::$_initialized = true; |
|
870 | + return false; |
|
871 | + } |
|
872 | + // and the registrations for the transaction |
|
873 | + $this->_get_registrations($this->checkout->transaction); |
|
874 | + } |
|
875 | + return true; |
|
876 | + } |
|
877 | + |
|
878 | + |
|
879 | + /** |
|
880 | + * _get_transaction_and_cart_for_previous_visit |
|
881 | + * |
|
882 | + * @access private |
|
883 | + * @return mixed EE_Transaction|NULL |
|
884 | + */ |
|
885 | + private function _get_transaction_and_cart_for_previous_visit() |
|
886 | + { |
|
887 | + /** @var $TXN_model EEM_Transaction */ |
|
888 | + $TXN_model = EE_Registry::instance()->load_model('Transaction'); |
|
889 | + // because the reg_url_link is present in the request, |
|
890 | + // this is a return visit to SPCO, so we'll get the transaction data from the db |
|
891 | + $transaction = $TXN_model->get_transaction_from_reg_url_link($this->checkout->reg_url_link); |
|
892 | + // verify transaction |
|
893 | + if ($transaction instanceof EE_Transaction) { |
|
894 | + // and get the cart that was used for that transaction |
|
895 | + $this->checkout->cart = $this->_get_cart_for_transaction($transaction); |
|
896 | + return $transaction; |
|
897 | + } |
|
898 | + EE_Error::add_error( |
|
899 | + esc_html__('Your Registration and Transaction information could not be retrieved from the db.', 'event_espresso'), |
|
900 | + __FILE__, |
|
901 | + __FUNCTION__, |
|
902 | + __LINE__ |
|
903 | + ); |
|
904 | + return null; |
|
905 | + } |
|
906 | + |
|
907 | + |
|
908 | + /** |
|
909 | + * _get_cart_for_transaction |
|
910 | + * |
|
911 | + * @access private |
|
912 | + * @param EE_Transaction $transaction |
|
913 | + * @return EE_Cart |
|
914 | + */ |
|
915 | + private function _get_cart_for_transaction($transaction) |
|
916 | + { |
|
917 | + return $this->checkout->get_cart_for_transaction($transaction); |
|
918 | + } |
|
919 | + |
|
920 | + |
|
921 | + /** |
|
922 | + * get_cart_for_transaction |
|
923 | + * |
|
924 | + * @access public |
|
925 | + * @param EE_Transaction $transaction |
|
926 | + * @return EE_Cart |
|
927 | + */ |
|
928 | + public function get_cart_for_transaction(EE_Transaction $transaction) |
|
929 | + { |
|
930 | + return $this->checkout->get_cart_for_transaction($transaction); |
|
931 | + } |
|
932 | + |
|
933 | + |
|
934 | + /** |
|
935 | + * _get_transaction_and_cart_for_current_session |
|
936 | + * generates a new EE_Transaction object and adds it to the $_transaction property. |
|
937 | + * |
|
938 | + * @access private |
|
939 | + * @return EE_Transaction |
|
940 | + * @throws EE_Error |
|
941 | + */ |
|
942 | + private function _get_cart_for_current_session_and_setup_new_transaction() |
|
943 | + { |
|
944 | + // if there's no transaction, then this is the FIRST visit to SPCO |
|
945 | + // so load up the cart ( passing nothing for the TXN because it doesn't exist yet ) |
|
946 | + $this->checkout->cart = $this->_get_cart_for_transaction(null); |
|
947 | + // and then create a new transaction |
|
948 | + $transaction = $this->_initialize_transaction(); |
|
949 | + // verify transaction |
|
950 | + if ($transaction instanceof EE_Transaction) { |
|
951 | + // save it so that we have an ID for other objects to use |
|
952 | + $transaction->save(); |
|
953 | + // and save TXN data to the cart |
|
954 | + $this->checkout->cart->get_grand_total()->save_this_and_descendants_to_txn($transaction->ID()); |
|
955 | + } else { |
|
956 | + EE_Error::add_error( |
|
957 | + esc_html__('A Valid Transaction could not be initialized.', 'event_espresso'), |
|
958 | + __FILE__, |
|
959 | + __FUNCTION__, |
|
960 | + __LINE__ |
|
961 | + ); |
|
962 | + } |
|
963 | + return $transaction; |
|
964 | + } |
|
965 | + |
|
966 | + |
|
967 | + /** |
|
968 | + * generates a new EE_Transaction object and adds it to the $_transaction property. |
|
969 | + * |
|
970 | + * @access private |
|
971 | + * @return mixed EE_Transaction|NULL |
|
972 | + */ |
|
973 | + private function _initialize_transaction() |
|
974 | + { |
|
975 | + try { |
|
976 | + // ensure cart totals have been calculated |
|
977 | + $this->checkout->cart->get_grand_total()->recalculate_total_including_taxes(); |
|
978 | + // grab the cart grand total |
|
979 | + $cart_total = $this->checkout->cart->get_cart_grand_total(); |
|
980 | + // create new TXN |
|
981 | + $transaction = EE_Transaction::new_instance( |
|
982 | + array( |
|
983 | + 'TXN_reg_steps' => $this->checkout->initialize_txn_reg_steps_array(), |
|
984 | + 'TXN_total' => $cart_total > 0 ? $cart_total : 0, |
|
985 | + 'TXN_paid' => 0, |
|
986 | + 'STS_ID' => EEM_Transaction::failed_status_code, |
|
987 | + ) |
|
988 | + ); |
|
989 | + // save it so that we have an ID for other objects to use |
|
990 | + $transaction->save(); |
|
991 | + // set cron job for following up on TXNs after their session has expired |
|
992 | + EE_Cron_Tasks::schedule_expired_transaction_check( |
|
993 | + EE_Registry::instance()->SSN->expiration() + 1, |
|
994 | + $transaction->ID() |
|
995 | + ); |
|
996 | + return $transaction; |
|
997 | + } catch (Exception $e) { |
|
998 | + EE_Error::add_error($e->getMessage(), __FILE__, __FUNCTION__, __LINE__); |
|
999 | + } |
|
1000 | + return null; |
|
1001 | + } |
|
1002 | + |
|
1003 | + |
|
1004 | + /** |
|
1005 | + * _get_registrations |
|
1006 | + * |
|
1007 | + * @access private |
|
1008 | + * @param EE_Transaction $transaction |
|
1009 | + * @return void |
|
1010 | + * @throws InvalidDataTypeException |
|
1011 | + * @throws InvalidEntityException |
|
1012 | + * @throws EE_Error |
|
1013 | + */ |
|
1014 | + private function _get_registrations(EE_Transaction $transaction) |
|
1015 | + { |
|
1016 | + // first step: grab the registrants { : o |
|
1017 | + $registrations = $transaction->registrations($this->checkout->reg_cache_where_params, false); |
|
1018 | + $this->checkout->total_ticket_count = count($registrations); |
|
1019 | + // verify registrations have been set |
|
1020 | + if (empty($registrations)) { |
|
1021 | + // if no cached registrations, then check the db |
|
1022 | + $registrations = $transaction->registrations($this->checkout->reg_cache_where_params, false); |
|
1023 | + // still nothing ? well as long as this isn't a revisit |
|
1024 | + if (empty($registrations) && ! $this->checkout->revisit) { |
|
1025 | + // generate new registrations from scratch |
|
1026 | + $registrations = $this->_initialize_registrations($transaction); |
|
1027 | + } |
|
1028 | + } |
|
1029 | + // sort by their original registration order |
|
1030 | + usort($registrations, array('EED_Single_Page_Checkout', 'sort_registrations_by_REG_count')); |
|
1031 | + // then loop thru the array |
|
1032 | + foreach ($registrations as $registration) { |
|
1033 | + // verify each registration |
|
1034 | + if ($registration instanceof EE_Registration) { |
|
1035 | + // we display all attendee info for the primary registrant |
|
1036 | + if ($this->checkout->reg_url_link === $registration->reg_url_link() |
|
1037 | + && $registration->is_primary_registrant() |
|
1038 | + ) { |
|
1039 | + $this->checkout->primary_revisit = true; |
|
1040 | + break; |
|
1041 | + } |
|
1042 | + if ($this->checkout->revisit && $this->checkout->reg_url_link !== $registration->reg_url_link()) { |
|
1043 | + // but hide info if it doesn't belong to you |
|
1044 | + $transaction->clear_cache('Registration', $registration->ID()); |
|
1045 | + $this->checkout->total_ticket_count--; |
|
1046 | + } |
|
1047 | + $this->checkout->set_reg_status_updated($registration->ID(), false); |
|
1048 | + } |
|
1049 | + } |
|
1050 | + } |
|
1051 | + |
|
1052 | + |
|
1053 | + /** |
|
1054 | + * adds related EE_Registration objects for each ticket in the cart to the current EE_Transaction object |
|
1055 | + * |
|
1056 | + * @access private |
|
1057 | + * @param EE_Transaction $transaction |
|
1058 | + * @return array |
|
1059 | + * @throws InvalidDataTypeException |
|
1060 | + * @throws InvalidEntityException |
|
1061 | + * @throws EE_Error |
|
1062 | + */ |
|
1063 | + private function _initialize_registrations(EE_Transaction $transaction) |
|
1064 | + { |
|
1065 | + $att_nmbr = 0; |
|
1066 | + $registrations = array(); |
|
1067 | + if ($transaction instanceof EE_Transaction) { |
|
1068 | + /** @type EE_Registration_Processor $registration_processor */ |
|
1069 | + $registration_processor = EE_Registry::instance()->load_class('Registration_Processor'); |
|
1070 | + $this->checkout->total_ticket_count = $this->checkout->cart->all_ticket_quantity_count(); |
|
1071 | + // now let's add the cart items to the $transaction |
|
1072 | + foreach ($this->checkout->cart->get_tickets() as $line_item) { |
|
1073 | + // do the following for each ticket of this type they selected |
|
1074 | + for ($x = 1; $x <= $line_item->quantity(); $x++) { |
|
1075 | + $att_nmbr++; |
|
1076 | + /** @var EventEspresso\core\services\commands\registration\CreateRegistrationCommand $CreateRegistrationCommand */ |
|
1077 | + $CreateRegistrationCommand = EE_Registry::instance()->create( |
|
1078 | + 'EventEspresso\core\services\commands\registration\CreateRegistrationCommand', |
|
1079 | + array( |
|
1080 | + $transaction, |
|
1081 | + $line_item, |
|
1082 | + $att_nmbr, |
|
1083 | + $this->checkout->total_ticket_count, |
|
1084 | + ) |
|
1085 | + ); |
|
1086 | + // override capabilities for frontend registrations |
|
1087 | + if (! is_admin()) { |
|
1088 | + $CreateRegistrationCommand->setCapCheck( |
|
1089 | + new PublicCapabilities('', 'create_new_registration') |
|
1090 | + ); |
|
1091 | + } |
|
1092 | + $registration = EE_Registry::instance()->BUS->execute($CreateRegistrationCommand); |
|
1093 | + if (! $registration instanceof EE_Registration) { |
|
1094 | + throw new InvalidEntityException($registration, 'EE_Registration'); |
|
1095 | + } |
|
1096 | + $registrations[ $registration->ID() ] = $registration; |
|
1097 | + } |
|
1098 | + } |
|
1099 | + $registration_processor->fix_reg_final_price_rounding_issue($transaction); |
|
1100 | + } |
|
1101 | + return $registrations; |
|
1102 | + } |
|
1103 | + |
|
1104 | + |
|
1105 | + /** |
|
1106 | + * sorts registrations by REG_count |
|
1107 | + * |
|
1108 | + * @access public |
|
1109 | + * @param EE_Registration $reg_A |
|
1110 | + * @param EE_Registration $reg_B |
|
1111 | + * @return int |
|
1112 | + */ |
|
1113 | + public static function sort_registrations_by_REG_count(EE_Registration $reg_A, EE_Registration $reg_B) |
|
1114 | + { |
|
1115 | + // this shouldn't ever happen within the same TXN, but oh well |
|
1116 | + if ($reg_A->count() === $reg_B->count()) { |
|
1117 | + return 0; |
|
1118 | + } |
|
1119 | + return ($reg_A->count() > $reg_B->count()) ? 1 : -1; |
|
1120 | + } |
|
1121 | + |
|
1122 | + |
|
1123 | + /** |
|
1124 | + * _final_verifications |
|
1125 | + * just makes sure that everything is set up correctly before proceeding |
|
1126 | + * |
|
1127 | + * @access private |
|
1128 | + * @return bool |
|
1129 | + * @throws EE_Error |
|
1130 | + */ |
|
1131 | + private function _final_verifications() |
|
1132 | + { |
|
1133 | + // filter checkout |
|
1134 | + $this->checkout = apply_filters( |
|
1135 | + 'FHEE__EED_Single_Page_Checkout___final_verifications__checkout', |
|
1136 | + $this->checkout |
|
1137 | + ); |
|
1138 | + // verify that current step is still set correctly |
|
1139 | + if (! $this->checkout->current_step instanceof EE_SPCO_Reg_Step) { |
|
1140 | + EE_Error::add_error( |
|
1141 | + esc_html__( |
|
1142 | + 'We\'re sorry but the registration process can not proceed because one or more registration steps were not setup correctly. Please refresh the page and try again or contact support.', |
|
1143 | + 'event_espresso' |
|
1144 | + ), |
|
1145 | + __FILE__, |
|
1146 | + __FUNCTION__, |
|
1147 | + __LINE__ |
|
1148 | + ); |
|
1149 | + return false; |
|
1150 | + } |
|
1151 | + // if returning to SPCO, then verify that primary registrant is set |
|
1152 | + if (! empty($this->checkout->reg_url_link)) { |
|
1153 | + $valid_registrant = $this->checkout->transaction->primary_registration(); |
|
1154 | + if (! $valid_registrant instanceof EE_Registration) { |
|
1155 | + EE_Error::add_error( |
|
1156 | + esc_html__( |
|
1157 | + 'We\'re sorry but there appears to be an error with the "reg_url_link" or the primary registrant for this transaction. Please refresh the page and try again or contact support.', |
|
1158 | + 'event_espresso' |
|
1159 | + ), |
|
1160 | + __FILE__, |
|
1161 | + __FUNCTION__, |
|
1162 | + __LINE__ |
|
1163 | + ); |
|
1164 | + return false; |
|
1165 | + } |
|
1166 | + $valid_registrant = null; |
|
1167 | + foreach ($this->checkout->transaction->registrations($this->checkout->reg_cache_where_params) as $registration) { |
|
1168 | + if ($registration instanceof EE_Registration |
|
1169 | + && $registration->reg_url_link() === $this->checkout->reg_url_link |
|
1170 | + ) { |
|
1171 | + $valid_registrant = $registration; |
|
1172 | + } |
|
1173 | + } |
|
1174 | + if (! $valid_registrant instanceof EE_Registration) { |
|
1175 | + // hmmm... maybe we have the wrong session because the user is opening multiple tabs ? |
|
1176 | + if (EED_Single_Page_Checkout::$_checkout_verified) { |
|
1177 | + // clear the session, mark the checkout as unverified, and try again |
|
1178 | + EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__); |
|
1179 | + EED_Single_Page_Checkout::$_initialized = false; |
|
1180 | + EED_Single_Page_Checkout::$_checkout_verified = false; |
|
1181 | + $this->_initialize(); |
|
1182 | + EE_Error::reset_notices(); |
|
1183 | + return false; |
|
1184 | + } |
|
1185 | + EE_Error::add_error( |
|
1186 | + esc_html__( |
|
1187 | + 'We\'re sorry but there appears to be an error with the "reg_url_link" or the transaction itself. Please refresh the page and try again or contact support.', |
|
1188 | + 'event_espresso' |
|
1189 | + ), |
|
1190 | + __FILE__, |
|
1191 | + __FUNCTION__, |
|
1192 | + __LINE__ |
|
1193 | + ); |
|
1194 | + return false; |
|
1195 | + } |
|
1196 | + } |
|
1197 | + // now that things have been kinda sufficiently verified, |
|
1198 | + // let's add the checkout to the session so that it's available to other systems |
|
1199 | + EE_Registry::instance()->SSN->set_checkout($this->checkout); |
|
1200 | + return true; |
|
1201 | + } |
|
1202 | + |
|
1203 | + |
|
1204 | + /** |
|
1205 | + * _initialize_reg_steps |
|
1206 | + * first makes sure that EE_Transaction_Processor::set_reg_step_initiated() is called as required |
|
1207 | + * then loops thru all of the active reg steps and calls the initialize_reg_step() method |
|
1208 | + * |
|
1209 | + * @access private |
|
1210 | + * @param bool $reinitializing |
|
1211 | + * @throws EE_Error |
|
1212 | + */ |
|
1213 | + private function _initialize_reg_steps($reinitializing = false) |
|
1214 | + { |
|
1215 | + $this->checkout->set_reg_step_initiated($this->checkout->current_step); |
|
1216 | + // loop thru all steps to call their individual "initialize" methods and set i18n strings for JS |
|
1217 | + foreach ($this->checkout->reg_steps as $reg_step) { |
|
1218 | + if (! $reg_step->initialize_reg_step()) { |
|
1219 | + // if not initialized then maybe this step is being removed... |
|
1220 | + if (! $reinitializing && $reg_step->is_current_step()) { |
|
1221 | + // if it was the current step, then we need to start over here |
|
1222 | + $this->_initialize_reg_steps(true); |
|
1223 | + return; |
|
1224 | + } |
|
1225 | + continue; |
|
1226 | + } |
|
1227 | + // add css and JS for current step |
|
1228 | + $reg_step->enqueue_styles_and_scripts(); |
|
1229 | + // i18n |
|
1230 | + $reg_step->translate_js_strings(); |
|
1231 | + if ($reg_step->is_current_step()) { |
|
1232 | + // the text that appears on the reg step form submit button |
|
1233 | + $reg_step->set_submit_button_text(); |
|
1234 | + } |
|
1235 | + } |
|
1236 | + // dynamically creates hook point like: AHEE__Single_Page_Checkout___initialize_reg_step__attendee_information |
|
1237 | + do_action( |
|
1238 | + "AHEE__Single_Page_Checkout___initialize_reg_step__{$this->checkout->current_step->slug()}", |
|
1239 | + $this->checkout->current_step |
|
1240 | + ); |
|
1241 | + } |
|
1242 | + |
|
1243 | + |
|
1244 | + /** |
|
1245 | + * _check_form_submission |
|
1246 | + * |
|
1247 | + * @access private |
|
1248 | + * @return boolean |
|
1249 | + */ |
|
1250 | + private function _check_form_submission() |
|
1251 | + { |
|
1252 | + // does this request require the reg form to be generated ? |
|
1253 | + if ($this->checkout->generate_reg_form) { |
|
1254 | + // ever heard that song by Blue Rodeo ? |
|
1255 | + try { |
|
1256 | + $this->checkout->current_step->reg_form = $this->checkout->current_step->generate_reg_form(); |
|
1257 | + // if not displaying a form, then check for form submission |
|
1258 | + if ($this->checkout->process_form_submission |
|
1259 | + && $this->checkout->current_step->reg_form->was_submitted() |
|
1260 | + ) { |
|
1261 | + // clear out any old data in case this step is being run again |
|
1262 | + $this->checkout->current_step->set_valid_data(array()); |
|
1263 | + // capture submitted form data |
|
1264 | + $this->checkout->current_step->reg_form->receive_form_submission( |
|
1265 | + apply_filters( |
|
1266 | + 'FHEE__Single_Page_Checkout___check_form_submission__request_params', |
|
1267 | + EE_Registry::instance()->REQ->params(), |
|
1268 | + $this->checkout |
|
1269 | + ) |
|
1270 | + ); |
|
1271 | + // validate submitted form data |
|
1272 | + if (! $this->checkout->continue_reg || ! $this->checkout->current_step->reg_form->is_valid()) { |
|
1273 | + // thou shall not pass !!! |
|
1274 | + $this->checkout->continue_reg = false; |
|
1275 | + // any form validation errors? |
|
1276 | + if ($this->checkout->current_step->reg_form->submission_error_message() !== '') { |
|
1277 | + EE_Error::add_error( |
|
1278 | + $this->checkout->current_step->reg_form->submission_error_message(), |
|
1279 | + __FILE__, |
|
1280 | + __FUNCTION__, |
|
1281 | + __LINE__ |
|
1282 | + ); |
|
1283 | + } |
|
1284 | + // well not really... what will happen is |
|
1285 | + // we'll just get redirected back to redo the current step |
|
1286 | + $this->go_to_next_step(); |
|
1287 | + return false; |
|
1288 | + } |
|
1289 | + } |
|
1290 | + } catch (EE_Error $e) { |
|
1291 | + $e->get_error(); |
|
1292 | + } |
|
1293 | + } |
|
1294 | + return true; |
|
1295 | + } |
|
1296 | + |
|
1297 | + |
|
1298 | + /** |
|
1299 | + * _process_action |
|
1300 | + * |
|
1301 | + * @access private |
|
1302 | + * @return void |
|
1303 | + * @throws EE_Error |
|
1304 | + */ |
|
1305 | + private function _process_form_action() |
|
1306 | + { |
|
1307 | + // what cha wanna do? |
|
1308 | + switch ($this->checkout->action) { |
|
1309 | + // AJAX next step reg form |
|
1310 | + case 'display_spco_reg_step': |
|
1311 | + $this->checkout->redirect = false; |
|
1312 | + if (EE_Registry::instance()->REQ->ajax) { |
|
1313 | + $this->checkout->json_response->set_reg_step_html( |
|
1314 | + $this->checkout->current_step->display_reg_form() |
|
1315 | + ); |
|
1316 | + } |
|
1317 | + break; |
|
1318 | + default: |
|
1319 | + // meh... do one of those other steps first |
|
1320 | + if (! empty($this->checkout->action) |
|
1321 | + && is_callable(array($this->checkout->current_step, $this->checkout->action)) |
|
1322 | + ) { |
|
1323 | + // dynamically creates hook point like: |
|
1324 | + // AHEE__Single_Page_Checkout__before_attendee_information__process_reg_step |
|
1325 | + do_action( |
|
1326 | + "AHEE__Single_Page_Checkout__before_{$this->checkout->current_step->slug()}__{$this->checkout->action}", |
|
1327 | + $this->checkout->current_step |
|
1328 | + ); |
|
1329 | + // call action on current step |
|
1330 | + if (call_user_func(array($this->checkout->current_step, $this->checkout->action))) { |
|
1331 | + // good registrant, you get to proceed |
|
1332 | + if ($this->checkout->current_step->success_message() !== '' |
|
1333 | + && apply_filters( |
|
1334 | + 'FHEE__Single_Page_Checkout___process_form_action__display_success', |
|
1335 | + false |
|
1336 | + ) |
|
1337 | + ) { |
|
1338 | + EE_Error::add_success( |
|
1339 | + $this->checkout->current_step->success_message() |
|
1340 | + . '<br />' . $this->checkout->next_step->_instructions() |
|
1341 | + ); |
|
1342 | + } |
|
1343 | + // pack it up, pack it in... |
|
1344 | + $this->_setup_redirect(); |
|
1345 | + } |
|
1346 | + // dynamically creates hook point like: |
|
1347 | + // AHEE__Single_Page_Checkout__after_payment_options__process_reg_step |
|
1348 | + do_action( |
|
1349 | + "AHEE__Single_Page_Checkout__after_{$this->checkout->current_step->slug()}__{$this->checkout->action}", |
|
1350 | + $this->checkout->current_step |
|
1351 | + ); |
|
1352 | + } else { |
|
1353 | + EE_Error::add_error( |
|
1354 | + sprintf( |
|
1355 | + esc_html__( |
|
1356 | + 'The requested form action "%s" does not exist for the current "%s" registration step.', |
|
1357 | + 'event_espresso' |
|
1358 | + ), |
|
1359 | + $this->checkout->action, |
|
1360 | + $this->checkout->current_step->name() |
|
1361 | + ), |
|
1362 | + __FILE__, |
|
1363 | + __FUNCTION__, |
|
1364 | + __LINE__ |
|
1365 | + ); |
|
1366 | + } |
|
1367 | + // end default |
|
1368 | + } |
|
1369 | + // store our progress so far |
|
1370 | + $this->checkout->stash_transaction_and_checkout(); |
|
1371 | + // advance to the next step! If you pass GO, collect $200 |
|
1372 | + $this->go_to_next_step(); |
|
1373 | + } |
|
1374 | + |
|
1375 | + |
|
1376 | + /** |
|
1377 | + * add_styles_and_scripts |
|
1378 | + * |
|
1379 | + * @access public |
|
1380 | + * @return void |
|
1381 | + */ |
|
1382 | + public function add_styles_and_scripts() |
|
1383 | + { |
|
1384 | + // i18n |
|
1385 | + $this->translate_js_strings(); |
|
1386 | + if ($this->checkout->admin_request) { |
|
1387 | + add_action('admin_enqueue_scripts', array($this, 'enqueue_styles_and_scripts'), 10); |
|
1388 | + } else { |
|
1389 | + add_action('wp_enqueue_scripts', array($this, 'enqueue_styles_and_scripts'), 10); |
|
1390 | + } |
|
1391 | + } |
|
1392 | + |
|
1393 | + |
|
1394 | + /** |
|
1395 | + * translate_js_strings |
|
1396 | + * |
|
1397 | + * @access public |
|
1398 | + * @return void |
|
1399 | + */ |
|
1400 | + public function translate_js_strings() |
|
1401 | + { |
|
1402 | + EE_Registry::$i18n_js_strings['revisit'] = $this->checkout->revisit; |
|
1403 | + EE_Registry::$i18n_js_strings['e_reg_url_link'] = $this->checkout->reg_url_link; |
|
1404 | + EE_Registry::$i18n_js_strings['server_error'] = esc_html__( |
|
1405 | + 'An unknown error occurred on the server while attempting to process your request. Please refresh the page and try again or contact support.', |
|
1406 | + 'event_espresso' |
|
1407 | + ); |
|
1408 | + EE_Registry::$i18n_js_strings['invalid_json_response'] = esc_html__( |
|
1409 | + 'An invalid response was returned from the server while attempting to process your request. Please refresh the page and try again or contact support.', |
|
1410 | + 'event_espresso' |
|
1411 | + ); |
|
1412 | + EE_Registry::$i18n_js_strings['validation_error'] = esc_html__( |
|
1413 | + 'There appears to be a problem with the form validation configuration! Please check the admin settings or contact support.', |
|
1414 | + 'event_espresso' |
|
1415 | + ); |
|
1416 | + EE_Registry::$i18n_js_strings['invalid_payment_method'] = esc_html__( |
|
1417 | + 'There appears to be a problem with the payment method configuration! Please refresh the page and try again or contact support.', |
|
1418 | + 'event_espresso' |
|
1419 | + ); |
|
1420 | + EE_Registry::$i18n_js_strings['reg_step_error'] = esc_html__( |
|
1421 | + 'This registration step could not be completed. Please refresh the page and try again.', |
|
1422 | + 'event_espresso' |
|
1423 | + ); |
|
1424 | + EE_Registry::$i18n_js_strings['invalid_coupon'] = esc_html__( |
|
1425 | + 'We\'re sorry but that coupon code does not appear to be valid. If this is incorrect, please contact the site administrator.', |
|
1426 | + 'event_espresso' |
|
1427 | + ); |
|
1428 | + EE_Registry::$i18n_js_strings['process_registration'] = sprintf( |
|
1429 | + esc_html__( |
|
1430 | + 'Please wait while we process your registration.%sDo not refresh the page or navigate away while this is happening.%sThank you for your patience.', |
|
1431 | + 'event_espresso' |
|
1432 | + ), |
|
1433 | + '<br/>', |
|
1434 | + '<br/>' |
|
1435 | + ); |
|
1436 | + EE_Registry::$i18n_js_strings['language'] = get_bloginfo('language'); |
|
1437 | + EE_Registry::$i18n_js_strings['EESID'] = EE_Registry::instance()->SSN->id(); |
|
1438 | + EE_Registry::$i18n_js_strings['currency'] = EE_Registry::instance()->CFG->currency; |
|
1439 | + EE_Registry::$i18n_js_strings['datepicker_yearRange'] = '-150:+20'; |
|
1440 | + EE_Registry::$i18n_js_strings['timer_years'] = esc_html__('years', 'event_espresso'); |
|
1441 | + EE_Registry::$i18n_js_strings['timer_months'] = esc_html__('months', 'event_espresso'); |
|
1442 | + EE_Registry::$i18n_js_strings['timer_weeks'] = esc_html__('weeks', 'event_espresso'); |
|
1443 | + EE_Registry::$i18n_js_strings['timer_days'] = esc_html__('days', 'event_espresso'); |
|
1444 | + EE_Registry::$i18n_js_strings['timer_hours'] = esc_html__('hours', 'event_espresso'); |
|
1445 | + EE_Registry::$i18n_js_strings['timer_minutes'] = esc_html__('minutes', 'event_espresso'); |
|
1446 | + EE_Registry::$i18n_js_strings['timer_seconds'] = esc_html__('seconds', 'event_espresso'); |
|
1447 | + EE_Registry::$i18n_js_strings['timer_year'] = esc_html__('year', 'event_espresso'); |
|
1448 | + EE_Registry::$i18n_js_strings['timer_month'] = esc_html__('month', 'event_espresso'); |
|
1449 | + EE_Registry::$i18n_js_strings['timer_week'] = esc_html__('week', 'event_espresso'); |
|
1450 | + EE_Registry::$i18n_js_strings['timer_day'] = esc_html__('day', 'event_espresso'); |
|
1451 | + EE_Registry::$i18n_js_strings['timer_hour'] = esc_html__('hour', 'event_espresso'); |
|
1452 | + EE_Registry::$i18n_js_strings['timer_minute'] = esc_html__('minute', 'event_espresso'); |
|
1453 | + EE_Registry::$i18n_js_strings['timer_second'] = esc_html__('second', 'event_espresso'); |
|
1454 | + EE_Registry::$i18n_js_strings['registration_expiration_notice'] = EED_Single_Page_Checkout::getRegistrationExpirationNotice( |
|
1455 | + ); |
|
1456 | + EE_Registry::$i18n_js_strings['ajax_submit'] = apply_filters( |
|
1457 | + 'FHEE__Single_Page_Checkout__translate_js_strings__ajax_submit', |
|
1458 | + true |
|
1459 | + ); |
|
1460 | + EE_Registry::$i18n_js_strings['session_extension'] = absint( |
|
1461 | + apply_filters('FHEE__EE_Session__extend_expiration__seconds_added', 10 * MINUTE_IN_SECONDS) |
|
1462 | + ); |
|
1463 | + EE_Registry::$i18n_js_strings['session_expiration'] = gmdate( |
|
1464 | + 'M d, Y H:i:s', |
|
1465 | + EE_Registry::instance()->SSN->expiration() + (get_option('gmt_offset') * HOUR_IN_SECONDS) |
|
1466 | + ); |
|
1467 | + } |
|
1468 | + |
|
1469 | + |
|
1470 | + /** |
|
1471 | + * enqueue_styles_and_scripts |
|
1472 | + * |
|
1473 | + * @access public |
|
1474 | + * @return void |
|
1475 | + * @throws EE_Error |
|
1476 | + */ |
|
1477 | + public function enqueue_styles_and_scripts() |
|
1478 | + { |
|
1479 | + // load css |
|
1480 | + wp_register_style( |
|
1481 | + 'single_page_checkout', |
|
1482 | + SPCO_CSS_URL . 'single_page_checkout.css', |
|
1483 | + array('espresso_default'), |
|
1484 | + EVENT_ESPRESSO_VERSION |
|
1485 | + ); |
|
1486 | + wp_enqueue_style('single_page_checkout'); |
|
1487 | + // load JS |
|
1488 | + wp_register_script( |
|
1489 | + 'jquery_plugin', |
|
1490 | + EE_THIRD_PARTY_URL . 'jquery .plugin.min.js', |
|
1491 | + array('jquery'), |
|
1492 | + '1.0.1', |
|
1493 | + true |
|
1494 | + ); |
|
1495 | + wp_register_script( |
|
1496 | + 'jquery_countdown', |
|
1497 | + EE_THIRD_PARTY_URL . 'jquery .countdown.min.js', |
|
1498 | + array('jquery_plugin'), |
|
1499 | + '2.1.0', |
|
1500 | + true |
|
1501 | + ); |
|
1502 | + wp_register_script( |
|
1503 | + 'single_page_checkout', |
|
1504 | + SPCO_JS_URL . 'single_page_checkout.js', |
|
1505 | + array('espresso_core', 'underscore', 'ee_form_section_validation'), |
|
1506 | + EVENT_ESPRESSO_VERSION, |
|
1507 | + true |
|
1508 | + ); |
|
1509 | + if ($this->checkout->registration_form instanceof EE_Form_Section_Proper) { |
|
1510 | + $this->checkout->registration_form->enqueue_js(); |
|
1511 | + } |
|
1512 | + if ($this->checkout->current_step->reg_form instanceof EE_Form_Section_Proper) { |
|
1513 | + $this->checkout->current_step->reg_form->enqueue_js(); |
|
1514 | + } |
|
1515 | + wp_enqueue_script('single_page_checkout'); |
|
1516 | + if (apply_filters('FHEE__registration_page_wrapper_template__display_time_limit', false)) { |
|
1517 | + wp_enqueue_script('jquery_countdown'); |
|
1518 | + } |
|
1519 | + /** |
|
1520 | + * global action hook for enqueueing styles and scripts with |
|
1521 | + * spco calls. |
|
1522 | + */ |
|
1523 | + do_action('AHEE__EED_Single_Page_Checkout__enqueue_styles_and_scripts', $this); |
|
1524 | + /** |
|
1525 | + * dynamic action hook for enqueueing styles and scripts with spco calls. |
|
1526 | + * The hook will end up being something like: |
|
1527 | + * AHEE__EED_Single_Page_Checkout__enqueue_styles_and_scripts__attendee_information |
|
1528 | + */ |
|
1529 | + do_action( |
|
1530 | + 'AHEE__EED_Single_Page_Checkout__enqueue_styles_and_scripts__' . $this->checkout->current_step->slug(), |
|
1531 | + $this |
|
1532 | + ); |
|
1533 | + } |
|
1534 | + |
|
1535 | + |
|
1536 | + /** |
|
1537 | + * display the Registration Single Page Checkout Form |
|
1538 | + * |
|
1539 | + * @access private |
|
1540 | + * @return void |
|
1541 | + * @throws EE_Error |
|
1542 | + */ |
|
1543 | + private function _display_spco_reg_form() |
|
1544 | + { |
|
1545 | + // if registering via the admin, just display the reg form for the current step |
|
1546 | + if ($this->checkout->admin_request) { |
|
1547 | + EE_Registry::instance()->REQ->add_output($this->checkout->current_step->display_reg_form()); |
|
1548 | + } else { |
|
1549 | + // add powered by EE msg |
|
1550 | + add_action('AHEE__SPCO__reg_form_footer', array('EED_Single_Page_Checkout', 'display_registration_footer')); |
|
1551 | + $empty_cart = count($this->checkout->transaction |
|
1552 | + ->registrations($this->checkout->reg_cache_where_params)) < 1; |
|
1553 | + EE_Registry::$i18n_js_strings['empty_cart'] = $empty_cart; |
|
1554 | + $cookies_not_set_msg = ''; |
|
1555 | + if ($empty_cart) { |
|
1556 | + $cookies_not_set_msg = apply_filters( |
|
1557 | + 'FHEE__Single_Page_Checkout__display_spco_reg_form__cookies_not_set_msg', |
|
1558 | + sprintf( |
|
1559 | + esc_html__( |
|
1560 | + '%1$s%3$sIt appears your browser is not currently set to accept Cookies%4$s%5$sIn order to register for events, you need to enable cookies.%7$sIf you require assistance, then click the following link to learn how to %8$senable cookies%9$s%6$s%2$s', |
|
1561 | + 'event_espresso' |
|
1562 | + ), |
|
1563 | + '<div class="ee-attention hidden" id="ee-cookies-not-set-msg">', |
|
1564 | + '</div>', |
|
1565 | + '<h6 class="important-notice">', |
|
1566 | + '</h6>', |
|
1567 | + '<p>', |
|
1568 | + '</p>', |
|
1569 | + '<br />', |
|
1570 | + '<a href="http://www.whatarecookies.com/enable.asp" target="_blank" rel="noopener noreferrer">', |
|
1571 | + '</a>' |
|
1572 | + ) |
|
1573 | + ); |
|
1574 | + } |
|
1575 | + $this->checkout->registration_form = new EE_Form_Section_Proper( |
|
1576 | + array( |
|
1577 | + 'name' => 'single-page-checkout', |
|
1578 | + 'html_id' => 'ee-single-page-checkout-dv', |
|
1579 | + 'layout_strategy' => |
|
1580 | + new EE_Template_Layout( |
|
1581 | + array( |
|
1582 | + 'layout_template_file' => SPCO_TEMPLATES_PATH . 'registration_page_wrapper.template.php', |
|
1583 | + 'template_args' => array( |
|
1584 | + 'empty_cart' => $empty_cart, |
|
1585 | + 'revisit' => $this->checkout->revisit, |
|
1586 | + 'reg_steps' => $this->checkout->reg_steps, |
|
1587 | + 'next_step' => $this->checkout->next_step instanceof EE_SPCO_Reg_Step |
|
1588 | + ? $this->checkout->next_step->slug() |
|
1589 | + : '', |
|
1590 | + 'empty_msg' => apply_filters( |
|
1591 | + 'FHEE__Single_Page_Checkout__display_spco_reg_form__empty_msg', |
|
1592 | + sprintf( |
|
1593 | + esc_html__( |
|
1594 | + 'You need to %1$sReturn to Events list%2$sselect at least one event%3$s before you can proceed with the registration process.', |
|
1595 | + 'event_espresso' |
|
1596 | + ), |
|
1597 | + '<a href="' |
|
1598 | + . get_post_type_archive_link('espresso_events') |
|
1599 | + . '" title="', |
|
1600 | + '">', |
|
1601 | + '</a>' |
|
1602 | + ) |
|
1603 | + ), |
|
1604 | + 'cookies_not_set_msg' => $cookies_not_set_msg, |
|
1605 | + 'registration_time_limit' => $this->checkout->get_registration_time_limit(), |
|
1606 | + 'session_expiration' => gmdate( |
|
1607 | + 'M d, Y H:i:s', |
|
1608 | + EE_Registry::instance()->SSN->expiration() |
|
1609 | + + (get_option('gmt_offset') * HOUR_IN_SECONDS) |
|
1610 | + ), |
|
1611 | + ), |
|
1612 | + ) |
|
1613 | + ), |
|
1614 | + ) |
|
1615 | + ); |
|
1616 | + // load template and add to output sent that gets filtered into the_content() |
|
1617 | + EE_Registry::instance()->REQ->add_output($this->checkout->registration_form->get_html()); |
|
1618 | + } |
|
1619 | + } |
|
1620 | + |
|
1621 | + |
|
1622 | + /** |
|
1623 | + * add_extra_finalize_registration_inputs |
|
1624 | + * |
|
1625 | + * @access public |
|
1626 | + * @param $next_step |
|
1627 | + * @internal param string $label |
|
1628 | + * @return void |
|
1629 | + */ |
|
1630 | + public function add_extra_finalize_registration_inputs($next_step) |
|
1631 | + { |
|
1632 | + if ($next_step === 'finalize_registration') { |
|
1633 | + echo '<div id="spco-extra-finalize_registration-inputs-dv"></div>'; |
|
1634 | + } |
|
1635 | + } |
|
1636 | + |
|
1637 | + |
|
1638 | + /** |
|
1639 | + * display_registration_footer |
|
1640 | + * |
|
1641 | + * @access public |
|
1642 | + * @return string |
|
1643 | + */ |
|
1644 | + public static function display_registration_footer() |
|
1645 | + { |
|
1646 | + if (apply_filters( |
|
1647 | + 'FHEE__EE_Front__Controller__show_reg_footer', |
|
1648 | + EE_Registry::instance()->CFG->admin->show_reg_footer |
|
1649 | + )) { |
|
1650 | + add_filter( |
|
1651 | + 'FHEE__EEH_Template__powered_by_event_espresso__url', |
|
1652 | + function ($url) { |
|
1653 | + return apply_filters('FHEE__EE_Front_Controller__registration_footer__url', $url); |
|
1654 | + } |
|
1655 | + ); |
|
1656 | + echo apply_filters( |
|
1657 | + 'FHEE__EE_Front_Controller__display_registration_footer', |
|
1658 | + \EEH_Template::powered_by_event_espresso( |
|
1659 | + '', |
|
1660 | + 'espresso-registration-footer-dv', |
|
1661 | + array('utm_content' => 'registration_checkout') |
|
1662 | + ) |
|
1663 | + ); |
|
1664 | + } |
|
1665 | + return ''; |
|
1666 | + } |
|
1667 | + |
|
1668 | + |
|
1669 | + /** |
|
1670 | + * unlock_transaction |
|
1671 | + * |
|
1672 | + * @access public |
|
1673 | + * @return void |
|
1674 | + * @throws EE_Error |
|
1675 | + */ |
|
1676 | + public function unlock_transaction() |
|
1677 | + { |
|
1678 | + if ($this->checkout->transaction instanceof EE_Transaction) { |
|
1679 | + $this->checkout->transaction->unlock(); |
|
1680 | + } |
|
1681 | + } |
|
1682 | + |
|
1683 | + |
|
1684 | + /** |
|
1685 | + * _setup_redirect |
|
1686 | + * |
|
1687 | + * @access private |
|
1688 | + * @return void |
|
1689 | + */ |
|
1690 | + private function _setup_redirect() |
|
1691 | + { |
|
1692 | + if ($this->checkout->continue_reg && $this->checkout->next_step instanceof EE_SPCO_Reg_Step) { |
|
1693 | + $this->checkout->redirect = true; |
|
1694 | + if (empty($this->checkout->redirect_url)) { |
|
1695 | + $this->checkout->redirect_url = $this->checkout->next_step->reg_step_url(); |
|
1696 | + } |
|
1697 | + $this->checkout->redirect_url = apply_filters( |
|
1698 | + 'FHEE__EED_Single_Page_Checkout___setup_redirect__checkout_redirect_url', |
|
1699 | + $this->checkout->redirect_url, |
|
1700 | + $this->checkout |
|
1701 | + ); |
|
1702 | + } |
|
1703 | + } |
|
1704 | + |
|
1705 | + |
|
1706 | + /** |
|
1707 | + * handle ajax message responses and redirects |
|
1708 | + * |
|
1709 | + * @access public |
|
1710 | + * @return void |
|
1711 | + * @throws EE_Error |
|
1712 | + */ |
|
1713 | + public function go_to_next_step() |
|
1714 | + { |
|
1715 | + if (EE_Registry::instance()->REQ->ajax) { |
|
1716 | + // capture contents of output buffer we started earlier in the request, and insert into JSON response |
|
1717 | + $this->checkout->json_response->set_unexpected_errors(ob_get_clean()); |
|
1718 | + } |
|
1719 | + $this->unlock_transaction(); |
|
1720 | + // just return for these conditions |
|
1721 | + if ($this->checkout->admin_request |
|
1722 | + || $this->checkout->action === 'redirect_form' |
|
1723 | + || $this->checkout->action === 'update_checkout' |
|
1724 | + ) { |
|
1725 | + return; |
|
1726 | + } |
|
1727 | + // AJAX response |
|
1728 | + $this->_handle_json_response(); |
|
1729 | + // redirect to next step or the Thank You page |
|
1730 | + $this->_handle_html_redirects(); |
|
1731 | + // hmmm... must be something wrong, so let's just display the form again ! |
|
1732 | + $this->_display_spco_reg_form(); |
|
1733 | + } |
|
1734 | + |
|
1735 | + |
|
1736 | + /** |
|
1737 | + * _handle_json_response |
|
1738 | + * |
|
1739 | + * @access protected |
|
1740 | + * @return void |
|
1741 | + */ |
|
1742 | + protected function _handle_json_response() |
|
1743 | + { |
|
1744 | + // if this is an ajax request |
|
1745 | + if (EE_Registry::instance()->REQ->ajax) { |
|
1746 | + $this->checkout->json_response->set_registration_time_limit( |
|
1747 | + $this->checkout->get_registration_time_limit() |
|
1748 | + ); |
|
1749 | + $this->checkout->json_response->set_payment_amount($this->checkout->amount_owing); |
|
1750 | + // just send the ajax ( |
|
1751 | + $json_response = apply_filters( |
|
1752 | + 'FHEE__EE_Single_Page_Checkout__JSON_response', |
|
1753 | + $this->checkout->json_response |
|
1754 | + ); |
|
1755 | + echo $json_response; |
|
1756 | + exit(); |
|
1757 | + } |
|
1758 | + } |
|
1759 | + |
|
1760 | + |
|
1761 | + /** |
|
1762 | + * _handle_redirects |
|
1763 | + * |
|
1764 | + * @access protected |
|
1765 | + * @return void |
|
1766 | + */ |
|
1767 | + protected function _handle_html_redirects() |
|
1768 | + { |
|
1769 | + // going somewhere ? |
|
1770 | + if ($this->checkout->redirect && ! empty($this->checkout->redirect_url)) { |
|
1771 | + // store notices in a transient |
|
1772 | + EE_Error::get_notices(false, true, true); |
|
1773 | + wp_safe_redirect($this->checkout->redirect_url); |
|
1774 | + exit(); |
|
1775 | + } |
|
1776 | + } |
|
1777 | + |
|
1778 | + |
|
1779 | + /** |
|
1780 | + * set_checkout_anchor |
|
1781 | + * |
|
1782 | + * @access public |
|
1783 | + * @return void |
|
1784 | + */ |
|
1785 | + public function set_checkout_anchor() |
|
1786 | + { |
|
1787 | + echo '<a id="checkout" style="float: left; margin-left: -999em;"></a>'; |
|
1788 | + } |
|
1789 | + |
|
1790 | + /** |
|
1791 | + * getRegistrationExpirationNotice |
|
1792 | + * |
|
1793 | + * @since 4.9.59.p |
|
1794 | + * @access public |
|
1795 | + * @return string |
|
1796 | + */ |
|
1797 | + public static function getRegistrationExpirationNotice() |
|
1798 | + { |
|
1799 | + return sprintf( |
|
1800 | + esc_html__( |
|
1801 | + '%1$sWe\'re sorry, but your registration time has expired.%2$s%3$s%4$sIf you still wish to complete your registration, please return to the %5$sEvent List%6$sEvent List%7$s and reselect your tickets if available. Please accept our apologies for any inconvenience this may have caused.%8$s', |
|
1802 | + 'event_espresso' |
|
1803 | + ), |
|
1804 | + '<h4 class="important-notice">', |
|
1805 | + '</h4>', |
|
1806 | + '<br />', |
|
1807 | + '<p>', |
|
1808 | + '<a href="' . get_post_type_archive_link('espresso_events') . '" title="', |
|
1809 | + '">', |
|
1810 | + '</a>', |
|
1811 | + '</p>' |
|
1812 | + ); |
|
1813 | + } |
|
1814 | 1814 | } |
@@ -100,7 +100,7 @@ discard block |
||
100 | 100 | public static function set_hooks_admin() |
101 | 101 | { |
102 | 102 | EED_Single_Page_Checkout::set_definitions(); |
103 | - if (! (defined('DOING_AJAX') && DOING_AJAX)) { |
|
103 | + if ( ! (defined('DOING_AJAX') && DOING_AJAX)) { |
|
104 | 104 | return; |
105 | 105 | } |
106 | 106 | // going to start an output buffer in case anything gets accidentally output |
@@ -206,14 +206,14 @@ discard block |
||
206 | 206 | } |
207 | 207 | define( |
208 | 208 | 'SPCO_BASE_PATH', |
209 | - rtrim(str_replace(array('\\', '/'), DS, plugin_dir_path(__FILE__)), DS) . DS |
|
209 | + rtrim(str_replace(array('\\', '/'), DS, plugin_dir_path(__FILE__)), DS).DS |
|
210 | 210 | ); |
211 | - define('SPCO_CSS_URL', plugin_dir_url(__FILE__) . 'css' . DS); |
|
212 | - define('SPCO_IMG_URL', plugin_dir_url(__FILE__) . 'img' . DS); |
|
213 | - define('SPCO_JS_URL', plugin_dir_url(__FILE__) . 'js' . DS); |
|
214 | - define('SPCO_INC_PATH', SPCO_BASE_PATH . 'inc' . DS); |
|
215 | - define('SPCO_REG_STEPS_PATH', SPCO_BASE_PATH . 'reg_steps' . DS); |
|
216 | - define('SPCO_TEMPLATES_PATH', SPCO_BASE_PATH . 'templates' . DS); |
|
211 | + define('SPCO_CSS_URL', plugin_dir_url(__FILE__).'css'.DS); |
|
212 | + define('SPCO_IMG_URL', plugin_dir_url(__FILE__).'img'.DS); |
|
213 | + define('SPCO_JS_URL', plugin_dir_url(__FILE__).'js'.DS); |
|
214 | + define('SPCO_INC_PATH', SPCO_BASE_PATH.'inc'.DS); |
|
215 | + define('SPCO_REG_STEPS_PATH', SPCO_BASE_PATH.'reg_steps'.DS); |
|
216 | + define('SPCO_TEMPLATES_PATH', SPCO_BASE_PATH.'templates'.DS); |
|
217 | 217 | EEH_Autoloader::register_autoloaders_for_each_file_in_folder(SPCO_BASE_PATH, true); |
218 | 218 | EE_Registry::$i18n_js_strings['registration_expiration_notice'] = EED_Single_Page_Checkout::getRegistrationExpirationNotice( |
219 | 219 | ); |
@@ -245,7 +245,7 @@ discard block |
||
245 | 245 | // we need a |
246 | 246 | if (isset($reg_step['file_path'], $reg_step['class_name'], $reg_step['slug'])) { |
247 | 247 | // copy over to the reg_steps_array |
248 | - EED_Single_Page_Checkout::$_reg_steps_array[ $order ] = $reg_step; |
|
248 | + EED_Single_Page_Checkout::$_reg_steps_array[$order] = $reg_step; |
|
249 | 249 | // register custom key route for each reg step |
250 | 250 | // ie: step=>"slug" - this is the entire reason we load the reg steps array now |
251 | 251 | EE_Config::register_route( |
@@ -257,7 +257,7 @@ discard block |
||
257 | 257 | // add AJAX or other hooks |
258 | 258 | if (isset($reg_step['has_hooks']) && $reg_step['has_hooks']) { |
259 | 259 | // setup autoloaders if necessary |
260 | - if (! class_exists($reg_step['class_name'])) { |
|
260 | + if ( ! class_exists($reg_step['class_name'])) { |
|
261 | 261 | EEH_Autoloader::register_autoloaders_for_each_file_in_folder( |
262 | 262 | $reg_step['file_path'], |
263 | 263 | true |
@@ -285,19 +285,19 @@ discard block |
||
285 | 285 | if (empty($reg_steps)) { |
286 | 286 | $reg_steps = array( |
287 | 287 | 10 => array( |
288 | - 'file_path' => SPCO_REG_STEPS_PATH . 'attendee_information', |
|
288 | + 'file_path' => SPCO_REG_STEPS_PATH.'attendee_information', |
|
289 | 289 | 'class_name' => 'EE_SPCO_Reg_Step_Attendee_Information', |
290 | 290 | 'slug' => 'attendee_information', |
291 | 291 | 'has_hooks' => false, |
292 | 292 | ), |
293 | 293 | 30 => array( |
294 | - 'file_path' => SPCO_REG_STEPS_PATH . 'payment_options', |
|
294 | + 'file_path' => SPCO_REG_STEPS_PATH.'payment_options', |
|
295 | 295 | 'class_name' => 'EE_SPCO_Reg_Step_Payment_Options', |
296 | 296 | 'slug' => 'payment_options', |
297 | 297 | 'has_hooks' => true, |
298 | 298 | ), |
299 | 299 | 999 => array( |
300 | - 'file_path' => SPCO_REG_STEPS_PATH . 'finalize_registration', |
|
300 | + 'file_path' => SPCO_REG_STEPS_PATH.'finalize_registration', |
|
301 | 301 | 'class_name' => 'EE_SPCO_Reg_Step_Finalize_Registration', |
302 | 302 | 'slug' => 'finalize_registration', |
303 | 303 | 'has_hooks' => false, |
@@ -450,7 +450,7 @@ discard block |
||
450 | 450 | $this->checkout |
451 | 451 | ); |
452 | 452 | // load the reg steps array |
453 | - if (! $this->_load_and_instantiate_reg_steps()) { |
|
453 | + if ( ! $this->_load_and_instantiate_reg_steps()) { |
|
454 | 454 | EED_Single_Page_Checkout::$_initialized = true; |
455 | 455 | return; |
456 | 456 | } |
@@ -459,7 +459,7 @@ discard block |
||
459 | 459 | // and the next step |
460 | 460 | $this->checkout->set_next_step(); |
461 | 461 | // verify that everything has been setup correctly |
462 | - if (! ($this->_verify_transaction_and_get_registrations() && $this->_final_verifications())) { |
|
462 | + if ( ! ($this->_verify_transaction_and_get_registrations() && $this->_final_verifications())) { |
|
463 | 463 | EED_Single_Page_Checkout::$_initialized = true; |
464 | 464 | return; |
465 | 465 | } |
@@ -474,7 +474,7 @@ discard block |
||
474 | 474 | // DEBUG LOG |
475 | 475 | // $this->checkout->log( __CLASS__, __FUNCTION__, __LINE__ ); |
476 | 476 | // get reg form |
477 | - if (! $this->_check_form_submission()) { |
|
477 | + if ( ! $this->_check_form_submission()) { |
|
478 | 478 | EED_Single_Page_Checkout::$_initialized = true; |
479 | 479 | return; |
480 | 480 | } |
@@ -505,7 +505,7 @@ discard block |
||
505 | 505 | */ |
506 | 506 | private function _verify_session() |
507 | 507 | { |
508 | - if (! EE_Registry::instance()->SSN instanceof EE_Session) { |
|
508 | + if ( ! EE_Registry::instance()->SSN instanceof EE_Session) { |
|
509 | 509 | throw new EE_Error(esc_html__('The EE_Session class could not be loaded.', 'event_espresso')); |
510 | 510 | } |
511 | 511 | $clear_session_requested = filter_var( |
@@ -523,7 +523,7 @@ discard block |
||
523 | 523 | // EE_Registry::instance()->SSN->reset_cart(); |
524 | 524 | // EE_Registry::instance()->SSN->reset_checkout(); |
525 | 525 | // EE_Registry::instance()->SSN->reset_transaction(); |
526 | - if (! $clear_session_requested) { |
|
526 | + if ( ! $clear_session_requested) { |
|
527 | 527 | EE_Error::add_attention( |
528 | 528 | EE_Registry::$i18n_js_strings['registration_expiration_notice'], |
529 | 529 | __FILE__, |
@@ -550,7 +550,7 @@ discard block |
||
550 | 550 | /** @type EE_Checkout $checkout */ |
551 | 551 | $checkout = EE_Registry::instance()->SSN->checkout(); |
552 | 552 | // verify |
553 | - if (! $checkout instanceof EE_Checkout) { |
|
553 | + if ( ! $checkout instanceof EE_Checkout) { |
|
554 | 554 | // instantiate EE_Checkout object for handling the properties of the current checkout process |
555 | 555 | $checkout = EE_Registry::instance()->load_file( |
556 | 556 | SPCO_INC_PATH, |
@@ -568,7 +568,7 @@ discard block |
||
568 | 568 | } |
569 | 569 | $checkout = apply_filters('FHEE__EED_Single_Page_Checkout___initialize_checkout__checkout', $checkout); |
570 | 570 | // verify again |
571 | - if (! $checkout instanceof EE_Checkout) { |
|
571 | + if ( ! $checkout instanceof EE_Checkout) { |
|
572 | 572 | throw new EE_Error(esc_html__('The EE_Checkout class could not be loaded.', 'event_espresso')); |
573 | 573 | } |
574 | 574 | // reset anything that needs a clean slate for each request |
@@ -640,7 +640,7 @@ discard block |
||
640 | 640 | */ |
641 | 641 | protected function _display_request_vars() |
642 | 642 | { |
643 | - if (! WP_DEBUG) { |
|
643 | + if ( ! WP_DEBUG) { |
|
644 | 644 | return; |
645 | 645 | } |
646 | 646 | EEH_Debug_Tools::printr($_REQUEST, '$_REQUEST', __FILE__, __LINE__); |
@@ -717,7 +717,7 @@ discard block |
||
717 | 717 | ) { |
718 | 718 | // if not, then loop through raw reg steps array |
719 | 719 | foreach (EED_Single_Page_Checkout::$_reg_steps_array as $order => $reg_step) { |
720 | - if (! $this->_load_and_instantiate_reg_step($reg_step, $order)) { |
|
720 | + if ( ! $this->_load_and_instantiate_reg_step($reg_step, $order)) { |
|
721 | 721 | return false; |
722 | 722 | } |
723 | 723 | } |
@@ -848,12 +848,12 @@ discard block |
||
848 | 848 | private function _verify_transaction_and_get_registrations() |
849 | 849 | { |
850 | 850 | // was there already a valid transaction in the checkout from the session ? |
851 | - if (! $this->checkout->transaction instanceof EE_Transaction) { |
|
851 | + if ( ! $this->checkout->transaction instanceof EE_Transaction) { |
|
852 | 852 | // get transaction from db or session |
853 | 853 | $this->checkout->transaction = $this->checkout->reg_url_link && ! is_admin() |
854 | 854 | ? $this->_get_transaction_and_cart_for_previous_visit() |
855 | 855 | : $this->_get_cart_for_current_session_and_setup_new_transaction(); |
856 | - if (! $this->checkout->transaction instanceof EE_Transaction) { |
|
856 | + if ( ! $this->checkout->transaction instanceof EE_Transaction) { |
|
857 | 857 | EE_Error::add_error( |
858 | 858 | esc_html__( |
859 | 859 | 'Your Registration and Transaction information could not be retrieved from the db.', |
@@ -1084,16 +1084,16 @@ discard block |
||
1084 | 1084 | ) |
1085 | 1085 | ); |
1086 | 1086 | // override capabilities for frontend registrations |
1087 | - if (! is_admin()) { |
|
1087 | + if ( ! is_admin()) { |
|
1088 | 1088 | $CreateRegistrationCommand->setCapCheck( |
1089 | 1089 | new PublicCapabilities('', 'create_new_registration') |
1090 | 1090 | ); |
1091 | 1091 | } |
1092 | 1092 | $registration = EE_Registry::instance()->BUS->execute($CreateRegistrationCommand); |
1093 | - if (! $registration instanceof EE_Registration) { |
|
1093 | + if ( ! $registration instanceof EE_Registration) { |
|
1094 | 1094 | throw new InvalidEntityException($registration, 'EE_Registration'); |
1095 | 1095 | } |
1096 | - $registrations[ $registration->ID() ] = $registration; |
|
1096 | + $registrations[$registration->ID()] = $registration; |
|
1097 | 1097 | } |
1098 | 1098 | } |
1099 | 1099 | $registration_processor->fix_reg_final_price_rounding_issue($transaction); |
@@ -1136,7 +1136,7 @@ discard block |
||
1136 | 1136 | $this->checkout |
1137 | 1137 | ); |
1138 | 1138 | // verify that current step is still set correctly |
1139 | - if (! $this->checkout->current_step instanceof EE_SPCO_Reg_Step) { |
|
1139 | + if ( ! $this->checkout->current_step instanceof EE_SPCO_Reg_Step) { |
|
1140 | 1140 | EE_Error::add_error( |
1141 | 1141 | esc_html__( |
1142 | 1142 | 'We\'re sorry but the registration process can not proceed because one or more registration steps were not setup correctly. Please refresh the page and try again or contact support.', |
@@ -1149,9 +1149,9 @@ discard block |
||
1149 | 1149 | return false; |
1150 | 1150 | } |
1151 | 1151 | // if returning to SPCO, then verify that primary registrant is set |
1152 | - if (! empty($this->checkout->reg_url_link)) { |
|
1152 | + if ( ! empty($this->checkout->reg_url_link)) { |
|
1153 | 1153 | $valid_registrant = $this->checkout->transaction->primary_registration(); |
1154 | - if (! $valid_registrant instanceof EE_Registration) { |
|
1154 | + if ( ! $valid_registrant instanceof EE_Registration) { |
|
1155 | 1155 | EE_Error::add_error( |
1156 | 1156 | esc_html__( |
1157 | 1157 | 'We\'re sorry but there appears to be an error with the "reg_url_link" or the primary registrant for this transaction. Please refresh the page and try again or contact support.', |
@@ -1171,7 +1171,7 @@ discard block |
||
1171 | 1171 | $valid_registrant = $registration; |
1172 | 1172 | } |
1173 | 1173 | } |
1174 | - if (! $valid_registrant instanceof EE_Registration) { |
|
1174 | + if ( ! $valid_registrant instanceof EE_Registration) { |
|
1175 | 1175 | // hmmm... maybe we have the wrong session because the user is opening multiple tabs ? |
1176 | 1176 | if (EED_Single_Page_Checkout::$_checkout_verified) { |
1177 | 1177 | // clear the session, mark the checkout as unverified, and try again |
@@ -1215,9 +1215,9 @@ discard block |
||
1215 | 1215 | $this->checkout->set_reg_step_initiated($this->checkout->current_step); |
1216 | 1216 | // loop thru all steps to call their individual "initialize" methods and set i18n strings for JS |
1217 | 1217 | foreach ($this->checkout->reg_steps as $reg_step) { |
1218 | - if (! $reg_step->initialize_reg_step()) { |
|
1218 | + if ( ! $reg_step->initialize_reg_step()) { |
|
1219 | 1219 | // if not initialized then maybe this step is being removed... |
1220 | - if (! $reinitializing && $reg_step->is_current_step()) { |
|
1220 | + if ( ! $reinitializing && $reg_step->is_current_step()) { |
|
1221 | 1221 | // if it was the current step, then we need to start over here |
1222 | 1222 | $this->_initialize_reg_steps(true); |
1223 | 1223 | return; |
@@ -1269,7 +1269,7 @@ discard block |
||
1269 | 1269 | ) |
1270 | 1270 | ); |
1271 | 1271 | // validate submitted form data |
1272 | - if (! $this->checkout->continue_reg || ! $this->checkout->current_step->reg_form->is_valid()) { |
|
1272 | + if ( ! $this->checkout->continue_reg || ! $this->checkout->current_step->reg_form->is_valid()) { |
|
1273 | 1273 | // thou shall not pass !!! |
1274 | 1274 | $this->checkout->continue_reg = false; |
1275 | 1275 | // any form validation errors? |
@@ -1317,7 +1317,7 @@ discard block |
||
1317 | 1317 | break; |
1318 | 1318 | default: |
1319 | 1319 | // meh... do one of those other steps first |
1320 | - if (! empty($this->checkout->action) |
|
1320 | + if ( ! empty($this->checkout->action) |
|
1321 | 1321 | && is_callable(array($this->checkout->current_step, $this->checkout->action)) |
1322 | 1322 | ) { |
1323 | 1323 | // dynamically creates hook point like: |
@@ -1337,7 +1337,7 @@ discard block |
||
1337 | 1337 | ) { |
1338 | 1338 | EE_Error::add_success( |
1339 | 1339 | $this->checkout->current_step->success_message() |
1340 | - . '<br />' . $this->checkout->next_step->_instructions() |
|
1340 | + . '<br />'.$this->checkout->next_step->_instructions() |
|
1341 | 1341 | ); |
1342 | 1342 | } |
1343 | 1343 | // pack it up, pack it in... |
@@ -1479,7 +1479,7 @@ discard block |
||
1479 | 1479 | // load css |
1480 | 1480 | wp_register_style( |
1481 | 1481 | 'single_page_checkout', |
1482 | - SPCO_CSS_URL . 'single_page_checkout.css', |
|
1482 | + SPCO_CSS_URL.'single_page_checkout.css', |
|
1483 | 1483 | array('espresso_default'), |
1484 | 1484 | EVENT_ESPRESSO_VERSION |
1485 | 1485 | ); |
@@ -1487,21 +1487,21 @@ discard block |
||
1487 | 1487 | // load JS |
1488 | 1488 | wp_register_script( |
1489 | 1489 | 'jquery_plugin', |
1490 | - EE_THIRD_PARTY_URL . 'jquery .plugin.min.js', |
|
1490 | + EE_THIRD_PARTY_URL.'jquery .plugin.min.js', |
|
1491 | 1491 | array('jquery'), |
1492 | 1492 | '1.0.1', |
1493 | 1493 | true |
1494 | 1494 | ); |
1495 | 1495 | wp_register_script( |
1496 | 1496 | 'jquery_countdown', |
1497 | - EE_THIRD_PARTY_URL . 'jquery .countdown.min.js', |
|
1497 | + EE_THIRD_PARTY_URL.'jquery .countdown.min.js', |
|
1498 | 1498 | array('jquery_plugin'), |
1499 | 1499 | '2.1.0', |
1500 | 1500 | true |
1501 | 1501 | ); |
1502 | 1502 | wp_register_script( |
1503 | 1503 | 'single_page_checkout', |
1504 | - SPCO_JS_URL . 'single_page_checkout.js', |
|
1504 | + SPCO_JS_URL.'single_page_checkout.js', |
|
1505 | 1505 | array('espresso_core', 'underscore', 'ee_form_section_validation'), |
1506 | 1506 | EVENT_ESPRESSO_VERSION, |
1507 | 1507 | true |
@@ -1527,7 +1527,7 @@ discard block |
||
1527 | 1527 | * AHEE__EED_Single_Page_Checkout__enqueue_styles_and_scripts__attendee_information |
1528 | 1528 | */ |
1529 | 1529 | do_action( |
1530 | - 'AHEE__EED_Single_Page_Checkout__enqueue_styles_and_scripts__' . $this->checkout->current_step->slug(), |
|
1530 | + 'AHEE__EED_Single_Page_Checkout__enqueue_styles_and_scripts__'.$this->checkout->current_step->slug(), |
|
1531 | 1531 | $this |
1532 | 1532 | ); |
1533 | 1533 | } |
@@ -1579,7 +1579,7 @@ discard block |
||
1579 | 1579 | 'layout_strategy' => |
1580 | 1580 | new EE_Template_Layout( |
1581 | 1581 | array( |
1582 | - 'layout_template_file' => SPCO_TEMPLATES_PATH . 'registration_page_wrapper.template.php', |
|
1582 | + 'layout_template_file' => SPCO_TEMPLATES_PATH.'registration_page_wrapper.template.php', |
|
1583 | 1583 | 'template_args' => array( |
1584 | 1584 | 'empty_cart' => $empty_cart, |
1585 | 1585 | 'revisit' => $this->checkout->revisit, |
@@ -1649,7 +1649,7 @@ discard block |
||
1649 | 1649 | )) { |
1650 | 1650 | add_filter( |
1651 | 1651 | 'FHEE__EEH_Template__powered_by_event_espresso__url', |
1652 | - function ($url) { |
|
1652 | + function($url) { |
|
1653 | 1653 | return apply_filters('FHEE__EE_Front_Controller__registration_footer__url', $url); |
1654 | 1654 | } |
1655 | 1655 | ); |
@@ -1805,7 +1805,7 @@ discard block |
||
1805 | 1805 | '</h4>', |
1806 | 1806 | '<br />', |
1807 | 1807 | '<p>', |
1808 | - '<a href="' . get_post_type_archive_link('espresso_events') . '" title="', |
|
1808 | + '<a href="'.get_post_type_archive_link('espresso_events').'" title="', |
|
1809 | 1809 | '">', |
1810 | 1810 | '</a>', |
1811 | 1811 | '</p>' |
@@ -4,10 +4,10 @@ discard block |
||
4 | 4 | </p> |
5 | 5 | <p> |
6 | 6 | <?php printf( |
7 | - esc_html__('See %1$shere%2$s for list of currencies supported by Paypal Pro.', 'event_espresso'), |
|
8 | - "<a href='https://www.paypal.com/multicurrency' target='_blank' rel='noopener noreferrer'>", |
|
9 | - "</a>" |
|
10 | - ); ?> |
|
7 | + esc_html__('See %1$shere%2$s for list of currencies supported by Paypal Pro.', 'event_espresso'), |
|
8 | + "<a href='https://www.paypal.com/multicurrency' target='_blank' rel='noopener noreferrer'>", |
|
9 | + "</a>" |
|
10 | + ); ?> |
|
11 | 11 | </p> |
12 | 12 | <p><strong><?php esc_html_e('PayPal Pro Settings', 'event_espresso'); ?></strong></p> |
13 | 13 | <ul> |
@@ -18,42 +18,42 @@ discard block |
||
18 | 18 | <li> |
19 | 19 | <strong><?php esc_html_e('PayPal API Username', 'event_espresso'); ?></strong><br/> |
20 | 20 | <?php printf( |
21 | - esc_html__( |
|
22 | - 'Enter your API Username for PayPal. Learn how to find your %1$sAPI Username%2$s.', |
|
23 | - 'event_espresso' |
|
24 | - ), |
|
25 | - '<a href="https://www.paypal.com/us/cgi-bin/webscr?cmd=xpt/cps/merchant/wppro/WPProIntegrationSteps-outside#SectionB" target="_blank" rel="noopener noreferrer">', |
|
26 | - '</a>' |
|
27 | - ); ?> |
|
21 | + esc_html__( |
|
22 | + 'Enter your API Username for PayPal. Learn how to find your %1$sAPI Username%2$s.', |
|
23 | + 'event_espresso' |
|
24 | + ), |
|
25 | + '<a href="https://www.paypal.com/us/cgi-bin/webscr?cmd=xpt/cps/merchant/wppro/WPProIntegrationSteps-outside#SectionB" target="_blank" rel="noopener noreferrer">', |
|
26 | + '</a>' |
|
27 | + ); ?> |
|
28 | 28 | </li> |
29 | 29 | <li> |
30 | 30 | <strong><?php esc_html_e('PayPal API Password', 'event_espresso'); ?></strong><br/> |
31 | 31 | <?php printf( |
32 | - esc_html__( |
|
33 | - 'Enter your API Password for PayPal. Learn how to find your %1$sAPI Password%2$s.', |
|
34 | - 'event_espresso' |
|
35 | - ), |
|
36 | - '<a href="https://www.paypal.com/us/cgi-bin/webscr?cmd=xpt/cps/merchant/wppro/WPProIntegrationSteps-outside#SectionB" target="_blank" rel="noopener noreferrer">', |
|
37 | - '</a>' |
|
38 | - ); ?> |
|
32 | + esc_html__( |
|
33 | + 'Enter your API Password for PayPal. Learn how to find your %1$sAPI Password%2$s.', |
|
34 | + 'event_espresso' |
|
35 | + ), |
|
36 | + '<a href="https://www.paypal.com/us/cgi-bin/webscr?cmd=xpt/cps/merchant/wppro/WPProIntegrationSteps-outside#SectionB" target="_blank" rel="noopener noreferrer">', |
|
37 | + '</a>' |
|
38 | + ); ?> |
|
39 | 39 | </li> |
40 | 40 | <li> |
41 | 41 | <strong><?php esc_html_e('PayPal API Signature', 'event_espresso'); ?></strong><br/> |
42 | 42 | <?php printf( |
43 | - esc_html__( |
|
44 | - 'Enter your API Signature for PayPal. Learn how to find your %1$sAPI Signature%2$s.', |
|
45 | - 'event_espresso' |
|
46 | - ), |
|
47 | - '<a href="https://www.paypal.com/us/cgi-bin/webscr?cmd=xpt/cps/merchant/wppro/WPProIntegrationSteps-outside#SectionB" target="_blank" rel="noopener noreferrer">', |
|
48 | - '</a>' |
|
49 | - ); ?> |
|
43 | + esc_html__( |
|
44 | + 'Enter your API Signature for PayPal. Learn how to find your %1$sAPI Signature%2$s.', |
|
45 | + 'event_espresso' |
|
46 | + ), |
|
47 | + '<a href="https://www.paypal.com/us/cgi-bin/webscr?cmd=xpt/cps/merchant/wppro/WPProIntegrationSteps-outside#SectionB" target="_blank" rel="noopener noreferrer">', |
|
48 | + '</a>' |
|
49 | + ); ?> |
|
50 | 50 | </li> |
51 | 51 | <li> |
52 | 52 | <strong><?php esc_html_e('Country Currency', 'event_espresso'); ?></strong><br/> |
53 | 53 | <?php esc_html_e( |
54 | - 'Select the currency for your country. Payments will be accepted in this currency.', |
|
55 | - 'event_espresso' |
|
56 | - ); ?> |
|
54 | + 'Select the currency for your country. Payments will be accepted in this currency.', |
|
55 | + 'event_espresso' |
|
56 | + ); ?> |
|
57 | 57 | </li> |
58 | 58 | <li> |
59 | 59 | <strong><?php esc_html_e('Accepted Card Types', 'event_espresso'); ?></strong><br/> |
@@ -62,9 +62,9 @@ discard block |
||
62 | 62 | <li> |
63 | 63 | <strong><?php esc_html_e('Use the Debugging Feature and the PayPal Sandbox', 'event_espresso'); ?></strong><br/> |
64 | 64 | <?php esc_html_e( |
65 | - 'Specify if you want to test the payment gateway by submitting a test transaction. If this option is enabled, be sure to enter your PayPal sandbox credentials in the fields above. Be sure to turn this setting off when you are done testing.', |
|
66 | - 'event_espresso' |
|
67 | - ); ?> |
|
65 | + 'Specify if you want to test the payment gateway by submitting a test transaction. If this option is enabled, be sure to enter your PayPal sandbox credentials in the fields above. Be sure to turn this setting off when you are done testing.', |
|
66 | + 'event_espresso' |
|
67 | + ); ?> |
|
68 | 68 | </li> |
69 | 69 | <li> |
70 | 70 | <strong><?php esc_html_e('Button Image URL', 'event_espresso'); ?></strong><br/> |
@@ -12,9 +12,9 @@ discard block |
||
12 | 12 | <?php esc_html_e('This option will save all Event Espresso registration form data, and debugging information to a file in the /wp-content/uploads/espresso/logs directory on your server. This will occur each time a page is accessed on your site until this option is turned off.', 'event_espresso'); ?> |
13 | 13 | <br/> |
14 | 14 | <?php printf( |
15 | - esc_html__('Note that if you are accessing your filesystem over FTP or SSH, and logging writes to the filesystem on every request, you should put your credentials in your wp-config.php file, as described %1$shere.%2$s', 'event_espresso'), |
|
16 | - '<a href="https://codex.wordpress.org/Editing_wp-config.php#WordPress_Upgrade_Constants" target="_blank" rel="noopener noreferrer">', |
|
17 | - '</a>' |
|
15 | + esc_html__('Note that if you are accessing your filesystem over FTP or SSH, and logging writes to the filesystem on every request, you should put your credentials in your wp-config.php file, as described %1$shere.%2$s', 'event_espresso'), |
|
16 | + '<a href="https://codex.wordpress.org/Editing_wp-config.php#WordPress_Upgrade_Constants" target="_blank" rel="noopener noreferrer">', |
|
17 | + '</a>' |
|
18 | 18 | ); ?> |
19 | 19 | </li> |
20 | 20 | <li> |
@@ -42,12 +42,12 @@ discard block |
||
42 | 42 | <li> |
43 | 43 | <strong><?php esc_html_e('Event Espresso Affiliate ID', 'event_espresso'); ?></strong><br /> |
44 | 44 | <?php printf( |
45 | - esc_html__( |
|
46 | - 'You can also monetize this link by signing up to our %1$saffiliate program%2$s and adding in your affiliate ID here.', |
|
47 | - 'event_espresso' |
|
48 | - ), |
|
49 | - '<a href="https://eventespresso.com/affiliates/">', |
|
50 | - '</a>' |
|
45 | + esc_html__( |
|
46 | + 'You can also monetize this link by signing up to our %1$saffiliate program%2$s and adding in your affiliate ID here.', |
|
47 | + 'event_espresso' |
|
48 | + ), |
|
49 | + '<a href="https://eventespresso.com/affiliates/">', |
|
50 | + '</a>' |
|
51 | 51 | ); ?> |
52 | 52 | </li> |
53 | 53 | </ul> |
@@ -21,2045 +21,2045 @@ |
||
21 | 21 | class EEH_Line_Item |
22 | 22 | { |
23 | 23 | |
24 | - /** |
|
25 | - * Adds a simple item (unrelated to any other model object) to the provided PARENT line item. |
|
26 | - * Does NOT automatically re-calculate the line item totals or update the related transaction. |
|
27 | - * You should call recalculate_total_including_taxes() on the grant total line item after this |
|
28 | - * to update the subtotals, and EE_Registration_Processor::calculate_reg_final_prices_per_line_item() |
|
29 | - * to keep the registration final prices in-sync with the transaction's total. |
|
30 | - * |
|
31 | - * @param EE_Line_Item $parent_line_item |
|
32 | - * @param string $name |
|
33 | - * @param float $unit_price |
|
34 | - * @param string $description |
|
35 | - * @param int $quantity |
|
36 | - * @param boolean $taxable |
|
37 | - * @param boolean $code if set to a value, ensures there is only one line item with that code |
|
38 | - * @return boolean success |
|
39 | - * @throws EE_Error |
|
40 | - * @throws InvalidArgumentException |
|
41 | - * @throws InvalidDataTypeException |
|
42 | - * @throws InvalidInterfaceException |
|
43 | - * @throws ReflectionException |
|
44 | - */ |
|
45 | - public static function add_unrelated_item( |
|
46 | - EE_Line_Item $parent_line_item, |
|
47 | - $name, |
|
48 | - $unit_price, |
|
49 | - $description = '', |
|
50 | - $quantity = 1, |
|
51 | - $taxable = false, |
|
52 | - $code = null |
|
53 | - ) { |
|
54 | - $items_subtotal = self::get_pre_tax_subtotal($parent_line_item); |
|
55 | - $line_item = EE_Line_Item::new_instance(array( |
|
56 | - 'LIN_name' => $name, |
|
57 | - 'LIN_desc' => $description, |
|
58 | - 'LIN_unit_price' => $unit_price, |
|
59 | - 'LIN_quantity' => $quantity, |
|
60 | - 'LIN_percent' => null, |
|
61 | - 'LIN_is_taxable' => $taxable, |
|
62 | - 'LIN_order' => $items_subtotal instanceof EE_Line_Item ? count($items_subtotal->children()) : 0, |
|
63 | - 'LIN_total' => (float) $unit_price * (int) $quantity, |
|
64 | - 'LIN_type' => EEM_Line_Item::type_line_item, |
|
65 | - 'LIN_code' => $code, |
|
66 | - )); |
|
67 | - $line_item = apply_filters( |
|
68 | - 'FHEE__EEH_Line_Item__add_unrelated_item__line_item', |
|
69 | - $line_item, |
|
70 | - $parent_line_item |
|
71 | - ); |
|
72 | - return self::add_item($parent_line_item, $line_item); |
|
73 | - } |
|
74 | - |
|
75 | - |
|
76 | - /** |
|
77 | - * Adds a simple item ( unrelated to any other model object) to the total line item, |
|
78 | - * in the correct spot in the line item tree. Does not automatically |
|
79 | - * re-calculate the line item totals, nor update the related transaction, nor upgrade the transaction's |
|
80 | - * registrations' final prices (which should probably change because of this). |
|
81 | - * You should call recalculate_total_including_taxes() on the grand total line item, then |
|
82 | - * update the transaction's total, and EE_Registration_Processor::update_registration_final_prices() |
|
83 | - * after using this, to keep the registration final prices in-sync with the transaction's total. |
|
84 | - * |
|
85 | - * @param EE_Line_Item $parent_line_item |
|
86 | - * @param string $name |
|
87 | - * @param float $percentage_amount |
|
88 | - * @param string $description |
|
89 | - * @param boolean $taxable |
|
90 | - * @return boolean success |
|
91 | - * @throws EE_Error |
|
92 | - */ |
|
93 | - public static function add_percentage_based_item( |
|
94 | - EE_Line_Item $parent_line_item, |
|
95 | - $name, |
|
96 | - $percentage_amount, |
|
97 | - $description = '', |
|
98 | - $taxable = false |
|
99 | - ) { |
|
100 | - $line_item = EE_Line_Item::new_instance(array( |
|
101 | - 'LIN_name' => $name, |
|
102 | - 'LIN_desc' => $description, |
|
103 | - 'LIN_unit_price' => 0, |
|
104 | - 'LIN_percent' => $percentage_amount, |
|
105 | - 'LIN_quantity' => 1, |
|
106 | - 'LIN_is_taxable' => $taxable, |
|
107 | - 'LIN_total' => (float) ($percentage_amount * ($parent_line_item->total() / 100)), |
|
108 | - 'LIN_type' => EEM_Line_Item::type_line_item, |
|
109 | - 'LIN_parent' => $parent_line_item->ID(), |
|
110 | - )); |
|
111 | - $line_item = apply_filters( |
|
112 | - 'FHEE__EEH_Line_Item__add_percentage_based_item__line_item', |
|
113 | - $line_item |
|
114 | - ); |
|
115 | - return $parent_line_item->add_child_line_item($line_item, false); |
|
116 | - } |
|
117 | - |
|
118 | - |
|
119 | - /** |
|
120 | - * Returns the new line item created by adding a purchase of the ticket |
|
121 | - * ensures that ticket line item is saved, and that cart total has been recalculated. |
|
122 | - * If this ticket has already been purchased, just increments its count. |
|
123 | - * Automatically re-calculates the line item totals and updates the related transaction. But |
|
124 | - * DOES NOT automatically upgrade the transaction's registrations' final prices (which |
|
125 | - * should probably change because of this). |
|
126 | - * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item() |
|
127 | - * after using this, to keep the registration final prices in-sync with the transaction's total. |
|
128 | - * |
|
129 | - * @param EE_Line_Item $total_line_item grand total line item of type EEM_Line_Item::type_total |
|
130 | - * @param EE_Ticket $ticket |
|
131 | - * @param int $qty |
|
132 | - * @return EE_Line_Item |
|
133 | - * @throws EE_Error |
|
134 | - * @throws InvalidArgumentException |
|
135 | - * @throws InvalidDataTypeException |
|
136 | - * @throws InvalidInterfaceException |
|
137 | - * @throws ReflectionException |
|
138 | - */ |
|
139 | - public static function add_ticket_purchase(EE_Line_Item $total_line_item, EE_Ticket $ticket, $qty = 1) |
|
140 | - { |
|
141 | - if (! $total_line_item instanceof EE_Line_Item || ! $total_line_item->is_total()) { |
|
142 | - throw new EE_Error( |
|
143 | - sprintf( |
|
144 | - esc_html__( |
|
145 | - 'A valid line item total is required in order to add tickets. A line item of type "%s" was passed.', |
|
146 | - 'event_espresso' |
|
147 | - ), |
|
148 | - $ticket->ID(), |
|
149 | - $total_line_item->ID() |
|
150 | - ) |
|
151 | - ); |
|
152 | - } |
|
153 | - // either increment the qty for an existing ticket |
|
154 | - $line_item = self::increment_ticket_qty_if_already_in_cart($total_line_item, $ticket, $qty); |
|
155 | - // or add a new one |
|
156 | - if (! $line_item instanceof EE_Line_Item) { |
|
157 | - $line_item = self::create_ticket_line_item($total_line_item, $ticket, $qty); |
|
158 | - } |
|
159 | - $total_line_item->recalculate_total_including_taxes(); |
|
160 | - return $line_item; |
|
161 | - } |
|
162 | - |
|
163 | - |
|
164 | - /** |
|
165 | - * Returns the new line item created by adding a purchase of the ticket |
|
166 | - * |
|
167 | - * @param EE_Line_Item $total_line_item |
|
168 | - * @param EE_Ticket $ticket |
|
169 | - * @param int $qty |
|
170 | - * @return EE_Line_Item |
|
171 | - * @throws EE_Error |
|
172 | - * @throws InvalidArgumentException |
|
173 | - * @throws InvalidDataTypeException |
|
174 | - * @throws InvalidInterfaceException |
|
175 | - * @throws ReflectionException |
|
176 | - */ |
|
177 | - public static function increment_ticket_qty_if_already_in_cart( |
|
178 | - EE_Line_Item $total_line_item, |
|
179 | - EE_Ticket $ticket, |
|
180 | - $qty = 1 |
|
181 | - ) { |
|
182 | - $line_item = null; |
|
183 | - if ($total_line_item instanceof EE_Line_Item && $total_line_item->is_total()) { |
|
184 | - $ticket_line_items = EEH_Line_Item::get_ticket_line_items($total_line_item); |
|
185 | - foreach ((array) $ticket_line_items as $ticket_line_item) { |
|
186 | - if ($ticket_line_item instanceof EE_Line_Item |
|
187 | - && (int) $ticket_line_item->OBJ_ID() === (int) $ticket->ID() |
|
188 | - ) { |
|
189 | - $line_item = $ticket_line_item; |
|
190 | - break; |
|
191 | - } |
|
192 | - } |
|
193 | - } |
|
194 | - if ($line_item instanceof EE_Line_Item) { |
|
195 | - EEH_Line_Item::increment_quantity($line_item, $qty); |
|
196 | - return $line_item; |
|
197 | - } |
|
198 | - return null; |
|
199 | - } |
|
200 | - |
|
201 | - |
|
202 | - /** |
|
203 | - * Increments the line item and all its children's quantity by $qty (but percent line items are unaffected). |
|
204 | - * Does NOT save or recalculate other line items totals |
|
205 | - * |
|
206 | - * @param EE_Line_Item $line_item |
|
207 | - * @param int $qty |
|
208 | - * @return void |
|
209 | - * @throws EE_Error |
|
210 | - * @throws InvalidArgumentException |
|
211 | - * @throws InvalidDataTypeException |
|
212 | - * @throws InvalidInterfaceException |
|
213 | - * @throws ReflectionException |
|
214 | - */ |
|
215 | - public static function increment_quantity(EE_Line_Item $line_item, $qty = 1) |
|
216 | - { |
|
217 | - if (! $line_item->is_percent()) { |
|
218 | - $qty += $line_item->quantity(); |
|
219 | - $line_item->set_quantity($qty); |
|
220 | - $line_item->set_total($line_item->unit_price() * $qty); |
|
221 | - $line_item->save(); |
|
222 | - } |
|
223 | - foreach ($line_item->children() as $child) { |
|
224 | - if ($child->is_sub_line_item()) { |
|
225 | - EEH_Line_Item::update_quantity($child, $qty); |
|
226 | - } |
|
227 | - } |
|
228 | - } |
|
229 | - |
|
230 | - |
|
231 | - /** |
|
232 | - * Decrements the line item and all its children's quantity by $qty (but percent line items are unaffected). |
|
233 | - * Does NOT save or recalculate other line items totals |
|
234 | - * |
|
235 | - * @param EE_Line_Item $line_item |
|
236 | - * @param int $qty |
|
237 | - * @return void |
|
238 | - * @throws EE_Error |
|
239 | - * @throws InvalidArgumentException |
|
240 | - * @throws InvalidDataTypeException |
|
241 | - * @throws InvalidInterfaceException |
|
242 | - * @throws ReflectionException |
|
243 | - */ |
|
244 | - public static function decrement_quantity(EE_Line_Item $line_item, $qty = 1) |
|
245 | - { |
|
246 | - if (! $line_item->is_percent()) { |
|
247 | - $qty = $line_item->quantity() - $qty; |
|
248 | - $qty = max($qty, 0); |
|
249 | - $line_item->set_quantity($qty); |
|
250 | - $line_item->set_total($line_item->unit_price() * $qty); |
|
251 | - $line_item->save(); |
|
252 | - } |
|
253 | - foreach ($line_item->children() as $child) { |
|
254 | - if ($child->is_sub_line_item()) { |
|
255 | - EEH_Line_Item::update_quantity($child, $qty); |
|
256 | - } |
|
257 | - } |
|
258 | - } |
|
259 | - |
|
260 | - |
|
261 | - /** |
|
262 | - * Updates the line item and its children's quantities to the specified number. |
|
263 | - * Does NOT save them or recalculate totals. |
|
264 | - * |
|
265 | - * @param EE_Line_Item $line_item |
|
266 | - * @param int $new_quantity |
|
267 | - * @throws EE_Error |
|
268 | - * @throws InvalidArgumentException |
|
269 | - * @throws InvalidDataTypeException |
|
270 | - * @throws InvalidInterfaceException |
|
271 | - * @throws ReflectionException |
|
272 | - */ |
|
273 | - public static function update_quantity(EE_Line_Item $line_item, $new_quantity) |
|
274 | - { |
|
275 | - if (! $line_item->is_percent()) { |
|
276 | - $line_item->set_quantity($new_quantity); |
|
277 | - $line_item->set_total($line_item->unit_price() * $new_quantity); |
|
278 | - $line_item->save(); |
|
279 | - } |
|
280 | - foreach ($line_item->children() as $child) { |
|
281 | - if ($child->is_sub_line_item()) { |
|
282 | - EEH_Line_Item::update_quantity($child, $new_quantity); |
|
283 | - } |
|
284 | - } |
|
285 | - } |
|
286 | - |
|
287 | - |
|
288 | - /** |
|
289 | - * Returns the new line item created by adding a purchase of the ticket |
|
290 | - * |
|
291 | - * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
292 | - * @param EE_Ticket $ticket |
|
293 | - * @param int $qty |
|
294 | - * @return EE_Line_Item |
|
295 | - * @throws EE_Error |
|
296 | - * @throws InvalidArgumentException |
|
297 | - * @throws InvalidDataTypeException |
|
298 | - * @throws InvalidInterfaceException |
|
299 | - * @throws ReflectionException |
|
300 | - */ |
|
301 | - public static function create_ticket_line_item(EE_Line_Item $total_line_item, EE_Ticket $ticket, $qty = 1) |
|
302 | - { |
|
303 | - $datetimes = $ticket->datetimes(); |
|
304 | - $first_datetime = reset($datetimes); |
|
305 | - $first_datetime_name = esc_html__('Event', 'event_espresso'); |
|
306 | - if ($first_datetime instanceof EE_Datetime && $first_datetime->event() instanceof EE_Event) { |
|
307 | - $first_datetime_name = $first_datetime->event()->name(); |
|
308 | - } |
|
309 | - $event = sprintf(_x('(For %1$s)', '(For Event Name)', 'event_espresso'), $first_datetime_name); |
|
310 | - // get event subtotal line |
|
311 | - $events_sub_total = self::get_event_line_item_for_ticket($total_line_item, $ticket); |
|
312 | - // add $ticket to cart |
|
313 | - $line_item = EE_Line_Item::new_instance(array( |
|
314 | - 'LIN_name' => $ticket->name(), |
|
315 | - 'LIN_desc' => $ticket->description() !== '' ? $ticket->description() . ' ' . $event : $event, |
|
316 | - 'LIN_unit_price' => $ticket->price(), |
|
317 | - 'LIN_quantity' => $qty, |
|
318 | - 'LIN_is_taxable' => $ticket->taxable(), |
|
319 | - 'LIN_order' => count($events_sub_total->children()), |
|
320 | - 'LIN_total' => $ticket->price() * $qty, |
|
321 | - 'LIN_type' => EEM_Line_Item::type_line_item, |
|
322 | - 'OBJ_ID' => $ticket->ID(), |
|
323 | - 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TICKET, |
|
324 | - )); |
|
325 | - $line_item = apply_filters( |
|
326 | - 'FHEE__EEH_Line_Item__create_ticket_line_item__line_item', |
|
327 | - $line_item |
|
328 | - ); |
|
329 | - $events_sub_total->add_child_line_item($line_item); |
|
330 | - // now add the sub-line items |
|
331 | - $running_total_for_ticket = 0; |
|
332 | - foreach ($ticket->prices(array('order_by' => array('PRC_order' => 'ASC'))) as $price) { |
|
333 | - $sign = $price->is_discount() ? -1 : 1; |
|
334 | - $price_total = $price->is_percent() |
|
335 | - ? $running_total_for_ticket * $price->amount() / 100 |
|
336 | - : $price->amount() * $qty; |
|
337 | - $sub_line_item = EE_Line_Item::new_instance(array( |
|
338 | - 'LIN_name' => $price->name(), |
|
339 | - 'LIN_desc' => $price->desc(), |
|
340 | - 'LIN_quantity' => $price->is_percent() ? null : $qty, |
|
341 | - 'LIN_is_taxable' => false, |
|
342 | - 'LIN_order' => $price->order(), |
|
343 | - 'LIN_total' => $sign * $price_total, |
|
344 | - 'LIN_type' => EEM_Line_Item::type_sub_line_item, |
|
345 | - 'OBJ_ID' => $price->ID(), |
|
346 | - 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_PRICE, |
|
347 | - )); |
|
348 | - $sub_line_item = apply_filters( |
|
349 | - 'FHEE__EEH_Line_Item__create_ticket_line_item__sub_line_item', |
|
350 | - $sub_line_item |
|
351 | - ); |
|
352 | - if ($price->is_percent()) { |
|
353 | - $sub_line_item->set_percent($sign * $price->amount()); |
|
354 | - } else { |
|
355 | - $sub_line_item->set_unit_price($sign * $price->amount()); |
|
356 | - } |
|
357 | - $running_total_for_ticket += $price_total; |
|
358 | - $line_item->add_child_line_item($sub_line_item); |
|
359 | - } |
|
360 | - return $line_item; |
|
361 | - } |
|
362 | - |
|
363 | - |
|
364 | - /** |
|
365 | - * Adds the specified item under the pre-tax-sub-total line item. Automatically |
|
366 | - * re-calculates the line item totals and updates the related transaction. But |
|
367 | - * DOES NOT automatically upgrade the transaction's registrations' final prices (which |
|
368 | - * should probably change because of this). |
|
369 | - * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item() |
|
370 | - * after using this, to keep the registration final prices in-sync with the transaction's total. |
|
371 | - * |
|
372 | - * @param EE_Line_Item $total_line_item |
|
373 | - * @param EE_Line_Item $item to be added |
|
374 | - * @return boolean |
|
375 | - * @throws EE_Error |
|
376 | - * @throws InvalidArgumentException |
|
377 | - * @throws InvalidDataTypeException |
|
378 | - * @throws InvalidInterfaceException |
|
379 | - * @throws ReflectionException |
|
380 | - */ |
|
381 | - public static function add_item(EE_Line_Item $total_line_item, EE_Line_Item $item) |
|
382 | - { |
|
383 | - $pre_tax_subtotal = self::get_pre_tax_subtotal($total_line_item); |
|
384 | - if ($pre_tax_subtotal instanceof EE_Line_Item) { |
|
385 | - $success = $pre_tax_subtotal->add_child_line_item($item); |
|
386 | - } else { |
|
387 | - return false; |
|
388 | - } |
|
389 | - $total_line_item->recalculate_total_including_taxes(); |
|
390 | - return $success; |
|
391 | - } |
|
392 | - |
|
393 | - |
|
394 | - /** |
|
395 | - * cancels an existing ticket line item, |
|
396 | - * by decrementing it's quantity by 1 and adding a new "type_cancellation" sub-line-item. |
|
397 | - * ALL totals and subtotals will NEED TO BE UPDATED after performing this action |
|
398 | - * |
|
399 | - * @param EE_Line_Item $ticket_line_item |
|
400 | - * @param int $qty |
|
401 | - * @return bool success |
|
402 | - * @throws EE_Error |
|
403 | - * @throws InvalidArgumentException |
|
404 | - * @throws InvalidDataTypeException |
|
405 | - * @throws InvalidInterfaceException |
|
406 | - * @throws ReflectionException |
|
407 | - */ |
|
408 | - public static function cancel_ticket_line_item(EE_Line_Item $ticket_line_item, $qty = 1) |
|
409 | - { |
|
410 | - // validate incoming line_item |
|
411 | - if ($ticket_line_item->OBJ_type() !== EEM_Line_Item::OBJ_TYPE_TICKET) { |
|
412 | - throw new EE_Error( |
|
413 | - sprintf( |
|
414 | - esc_html__( |
|
415 | - 'The supplied line item must have an Object Type of "Ticket", not %1$s.', |
|
416 | - 'event_espresso' |
|
417 | - ), |
|
418 | - $ticket_line_item->type() |
|
419 | - ) |
|
420 | - ); |
|
421 | - } |
|
422 | - if ($ticket_line_item->quantity() < $qty) { |
|
423 | - throw new EE_Error( |
|
424 | - sprintf( |
|
425 | - esc_html__( |
|
426 | - 'Can not cancel %1$d ticket(s) because the supplied line item has a quantity of %2$d.', |
|
427 | - 'event_espresso' |
|
428 | - ), |
|
429 | - $qty, |
|
430 | - $ticket_line_item->quantity() |
|
431 | - ) |
|
432 | - ); |
|
433 | - } |
|
434 | - // decrement ticket quantity; don't rely on auto-fixing when recalculating totals to do this |
|
435 | - $ticket_line_item->set_quantity($ticket_line_item->quantity() - $qty); |
|
436 | - foreach ($ticket_line_item->children() as $child_line_item) { |
|
437 | - if ($child_line_item->is_sub_line_item() |
|
438 | - && ! $child_line_item->is_percent() |
|
439 | - && ! $child_line_item->is_cancellation() |
|
440 | - ) { |
|
441 | - $child_line_item->set_quantity($child_line_item->quantity() - $qty); |
|
442 | - } |
|
443 | - } |
|
444 | - // get cancellation sub line item |
|
445 | - $cancellation_line_item = EEH_Line_Item::get_descendants_of_type( |
|
446 | - $ticket_line_item, |
|
447 | - EEM_Line_Item::type_cancellation |
|
448 | - ); |
|
449 | - $cancellation_line_item = reset($cancellation_line_item); |
|
450 | - // verify that this ticket was indeed previously cancelled |
|
451 | - if ($cancellation_line_item instanceof EE_Line_Item) { |
|
452 | - // increment cancelled quantity |
|
453 | - $cancellation_line_item->set_quantity($cancellation_line_item->quantity() + $qty); |
|
454 | - } else { |
|
455 | - // create cancellation sub line item |
|
456 | - $cancellation_line_item = EE_Line_Item::new_instance(array( |
|
457 | - 'LIN_name' => esc_html__('Cancellation', 'event_espresso'), |
|
458 | - 'LIN_desc' => sprintf( |
|
459 | - esc_html_x( |
|
460 | - 'Cancelled %1$s : %2$s', |
|
461 | - 'Cancelled Ticket Name : 2015-01-01 11:11', |
|
462 | - 'event_espresso' |
|
463 | - ), |
|
464 | - $ticket_line_item->name(), |
|
465 | - current_time(get_option('date_format') . ' ' . get_option('time_format')) |
|
466 | - ), |
|
467 | - 'LIN_unit_price' => 0, // $ticket_line_item->unit_price() |
|
468 | - 'LIN_quantity' => $qty, |
|
469 | - 'LIN_is_taxable' => $ticket_line_item->is_taxable(), |
|
470 | - 'LIN_order' => count($ticket_line_item->children()), |
|
471 | - 'LIN_total' => 0, // $ticket_line_item->unit_price() |
|
472 | - 'LIN_type' => EEM_Line_Item::type_cancellation, |
|
473 | - )); |
|
474 | - $ticket_line_item->add_child_line_item($cancellation_line_item); |
|
475 | - } |
|
476 | - if ($ticket_line_item->save_this_and_descendants() > 0) { |
|
477 | - // decrement parent line item quantity |
|
478 | - $event_line_item = $ticket_line_item->parent(); |
|
479 | - if ($event_line_item instanceof EE_Line_Item |
|
480 | - && $event_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_EVENT |
|
481 | - ) { |
|
482 | - $event_line_item->set_quantity($event_line_item->quantity() - $qty); |
|
483 | - $event_line_item->save(); |
|
484 | - } |
|
485 | - EEH_Line_Item::get_grand_total_and_recalculate_everything($ticket_line_item); |
|
486 | - return true; |
|
487 | - } |
|
488 | - return false; |
|
489 | - } |
|
490 | - |
|
491 | - |
|
492 | - /** |
|
493 | - * reinstates (un-cancels?) a previously canceled ticket line item, |
|
494 | - * by incrementing it's quantity by 1, and decrementing it's "type_cancellation" sub-line-item. |
|
495 | - * ALL totals and subtotals will NEED TO BE UPDATED after performing this action |
|
496 | - * |
|
497 | - * @param EE_Line_Item $ticket_line_item |
|
498 | - * @param int $qty |
|
499 | - * @return bool success |
|
500 | - * @throws EE_Error |
|
501 | - * @throws InvalidArgumentException |
|
502 | - * @throws InvalidDataTypeException |
|
503 | - * @throws InvalidInterfaceException |
|
504 | - * @throws ReflectionException |
|
505 | - */ |
|
506 | - public static function reinstate_canceled_ticket_line_item(EE_Line_Item $ticket_line_item, $qty = 1) |
|
507 | - { |
|
508 | - // validate incoming line_item |
|
509 | - if ($ticket_line_item->OBJ_type() !== EEM_Line_Item::OBJ_TYPE_TICKET) { |
|
510 | - throw new EE_Error( |
|
511 | - sprintf( |
|
512 | - esc_html__( |
|
513 | - 'The supplied line item must have an Object Type of "Ticket", not %1$s.', |
|
514 | - 'event_espresso' |
|
515 | - ), |
|
516 | - $ticket_line_item->type() |
|
517 | - ) |
|
518 | - ); |
|
519 | - } |
|
520 | - // get cancellation sub line item |
|
521 | - $cancellation_line_item = EEH_Line_Item::get_descendants_of_type( |
|
522 | - $ticket_line_item, |
|
523 | - EEM_Line_Item::type_cancellation |
|
524 | - ); |
|
525 | - $cancellation_line_item = reset($cancellation_line_item); |
|
526 | - // verify that this ticket was indeed previously cancelled |
|
527 | - if (! $cancellation_line_item instanceof EE_Line_Item) { |
|
528 | - return false; |
|
529 | - } |
|
530 | - if ($cancellation_line_item->quantity() > $qty) { |
|
531 | - // decrement cancelled quantity |
|
532 | - $cancellation_line_item->set_quantity($cancellation_line_item->quantity() - $qty); |
|
533 | - } elseif ($cancellation_line_item->quantity() === $qty) { |
|
534 | - // decrement cancelled quantity in case anyone still has the object kicking around |
|
535 | - $cancellation_line_item->set_quantity($cancellation_line_item->quantity() - $qty); |
|
536 | - // delete because quantity will end up as 0 |
|
537 | - $cancellation_line_item->delete(); |
|
538 | - // and attempt to destroy the object, |
|
539 | - // even though PHP won't actually destroy it until it needs the memory |
|
540 | - unset($cancellation_line_item); |
|
541 | - } else { |
|
542 | - // what ?!?! negative quantity ?!?! |
|
543 | - throw new EE_Error( |
|
544 | - sprintf( |
|
545 | - esc_html__( |
|
546 | - 'Can not reinstate %1$d cancelled ticket(s) because the cancelled ticket quantity is only %2$d.', |
|
547 | - 'event_espresso' |
|
548 | - ), |
|
549 | - $qty, |
|
550 | - $cancellation_line_item->quantity() |
|
551 | - ) |
|
552 | - ); |
|
553 | - } |
|
554 | - // increment ticket quantity |
|
555 | - $ticket_line_item->set_quantity($ticket_line_item->quantity() + $qty); |
|
556 | - if ($ticket_line_item->save_this_and_descendants() > 0) { |
|
557 | - // increment parent line item quantity |
|
558 | - $event_line_item = $ticket_line_item->parent(); |
|
559 | - if ($event_line_item instanceof EE_Line_Item |
|
560 | - && $event_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_EVENT |
|
561 | - ) { |
|
562 | - $event_line_item->set_quantity($event_line_item->quantity() + $qty); |
|
563 | - } |
|
564 | - EEH_Line_Item::get_grand_total_and_recalculate_everything($ticket_line_item); |
|
565 | - return true; |
|
566 | - } |
|
567 | - return false; |
|
568 | - } |
|
569 | - |
|
570 | - |
|
571 | - /** |
|
572 | - * calls EEH_Line_Item::find_transaction_grand_total_for_line_item() |
|
573 | - * then EE_Line_Item::recalculate_total_including_taxes() on the result |
|
574 | - * |
|
575 | - * @param EE_Line_Item $line_item |
|
576 | - * @return float |
|
577 | - * @throws EE_Error |
|
578 | - * @throws InvalidArgumentException |
|
579 | - * @throws InvalidDataTypeException |
|
580 | - * @throws InvalidInterfaceException |
|
581 | - * @throws ReflectionException |
|
582 | - */ |
|
583 | - public static function get_grand_total_and_recalculate_everything(EE_Line_Item $line_item) |
|
584 | - { |
|
585 | - $grand_total_line_item = EEH_Line_Item::find_transaction_grand_total_for_line_item($line_item); |
|
586 | - return $grand_total_line_item->recalculate_total_including_taxes(); |
|
587 | - } |
|
588 | - |
|
589 | - |
|
590 | - /** |
|
591 | - * Gets the line item which contains the subtotal of all the items |
|
592 | - * |
|
593 | - * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
594 | - * @return EE_Line_Item |
|
595 | - * @throws EE_Error |
|
596 | - * @throws InvalidArgumentException |
|
597 | - * @throws InvalidDataTypeException |
|
598 | - * @throws InvalidInterfaceException |
|
599 | - * @throws ReflectionException |
|
600 | - */ |
|
601 | - public static function get_pre_tax_subtotal(EE_Line_Item $total_line_item) |
|
602 | - { |
|
603 | - $pre_tax_subtotal = $total_line_item->get_child_line_item('pre-tax-subtotal'); |
|
604 | - return $pre_tax_subtotal instanceof EE_Line_Item |
|
605 | - ? $pre_tax_subtotal |
|
606 | - : self::create_pre_tax_subtotal($total_line_item); |
|
607 | - } |
|
608 | - |
|
609 | - |
|
610 | - /** |
|
611 | - * Gets the line item for the taxes subtotal |
|
612 | - * |
|
613 | - * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
614 | - * @return EE_Line_Item |
|
615 | - * @throws EE_Error |
|
616 | - * @throws InvalidArgumentException |
|
617 | - * @throws InvalidDataTypeException |
|
618 | - * @throws InvalidInterfaceException |
|
619 | - * @throws ReflectionException |
|
620 | - */ |
|
621 | - public static function get_taxes_subtotal(EE_Line_Item $total_line_item) |
|
622 | - { |
|
623 | - $taxes = $total_line_item->get_child_line_item('taxes'); |
|
624 | - return $taxes ? $taxes : self::create_taxes_subtotal($total_line_item); |
|
625 | - } |
|
626 | - |
|
627 | - |
|
628 | - /** |
|
629 | - * sets the TXN ID on an EE_Line_Item if passed a valid EE_Transaction object |
|
630 | - * |
|
631 | - * @param EE_Line_Item $line_item |
|
632 | - * @param EE_Transaction $transaction |
|
633 | - * @return void |
|
634 | - * @throws EE_Error |
|
635 | - * @throws InvalidArgumentException |
|
636 | - * @throws InvalidDataTypeException |
|
637 | - * @throws InvalidInterfaceException |
|
638 | - * @throws ReflectionException |
|
639 | - */ |
|
640 | - public static function set_TXN_ID(EE_Line_Item $line_item, $transaction = null) |
|
641 | - { |
|
642 | - if ($transaction) { |
|
643 | - /** @type EEM_Transaction $EEM_Transaction */ |
|
644 | - $EEM_Transaction = EE_Registry::instance()->load_model('Transaction'); |
|
645 | - $TXN_ID = $EEM_Transaction->ensure_is_ID($transaction); |
|
646 | - $line_item->set_TXN_ID($TXN_ID); |
|
647 | - } |
|
648 | - } |
|
649 | - |
|
650 | - |
|
651 | - /** |
|
652 | - * Creates a new default total line item for the transaction, |
|
653 | - * and its tickets subtotal and taxes subtotal line items (and adds the |
|
654 | - * existing taxes as children of the taxes subtotal line item) |
|
655 | - * |
|
656 | - * @param EE_Transaction $transaction |
|
657 | - * @return EE_Line_Item of type total |
|
658 | - * @throws EE_Error |
|
659 | - * @throws InvalidArgumentException |
|
660 | - * @throws InvalidDataTypeException |
|
661 | - * @throws InvalidInterfaceException |
|
662 | - * @throws ReflectionException |
|
663 | - */ |
|
664 | - public static function create_total_line_item($transaction = null) |
|
665 | - { |
|
666 | - $total_line_item = EE_Line_Item::new_instance(array( |
|
667 | - 'LIN_code' => 'total', |
|
668 | - 'LIN_name' => esc_html__('Grand Total', 'event_espresso'), |
|
669 | - 'LIN_type' => EEM_Line_Item::type_total, |
|
670 | - 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TRANSACTION, |
|
671 | - )); |
|
672 | - $total_line_item = apply_filters( |
|
673 | - 'FHEE__EEH_Line_Item__create_total_line_item__total_line_item', |
|
674 | - $total_line_item |
|
675 | - ); |
|
676 | - self::set_TXN_ID($total_line_item, $transaction); |
|
677 | - self::create_pre_tax_subtotal($total_line_item, $transaction); |
|
678 | - self::create_taxes_subtotal($total_line_item, $transaction); |
|
679 | - return $total_line_item; |
|
680 | - } |
|
681 | - |
|
682 | - |
|
683 | - /** |
|
684 | - * Creates a default items subtotal line item |
|
685 | - * |
|
686 | - * @param EE_Line_Item $total_line_item |
|
687 | - * @param EE_Transaction $transaction |
|
688 | - * @return EE_Line_Item |
|
689 | - * @throws EE_Error |
|
690 | - * @throws InvalidArgumentException |
|
691 | - * @throws InvalidDataTypeException |
|
692 | - * @throws InvalidInterfaceException |
|
693 | - * @throws ReflectionException |
|
694 | - */ |
|
695 | - protected static function create_pre_tax_subtotal(EE_Line_Item $total_line_item, $transaction = null) |
|
696 | - { |
|
697 | - $pre_tax_line_item = EE_Line_Item::new_instance(array( |
|
698 | - 'LIN_code' => 'pre-tax-subtotal', |
|
699 | - 'LIN_name' => esc_html__('Pre-Tax Subtotal', 'event_espresso'), |
|
700 | - 'LIN_type' => EEM_Line_Item::type_sub_total, |
|
701 | - )); |
|
702 | - $pre_tax_line_item = apply_filters( |
|
703 | - 'FHEE__EEH_Line_Item__create_pre_tax_subtotal__pre_tax_line_item', |
|
704 | - $pre_tax_line_item |
|
705 | - ); |
|
706 | - self::set_TXN_ID($pre_tax_line_item, $transaction); |
|
707 | - $total_line_item->add_child_line_item($pre_tax_line_item); |
|
708 | - self::create_event_subtotal($pre_tax_line_item, $transaction); |
|
709 | - return $pre_tax_line_item; |
|
710 | - } |
|
711 | - |
|
712 | - |
|
713 | - /** |
|
714 | - * Creates a line item for the taxes subtotal and finds all the tax prices |
|
715 | - * and applies taxes to it |
|
716 | - * |
|
717 | - * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
718 | - * @param EE_Transaction $transaction |
|
719 | - * @return EE_Line_Item |
|
720 | - * @throws EE_Error |
|
721 | - * @throws InvalidArgumentException |
|
722 | - * @throws InvalidDataTypeException |
|
723 | - * @throws InvalidInterfaceException |
|
724 | - * @throws ReflectionException |
|
725 | - */ |
|
726 | - protected static function create_taxes_subtotal(EE_Line_Item $total_line_item, $transaction = null) |
|
727 | - { |
|
728 | - $tax_line_item = EE_Line_Item::new_instance(array( |
|
729 | - 'LIN_code' => 'taxes', |
|
730 | - 'LIN_name' => esc_html__('Taxes', 'event_espresso'), |
|
731 | - 'LIN_type' => EEM_Line_Item::type_tax_sub_total, |
|
732 | - 'LIN_order' => 1000,// this should always come last |
|
733 | - )); |
|
734 | - $tax_line_item = apply_filters( |
|
735 | - 'FHEE__EEH_Line_Item__create_taxes_subtotal__tax_line_item', |
|
736 | - $tax_line_item |
|
737 | - ); |
|
738 | - self::set_TXN_ID($tax_line_item, $transaction); |
|
739 | - $total_line_item->add_child_line_item($tax_line_item); |
|
740 | - // and lastly, add the actual taxes |
|
741 | - self::apply_taxes($total_line_item); |
|
742 | - return $tax_line_item; |
|
743 | - } |
|
744 | - |
|
745 | - |
|
746 | - /** |
|
747 | - * Creates a default items subtotal line item |
|
748 | - * |
|
749 | - * @param EE_Line_Item $pre_tax_line_item |
|
750 | - * @param EE_Transaction $transaction |
|
751 | - * @param EE_Event $event |
|
752 | - * @return EE_Line_Item |
|
753 | - * @throws EE_Error |
|
754 | - * @throws InvalidArgumentException |
|
755 | - * @throws InvalidDataTypeException |
|
756 | - * @throws InvalidInterfaceException |
|
757 | - * @throws ReflectionException |
|
758 | - */ |
|
759 | - public static function create_event_subtotal(EE_Line_Item $pre_tax_line_item, $transaction = null, $event = null) |
|
760 | - { |
|
761 | - $event_line_item = EE_Line_Item::new_instance(array( |
|
762 | - 'LIN_code' => self::get_event_code($event), |
|
763 | - 'LIN_name' => self::get_event_name($event), |
|
764 | - 'LIN_desc' => self::get_event_desc($event), |
|
765 | - 'LIN_type' => EEM_Line_Item::type_sub_total, |
|
766 | - 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_EVENT, |
|
767 | - 'OBJ_ID' => $event instanceof EE_Event ? $event->ID() : 0, |
|
768 | - )); |
|
769 | - $event_line_item = apply_filters( |
|
770 | - 'FHEE__EEH_Line_Item__create_event_subtotal__event_line_item', |
|
771 | - $event_line_item |
|
772 | - ); |
|
773 | - self::set_TXN_ID($event_line_item, $transaction); |
|
774 | - $pre_tax_line_item->add_child_line_item($event_line_item); |
|
775 | - return $event_line_item; |
|
776 | - } |
|
777 | - |
|
778 | - |
|
779 | - /** |
|
780 | - * Gets what the event ticket's code SHOULD be |
|
781 | - * |
|
782 | - * @param EE_Event $event |
|
783 | - * @return string |
|
784 | - * @throws EE_Error |
|
785 | - */ |
|
786 | - public static function get_event_code($event) |
|
787 | - { |
|
788 | - return 'event-' . ($event instanceof EE_Event ? $event->ID() : '0'); |
|
789 | - } |
|
790 | - |
|
791 | - |
|
792 | - /** |
|
793 | - * Gets the event name |
|
794 | - * |
|
795 | - * @param EE_Event $event |
|
796 | - * @return string |
|
797 | - * @throws EE_Error |
|
798 | - */ |
|
799 | - public static function get_event_name($event) |
|
800 | - { |
|
801 | - return $event instanceof EE_Event |
|
802 | - ? mb_substr($event->name(), 0, 245) |
|
803 | - : esc_html__('Event', 'event_espresso'); |
|
804 | - } |
|
805 | - |
|
806 | - |
|
807 | - /** |
|
808 | - * Gets the event excerpt |
|
809 | - * |
|
810 | - * @param EE_Event $event |
|
811 | - * @return string |
|
812 | - * @throws EE_Error |
|
813 | - */ |
|
814 | - public static function get_event_desc($event) |
|
815 | - { |
|
816 | - return $event instanceof EE_Event ? $event->short_description() : ''; |
|
817 | - } |
|
818 | - |
|
819 | - |
|
820 | - /** |
|
821 | - * Given the grand total line item and a ticket, finds the event sub-total |
|
822 | - * line item the ticket's purchase should be added onto |
|
823 | - * |
|
824 | - * @access public |
|
825 | - * @param EE_Line_Item $grand_total the grand total line item |
|
826 | - * @param EE_Ticket $ticket |
|
827 | - * @return EE_Line_Item |
|
828 | - * @throws EE_Error |
|
829 | - * @throws InvalidArgumentException |
|
830 | - * @throws InvalidDataTypeException |
|
831 | - * @throws InvalidInterfaceException |
|
832 | - * @throws ReflectionException |
|
833 | - */ |
|
834 | - public static function get_event_line_item_for_ticket(EE_Line_Item $grand_total, EE_Ticket $ticket) |
|
835 | - { |
|
836 | - $first_datetime = $ticket->first_datetime(); |
|
837 | - if (! $first_datetime instanceof EE_Datetime) { |
|
838 | - throw new EE_Error( |
|
839 | - sprintf( |
|
840 | - __('The supplied ticket (ID %d) has no datetimes', 'event_espresso'), |
|
841 | - $ticket->ID() |
|
842 | - ) |
|
843 | - ); |
|
844 | - } |
|
845 | - $event = $first_datetime->event(); |
|
846 | - if (! $event instanceof EE_Event) { |
|
847 | - throw new EE_Error( |
|
848 | - sprintf( |
|
849 | - esc_html__( |
|
850 | - 'The supplied ticket (ID %d) has no event data associated with it.', |
|
851 | - 'event_espresso' |
|
852 | - ), |
|
853 | - $ticket->ID() |
|
854 | - ) |
|
855 | - ); |
|
856 | - } |
|
857 | - $events_sub_total = EEH_Line_Item::get_event_line_item($grand_total, $event); |
|
858 | - if (! $events_sub_total instanceof EE_Line_Item) { |
|
859 | - throw new EE_Error( |
|
860 | - sprintf( |
|
861 | - esc_html__( |
|
862 | - 'There is no events sub-total for ticket %s on total line item %d', |
|
863 | - 'event_espresso' |
|
864 | - ), |
|
865 | - $ticket->ID(), |
|
866 | - $grand_total->ID() |
|
867 | - ) |
|
868 | - ); |
|
869 | - } |
|
870 | - return $events_sub_total; |
|
871 | - } |
|
872 | - |
|
873 | - |
|
874 | - /** |
|
875 | - * Gets the event line item |
|
876 | - * |
|
877 | - * @param EE_Line_Item $grand_total |
|
878 | - * @param EE_Event $event |
|
879 | - * @return EE_Line_Item for the event subtotal which is a child of $grand_total |
|
880 | - * @throws EE_Error |
|
881 | - * @throws InvalidArgumentException |
|
882 | - * @throws InvalidDataTypeException |
|
883 | - * @throws InvalidInterfaceException |
|
884 | - * @throws ReflectionException |
|
885 | - */ |
|
886 | - public static function get_event_line_item(EE_Line_Item $grand_total, $event) |
|
887 | - { |
|
888 | - /** @type EE_Event $event */ |
|
889 | - $event = EEM_Event::instance()->ensure_is_obj($event, true); |
|
890 | - $event_line_item = null; |
|
891 | - $found = false; |
|
892 | - foreach (EEH_Line_Item::get_event_subtotals($grand_total) as $event_line_item) { |
|
893 | - // default event subtotal, we should only ever find this the first time this method is called |
|
894 | - if (! $event_line_item->OBJ_ID()) { |
|
895 | - // let's use this! but first... set the event details |
|
896 | - EEH_Line_Item::set_event_subtotal_details($event_line_item, $event); |
|
897 | - $found = true; |
|
898 | - break; |
|
899 | - } |
|
900 | - if ($event_line_item->OBJ_ID() === $event->ID()) { |
|
901 | - // found existing line item for this event in the cart, so break out of loop and use this one |
|
902 | - $found = true; |
|
903 | - break; |
|
904 | - } |
|
905 | - } |
|
906 | - if (! $found) { |
|
907 | - // there is no event sub-total yet, so add it |
|
908 | - $pre_tax_subtotal = EEH_Line_Item::get_pre_tax_subtotal($grand_total); |
|
909 | - // create a new "event" subtotal below that |
|
910 | - $event_line_item = EEH_Line_Item::create_event_subtotal($pre_tax_subtotal, null, $event); |
|
911 | - // and set the event details |
|
912 | - EEH_Line_Item::set_event_subtotal_details($event_line_item, $event); |
|
913 | - } |
|
914 | - return $event_line_item; |
|
915 | - } |
|
916 | - |
|
917 | - |
|
918 | - /** |
|
919 | - * Creates a default items subtotal line item |
|
920 | - * |
|
921 | - * @param EE_Line_Item $event_line_item |
|
922 | - * @param EE_Event $event |
|
923 | - * @param EE_Transaction $transaction |
|
924 | - * @return void |
|
925 | - * @throws EE_Error |
|
926 | - * @throws InvalidArgumentException |
|
927 | - * @throws InvalidDataTypeException |
|
928 | - * @throws InvalidInterfaceException |
|
929 | - * @throws ReflectionException |
|
930 | - */ |
|
931 | - public static function set_event_subtotal_details( |
|
932 | - EE_Line_Item $event_line_item, |
|
933 | - EE_Event $event, |
|
934 | - $transaction = null |
|
935 | - ) { |
|
936 | - if ($event instanceof EE_Event) { |
|
937 | - $event_line_item->set_code(self::get_event_code($event)); |
|
938 | - $event_line_item->set_name(self::get_event_name($event)); |
|
939 | - $event_line_item->set_desc(self::get_event_desc($event)); |
|
940 | - $event_line_item->set_OBJ_ID($event->ID()); |
|
941 | - } |
|
942 | - self::set_TXN_ID($event_line_item, $transaction); |
|
943 | - } |
|
944 | - |
|
945 | - |
|
946 | - /** |
|
947 | - * Finds what taxes should apply, adds them as tax line items under the taxes sub-total, |
|
948 | - * and recalculates the taxes sub-total and the grand total. Resets the taxes, so |
|
949 | - * any old taxes are removed |
|
950 | - * |
|
951 | - * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
952 | - * @param bool $update_txn_status |
|
953 | - * @return bool |
|
954 | - * @throws EE_Error |
|
955 | - * @throws InvalidArgumentException |
|
956 | - * @throws InvalidDataTypeException |
|
957 | - * @throws InvalidInterfaceException |
|
958 | - * @throws ReflectionException |
|
959 | - * @throws RuntimeException |
|
960 | - */ |
|
961 | - public static function apply_taxes(EE_Line_Item $total_line_item, $update_txn_status = false) |
|
962 | - { |
|
963 | - /** @type EEM_Price $EEM_Price */ |
|
964 | - $EEM_Price = EE_Registry::instance()->load_model('Price'); |
|
965 | - // get array of taxes via Price Model |
|
966 | - $ordered_taxes = $EEM_Price->get_all_prices_that_are_taxes(); |
|
967 | - ksort($ordered_taxes); |
|
968 | - $taxes_line_item = self::get_taxes_subtotal($total_line_item); |
|
969 | - // just to be safe, remove its old tax line items |
|
970 | - $deleted = $taxes_line_item->delete_children_line_items(); |
|
971 | - $updates = false; |
|
972 | - // loop thru taxes |
|
973 | - foreach ($ordered_taxes as $order => $taxes) { |
|
974 | - foreach ($taxes as $tax) { |
|
975 | - if ($tax instanceof EE_Price) { |
|
976 | - $tax_line_item = EE_Line_Item::new_instance( |
|
977 | - array( |
|
978 | - 'LIN_name' => $tax->name(), |
|
979 | - 'LIN_desc' => $tax->desc(), |
|
980 | - 'LIN_percent' => $tax->amount(), |
|
981 | - 'LIN_is_taxable' => false, |
|
982 | - 'LIN_order' => $order, |
|
983 | - 'LIN_total' => 0, |
|
984 | - 'LIN_type' => EEM_Line_Item::type_tax, |
|
985 | - 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_PRICE, |
|
986 | - 'OBJ_ID' => $tax->ID(), |
|
987 | - ) |
|
988 | - ); |
|
989 | - $tax_line_item = apply_filters( |
|
990 | - 'FHEE__EEH_Line_Item__apply_taxes__tax_line_item', |
|
991 | - $tax_line_item |
|
992 | - ); |
|
993 | - $updates = $taxes_line_item->add_child_line_item($tax_line_item) ? |
|
994 | - true : |
|
995 | - $updates; |
|
996 | - } |
|
997 | - } |
|
998 | - } |
|
999 | - // only recalculate totals if something changed |
|
1000 | - if ($deleted || $updates) { |
|
1001 | - $total_line_item->recalculate_total_including_taxes($update_txn_status); |
|
1002 | - return true; |
|
1003 | - } |
|
1004 | - return false; |
|
1005 | - } |
|
1006 | - |
|
1007 | - |
|
1008 | - /** |
|
1009 | - * Ensures that taxes have been applied to the order, if not applies them. |
|
1010 | - * Returns the total amount of tax |
|
1011 | - * |
|
1012 | - * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
1013 | - * @return float |
|
1014 | - * @throws EE_Error |
|
1015 | - * @throws InvalidArgumentException |
|
1016 | - * @throws InvalidDataTypeException |
|
1017 | - * @throws InvalidInterfaceException |
|
1018 | - * @throws ReflectionException |
|
1019 | - */ |
|
1020 | - public static function ensure_taxes_applied($total_line_item) |
|
1021 | - { |
|
1022 | - $taxes_subtotal = self::get_taxes_subtotal($total_line_item); |
|
1023 | - if (! $taxes_subtotal->children()) { |
|
1024 | - self::apply_taxes($total_line_item); |
|
1025 | - } |
|
1026 | - return $taxes_subtotal->total(); |
|
1027 | - } |
|
1028 | - |
|
1029 | - |
|
1030 | - /** |
|
1031 | - * Deletes ALL children of the passed line item |
|
1032 | - * |
|
1033 | - * @param EE_Line_Item $parent_line_item |
|
1034 | - * @return bool |
|
1035 | - * @throws EE_Error |
|
1036 | - * @throws InvalidArgumentException |
|
1037 | - * @throws InvalidDataTypeException |
|
1038 | - * @throws InvalidInterfaceException |
|
1039 | - * @throws ReflectionException |
|
1040 | - */ |
|
1041 | - public static function delete_all_child_items(EE_Line_Item $parent_line_item) |
|
1042 | - { |
|
1043 | - $deleted = 0; |
|
1044 | - foreach ($parent_line_item->children() as $child_line_item) { |
|
1045 | - if ($child_line_item instanceof EE_Line_Item) { |
|
1046 | - $deleted += EEH_Line_Item::delete_all_child_items($child_line_item); |
|
1047 | - if ($child_line_item->ID()) { |
|
1048 | - $child_line_item->delete(); |
|
1049 | - unset($child_line_item); |
|
1050 | - } else { |
|
1051 | - $parent_line_item->delete_child_line_item($child_line_item->code()); |
|
1052 | - } |
|
1053 | - $deleted++; |
|
1054 | - } |
|
1055 | - } |
|
1056 | - return $deleted; |
|
1057 | - } |
|
1058 | - |
|
1059 | - |
|
1060 | - /** |
|
1061 | - * Deletes the line items as indicated by the line item code(s) provided, |
|
1062 | - * regardless of where they're found in the line item tree. Automatically |
|
1063 | - * re-calculates the line item totals and updates the related transaction. But |
|
1064 | - * DOES NOT automatically upgrade the transaction's registrations' final prices (which |
|
1065 | - * should probably change because of this). |
|
1066 | - * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item() |
|
1067 | - * after using this, to keep the registration final prices in-sync with the transaction's total. |
|
1068 | - * |
|
1069 | - * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
1070 | - * @param array|bool|string $line_item_codes |
|
1071 | - * @return int number of items successfully removed |
|
1072 | - * @throws EE_Error |
|
1073 | - */ |
|
1074 | - public static function delete_items(EE_Line_Item $total_line_item, $line_item_codes = false) |
|
1075 | - { |
|
1076 | - |
|
1077 | - if ($total_line_item->type() !== EEM_Line_Item::type_total) { |
|
1078 | - EE_Error::doing_it_wrong( |
|
1079 | - 'EEH_Line_Item::delete_items', |
|
1080 | - esc_html__( |
|
1081 | - 'This static method should only be called with a TOTAL line item, otherwise we won\'t recalculate the totals correctly', |
|
1082 | - 'event_espresso' |
|
1083 | - ), |
|
1084 | - '4.6.18' |
|
1085 | - ); |
|
1086 | - } |
|
1087 | - do_action('AHEE_log', __FILE__, __FUNCTION__, ''); |
|
1088 | - |
|
1089 | - // check if only a single line_item_id was passed |
|
1090 | - if (! empty($line_item_codes) && ! is_array($line_item_codes)) { |
|
1091 | - // place single line_item_id in an array to appear as multiple line_item_ids |
|
1092 | - $line_item_codes = array($line_item_codes); |
|
1093 | - } |
|
1094 | - $removals = 0; |
|
1095 | - // cycle thru line_item_ids |
|
1096 | - foreach ($line_item_codes as $line_item_id) { |
|
1097 | - $removals += $total_line_item->delete_child_line_item($line_item_id); |
|
1098 | - } |
|
1099 | - |
|
1100 | - if ($removals > 0) { |
|
1101 | - $total_line_item->recalculate_taxes_and_tax_total(); |
|
1102 | - return $removals; |
|
1103 | - } else { |
|
1104 | - return false; |
|
1105 | - } |
|
1106 | - } |
|
1107 | - |
|
1108 | - |
|
1109 | - /** |
|
1110 | - * Overwrites the previous tax by clearing out the old taxes, and creates a new |
|
1111 | - * tax and updates the total line item accordingly |
|
1112 | - * |
|
1113 | - * @param EE_Line_Item $total_line_item |
|
1114 | - * @param float $amount |
|
1115 | - * @param string $name |
|
1116 | - * @param string $description |
|
1117 | - * @param string $code |
|
1118 | - * @param boolean $add_to_existing_line_item |
|
1119 | - * if true, and a duplicate line item with the same code is found, |
|
1120 | - * $amount will be added onto it; otherwise will simply set the taxes to match $amount |
|
1121 | - * @return EE_Line_Item the new tax line item created |
|
1122 | - * @throws EE_Error |
|
1123 | - * @throws InvalidArgumentException |
|
1124 | - * @throws InvalidDataTypeException |
|
1125 | - * @throws InvalidInterfaceException |
|
1126 | - * @throws ReflectionException |
|
1127 | - */ |
|
1128 | - public static function set_total_tax_to( |
|
1129 | - EE_Line_Item $total_line_item, |
|
1130 | - $amount, |
|
1131 | - $name = null, |
|
1132 | - $description = null, |
|
1133 | - $code = null, |
|
1134 | - $add_to_existing_line_item = false |
|
1135 | - ) { |
|
1136 | - $tax_subtotal = self::get_taxes_subtotal($total_line_item); |
|
1137 | - $taxable_total = $total_line_item->taxable_total(); |
|
1138 | - |
|
1139 | - if ($add_to_existing_line_item) { |
|
1140 | - $new_tax = $tax_subtotal->get_child_line_item($code); |
|
1141 | - EEM_Line_Item::instance()->delete( |
|
1142 | - array(array('LIN_code' => array('!=', $code), 'LIN_parent' => $tax_subtotal->ID())) |
|
1143 | - ); |
|
1144 | - } else { |
|
1145 | - $new_tax = null; |
|
1146 | - $tax_subtotal->delete_children_line_items(); |
|
1147 | - } |
|
1148 | - if ($new_tax) { |
|
1149 | - $new_tax->set_total($new_tax->total() + $amount); |
|
1150 | - $new_tax->set_percent($taxable_total ? $new_tax->total() / $taxable_total * 100 : 0); |
|
1151 | - } else { |
|
1152 | - // no existing tax item. Create it |
|
1153 | - $new_tax = EE_Line_Item::new_instance(array( |
|
1154 | - 'TXN_ID' => $total_line_item->TXN_ID(), |
|
1155 | - 'LIN_name' => $name ? $name : esc_html__('Tax', 'event_espresso'), |
|
1156 | - 'LIN_desc' => $description ? $description : '', |
|
1157 | - 'LIN_percent' => $taxable_total ? ($amount / $taxable_total * 100) : 0, |
|
1158 | - 'LIN_total' => $amount, |
|
1159 | - 'LIN_parent' => $tax_subtotal->ID(), |
|
1160 | - 'LIN_type' => EEM_Line_Item::type_tax, |
|
1161 | - 'LIN_code' => $code, |
|
1162 | - )); |
|
1163 | - } |
|
1164 | - |
|
1165 | - $new_tax = apply_filters( |
|
1166 | - 'FHEE__EEH_Line_Item__set_total_tax_to__new_tax_subtotal', |
|
1167 | - $new_tax, |
|
1168 | - $total_line_item |
|
1169 | - ); |
|
1170 | - $new_tax->save(); |
|
1171 | - $tax_subtotal->set_total($new_tax->total()); |
|
1172 | - $tax_subtotal->save(); |
|
1173 | - $total_line_item->recalculate_total_including_taxes(); |
|
1174 | - return $new_tax; |
|
1175 | - } |
|
1176 | - |
|
1177 | - |
|
1178 | - /** |
|
1179 | - * Makes all the line items which are children of $line_item taxable (or not). |
|
1180 | - * Does NOT save the line items |
|
1181 | - * |
|
1182 | - * @param EE_Line_Item $line_item |
|
1183 | - * @param boolean $taxable |
|
1184 | - * @param string $code_substring_for_whitelist if this string is part of the line item's code |
|
1185 | - * it will be whitelisted (ie, except from becoming taxable) |
|
1186 | - * @throws EE_Error |
|
1187 | - */ |
|
1188 | - public static function set_line_items_taxable( |
|
1189 | - EE_Line_Item $line_item, |
|
1190 | - $taxable = true, |
|
1191 | - $code_substring_for_whitelist = null |
|
1192 | - ) { |
|
1193 | - $whitelisted = false; |
|
1194 | - if ($code_substring_for_whitelist !== null) { |
|
1195 | - $whitelisted = strpos($line_item->code(), $code_substring_for_whitelist) !== false; |
|
1196 | - } |
|
1197 | - if (! $whitelisted && $line_item->is_line_item()) { |
|
1198 | - $line_item->set_is_taxable($taxable); |
|
1199 | - } |
|
1200 | - foreach ($line_item->children() as $child_line_item) { |
|
1201 | - EEH_Line_Item::set_line_items_taxable( |
|
1202 | - $child_line_item, |
|
1203 | - $taxable, |
|
1204 | - $code_substring_for_whitelist |
|
1205 | - ); |
|
1206 | - } |
|
1207 | - } |
|
1208 | - |
|
1209 | - |
|
1210 | - /** |
|
1211 | - * Gets all descendants that are event subtotals |
|
1212 | - * |
|
1213 | - * @uses EEH_Line_Item::get_subtotals_of_object_type() |
|
1214 | - * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1215 | - * @return EE_Line_Item[] |
|
1216 | - * @throws EE_Error |
|
1217 | - */ |
|
1218 | - public static function get_event_subtotals(EE_Line_Item $parent_line_item) |
|
1219 | - { |
|
1220 | - return self::get_subtotals_of_object_type($parent_line_item, EEM_Line_Item::OBJ_TYPE_EVENT); |
|
1221 | - } |
|
1222 | - |
|
1223 | - |
|
1224 | - /** |
|
1225 | - * Gets all descendants subtotals that match the supplied object type |
|
1226 | - * |
|
1227 | - * @uses EEH_Line_Item::_get_descendants_by_type_and_object_type() |
|
1228 | - * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1229 | - * @param string $obj_type |
|
1230 | - * @return EE_Line_Item[] |
|
1231 | - * @throws EE_Error |
|
1232 | - */ |
|
1233 | - public static function get_subtotals_of_object_type(EE_Line_Item $parent_line_item, $obj_type = '') |
|
1234 | - { |
|
1235 | - return self::_get_descendants_by_type_and_object_type( |
|
1236 | - $parent_line_item, |
|
1237 | - EEM_Line_Item::type_sub_total, |
|
1238 | - $obj_type |
|
1239 | - ); |
|
1240 | - } |
|
1241 | - |
|
1242 | - |
|
1243 | - /** |
|
1244 | - * Gets all descendants that are tickets |
|
1245 | - * |
|
1246 | - * @uses EEH_Line_Item::get_line_items_of_object_type() |
|
1247 | - * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1248 | - * @return EE_Line_Item[] |
|
1249 | - * @throws EE_Error |
|
1250 | - */ |
|
1251 | - public static function get_ticket_line_items(EE_Line_Item $parent_line_item) |
|
1252 | - { |
|
1253 | - return self::get_line_items_of_object_type( |
|
1254 | - $parent_line_item, |
|
1255 | - EEM_Line_Item::OBJ_TYPE_TICKET |
|
1256 | - ); |
|
1257 | - } |
|
1258 | - |
|
1259 | - |
|
1260 | - /** |
|
1261 | - * Gets all descendants subtotals that match the supplied object type |
|
1262 | - * |
|
1263 | - * @uses EEH_Line_Item::_get_descendants_by_type_and_object_type() |
|
1264 | - * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1265 | - * @param string $obj_type |
|
1266 | - * @return EE_Line_Item[] |
|
1267 | - * @throws EE_Error |
|
1268 | - */ |
|
1269 | - public static function get_line_items_of_object_type(EE_Line_Item $parent_line_item, $obj_type = '') |
|
1270 | - { |
|
1271 | - return self::_get_descendants_by_type_and_object_type( |
|
1272 | - $parent_line_item, |
|
1273 | - EEM_Line_Item::type_line_item, |
|
1274 | - $obj_type |
|
1275 | - ); |
|
1276 | - } |
|
1277 | - |
|
1278 | - |
|
1279 | - /** |
|
1280 | - * Gets all the descendants (ie, children or children of children etc) that are of the type 'tax' |
|
1281 | - * |
|
1282 | - * @uses EEH_Line_Item::get_descendants_of_type() |
|
1283 | - * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1284 | - * @return EE_Line_Item[] |
|
1285 | - * @throws EE_Error |
|
1286 | - */ |
|
1287 | - public static function get_tax_descendants(EE_Line_Item $parent_line_item) |
|
1288 | - { |
|
1289 | - return EEH_Line_Item::get_descendants_of_type( |
|
1290 | - $parent_line_item, |
|
1291 | - EEM_Line_Item::type_tax |
|
1292 | - ); |
|
1293 | - } |
|
1294 | - |
|
1295 | - |
|
1296 | - /** |
|
1297 | - * Gets all the real items purchased which are children of this item |
|
1298 | - * |
|
1299 | - * @uses EEH_Line_Item::get_descendants_of_type() |
|
1300 | - * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1301 | - * @return EE_Line_Item[] |
|
1302 | - * @throws EE_Error |
|
1303 | - */ |
|
1304 | - public static function get_line_item_descendants(EE_Line_Item $parent_line_item) |
|
1305 | - { |
|
1306 | - return EEH_Line_Item::get_descendants_of_type( |
|
1307 | - $parent_line_item, |
|
1308 | - EEM_Line_Item::type_line_item |
|
1309 | - ); |
|
1310 | - } |
|
1311 | - |
|
1312 | - |
|
1313 | - /** |
|
1314 | - * Gets all descendants of supplied line item that match the supplied line item type |
|
1315 | - * |
|
1316 | - * @uses EEH_Line_Item::_get_descendants_by_type_and_object_type() |
|
1317 | - * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1318 | - * @param string $line_item_type one of the EEM_Line_Item constants |
|
1319 | - * @return EE_Line_Item[] |
|
1320 | - * @throws EE_Error |
|
1321 | - */ |
|
1322 | - public static function get_descendants_of_type(EE_Line_Item $parent_line_item, $line_item_type) |
|
1323 | - { |
|
1324 | - return self::_get_descendants_by_type_and_object_type( |
|
1325 | - $parent_line_item, |
|
1326 | - $line_item_type, |
|
1327 | - null |
|
1328 | - ); |
|
1329 | - } |
|
1330 | - |
|
1331 | - |
|
1332 | - /** |
|
1333 | - * Gets all descendants of supplied line item that match the supplied line item type and possibly the object type |
|
1334 | - * as well |
|
1335 | - * |
|
1336 | - * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1337 | - * @param string $line_item_type one of the EEM_Line_Item constants |
|
1338 | - * @param string | NULL $obj_type object model class name (minus prefix) or NULL to ignore object type when |
|
1339 | - * searching |
|
1340 | - * @return EE_Line_Item[] |
|
1341 | - * @throws EE_Error |
|
1342 | - */ |
|
1343 | - protected static function _get_descendants_by_type_and_object_type( |
|
1344 | - EE_Line_Item $parent_line_item, |
|
1345 | - $line_item_type, |
|
1346 | - $obj_type = null |
|
1347 | - ) { |
|
1348 | - $objects = array(); |
|
1349 | - foreach ($parent_line_item->children() as $child_line_item) { |
|
1350 | - if ($child_line_item instanceof EE_Line_Item) { |
|
1351 | - if ($child_line_item->type() === $line_item_type |
|
1352 | - && ( |
|
1353 | - $child_line_item->OBJ_type() === $obj_type || $obj_type === null |
|
1354 | - ) |
|
1355 | - ) { |
|
1356 | - $objects[] = $child_line_item; |
|
1357 | - } else { |
|
1358 | - // go-through-all-its children looking for more matches |
|
1359 | - $objects = array_merge( |
|
1360 | - $objects, |
|
1361 | - self::_get_descendants_by_type_and_object_type( |
|
1362 | - $child_line_item, |
|
1363 | - $line_item_type, |
|
1364 | - $obj_type |
|
1365 | - ) |
|
1366 | - ); |
|
1367 | - } |
|
1368 | - } |
|
1369 | - } |
|
1370 | - return $objects; |
|
1371 | - } |
|
1372 | - |
|
1373 | - |
|
1374 | - /** |
|
1375 | - * Gets all descendants subtotals that match the supplied object type |
|
1376 | - * |
|
1377 | - * @uses EEH_Line_Item::_get_descendants_by_type_and_object_type() |
|
1378 | - * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1379 | - * @param string $OBJ_type object type (like Event) |
|
1380 | - * @param array $OBJ_IDs array of OBJ_IDs |
|
1381 | - * @return EE_Line_Item[] |
|
1382 | - * @throws EE_Error |
|
1383 | - */ |
|
1384 | - public static function get_line_items_by_object_type_and_IDs( |
|
1385 | - EE_Line_Item $parent_line_item, |
|
1386 | - $OBJ_type = '', |
|
1387 | - $OBJ_IDs = array() |
|
1388 | - ) { |
|
1389 | - return self::_get_descendants_by_object_type_and_object_ID( |
|
1390 | - $parent_line_item, |
|
1391 | - $OBJ_type, |
|
1392 | - $OBJ_IDs |
|
1393 | - ); |
|
1394 | - } |
|
1395 | - |
|
1396 | - |
|
1397 | - /** |
|
1398 | - * Gets all descendants of supplied line item that match the supplied line item type and possibly the object type |
|
1399 | - * as well |
|
1400 | - * |
|
1401 | - * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1402 | - * @param string $OBJ_type object type (like Event) |
|
1403 | - * @param array $OBJ_IDs array of OBJ_IDs |
|
1404 | - * @return EE_Line_Item[] |
|
1405 | - * @throws EE_Error |
|
1406 | - */ |
|
1407 | - protected static function _get_descendants_by_object_type_and_object_ID( |
|
1408 | - EE_Line_Item $parent_line_item, |
|
1409 | - $OBJ_type, |
|
1410 | - $OBJ_IDs |
|
1411 | - ) { |
|
1412 | - $objects = array(); |
|
1413 | - foreach ($parent_line_item->children() as $child_line_item) { |
|
1414 | - if ($child_line_item instanceof EE_Line_Item) { |
|
1415 | - if ($child_line_item->OBJ_type() === $OBJ_type |
|
1416 | - && is_array($OBJ_IDs) |
|
1417 | - && in_array($child_line_item->OBJ_ID(), $OBJ_IDs) |
|
1418 | - ) { |
|
1419 | - $objects[] = $child_line_item; |
|
1420 | - } else { |
|
1421 | - // go-through-all-its children looking for more matches |
|
1422 | - $objects = array_merge( |
|
1423 | - $objects, |
|
1424 | - self::_get_descendants_by_object_type_and_object_ID( |
|
1425 | - $child_line_item, |
|
1426 | - $OBJ_type, |
|
1427 | - $OBJ_IDs |
|
1428 | - ) |
|
1429 | - ); |
|
1430 | - } |
|
1431 | - } |
|
1432 | - } |
|
1433 | - return $objects; |
|
1434 | - } |
|
1435 | - |
|
1436 | - |
|
1437 | - /** |
|
1438 | - * Uses a breadth-first-search in order to find the nearest descendant of |
|
1439 | - * the specified type and returns it, else NULL |
|
1440 | - * |
|
1441 | - * @uses EEH_Line_Item::_get_nearest_descendant() |
|
1442 | - * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1443 | - * @param string $type like one of the EEM_Line_Item::type_* |
|
1444 | - * @return EE_Line_Item |
|
1445 | - * @throws EE_Error |
|
1446 | - * @throws InvalidArgumentException |
|
1447 | - * @throws InvalidDataTypeException |
|
1448 | - * @throws InvalidInterfaceException |
|
1449 | - * @throws ReflectionException |
|
1450 | - */ |
|
1451 | - public static function get_nearest_descendant_of_type(EE_Line_Item $parent_line_item, $type) |
|
1452 | - { |
|
1453 | - return self::_get_nearest_descendant($parent_line_item, 'LIN_type', $type); |
|
1454 | - } |
|
1455 | - |
|
1456 | - |
|
1457 | - /** |
|
1458 | - * Uses a breadth-first-search in order to find the nearest descendant |
|
1459 | - * having the specified LIN_code and returns it, else NULL |
|
1460 | - * |
|
1461 | - * @uses EEH_Line_Item::_get_nearest_descendant() |
|
1462 | - * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1463 | - * @param string $code any value used for LIN_code |
|
1464 | - * @return EE_Line_Item |
|
1465 | - * @throws EE_Error |
|
1466 | - * @throws InvalidArgumentException |
|
1467 | - * @throws InvalidDataTypeException |
|
1468 | - * @throws InvalidInterfaceException |
|
1469 | - * @throws ReflectionException |
|
1470 | - */ |
|
1471 | - public static function get_nearest_descendant_having_code(EE_Line_Item $parent_line_item, $code) |
|
1472 | - { |
|
1473 | - return self::_get_nearest_descendant($parent_line_item, 'LIN_code', $code); |
|
1474 | - } |
|
1475 | - |
|
1476 | - |
|
1477 | - /** |
|
1478 | - * Uses a breadth-first-search in order to find the nearest descendant |
|
1479 | - * having the specified LIN_code and returns it, else NULL |
|
1480 | - * |
|
1481 | - * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1482 | - * @param string $search_field name of EE_Line_Item property |
|
1483 | - * @param string $value any value stored in $search_field |
|
1484 | - * @return EE_Line_Item |
|
1485 | - * @throws EE_Error |
|
1486 | - * @throws InvalidArgumentException |
|
1487 | - * @throws InvalidDataTypeException |
|
1488 | - * @throws InvalidInterfaceException |
|
1489 | - * @throws ReflectionException |
|
1490 | - */ |
|
1491 | - protected static function _get_nearest_descendant(EE_Line_Item $parent_line_item, $search_field, $value) |
|
1492 | - { |
|
1493 | - foreach ($parent_line_item->children() as $child) { |
|
1494 | - if ($child->get($search_field) == $value) { |
|
1495 | - return $child; |
|
1496 | - } |
|
1497 | - } |
|
1498 | - foreach ($parent_line_item->children() as $child) { |
|
1499 | - $descendant_found = self::_get_nearest_descendant( |
|
1500 | - $child, |
|
1501 | - $search_field, |
|
1502 | - $value |
|
1503 | - ); |
|
1504 | - if ($descendant_found) { |
|
1505 | - return $descendant_found; |
|
1506 | - } |
|
1507 | - } |
|
1508 | - return null; |
|
1509 | - } |
|
1510 | - |
|
1511 | - |
|
1512 | - /** |
|
1513 | - * if passed line item has a TXN ID, uses that to jump directly to the grand total line item for the transaction, |
|
1514 | - * else recursively walks up the line item tree until a parent of type total is found, |
|
1515 | - * |
|
1516 | - * @param EE_Line_Item $line_item |
|
1517 | - * @return EE_Line_Item |
|
1518 | - * @throws EE_Error |
|
1519 | - */ |
|
1520 | - public static function find_transaction_grand_total_for_line_item(EE_Line_Item $line_item) |
|
1521 | - { |
|
1522 | - if ($line_item->TXN_ID()) { |
|
1523 | - $total_line_item = $line_item->transaction()->total_line_item(false); |
|
1524 | - if ($total_line_item instanceof EE_Line_Item) { |
|
1525 | - return $total_line_item; |
|
1526 | - } |
|
1527 | - } else { |
|
1528 | - $line_item_parent = $line_item->parent(); |
|
1529 | - if ($line_item_parent instanceof EE_Line_Item) { |
|
1530 | - if ($line_item_parent->is_total()) { |
|
1531 | - return $line_item_parent; |
|
1532 | - } |
|
1533 | - return EEH_Line_Item::find_transaction_grand_total_for_line_item($line_item_parent); |
|
1534 | - } |
|
1535 | - } |
|
1536 | - throw new EE_Error( |
|
1537 | - sprintf( |
|
1538 | - esc_html__( |
|
1539 | - 'A valid grand total for line item %1$d was not found.', |
|
1540 | - 'event_espresso' |
|
1541 | - ), |
|
1542 | - $line_item->ID() |
|
1543 | - ) |
|
1544 | - ); |
|
1545 | - } |
|
1546 | - |
|
1547 | - |
|
1548 | - /** |
|
1549 | - * Prints out a representation of the line item tree |
|
1550 | - * |
|
1551 | - * @param EE_Line_Item $line_item |
|
1552 | - * @param int $indentation |
|
1553 | - * @return void |
|
1554 | - * @throws EE_Error |
|
1555 | - */ |
|
1556 | - public static function visualize(EE_Line_Item $line_item, $indentation = 0) |
|
1557 | - { |
|
1558 | - echo defined('EE_TESTS_DIR') ? "\n" : '<br />'; |
|
1559 | - if (! $indentation) { |
|
1560 | - echo defined('EE_TESTS_DIR') ? "\n" : '<br />'; |
|
1561 | - } |
|
1562 | - for ($i = 0; $i < $indentation; $i++) { |
|
1563 | - echo '. '; |
|
1564 | - } |
|
1565 | - $breakdown = ''; |
|
1566 | - if ($line_item->is_line_item()) { |
|
1567 | - if ($line_item->is_percent()) { |
|
1568 | - $breakdown = "{$line_item->percent()}%"; |
|
1569 | - } else { |
|
1570 | - $breakdown = '$' . "{$line_item->unit_price()} x {$line_item->quantity()}"; |
|
1571 | - } |
|
1572 | - } |
|
1573 | - echo $line_item->name(); |
|
1574 | - echo " [ ID:{$line_item->ID()} | qty:{$line_item->quantity()} ] {$line_item->type()} : "; |
|
1575 | - echo '$' . (string) $line_item->total(); |
|
1576 | - if ($breakdown) { |
|
1577 | - echo " ( {$breakdown} )"; |
|
1578 | - } |
|
1579 | - if ($line_item->is_taxable()) { |
|
1580 | - echo ' * taxable'; |
|
1581 | - } |
|
1582 | - if ($line_item->children()) { |
|
1583 | - foreach ($line_item->children() as $child) { |
|
1584 | - self::visualize($child, $indentation + 1); |
|
1585 | - } |
|
1586 | - } |
|
1587 | - } |
|
1588 | - |
|
1589 | - |
|
1590 | - /** |
|
1591 | - * Calculates the registration's final price, taking into account that they |
|
1592 | - * need to not only help pay for their OWN ticket, but also any transaction-wide surcharges and taxes, |
|
1593 | - * and receive a portion of any transaction-wide discounts. |
|
1594 | - * eg1, if I buy a $1 ticket and brent buys a $9 ticket, and we receive a $5 discount |
|
1595 | - * then I'll get 1/10 of that $5 discount, which is $0.50, and brent will get |
|
1596 | - * 9/10ths of that $5 discount, which is $4.50. So my final price should be $0.50 |
|
1597 | - * and brent's final price should be $5.50. |
|
1598 | - * In order to do this, we basically need to traverse the line item tree calculating |
|
1599 | - * the running totals (just as if we were recalculating the total), but when we identify |
|
1600 | - * regular line items, we need to keep track of their share of the grand total. |
|
1601 | - * Also, we need to keep track of the TAXABLE total for each ticket purchase, so |
|
1602 | - * we can know how to apply taxes to it. (Note: "taxable total" does not equal the "pretax total" |
|
1603 | - * when there are non-taxable items; otherwise they would be the same) |
|
1604 | - * |
|
1605 | - * @param EE_Line_Item $line_item |
|
1606 | - * @param array $billable_ticket_quantities array of EE_Ticket IDs and their corresponding quantity that |
|
1607 | - * can be included in price calculations at this moment |
|
1608 | - * @return array keys are line items for tickets IDs and values are their share of the running total, |
|
1609 | - * plus the key 'total', and 'taxable' which also has keys of all |
|
1610 | - * the ticket IDs. |
|
1611 | - * Eg array( |
|
1612 | - * 12 => 4.3 |
|
1613 | - * 23 => 8.0 |
|
1614 | - * 'total' => 16.6, |
|
1615 | - * 'taxable' => array( |
|
1616 | - * 12 => 10, |
|
1617 | - * 23 => 4 |
|
1618 | - * ). |
|
1619 | - * So to find which registrations have which final price, we need |
|
1620 | - * to find which line item is theirs, which can be done with |
|
1621 | - * `EEM_Line_Item::instance()->get_line_item_for_registration( |
|
1622 | - * $registration );` |
|
1623 | - * @throws EE_Error |
|
1624 | - * @throws InvalidArgumentException |
|
1625 | - * @throws InvalidDataTypeException |
|
1626 | - * @throws InvalidInterfaceException |
|
1627 | - * @throws ReflectionException |
|
1628 | - */ |
|
1629 | - public static function calculate_reg_final_prices_per_line_item( |
|
1630 | - EE_Line_Item $line_item, |
|
1631 | - $billable_ticket_quantities = array() |
|
1632 | - ) { |
|
1633 | - $running_totals = [ |
|
1634 | - 'total' => 0, |
|
1635 | - 'taxable' => ['total' => 0] |
|
1636 | - ]; |
|
1637 | - foreach ($line_item->children() as $child_line_item) { |
|
1638 | - switch ($child_line_item->type()) { |
|
1639 | - case EEM_Line_Item::type_sub_total: |
|
1640 | - $running_totals_from_subtotal = EEH_Line_Item::calculate_reg_final_prices_per_line_item( |
|
1641 | - $child_line_item, |
|
1642 | - $billable_ticket_quantities |
|
1643 | - ); |
|
1644 | - // combine arrays but preserve numeric keys |
|
1645 | - $running_totals = array_replace_recursive($running_totals_from_subtotal, $running_totals); |
|
1646 | - $running_totals['total'] += $running_totals_from_subtotal['total']; |
|
1647 | - $running_totals['taxable']['total'] += $running_totals_from_subtotal['taxable']['total']; |
|
1648 | - break; |
|
1649 | - |
|
1650 | - case EEM_Line_Item::type_tax_sub_total: |
|
1651 | - // find how much the taxes percentage is |
|
1652 | - if ($child_line_item->percent() !== 0) { |
|
1653 | - $tax_percent_decimal = $child_line_item->percent() / 100; |
|
1654 | - } else { |
|
1655 | - $tax_percent_decimal = EE_Taxes::get_total_taxes_percentage() / 100; |
|
1656 | - } |
|
1657 | - // and apply to all the taxable totals, and add to the pretax totals |
|
1658 | - foreach ($running_totals as $line_item_id => $this_running_total) { |
|
1659 | - // "total" and "taxable" array key is an exception |
|
1660 | - if ($line_item_id === 'taxable') { |
|
1661 | - continue; |
|
1662 | - } |
|
1663 | - $taxable_total = $running_totals['taxable'][ $line_item_id ]; |
|
1664 | - $running_totals[ $line_item_id ] += ($taxable_total * $tax_percent_decimal); |
|
1665 | - } |
|
1666 | - break; |
|
1667 | - |
|
1668 | - case EEM_Line_Item::type_line_item: |
|
1669 | - // ticket line items or ???? |
|
1670 | - if ($child_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET) { |
|
1671 | - // kk it's a ticket |
|
1672 | - if (isset($running_totals[ $child_line_item->ID() ])) { |
|
1673 | - // huh? that shouldn't happen. |
|
1674 | - $running_totals['total'] += $child_line_item->total(); |
|
1675 | - } else { |
|
1676 | - // its not in our running totals yet. great. |
|
1677 | - if ($child_line_item->is_taxable()) { |
|
1678 | - $taxable_amount = $child_line_item->unit_price(); |
|
1679 | - } else { |
|
1680 | - $taxable_amount = 0; |
|
1681 | - } |
|
1682 | - // are we only calculating totals for some tickets? |
|
1683 | - if (isset($billable_ticket_quantities[ $child_line_item->OBJ_ID() ])) { |
|
1684 | - $quantity = $billable_ticket_quantities[ $child_line_item->OBJ_ID() ]; |
|
1685 | - $running_totals[ $child_line_item->ID() ] = $quantity |
|
1686 | - ? $child_line_item->unit_price() |
|
1687 | - : 0; |
|
1688 | - $running_totals['taxable'][ $child_line_item->ID() ] = $quantity |
|
1689 | - ? $taxable_amount |
|
1690 | - : 0; |
|
1691 | - } else { |
|
1692 | - $quantity = $child_line_item->quantity(); |
|
1693 | - $running_totals[ $child_line_item->ID() ] = $child_line_item->unit_price(); |
|
1694 | - $running_totals['taxable'][ $child_line_item->ID() ] = $taxable_amount; |
|
1695 | - } |
|
1696 | - $running_totals['taxable']['total'] += $taxable_amount * $quantity; |
|
1697 | - $running_totals['total'] += $child_line_item->unit_price() * $quantity; |
|
1698 | - } |
|
1699 | - } else { |
|
1700 | - // it's some other type of item added to the cart |
|
1701 | - // it should affect the running totals |
|
1702 | - // basically we want to convert it into a PERCENT modifier. Because |
|
1703 | - // more clearly affect all registration's final price equally |
|
1704 | - $line_items_percent_of_running_total = $running_totals['total'] > 0 |
|
1705 | - ? ($child_line_item->total() / $running_totals['total']) + 1 |
|
1706 | - : 1; |
|
1707 | - foreach ($running_totals as $line_item_id => $this_running_total) { |
|
1708 | - // the "taxable" array key is an exception |
|
1709 | - if ($line_item_id === 'taxable') { |
|
1710 | - continue; |
|
1711 | - } |
|
1712 | - // update the running totals |
|
1713 | - // yes this actually even works for the running grand total! |
|
1714 | - $running_totals[ $line_item_id ] = |
|
1715 | - $line_items_percent_of_running_total * $this_running_total; |
|
1716 | - |
|
1717 | - if ($child_line_item->is_taxable()) { |
|
1718 | - $running_totals['taxable'][ $line_item_id ] = |
|
1719 | - $line_items_percent_of_running_total * $running_totals['taxable'][ $line_item_id ]; |
|
1720 | - } |
|
1721 | - } |
|
1722 | - } |
|
1723 | - break; |
|
1724 | - } |
|
1725 | - } |
|
1726 | - return $running_totals; |
|
1727 | - } |
|
1728 | - |
|
1729 | - |
|
1730 | - /** |
|
1731 | - * @param EE_Line_Item $total_line_item |
|
1732 | - * @param EE_Line_Item $ticket_line_item |
|
1733 | - * @return float | null |
|
1734 | - * @throws EE_Error |
|
1735 | - * @throws InvalidArgumentException |
|
1736 | - * @throws InvalidDataTypeException |
|
1737 | - * @throws InvalidInterfaceException |
|
1738 | - * @throws OutOfRangeException |
|
1739 | - * @throws ReflectionException |
|
1740 | - */ |
|
1741 | - public static function calculate_final_price_for_ticket_line_item( |
|
1742 | - EE_Line_Item $total_line_item, |
|
1743 | - EE_Line_Item $ticket_line_item |
|
1744 | - ) { |
|
1745 | - static $final_prices_per_ticket_line_item = array(); |
|
1746 | - if (empty($final_prices_per_ticket_line_item)) { |
|
1747 | - $final_prices_per_ticket_line_item = EEH_Line_Item::calculate_reg_final_prices_per_line_item( |
|
1748 | - $total_line_item |
|
1749 | - ); |
|
1750 | - } |
|
1751 | - // ok now find this new registration's final price |
|
1752 | - if (isset($final_prices_per_ticket_line_item[ $ticket_line_item->ID() ])) { |
|
1753 | - return $final_prices_per_ticket_line_item[ $ticket_line_item->ID() ]; |
|
1754 | - } |
|
1755 | - $message = sprintf( |
|
1756 | - esc_html__( |
|
1757 | - 'The final price for the ticket line item (ID:%1$d) could not be calculated.', |
|
1758 | - 'event_espresso' |
|
1759 | - ), |
|
1760 | - $ticket_line_item->ID() |
|
1761 | - ); |
|
1762 | - if (WP_DEBUG) { |
|
1763 | - $message .= '<br>' . print_r($final_prices_per_ticket_line_item, true); |
|
1764 | - throw new OutOfRangeException($message); |
|
1765 | - } |
|
1766 | - EE_Log::instance()->log(__CLASS__, __FUNCTION__, $message); |
|
1767 | - return null; |
|
1768 | - } |
|
1769 | - |
|
1770 | - |
|
1771 | - /** |
|
1772 | - * Creates a duplicate of the line item tree, except only includes billable items |
|
1773 | - * and the portion of line items attributed to billable things |
|
1774 | - * |
|
1775 | - * @param EE_Line_Item $line_item |
|
1776 | - * @param EE_Registration[] $registrations |
|
1777 | - * @return EE_Line_Item |
|
1778 | - * @throws EE_Error |
|
1779 | - * @throws InvalidArgumentException |
|
1780 | - * @throws InvalidDataTypeException |
|
1781 | - * @throws InvalidInterfaceException |
|
1782 | - * @throws ReflectionException |
|
1783 | - */ |
|
1784 | - public static function billable_line_item_tree(EE_Line_Item $line_item, $registrations) |
|
1785 | - { |
|
1786 | - $copy_li = EEH_Line_Item::billable_line_item($line_item, $registrations); |
|
1787 | - foreach ($line_item->children() as $child_li) { |
|
1788 | - $copy_li->add_child_line_item( |
|
1789 | - EEH_Line_Item::billable_line_item_tree($child_li, $registrations) |
|
1790 | - ); |
|
1791 | - } |
|
1792 | - // if this is the grand total line item, make sure the totals all add up |
|
1793 | - // (we could have duplicated this logic AS we copied the line items, but |
|
1794 | - // it seems DRYer this way) |
|
1795 | - if ($copy_li->type() === EEM_Line_Item::type_total) { |
|
1796 | - $copy_li->recalculate_total_including_taxes(); |
|
1797 | - } |
|
1798 | - return $copy_li; |
|
1799 | - } |
|
1800 | - |
|
1801 | - |
|
1802 | - /** |
|
1803 | - * Creates a new, unsaved line item from $line_item that factors in the |
|
1804 | - * number of billable registrations on $registrations. |
|
1805 | - * |
|
1806 | - * @param EE_Line_Item $line_item |
|
1807 | - * @param EE_Registration[] $registrations |
|
1808 | - * @return EE_Line_Item |
|
1809 | - * @throws EE_Error |
|
1810 | - * @throws InvalidArgumentException |
|
1811 | - * @throws InvalidDataTypeException |
|
1812 | - * @throws InvalidInterfaceException |
|
1813 | - * @throws ReflectionException |
|
1814 | - */ |
|
1815 | - public static function billable_line_item(EE_Line_Item $line_item, $registrations) |
|
1816 | - { |
|
1817 | - $new_li_fields = $line_item->model_field_array(); |
|
1818 | - if ($line_item->type() === EEM_Line_Item::type_line_item && |
|
1819 | - $line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET |
|
1820 | - ) { |
|
1821 | - $count = 0; |
|
1822 | - foreach ($registrations as $registration) { |
|
1823 | - if ($line_item->OBJ_ID() === $registration->ticket_ID() && |
|
1824 | - in_array( |
|
1825 | - $registration->status_ID(), |
|
1826 | - EEM_Registration::reg_statuses_that_allow_payment(), |
|
1827 | - true |
|
1828 | - ) |
|
1829 | - ) { |
|
1830 | - $count++; |
|
1831 | - } |
|
1832 | - } |
|
1833 | - $new_li_fields['LIN_quantity'] = $count; |
|
1834 | - } |
|
1835 | - // don't set the total. We'll leave that up to the code that calculates it |
|
1836 | - unset($new_li_fields['LIN_ID'], $new_li_fields['LIN_parent'], $new_li_fields['LIN_total']); |
|
1837 | - return EE_Line_Item::new_instance($new_li_fields); |
|
1838 | - } |
|
1839 | - |
|
1840 | - |
|
1841 | - /** |
|
1842 | - * Returns a modified line item tree where all the subtotals which have a total of 0 |
|
1843 | - * are removed, and line items with a quantity of 0 |
|
1844 | - * |
|
1845 | - * @param EE_Line_Item $line_item |null |
|
1846 | - * @return EE_Line_Item|null |
|
1847 | - * @throws EE_Error |
|
1848 | - * @throws InvalidArgumentException |
|
1849 | - * @throws InvalidDataTypeException |
|
1850 | - * @throws InvalidInterfaceException |
|
1851 | - * @throws ReflectionException |
|
1852 | - */ |
|
1853 | - public static function non_empty_line_items(EE_Line_Item $line_item) |
|
1854 | - { |
|
1855 | - $copied_li = EEH_Line_Item::non_empty_line_item($line_item); |
|
1856 | - if ($copied_li === null) { |
|
1857 | - return null; |
|
1858 | - } |
|
1859 | - // if this is an event subtotal, we want to only include it if it |
|
1860 | - // has a non-zero total and at least one ticket line item child |
|
1861 | - $ticket_children = 0; |
|
1862 | - foreach ($line_item->children() as $child_li) { |
|
1863 | - $child_li_copy = EEH_Line_Item::non_empty_line_items($child_li); |
|
1864 | - if ($child_li_copy !== null) { |
|
1865 | - $copied_li->add_child_line_item($child_li_copy); |
|
1866 | - if ($child_li_copy->type() === EEM_Line_Item::type_line_item && |
|
1867 | - $child_li_copy->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET |
|
1868 | - ) { |
|
1869 | - $ticket_children++; |
|
1870 | - } |
|
1871 | - } |
|
1872 | - } |
|
1873 | - // if this is an event subtotal with NO ticket children |
|
1874 | - // we basically want to ignore it |
|
1875 | - if ($ticket_children === 0 |
|
1876 | - && $line_item->type() === EEM_Line_Item::type_sub_total |
|
1877 | - && $line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_EVENT |
|
1878 | - && $line_item->total() === 0 |
|
1879 | - ) { |
|
1880 | - return null; |
|
1881 | - } |
|
1882 | - return $copied_li; |
|
1883 | - } |
|
1884 | - |
|
1885 | - |
|
1886 | - /** |
|
1887 | - * Creates a new, unsaved line item, but if it's a ticket line item |
|
1888 | - * with a total of 0, or a subtotal of 0, returns null instead |
|
1889 | - * |
|
1890 | - * @param EE_Line_Item $line_item |
|
1891 | - * @return EE_Line_Item |
|
1892 | - * @throws EE_Error |
|
1893 | - * @throws InvalidArgumentException |
|
1894 | - * @throws InvalidDataTypeException |
|
1895 | - * @throws InvalidInterfaceException |
|
1896 | - * @throws ReflectionException |
|
1897 | - */ |
|
1898 | - public static function non_empty_line_item(EE_Line_Item $line_item) |
|
1899 | - { |
|
1900 | - if ($line_item->type() === EEM_Line_Item::type_line_item |
|
1901 | - && $line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET |
|
1902 | - && $line_item->quantity() === 0 |
|
1903 | - ) { |
|
1904 | - return null; |
|
1905 | - } |
|
1906 | - $new_li_fields = $line_item->model_field_array(); |
|
1907 | - // don't set the total. We'll leave that up to the code that calculates it |
|
1908 | - unset($new_li_fields['LIN_ID'], $new_li_fields['LIN_parent']); |
|
1909 | - return EE_Line_Item::new_instance($new_li_fields); |
|
1910 | - } |
|
1911 | - |
|
1912 | - |
|
1913 | - /** |
|
1914 | - * Cycles through all of the ticket line items for the supplied total line item |
|
1915 | - * and ensures that the line item's "is_taxable" field matches that of its corresponding ticket |
|
1916 | - * |
|
1917 | - * @param EE_Line_Item $total_line_item |
|
1918 | - * @since 4.9.79.p |
|
1919 | - * @throws EE_Error |
|
1920 | - * @throws InvalidArgumentException |
|
1921 | - * @throws InvalidDataTypeException |
|
1922 | - * @throws InvalidInterfaceException |
|
1923 | - * @throws ReflectionException |
|
1924 | - */ |
|
1925 | - public static function resetIsTaxableForTickets(EE_Line_Item $total_line_item) |
|
1926 | - { |
|
1927 | - $ticket_line_items = self::get_ticket_line_items($total_line_item); |
|
1928 | - foreach ($ticket_line_items as $ticket_line_item) { |
|
1929 | - if ($ticket_line_item instanceof EE_Line_Item |
|
1930 | - && $ticket_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET |
|
1931 | - ) { |
|
1932 | - $ticket = $ticket_line_item->ticket(); |
|
1933 | - if ($ticket instanceof EE_Ticket && $ticket->taxable() !== $ticket_line_item->is_taxable()) { |
|
1934 | - $ticket_line_item->set_is_taxable($ticket->taxable()); |
|
1935 | - $ticket_line_item->save(); |
|
1936 | - } |
|
1937 | - } |
|
1938 | - } |
|
1939 | - } |
|
1940 | - |
|
1941 | - |
|
1942 | - |
|
1943 | - /**************************************** @DEPRECATED METHODS *************************************** */ |
|
1944 | - /** |
|
1945 | - * @deprecated |
|
1946 | - * @param EE_Line_Item $total_line_item |
|
1947 | - * @return EE_Line_Item |
|
1948 | - * @throws EE_Error |
|
1949 | - * @throws InvalidArgumentException |
|
1950 | - * @throws InvalidDataTypeException |
|
1951 | - * @throws InvalidInterfaceException |
|
1952 | - * @throws ReflectionException |
|
1953 | - */ |
|
1954 | - public static function get_items_subtotal(EE_Line_Item $total_line_item) |
|
1955 | - { |
|
1956 | - EE_Error::doing_it_wrong( |
|
1957 | - 'EEH_Line_Item::get_items_subtotal()', |
|
1958 | - sprintf( |
|
1959 | - esc_html__('Method replaced with %1$s', 'event_espresso'), |
|
1960 | - 'EEH_Line_Item::get_pre_tax_subtotal()' |
|
1961 | - ), |
|
1962 | - '4.6.0' |
|
1963 | - ); |
|
1964 | - return self::get_pre_tax_subtotal($total_line_item); |
|
1965 | - } |
|
1966 | - |
|
1967 | - |
|
1968 | - /** |
|
1969 | - * @deprecated |
|
1970 | - * @param EE_Transaction $transaction |
|
1971 | - * @return EE_Line_Item |
|
1972 | - * @throws EE_Error |
|
1973 | - * @throws InvalidArgumentException |
|
1974 | - * @throws InvalidDataTypeException |
|
1975 | - * @throws InvalidInterfaceException |
|
1976 | - * @throws ReflectionException |
|
1977 | - */ |
|
1978 | - public static function create_default_total_line_item($transaction = null) |
|
1979 | - { |
|
1980 | - EE_Error::doing_it_wrong( |
|
1981 | - 'EEH_Line_Item::create_default_total_line_item()', |
|
1982 | - sprintf( |
|
1983 | - esc_html__('Method replaced with %1$s', 'event_espresso'), |
|
1984 | - 'EEH_Line_Item::create_total_line_item()' |
|
1985 | - ), |
|
1986 | - '4.6.0' |
|
1987 | - ); |
|
1988 | - return self::create_total_line_item($transaction); |
|
1989 | - } |
|
1990 | - |
|
1991 | - |
|
1992 | - /** |
|
1993 | - * @deprecated |
|
1994 | - * @param EE_Line_Item $total_line_item |
|
1995 | - * @param EE_Transaction $transaction |
|
1996 | - * @return EE_Line_Item |
|
1997 | - * @throws EE_Error |
|
1998 | - * @throws InvalidArgumentException |
|
1999 | - * @throws InvalidDataTypeException |
|
2000 | - * @throws InvalidInterfaceException |
|
2001 | - * @throws ReflectionException |
|
2002 | - */ |
|
2003 | - public static function create_default_tickets_subtotal(EE_Line_Item $total_line_item, $transaction = null) |
|
2004 | - { |
|
2005 | - EE_Error::doing_it_wrong( |
|
2006 | - 'EEH_Line_Item::create_default_tickets_subtotal()', |
|
2007 | - sprintf( |
|
2008 | - esc_html__('Method replaced with %1$s', 'event_espresso'), |
|
2009 | - 'EEH_Line_Item::create_pre_tax_subtotal()' |
|
2010 | - ), |
|
2011 | - '4.6.0' |
|
2012 | - ); |
|
2013 | - return self::create_pre_tax_subtotal($total_line_item, $transaction); |
|
2014 | - } |
|
2015 | - |
|
2016 | - |
|
2017 | - /** |
|
2018 | - * @deprecated |
|
2019 | - * @param EE_Line_Item $total_line_item |
|
2020 | - * @param EE_Transaction $transaction |
|
2021 | - * @return EE_Line_Item |
|
2022 | - * @throws EE_Error |
|
2023 | - * @throws InvalidArgumentException |
|
2024 | - * @throws InvalidDataTypeException |
|
2025 | - * @throws InvalidInterfaceException |
|
2026 | - * @throws ReflectionException |
|
2027 | - */ |
|
2028 | - public static function create_default_taxes_subtotal(EE_Line_Item $total_line_item, $transaction = null) |
|
2029 | - { |
|
2030 | - EE_Error::doing_it_wrong( |
|
2031 | - 'EEH_Line_Item::create_default_taxes_subtotal()', |
|
2032 | - sprintf( |
|
2033 | - esc_html__('Method replaced with %1$s', 'event_espresso'), |
|
2034 | - 'EEH_Line_Item::create_taxes_subtotal()' |
|
2035 | - ), |
|
2036 | - '4.6.0' |
|
2037 | - ); |
|
2038 | - return self::create_taxes_subtotal($total_line_item, $transaction); |
|
2039 | - } |
|
2040 | - |
|
2041 | - |
|
2042 | - /** |
|
2043 | - * @deprecated |
|
2044 | - * @param EE_Line_Item $total_line_item |
|
2045 | - * @param EE_Transaction $transaction |
|
2046 | - * @return EE_Line_Item |
|
2047 | - * @throws EE_Error |
|
2048 | - * @throws InvalidArgumentException |
|
2049 | - * @throws InvalidDataTypeException |
|
2050 | - * @throws InvalidInterfaceException |
|
2051 | - * @throws ReflectionException |
|
2052 | - */ |
|
2053 | - public static function create_default_event_subtotal(EE_Line_Item $total_line_item, $transaction = null) |
|
2054 | - { |
|
2055 | - EE_Error::doing_it_wrong( |
|
2056 | - 'EEH_Line_Item::create_default_event_subtotal()', |
|
2057 | - sprintf( |
|
2058 | - esc_html__('Method replaced with %1$s', 'event_espresso'), |
|
2059 | - 'EEH_Line_Item::create_event_subtotal()' |
|
2060 | - ), |
|
2061 | - '4.6.0' |
|
2062 | - ); |
|
2063 | - return self::create_event_subtotal($total_line_item, $transaction); |
|
2064 | - } |
|
24 | + /** |
|
25 | + * Adds a simple item (unrelated to any other model object) to the provided PARENT line item. |
|
26 | + * Does NOT automatically re-calculate the line item totals or update the related transaction. |
|
27 | + * You should call recalculate_total_including_taxes() on the grant total line item after this |
|
28 | + * to update the subtotals, and EE_Registration_Processor::calculate_reg_final_prices_per_line_item() |
|
29 | + * to keep the registration final prices in-sync with the transaction's total. |
|
30 | + * |
|
31 | + * @param EE_Line_Item $parent_line_item |
|
32 | + * @param string $name |
|
33 | + * @param float $unit_price |
|
34 | + * @param string $description |
|
35 | + * @param int $quantity |
|
36 | + * @param boolean $taxable |
|
37 | + * @param boolean $code if set to a value, ensures there is only one line item with that code |
|
38 | + * @return boolean success |
|
39 | + * @throws EE_Error |
|
40 | + * @throws InvalidArgumentException |
|
41 | + * @throws InvalidDataTypeException |
|
42 | + * @throws InvalidInterfaceException |
|
43 | + * @throws ReflectionException |
|
44 | + */ |
|
45 | + public static function add_unrelated_item( |
|
46 | + EE_Line_Item $parent_line_item, |
|
47 | + $name, |
|
48 | + $unit_price, |
|
49 | + $description = '', |
|
50 | + $quantity = 1, |
|
51 | + $taxable = false, |
|
52 | + $code = null |
|
53 | + ) { |
|
54 | + $items_subtotal = self::get_pre_tax_subtotal($parent_line_item); |
|
55 | + $line_item = EE_Line_Item::new_instance(array( |
|
56 | + 'LIN_name' => $name, |
|
57 | + 'LIN_desc' => $description, |
|
58 | + 'LIN_unit_price' => $unit_price, |
|
59 | + 'LIN_quantity' => $quantity, |
|
60 | + 'LIN_percent' => null, |
|
61 | + 'LIN_is_taxable' => $taxable, |
|
62 | + 'LIN_order' => $items_subtotal instanceof EE_Line_Item ? count($items_subtotal->children()) : 0, |
|
63 | + 'LIN_total' => (float) $unit_price * (int) $quantity, |
|
64 | + 'LIN_type' => EEM_Line_Item::type_line_item, |
|
65 | + 'LIN_code' => $code, |
|
66 | + )); |
|
67 | + $line_item = apply_filters( |
|
68 | + 'FHEE__EEH_Line_Item__add_unrelated_item__line_item', |
|
69 | + $line_item, |
|
70 | + $parent_line_item |
|
71 | + ); |
|
72 | + return self::add_item($parent_line_item, $line_item); |
|
73 | + } |
|
74 | + |
|
75 | + |
|
76 | + /** |
|
77 | + * Adds a simple item ( unrelated to any other model object) to the total line item, |
|
78 | + * in the correct spot in the line item tree. Does not automatically |
|
79 | + * re-calculate the line item totals, nor update the related transaction, nor upgrade the transaction's |
|
80 | + * registrations' final prices (which should probably change because of this). |
|
81 | + * You should call recalculate_total_including_taxes() on the grand total line item, then |
|
82 | + * update the transaction's total, and EE_Registration_Processor::update_registration_final_prices() |
|
83 | + * after using this, to keep the registration final prices in-sync with the transaction's total. |
|
84 | + * |
|
85 | + * @param EE_Line_Item $parent_line_item |
|
86 | + * @param string $name |
|
87 | + * @param float $percentage_amount |
|
88 | + * @param string $description |
|
89 | + * @param boolean $taxable |
|
90 | + * @return boolean success |
|
91 | + * @throws EE_Error |
|
92 | + */ |
|
93 | + public static function add_percentage_based_item( |
|
94 | + EE_Line_Item $parent_line_item, |
|
95 | + $name, |
|
96 | + $percentage_amount, |
|
97 | + $description = '', |
|
98 | + $taxable = false |
|
99 | + ) { |
|
100 | + $line_item = EE_Line_Item::new_instance(array( |
|
101 | + 'LIN_name' => $name, |
|
102 | + 'LIN_desc' => $description, |
|
103 | + 'LIN_unit_price' => 0, |
|
104 | + 'LIN_percent' => $percentage_amount, |
|
105 | + 'LIN_quantity' => 1, |
|
106 | + 'LIN_is_taxable' => $taxable, |
|
107 | + 'LIN_total' => (float) ($percentage_amount * ($parent_line_item->total() / 100)), |
|
108 | + 'LIN_type' => EEM_Line_Item::type_line_item, |
|
109 | + 'LIN_parent' => $parent_line_item->ID(), |
|
110 | + )); |
|
111 | + $line_item = apply_filters( |
|
112 | + 'FHEE__EEH_Line_Item__add_percentage_based_item__line_item', |
|
113 | + $line_item |
|
114 | + ); |
|
115 | + return $parent_line_item->add_child_line_item($line_item, false); |
|
116 | + } |
|
117 | + |
|
118 | + |
|
119 | + /** |
|
120 | + * Returns the new line item created by adding a purchase of the ticket |
|
121 | + * ensures that ticket line item is saved, and that cart total has been recalculated. |
|
122 | + * If this ticket has already been purchased, just increments its count. |
|
123 | + * Automatically re-calculates the line item totals and updates the related transaction. But |
|
124 | + * DOES NOT automatically upgrade the transaction's registrations' final prices (which |
|
125 | + * should probably change because of this). |
|
126 | + * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item() |
|
127 | + * after using this, to keep the registration final prices in-sync with the transaction's total. |
|
128 | + * |
|
129 | + * @param EE_Line_Item $total_line_item grand total line item of type EEM_Line_Item::type_total |
|
130 | + * @param EE_Ticket $ticket |
|
131 | + * @param int $qty |
|
132 | + * @return EE_Line_Item |
|
133 | + * @throws EE_Error |
|
134 | + * @throws InvalidArgumentException |
|
135 | + * @throws InvalidDataTypeException |
|
136 | + * @throws InvalidInterfaceException |
|
137 | + * @throws ReflectionException |
|
138 | + */ |
|
139 | + public static function add_ticket_purchase(EE_Line_Item $total_line_item, EE_Ticket $ticket, $qty = 1) |
|
140 | + { |
|
141 | + if (! $total_line_item instanceof EE_Line_Item || ! $total_line_item->is_total()) { |
|
142 | + throw new EE_Error( |
|
143 | + sprintf( |
|
144 | + esc_html__( |
|
145 | + 'A valid line item total is required in order to add tickets. A line item of type "%s" was passed.', |
|
146 | + 'event_espresso' |
|
147 | + ), |
|
148 | + $ticket->ID(), |
|
149 | + $total_line_item->ID() |
|
150 | + ) |
|
151 | + ); |
|
152 | + } |
|
153 | + // either increment the qty for an existing ticket |
|
154 | + $line_item = self::increment_ticket_qty_if_already_in_cart($total_line_item, $ticket, $qty); |
|
155 | + // or add a new one |
|
156 | + if (! $line_item instanceof EE_Line_Item) { |
|
157 | + $line_item = self::create_ticket_line_item($total_line_item, $ticket, $qty); |
|
158 | + } |
|
159 | + $total_line_item->recalculate_total_including_taxes(); |
|
160 | + return $line_item; |
|
161 | + } |
|
162 | + |
|
163 | + |
|
164 | + /** |
|
165 | + * Returns the new line item created by adding a purchase of the ticket |
|
166 | + * |
|
167 | + * @param EE_Line_Item $total_line_item |
|
168 | + * @param EE_Ticket $ticket |
|
169 | + * @param int $qty |
|
170 | + * @return EE_Line_Item |
|
171 | + * @throws EE_Error |
|
172 | + * @throws InvalidArgumentException |
|
173 | + * @throws InvalidDataTypeException |
|
174 | + * @throws InvalidInterfaceException |
|
175 | + * @throws ReflectionException |
|
176 | + */ |
|
177 | + public static function increment_ticket_qty_if_already_in_cart( |
|
178 | + EE_Line_Item $total_line_item, |
|
179 | + EE_Ticket $ticket, |
|
180 | + $qty = 1 |
|
181 | + ) { |
|
182 | + $line_item = null; |
|
183 | + if ($total_line_item instanceof EE_Line_Item && $total_line_item->is_total()) { |
|
184 | + $ticket_line_items = EEH_Line_Item::get_ticket_line_items($total_line_item); |
|
185 | + foreach ((array) $ticket_line_items as $ticket_line_item) { |
|
186 | + if ($ticket_line_item instanceof EE_Line_Item |
|
187 | + && (int) $ticket_line_item->OBJ_ID() === (int) $ticket->ID() |
|
188 | + ) { |
|
189 | + $line_item = $ticket_line_item; |
|
190 | + break; |
|
191 | + } |
|
192 | + } |
|
193 | + } |
|
194 | + if ($line_item instanceof EE_Line_Item) { |
|
195 | + EEH_Line_Item::increment_quantity($line_item, $qty); |
|
196 | + return $line_item; |
|
197 | + } |
|
198 | + return null; |
|
199 | + } |
|
200 | + |
|
201 | + |
|
202 | + /** |
|
203 | + * Increments the line item and all its children's quantity by $qty (but percent line items are unaffected). |
|
204 | + * Does NOT save or recalculate other line items totals |
|
205 | + * |
|
206 | + * @param EE_Line_Item $line_item |
|
207 | + * @param int $qty |
|
208 | + * @return void |
|
209 | + * @throws EE_Error |
|
210 | + * @throws InvalidArgumentException |
|
211 | + * @throws InvalidDataTypeException |
|
212 | + * @throws InvalidInterfaceException |
|
213 | + * @throws ReflectionException |
|
214 | + */ |
|
215 | + public static function increment_quantity(EE_Line_Item $line_item, $qty = 1) |
|
216 | + { |
|
217 | + if (! $line_item->is_percent()) { |
|
218 | + $qty += $line_item->quantity(); |
|
219 | + $line_item->set_quantity($qty); |
|
220 | + $line_item->set_total($line_item->unit_price() * $qty); |
|
221 | + $line_item->save(); |
|
222 | + } |
|
223 | + foreach ($line_item->children() as $child) { |
|
224 | + if ($child->is_sub_line_item()) { |
|
225 | + EEH_Line_Item::update_quantity($child, $qty); |
|
226 | + } |
|
227 | + } |
|
228 | + } |
|
229 | + |
|
230 | + |
|
231 | + /** |
|
232 | + * Decrements the line item and all its children's quantity by $qty (but percent line items are unaffected). |
|
233 | + * Does NOT save or recalculate other line items totals |
|
234 | + * |
|
235 | + * @param EE_Line_Item $line_item |
|
236 | + * @param int $qty |
|
237 | + * @return void |
|
238 | + * @throws EE_Error |
|
239 | + * @throws InvalidArgumentException |
|
240 | + * @throws InvalidDataTypeException |
|
241 | + * @throws InvalidInterfaceException |
|
242 | + * @throws ReflectionException |
|
243 | + */ |
|
244 | + public static function decrement_quantity(EE_Line_Item $line_item, $qty = 1) |
|
245 | + { |
|
246 | + if (! $line_item->is_percent()) { |
|
247 | + $qty = $line_item->quantity() - $qty; |
|
248 | + $qty = max($qty, 0); |
|
249 | + $line_item->set_quantity($qty); |
|
250 | + $line_item->set_total($line_item->unit_price() * $qty); |
|
251 | + $line_item->save(); |
|
252 | + } |
|
253 | + foreach ($line_item->children() as $child) { |
|
254 | + if ($child->is_sub_line_item()) { |
|
255 | + EEH_Line_Item::update_quantity($child, $qty); |
|
256 | + } |
|
257 | + } |
|
258 | + } |
|
259 | + |
|
260 | + |
|
261 | + /** |
|
262 | + * Updates the line item and its children's quantities to the specified number. |
|
263 | + * Does NOT save them or recalculate totals. |
|
264 | + * |
|
265 | + * @param EE_Line_Item $line_item |
|
266 | + * @param int $new_quantity |
|
267 | + * @throws EE_Error |
|
268 | + * @throws InvalidArgumentException |
|
269 | + * @throws InvalidDataTypeException |
|
270 | + * @throws InvalidInterfaceException |
|
271 | + * @throws ReflectionException |
|
272 | + */ |
|
273 | + public static function update_quantity(EE_Line_Item $line_item, $new_quantity) |
|
274 | + { |
|
275 | + if (! $line_item->is_percent()) { |
|
276 | + $line_item->set_quantity($new_quantity); |
|
277 | + $line_item->set_total($line_item->unit_price() * $new_quantity); |
|
278 | + $line_item->save(); |
|
279 | + } |
|
280 | + foreach ($line_item->children() as $child) { |
|
281 | + if ($child->is_sub_line_item()) { |
|
282 | + EEH_Line_Item::update_quantity($child, $new_quantity); |
|
283 | + } |
|
284 | + } |
|
285 | + } |
|
286 | + |
|
287 | + |
|
288 | + /** |
|
289 | + * Returns the new line item created by adding a purchase of the ticket |
|
290 | + * |
|
291 | + * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
292 | + * @param EE_Ticket $ticket |
|
293 | + * @param int $qty |
|
294 | + * @return EE_Line_Item |
|
295 | + * @throws EE_Error |
|
296 | + * @throws InvalidArgumentException |
|
297 | + * @throws InvalidDataTypeException |
|
298 | + * @throws InvalidInterfaceException |
|
299 | + * @throws ReflectionException |
|
300 | + */ |
|
301 | + public static function create_ticket_line_item(EE_Line_Item $total_line_item, EE_Ticket $ticket, $qty = 1) |
|
302 | + { |
|
303 | + $datetimes = $ticket->datetimes(); |
|
304 | + $first_datetime = reset($datetimes); |
|
305 | + $first_datetime_name = esc_html__('Event', 'event_espresso'); |
|
306 | + if ($first_datetime instanceof EE_Datetime && $first_datetime->event() instanceof EE_Event) { |
|
307 | + $first_datetime_name = $first_datetime->event()->name(); |
|
308 | + } |
|
309 | + $event = sprintf(_x('(For %1$s)', '(For Event Name)', 'event_espresso'), $first_datetime_name); |
|
310 | + // get event subtotal line |
|
311 | + $events_sub_total = self::get_event_line_item_for_ticket($total_line_item, $ticket); |
|
312 | + // add $ticket to cart |
|
313 | + $line_item = EE_Line_Item::new_instance(array( |
|
314 | + 'LIN_name' => $ticket->name(), |
|
315 | + 'LIN_desc' => $ticket->description() !== '' ? $ticket->description() . ' ' . $event : $event, |
|
316 | + 'LIN_unit_price' => $ticket->price(), |
|
317 | + 'LIN_quantity' => $qty, |
|
318 | + 'LIN_is_taxable' => $ticket->taxable(), |
|
319 | + 'LIN_order' => count($events_sub_total->children()), |
|
320 | + 'LIN_total' => $ticket->price() * $qty, |
|
321 | + 'LIN_type' => EEM_Line_Item::type_line_item, |
|
322 | + 'OBJ_ID' => $ticket->ID(), |
|
323 | + 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TICKET, |
|
324 | + )); |
|
325 | + $line_item = apply_filters( |
|
326 | + 'FHEE__EEH_Line_Item__create_ticket_line_item__line_item', |
|
327 | + $line_item |
|
328 | + ); |
|
329 | + $events_sub_total->add_child_line_item($line_item); |
|
330 | + // now add the sub-line items |
|
331 | + $running_total_for_ticket = 0; |
|
332 | + foreach ($ticket->prices(array('order_by' => array('PRC_order' => 'ASC'))) as $price) { |
|
333 | + $sign = $price->is_discount() ? -1 : 1; |
|
334 | + $price_total = $price->is_percent() |
|
335 | + ? $running_total_for_ticket * $price->amount() / 100 |
|
336 | + : $price->amount() * $qty; |
|
337 | + $sub_line_item = EE_Line_Item::new_instance(array( |
|
338 | + 'LIN_name' => $price->name(), |
|
339 | + 'LIN_desc' => $price->desc(), |
|
340 | + 'LIN_quantity' => $price->is_percent() ? null : $qty, |
|
341 | + 'LIN_is_taxable' => false, |
|
342 | + 'LIN_order' => $price->order(), |
|
343 | + 'LIN_total' => $sign * $price_total, |
|
344 | + 'LIN_type' => EEM_Line_Item::type_sub_line_item, |
|
345 | + 'OBJ_ID' => $price->ID(), |
|
346 | + 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_PRICE, |
|
347 | + )); |
|
348 | + $sub_line_item = apply_filters( |
|
349 | + 'FHEE__EEH_Line_Item__create_ticket_line_item__sub_line_item', |
|
350 | + $sub_line_item |
|
351 | + ); |
|
352 | + if ($price->is_percent()) { |
|
353 | + $sub_line_item->set_percent($sign * $price->amount()); |
|
354 | + } else { |
|
355 | + $sub_line_item->set_unit_price($sign * $price->amount()); |
|
356 | + } |
|
357 | + $running_total_for_ticket += $price_total; |
|
358 | + $line_item->add_child_line_item($sub_line_item); |
|
359 | + } |
|
360 | + return $line_item; |
|
361 | + } |
|
362 | + |
|
363 | + |
|
364 | + /** |
|
365 | + * Adds the specified item under the pre-tax-sub-total line item. Automatically |
|
366 | + * re-calculates the line item totals and updates the related transaction. But |
|
367 | + * DOES NOT automatically upgrade the transaction's registrations' final prices (which |
|
368 | + * should probably change because of this). |
|
369 | + * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item() |
|
370 | + * after using this, to keep the registration final prices in-sync with the transaction's total. |
|
371 | + * |
|
372 | + * @param EE_Line_Item $total_line_item |
|
373 | + * @param EE_Line_Item $item to be added |
|
374 | + * @return boolean |
|
375 | + * @throws EE_Error |
|
376 | + * @throws InvalidArgumentException |
|
377 | + * @throws InvalidDataTypeException |
|
378 | + * @throws InvalidInterfaceException |
|
379 | + * @throws ReflectionException |
|
380 | + */ |
|
381 | + public static function add_item(EE_Line_Item $total_line_item, EE_Line_Item $item) |
|
382 | + { |
|
383 | + $pre_tax_subtotal = self::get_pre_tax_subtotal($total_line_item); |
|
384 | + if ($pre_tax_subtotal instanceof EE_Line_Item) { |
|
385 | + $success = $pre_tax_subtotal->add_child_line_item($item); |
|
386 | + } else { |
|
387 | + return false; |
|
388 | + } |
|
389 | + $total_line_item->recalculate_total_including_taxes(); |
|
390 | + return $success; |
|
391 | + } |
|
392 | + |
|
393 | + |
|
394 | + /** |
|
395 | + * cancels an existing ticket line item, |
|
396 | + * by decrementing it's quantity by 1 and adding a new "type_cancellation" sub-line-item. |
|
397 | + * ALL totals and subtotals will NEED TO BE UPDATED after performing this action |
|
398 | + * |
|
399 | + * @param EE_Line_Item $ticket_line_item |
|
400 | + * @param int $qty |
|
401 | + * @return bool success |
|
402 | + * @throws EE_Error |
|
403 | + * @throws InvalidArgumentException |
|
404 | + * @throws InvalidDataTypeException |
|
405 | + * @throws InvalidInterfaceException |
|
406 | + * @throws ReflectionException |
|
407 | + */ |
|
408 | + public static function cancel_ticket_line_item(EE_Line_Item $ticket_line_item, $qty = 1) |
|
409 | + { |
|
410 | + // validate incoming line_item |
|
411 | + if ($ticket_line_item->OBJ_type() !== EEM_Line_Item::OBJ_TYPE_TICKET) { |
|
412 | + throw new EE_Error( |
|
413 | + sprintf( |
|
414 | + esc_html__( |
|
415 | + 'The supplied line item must have an Object Type of "Ticket", not %1$s.', |
|
416 | + 'event_espresso' |
|
417 | + ), |
|
418 | + $ticket_line_item->type() |
|
419 | + ) |
|
420 | + ); |
|
421 | + } |
|
422 | + if ($ticket_line_item->quantity() < $qty) { |
|
423 | + throw new EE_Error( |
|
424 | + sprintf( |
|
425 | + esc_html__( |
|
426 | + 'Can not cancel %1$d ticket(s) because the supplied line item has a quantity of %2$d.', |
|
427 | + 'event_espresso' |
|
428 | + ), |
|
429 | + $qty, |
|
430 | + $ticket_line_item->quantity() |
|
431 | + ) |
|
432 | + ); |
|
433 | + } |
|
434 | + // decrement ticket quantity; don't rely on auto-fixing when recalculating totals to do this |
|
435 | + $ticket_line_item->set_quantity($ticket_line_item->quantity() - $qty); |
|
436 | + foreach ($ticket_line_item->children() as $child_line_item) { |
|
437 | + if ($child_line_item->is_sub_line_item() |
|
438 | + && ! $child_line_item->is_percent() |
|
439 | + && ! $child_line_item->is_cancellation() |
|
440 | + ) { |
|
441 | + $child_line_item->set_quantity($child_line_item->quantity() - $qty); |
|
442 | + } |
|
443 | + } |
|
444 | + // get cancellation sub line item |
|
445 | + $cancellation_line_item = EEH_Line_Item::get_descendants_of_type( |
|
446 | + $ticket_line_item, |
|
447 | + EEM_Line_Item::type_cancellation |
|
448 | + ); |
|
449 | + $cancellation_line_item = reset($cancellation_line_item); |
|
450 | + // verify that this ticket was indeed previously cancelled |
|
451 | + if ($cancellation_line_item instanceof EE_Line_Item) { |
|
452 | + // increment cancelled quantity |
|
453 | + $cancellation_line_item->set_quantity($cancellation_line_item->quantity() + $qty); |
|
454 | + } else { |
|
455 | + // create cancellation sub line item |
|
456 | + $cancellation_line_item = EE_Line_Item::new_instance(array( |
|
457 | + 'LIN_name' => esc_html__('Cancellation', 'event_espresso'), |
|
458 | + 'LIN_desc' => sprintf( |
|
459 | + esc_html_x( |
|
460 | + 'Cancelled %1$s : %2$s', |
|
461 | + 'Cancelled Ticket Name : 2015-01-01 11:11', |
|
462 | + 'event_espresso' |
|
463 | + ), |
|
464 | + $ticket_line_item->name(), |
|
465 | + current_time(get_option('date_format') . ' ' . get_option('time_format')) |
|
466 | + ), |
|
467 | + 'LIN_unit_price' => 0, // $ticket_line_item->unit_price() |
|
468 | + 'LIN_quantity' => $qty, |
|
469 | + 'LIN_is_taxable' => $ticket_line_item->is_taxable(), |
|
470 | + 'LIN_order' => count($ticket_line_item->children()), |
|
471 | + 'LIN_total' => 0, // $ticket_line_item->unit_price() |
|
472 | + 'LIN_type' => EEM_Line_Item::type_cancellation, |
|
473 | + )); |
|
474 | + $ticket_line_item->add_child_line_item($cancellation_line_item); |
|
475 | + } |
|
476 | + if ($ticket_line_item->save_this_and_descendants() > 0) { |
|
477 | + // decrement parent line item quantity |
|
478 | + $event_line_item = $ticket_line_item->parent(); |
|
479 | + if ($event_line_item instanceof EE_Line_Item |
|
480 | + && $event_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_EVENT |
|
481 | + ) { |
|
482 | + $event_line_item->set_quantity($event_line_item->quantity() - $qty); |
|
483 | + $event_line_item->save(); |
|
484 | + } |
|
485 | + EEH_Line_Item::get_grand_total_and_recalculate_everything($ticket_line_item); |
|
486 | + return true; |
|
487 | + } |
|
488 | + return false; |
|
489 | + } |
|
490 | + |
|
491 | + |
|
492 | + /** |
|
493 | + * reinstates (un-cancels?) a previously canceled ticket line item, |
|
494 | + * by incrementing it's quantity by 1, and decrementing it's "type_cancellation" sub-line-item. |
|
495 | + * ALL totals and subtotals will NEED TO BE UPDATED after performing this action |
|
496 | + * |
|
497 | + * @param EE_Line_Item $ticket_line_item |
|
498 | + * @param int $qty |
|
499 | + * @return bool success |
|
500 | + * @throws EE_Error |
|
501 | + * @throws InvalidArgumentException |
|
502 | + * @throws InvalidDataTypeException |
|
503 | + * @throws InvalidInterfaceException |
|
504 | + * @throws ReflectionException |
|
505 | + */ |
|
506 | + public static function reinstate_canceled_ticket_line_item(EE_Line_Item $ticket_line_item, $qty = 1) |
|
507 | + { |
|
508 | + // validate incoming line_item |
|
509 | + if ($ticket_line_item->OBJ_type() !== EEM_Line_Item::OBJ_TYPE_TICKET) { |
|
510 | + throw new EE_Error( |
|
511 | + sprintf( |
|
512 | + esc_html__( |
|
513 | + 'The supplied line item must have an Object Type of "Ticket", not %1$s.', |
|
514 | + 'event_espresso' |
|
515 | + ), |
|
516 | + $ticket_line_item->type() |
|
517 | + ) |
|
518 | + ); |
|
519 | + } |
|
520 | + // get cancellation sub line item |
|
521 | + $cancellation_line_item = EEH_Line_Item::get_descendants_of_type( |
|
522 | + $ticket_line_item, |
|
523 | + EEM_Line_Item::type_cancellation |
|
524 | + ); |
|
525 | + $cancellation_line_item = reset($cancellation_line_item); |
|
526 | + // verify that this ticket was indeed previously cancelled |
|
527 | + if (! $cancellation_line_item instanceof EE_Line_Item) { |
|
528 | + return false; |
|
529 | + } |
|
530 | + if ($cancellation_line_item->quantity() > $qty) { |
|
531 | + // decrement cancelled quantity |
|
532 | + $cancellation_line_item->set_quantity($cancellation_line_item->quantity() - $qty); |
|
533 | + } elseif ($cancellation_line_item->quantity() === $qty) { |
|
534 | + // decrement cancelled quantity in case anyone still has the object kicking around |
|
535 | + $cancellation_line_item->set_quantity($cancellation_line_item->quantity() - $qty); |
|
536 | + // delete because quantity will end up as 0 |
|
537 | + $cancellation_line_item->delete(); |
|
538 | + // and attempt to destroy the object, |
|
539 | + // even though PHP won't actually destroy it until it needs the memory |
|
540 | + unset($cancellation_line_item); |
|
541 | + } else { |
|
542 | + // what ?!?! negative quantity ?!?! |
|
543 | + throw new EE_Error( |
|
544 | + sprintf( |
|
545 | + esc_html__( |
|
546 | + 'Can not reinstate %1$d cancelled ticket(s) because the cancelled ticket quantity is only %2$d.', |
|
547 | + 'event_espresso' |
|
548 | + ), |
|
549 | + $qty, |
|
550 | + $cancellation_line_item->quantity() |
|
551 | + ) |
|
552 | + ); |
|
553 | + } |
|
554 | + // increment ticket quantity |
|
555 | + $ticket_line_item->set_quantity($ticket_line_item->quantity() + $qty); |
|
556 | + if ($ticket_line_item->save_this_and_descendants() > 0) { |
|
557 | + // increment parent line item quantity |
|
558 | + $event_line_item = $ticket_line_item->parent(); |
|
559 | + if ($event_line_item instanceof EE_Line_Item |
|
560 | + && $event_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_EVENT |
|
561 | + ) { |
|
562 | + $event_line_item->set_quantity($event_line_item->quantity() + $qty); |
|
563 | + } |
|
564 | + EEH_Line_Item::get_grand_total_and_recalculate_everything($ticket_line_item); |
|
565 | + return true; |
|
566 | + } |
|
567 | + return false; |
|
568 | + } |
|
569 | + |
|
570 | + |
|
571 | + /** |
|
572 | + * calls EEH_Line_Item::find_transaction_grand_total_for_line_item() |
|
573 | + * then EE_Line_Item::recalculate_total_including_taxes() on the result |
|
574 | + * |
|
575 | + * @param EE_Line_Item $line_item |
|
576 | + * @return float |
|
577 | + * @throws EE_Error |
|
578 | + * @throws InvalidArgumentException |
|
579 | + * @throws InvalidDataTypeException |
|
580 | + * @throws InvalidInterfaceException |
|
581 | + * @throws ReflectionException |
|
582 | + */ |
|
583 | + public static function get_grand_total_and_recalculate_everything(EE_Line_Item $line_item) |
|
584 | + { |
|
585 | + $grand_total_line_item = EEH_Line_Item::find_transaction_grand_total_for_line_item($line_item); |
|
586 | + return $grand_total_line_item->recalculate_total_including_taxes(); |
|
587 | + } |
|
588 | + |
|
589 | + |
|
590 | + /** |
|
591 | + * Gets the line item which contains the subtotal of all the items |
|
592 | + * |
|
593 | + * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
594 | + * @return EE_Line_Item |
|
595 | + * @throws EE_Error |
|
596 | + * @throws InvalidArgumentException |
|
597 | + * @throws InvalidDataTypeException |
|
598 | + * @throws InvalidInterfaceException |
|
599 | + * @throws ReflectionException |
|
600 | + */ |
|
601 | + public static function get_pre_tax_subtotal(EE_Line_Item $total_line_item) |
|
602 | + { |
|
603 | + $pre_tax_subtotal = $total_line_item->get_child_line_item('pre-tax-subtotal'); |
|
604 | + return $pre_tax_subtotal instanceof EE_Line_Item |
|
605 | + ? $pre_tax_subtotal |
|
606 | + : self::create_pre_tax_subtotal($total_line_item); |
|
607 | + } |
|
608 | + |
|
609 | + |
|
610 | + /** |
|
611 | + * Gets the line item for the taxes subtotal |
|
612 | + * |
|
613 | + * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
614 | + * @return EE_Line_Item |
|
615 | + * @throws EE_Error |
|
616 | + * @throws InvalidArgumentException |
|
617 | + * @throws InvalidDataTypeException |
|
618 | + * @throws InvalidInterfaceException |
|
619 | + * @throws ReflectionException |
|
620 | + */ |
|
621 | + public static function get_taxes_subtotal(EE_Line_Item $total_line_item) |
|
622 | + { |
|
623 | + $taxes = $total_line_item->get_child_line_item('taxes'); |
|
624 | + return $taxes ? $taxes : self::create_taxes_subtotal($total_line_item); |
|
625 | + } |
|
626 | + |
|
627 | + |
|
628 | + /** |
|
629 | + * sets the TXN ID on an EE_Line_Item if passed a valid EE_Transaction object |
|
630 | + * |
|
631 | + * @param EE_Line_Item $line_item |
|
632 | + * @param EE_Transaction $transaction |
|
633 | + * @return void |
|
634 | + * @throws EE_Error |
|
635 | + * @throws InvalidArgumentException |
|
636 | + * @throws InvalidDataTypeException |
|
637 | + * @throws InvalidInterfaceException |
|
638 | + * @throws ReflectionException |
|
639 | + */ |
|
640 | + public static function set_TXN_ID(EE_Line_Item $line_item, $transaction = null) |
|
641 | + { |
|
642 | + if ($transaction) { |
|
643 | + /** @type EEM_Transaction $EEM_Transaction */ |
|
644 | + $EEM_Transaction = EE_Registry::instance()->load_model('Transaction'); |
|
645 | + $TXN_ID = $EEM_Transaction->ensure_is_ID($transaction); |
|
646 | + $line_item->set_TXN_ID($TXN_ID); |
|
647 | + } |
|
648 | + } |
|
649 | + |
|
650 | + |
|
651 | + /** |
|
652 | + * Creates a new default total line item for the transaction, |
|
653 | + * and its tickets subtotal and taxes subtotal line items (and adds the |
|
654 | + * existing taxes as children of the taxes subtotal line item) |
|
655 | + * |
|
656 | + * @param EE_Transaction $transaction |
|
657 | + * @return EE_Line_Item of type total |
|
658 | + * @throws EE_Error |
|
659 | + * @throws InvalidArgumentException |
|
660 | + * @throws InvalidDataTypeException |
|
661 | + * @throws InvalidInterfaceException |
|
662 | + * @throws ReflectionException |
|
663 | + */ |
|
664 | + public static function create_total_line_item($transaction = null) |
|
665 | + { |
|
666 | + $total_line_item = EE_Line_Item::new_instance(array( |
|
667 | + 'LIN_code' => 'total', |
|
668 | + 'LIN_name' => esc_html__('Grand Total', 'event_espresso'), |
|
669 | + 'LIN_type' => EEM_Line_Item::type_total, |
|
670 | + 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_TRANSACTION, |
|
671 | + )); |
|
672 | + $total_line_item = apply_filters( |
|
673 | + 'FHEE__EEH_Line_Item__create_total_line_item__total_line_item', |
|
674 | + $total_line_item |
|
675 | + ); |
|
676 | + self::set_TXN_ID($total_line_item, $transaction); |
|
677 | + self::create_pre_tax_subtotal($total_line_item, $transaction); |
|
678 | + self::create_taxes_subtotal($total_line_item, $transaction); |
|
679 | + return $total_line_item; |
|
680 | + } |
|
681 | + |
|
682 | + |
|
683 | + /** |
|
684 | + * Creates a default items subtotal line item |
|
685 | + * |
|
686 | + * @param EE_Line_Item $total_line_item |
|
687 | + * @param EE_Transaction $transaction |
|
688 | + * @return EE_Line_Item |
|
689 | + * @throws EE_Error |
|
690 | + * @throws InvalidArgumentException |
|
691 | + * @throws InvalidDataTypeException |
|
692 | + * @throws InvalidInterfaceException |
|
693 | + * @throws ReflectionException |
|
694 | + */ |
|
695 | + protected static function create_pre_tax_subtotal(EE_Line_Item $total_line_item, $transaction = null) |
|
696 | + { |
|
697 | + $pre_tax_line_item = EE_Line_Item::new_instance(array( |
|
698 | + 'LIN_code' => 'pre-tax-subtotal', |
|
699 | + 'LIN_name' => esc_html__('Pre-Tax Subtotal', 'event_espresso'), |
|
700 | + 'LIN_type' => EEM_Line_Item::type_sub_total, |
|
701 | + )); |
|
702 | + $pre_tax_line_item = apply_filters( |
|
703 | + 'FHEE__EEH_Line_Item__create_pre_tax_subtotal__pre_tax_line_item', |
|
704 | + $pre_tax_line_item |
|
705 | + ); |
|
706 | + self::set_TXN_ID($pre_tax_line_item, $transaction); |
|
707 | + $total_line_item->add_child_line_item($pre_tax_line_item); |
|
708 | + self::create_event_subtotal($pre_tax_line_item, $transaction); |
|
709 | + return $pre_tax_line_item; |
|
710 | + } |
|
711 | + |
|
712 | + |
|
713 | + /** |
|
714 | + * Creates a line item for the taxes subtotal and finds all the tax prices |
|
715 | + * and applies taxes to it |
|
716 | + * |
|
717 | + * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
718 | + * @param EE_Transaction $transaction |
|
719 | + * @return EE_Line_Item |
|
720 | + * @throws EE_Error |
|
721 | + * @throws InvalidArgumentException |
|
722 | + * @throws InvalidDataTypeException |
|
723 | + * @throws InvalidInterfaceException |
|
724 | + * @throws ReflectionException |
|
725 | + */ |
|
726 | + protected static function create_taxes_subtotal(EE_Line_Item $total_line_item, $transaction = null) |
|
727 | + { |
|
728 | + $tax_line_item = EE_Line_Item::new_instance(array( |
|
729 | + 'LIN_code' => 'taxes', |
|
730 | + 'LIN_name' => esc_html__('Taxes', 'event_espresso'), |
|
731 | + 'LIN_type' => EEM_Line_Item::type_tax_sub_total, |
|
732 | + 'LIN_order' => 1000,// this should always come last |
|
733 | + )); |
|
734 | + $tax_line_item = apply_filters( |
|
735 | + 'FHEE__EEH_Line_Item__create_taxes_subtotal__tax_line_item', |
|
736 | + $tax_line_item |
|
737 | + ); |
|
738 | + self::set_TXN_ID($tax_line_item, $transaction); |
|
739 | + $total_line_item->add_child_line_item($tax_line_item); |
|
740 | + // and lastly, add the actual taxes |
|
741 | + self::apply_taxes($total_line_item); |
|
742 | + return $tax_line_item; |
|
743 | + } |
|
744 | + |
|
745 | + |
|
746 | + /** |
|
747 | + * Creates a default items subtotal line item |
|
748 | + * |
|
749 | + * @param EE_Line_Item $pre_tax_line_item |
|
750 | + * @param EE_Transaction $transaction |
|
751 | + * @param EE_Event $event |
|
752 | + * @return EE_Line_Item |
|
753 | + * @throws EE_Error |
|
754 | + * @throws InvalidArgumentException |
|
755 | + * @throws InvalidDataTypeException |
|
756 | + * @throws InvalidInterfaceException |
|
757 | + * @throws ReflectionException |
|
758 | + */ |
|
759 | + public static function create_event_subtotal(EE_Line_Item $pre_tax_line_item, $transaction = null, $event = null) |
|
760 | + { |
|
761 | + $event_line_item = EE_Line_Item::new_instance(array( |
|
762 | + 'LIN_code' => self::get_event_code($event), |
|
763 | + 'LIN_name' => self::get_event_name($event), |
|
764 | + 'LIN_desc' => self::get_event_desc($event), |
|
765 | + 'LIN_type' => EEM_Line_Item::type_sub_total, |
|
766 | + 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_EVENT, |
|
767 | + 'OBJ_ID' => $event instanceof EE_Event ? $event->ID() : 0, |
|
768 | + )); |
|
769 | + $event_line_item = apply_filters( |
|
770 | + 'FHEE__EEH_Line_Item__create_event_subtotal__event_line_item', |
|
771 | + $event_line_item |
|
772 | + ); |
|
773 | + self::set_TXN_ID($event_line_item, $transaction); |
|
774 | + $pre_tax_line_item->add_child_line_item($event_line_item); |
|
775 | + return $event_line_item; |
|
776 | + } |
|
777 | + |
|
778 | + |
|
779 | + /** |
|
780 | + * Gets what the event ticket's code SHOULD be |
|
781 | + * |
|
782 | + * @param EE_Event $event |
|
783 | + * @return string |
|
784 | + * @throws EE_Error |
|
785 | + */ |
|
786 | + public static function get_event_code($event) |
|
787 | + { |
|
788 | + return 'event-' . ($event instanceof EE_Event ? $event->ID() : '0'); |
|
789 | + } |
|
790 | + |
|
791 | + |
|
792 | + /** |
|
793 | + * Gets the event name |
|
794 | + * |
|
795 | + * @param EE_Event $event |
|
796 | + * @return string |
|
797 | + * @throws EE_Error |
|
798 | + */ |
|
799 | + public static function get_event_name($event) |
|
800 | + { |
|
801 | + return $event instanceof EE_Event |
|
802 | + ? mb_substr($event->name(), 0, 245) |
|
803 | + : esc_html__('Event', 'event_espresso'); |
|
804 | + } |
|
805 | + |
|
806 | + |
|
807 | + /** |
|
808 | + * Gets the event excerpt |
|
809 | + * |
|
810 | + * @param EE_Event $event |
|
811 | + * @return string |
|
812 | + * @throws EE_Error |
|
813 | + */ |
|
814 | + public static function get_event_desc($event) |
|
815 | + { |
|
816 | + return $event instanceof EE_Event ? $event->short_description() : ''; |
|
817 | + } |
|
818 | + |
|
819 | + |
|
820 | + /** |
|
821 | + * Given the grand total line item and a ticket, finds the event sub-total |
|
822 | + * line item the ticket's purchase should be added onto |
|
823 | + * |
|
824 | + * @access public |
|
825 | + * @param EE_Line_Item $grand_total the grand total line item |
|
826 | + * @param EE_Ticket $ticket |
|
827 | + * @return EE_Line_Item |
|
828 | + * @throws EE_Error |
|
829 | + * @throws InvalidArgumentException |
|
830 | + * @throws InvalidDataTypeException |
|
831 | + * @throws InvalidInterfaceException |
|
832 | + * @throws ReflectionException |
|
833 | + */ |
|
834 | + public static function get_event_line_item_for_ticket(EE_Line_Item $grand_total, EE_Ticket $ticket) |
|
835 | + { |
|
836 | + $first_datetime = $ticket->first_datetime(); |
|
837 | + if (! $first_datetime instanceof EE_Datetime) { |
|
838 | + throw new EE_Error( |
|
839 | + sprintf( |
|
840 | + __('The supplied ticket (ID %d) has no datetimes', 'event_espresso'), |
|
841 | + $ticket->ID() |
|
842 | + ) |
|
843 | + ); |
|
844 | + } |
|
845 | + $event = $first_datetime->event(); |
|
846 | + if (! $event instanceof EE_Event) { |
|
847 | + throw new EE_Error( |
|
848 | + sprintf( |
|
849 | + esc_html__( |
|
850 | + 'The supplied ticket (ID %d) has no event data associated with it.', |
|
851 | + 'event_espresso' |
|
852 | + ), |
|
853 | + $ticket->ID() |
|
854 | + ) |
|
855 | + ); |
|
856 | + } |
|
857 | + $events_sub_total = EEH_Line_Item::get_event_line_item($grand_total, $event); |
|
858 | + if (! $events_sub_total instanceof EE_Line_Item) { |
|
859 | + throw new EE_Error( |
|
860 | + sprintf( |
|
861 | + esc_html__( |
|
862 | + 'There is no events sub-total for ticket %s on total line item %d', |
|
863 | + 'event_espresso' |
|
864 | + ), |
|
865 | + $ticket->ID(), |
|
866 | + $grand_total->ID() |
|
867 | + ) |
|
868 | + ); |
|
869 | + } |
|
870 | + return $events_sub_total; |
|
871 | + } |
|
872 | + |
|
873 | + |
|
874 | + /** |
|
875 | + * Gets the event line item |
|
876 | + * |
|
877 | + * @param EE_Line_Item $grand_total |
|
878 | + * @param EE_Event $event |
|
879 | + * @return EE_Line_Item for the event subtotal which is a child of $grand_total |
|
880 | + * @throws EE_Error |
|
881 | + * @throws InvalidArgumentException |
|
882 | + * @throws InvalidDataTypeException |
|
883 | + * @throws InvalidInterfaceException |
|
884 | + * @throws ReflectionException |
|
885 | + */ |
|
886 | + public static function get_event_line_item(EE_Line_Item $grand_total, $event) |
|
887 | + { |
|
888 | + /** @type EE_Event $event */ |
|
889 | + $event = EEM_Event::instance()->ensure_is_obj($event, true); |
|
890 | + $event_line_item = null; |
|
891 | + $found = false; |
|
892 | + foreach (EEH_Line_Item::get_event_subtotals($grand_total) as $event_line_item) { |
|
893 | + // default event subtotal, we should only ever find this the first time this method is called |
|
894 | + if (! $event_line_item->OBJ_ID()) { |
|
895 | + // let's use this! but first... set the event details |
|
896 | + EEH_Line_Item::set_event_subtotal_details($event_line_item, $event); |
|
897 | + $found = true; |
|
898 | + break; |
|
899 | + } |
|
900 | + if ($event_line_item->OBJ_ID() === $event->ID()) { |
|
901 | + // found existing line item for this event in the cart, so break out of loop and use this one |
|
902 | + $found = true; |
|
903 | + break; |
|
904 | + } |
|
905 | + } |
|
906 | + if (! $found) { |
|
907 | + // there is no event sub-total yet, so add it |
|
908 | + $pre_tax_subtotal = EEH_Line_Item::get_pre_tax_subtotal($grand_total); |
|
909 | + // create a new "event" subtotal below that |
|
910 | + $event_line_item = EEH_Line_Item::create_event_subtotal($pre_tax_subtotal, null, $event); |
|
911 | + // and set the event details |
|
912 | + EEH_Line_Item::set_event_subtotal_details($event_line_item, $event); |
|
913 | + } |
|
914 | + return $event_line_item; |
|
915 | + } |
|
916 | + |
|
917 | + |
|
918 | + /** |
|
919 | + * Creates a default items subtotal line item |
|
920 | + * |
|
921 | + * @param EE_Line_Item $event_line_item |
|
922 | + * @param EE_Event $event |
|
923 | + * @param EE_Transaction $transaction |
|
924 | + * @return void |
|
925 | + * @throws EE_Error |
|
926 | + * @throws InvalidArgumentException |
|
927 | + * @throws InvalidDataTypeException |
|
928 | + * @throws InvalidInterfaceException |
|
929 | + * @throws ReflectionException |
|
930 | + */ |
|
931 | + public static function set_event_subtotal_details( |
|
932 | + EE_Line_Item $event_line_item, |
|
933 | + EE_Event $event, |
|
934 | + $transaction = null |
|
935 | + ) { |
|
936 | + if ($event instanceof EE_Event) { |
|
937 | + $event_line_item->set_code(self::get_event_code($event)); |
|
938 | + $event_line_item->set_name(self::get_event_name($event)); |
|
939 | + $event_line_item->set_desc(self::get_event_desc($event)); |
|
940 | + $event_line_item->set_OBJ_ID($event->ID()); |
|
941 | + } |
|
942 | + self::set_TXN_ID($event_line_item, $transaction); |
|
943 | + } |
|
944 | + |
|
945 | + |
|
946 | + /** |
|
947 | + * Finds what taxes should apply, adds them as tax line items under the taxes sub-total, |
|
948 | + * and recalculates the taxes sub-total and the grand total. Resets the taxes, so |
|
949 | + * any old taxes are removed |
|
950 | + * |
|
951 | + * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
952 | + * @param bool $update_txn_status |
|
953 | + * @return bool |
|
954 | + * @throws EE_Error |
|
955 | + * @throws InvalidArgumentException |
|
956 | + * @throws InvalidDataTypeException |
|
957 | + * @throws InvalidInterfaceException |
|
958 | + * @throws ReflectionException |
|
959 | + * @throws RuntimeException |
|
960 | + */ |
|
961 | + public static function apply_taxes(EE_Line_Item $total_line_item, $update_txn_status = false) |
|
962 | + { |
|
963 | + /** @type EEM_Price $EEM_Price */ |
|
964 | + $EEM_Price = EE_Registry::instance()->load_model('Price'); |
|
965 | + // get array of taxes via Price Model |
|
966 | + $ordered_taxes = $EEM_Price->get_all_prices_that_are_taxes(); |
|
967 | + ksort($ordered_taxes); |
|
968 | + $taxes_line_item = self::get_taxes_subtotal($total_line_item); |
|
969 | + // just to be safe, remove its old tax line items |
|
970 | + $deleted = $taxes_line_item->delete_children_line_items(); |
|
971 | + $updates = false; |
|
972 | + // loop thru taxes |
|
973 | + foreach ($ordered_taxes as $order => $taxes) { |
|
974 | + foreach ($taxes as $tax) { |
|
975 | + if ($tax instanceof EE_Price) { |
|
976 | + $tax_line_item = EE_Line_Item::new_instance( |
|
977 | + array( |
|
978 | + 'LIN_name' => $tax->name(), |
|
979 | + 'LIN_desc' => $tax->desc(), |
|
980 | + 'LIN_percent' => $tax->amount(), |
|
981 | + 'LIN_is_taxable' => false, |
|
982 | + 'LIN_order' => $order, |
|
983 | + 'LIN_total' => 0, |
|
984 | + 'LIN_type' => EEM_Line_Item::type_tax, |
|
985 | + 'OBJ_type' => EEM_Line_Item::OBJ_TYPE_PRICE, |
|
986 | + 'OBJ_ID' => $tax->ID(), |
|
987 | + ) |
|
988 | + ); |
|
989 | + $tax_line_item = apply_filters( |
|
990 | + 'FHEE__EEH_Line_Item__apply_taxes__tax_line_item', |
|
991 | + $tax_line_item |
|
992 | + ); |
|
993 | + $updates = $taxes_line_item->add_child_line_item($tax_line_item) ? |
|
994 | + true : |
|
995 | + $updates; |
|
996 | + } |
|
997 | + } |
|
998 | + } |
|
999 | + // only recalculate totals if something changed |
|
1000 | + if ($deleted || $updates) { |
|
1001 | + $total_line_item->recalculate_total_including_taxes($update_txn_status); |
|
1002 | + return true; |
|
1003 | + } |
|
1004 | + return false; |
|
1005 | + } |
|
1006 | + |
|
1007 | + |
|
1008 | + /** |
|
1009 | + * Ensures that taxes have been applied to the order, if not applies them. |
|
1010 | + * Returns the total amount of tax |
|
1011 | + * |
|
1012 | + * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
1013 | + * @return float |
|
1014 | + * @throws EE_Error |
|
1015 | + * @throws InvalidArgumentException |
|
1016 | + * @throws InvalidDataTypeException |
|
1017 | + * @throws InvalidInterfaceException |
|
1018 | + * @throws ReflectionException |
|
1019 | + */ |
|
1020 | + public static function ensure_taxes_applied($total_line_item) |
|
1021 | + { |
|
1022 | + $taxes_subtotal = self::get_taxes_subtotal($total_line_item); |
|
1023 | + if (! $taxes_subtotal->children()) { |
|
1024 | + self::apply_taxes($total_line_item); |
|
1025 | + } |
|
1026 | + return $taxes_subtotal->total(); |
|
1027 | + } |
|
1028 | + |
|
1029 | + |
|
1030 | + /** |
|
1031 | + * Deletes ALL children of the passed line item |
|
1032 | + * |
|
1033 | + * @param EE_Line_Item $parent_line_item |
|
1034 | + * @return bool |
|
1035 | + * @throws EE_Error |
|
1036 | + * @throws InvalidArgumentException |
|
1037 | + * @throws InvalidDataTypeException |
|
1038 | + * @throws InvalidInterfaceException |
|
1039 | + * @throws ReflectionException |
|
1040 | + */ |
|
1041 | + public static function delete_all_child_items(EE_Line_Item $parent_line_item) |
|
1042 | + { |
|
1043 | + $deleted = 0; |
|
1044 | + foreach ($parent_line_item->children() as $child_line_item) { |
|
1045 | + if ($child_line_item instanceof EE_Line_Item) { |
|
1046 | + $deleted += EEH_Line_Item::delete_all_child_items($child_line_item); |
|
1047 | + if ($child_line_item->ID()) { |
|
1048 | + $child_line_item->delete(); |
|
1049 | + unset($child_line_item); |
|
1050 | + } else { |
|
1051 | + $parent_line_item->delete_child_line_item($child_line_item->code()); |
|
1052 | + } |
|
1053 | + $deleted++; |
|
1054 | + } |
|
1055 | + } |
|
1056 | + return $deleted; |
|
1057 | + } |
|
1058 | + |
|
1059 | + |
|
1060 | + /** |
|
1061 | + * Deletes the line items as indicated by the line item code(s) provided, |
|
1062 | + * regardless of where they're found in the line item tree. Automatically |
|
1063 | + * re-calculates the line item totals and updates the related transaction. But |
|
1064 | + * DOES NOT automatically upgrade the transaction's registrations' final prices (which |
|
1065 | + * should probably change because of this). |
|
1066 | + * You should call EE_Registration_Processor::calculate_reg_final_prices_per_line_item() |
|
1067 | + * after using this, to keep the registration final prices in-sync with the transaction's total. |
|
1068 | + * |
|
1069 | + * @param EE_Line_Item $total_line_item of type EEM_Line_Item::type_total |
|
1070 | + * @param array|bool|string $line_item_codes |
|
1071 | + * @return int number of items successfully removed |
|
1072 | + * @throws EE_Error |
|
1073 | + */ |
|
1074 | + public static function delete_items(EE_Line_Item $total_line_item, $line_item_codes = false) |
|
1075 | + { |
|
1076 | + |
|
1077 | + if ($total_line_item->type() !== EEM_Line_Item::type_total) { |
|
1078 | + EE_Error::doing_it_wrong( |
|
1079 | + 'EEH_Line_Item::delete_items', |
|
1080 | + esc_html__( |
|
1081 | + 'This static method should only be called with a TOTAL line item, otherwise we won\'t recalculate the totals correctly', |
|
1082 | + 'event_espresso' |
|
1083 | + ), |
|
1084 | + '4.6.18' |
|
1085 | + ); |
|
1086 | + } |
|
1087 | + do_action('AHEE_log', __FILE__, __FUNCTION__, ''); |
|
1088 | + |
|
1089 | + // check if only a single line_item_id was passed |
|
1090 | + if (! empty($line_item_codes) && ! is_array($line_item_codes)) { |
|
1091 | + // place single line_item_id in an array to appear as multiple line_item_ids |
|
1092 | + $line_item_codes = array($line_item_codes); |
|
1093 | + } |
|
1094 | + $removals = 0; |
|
1095 | + // cycle thru line_item_ids |
|
1096 | + foreach ($line_item_codes as $line_item_id) { |
|
1097 | + $removals += $total_line_item->delete_child_line_item($line_item_id); |
|
1098 | + } |
|
1099 | + |
|
1100 | + if ($removals > 0) { |
|
1101 | + $total_line_item->recalculate_taxes_and_tax_total(); |
|
1102 | + return $removals; |
|
1103 | + } else { |
|
1104 | + return false; |
|
1105 | + } |
|
1106 | + } |
|
1107 | + |
|
1108 | + |
|
1109 | + /** |
|
1110 | + * Overwrites the previous tax by clearing out the old taxes, and creates a new |
|
1111 | + * tax and updates the total line item accordingly |
|
1112 | + * |
|
1113 | + * @param EE_Line_Item $total_line_item |
|
1114 | + * @param float $amount |
|
1115 | + * @param string $name |
|
1116 | + * @param string $description |
|
1117 | + * @param string $code |
|
1118 | + * @param boolean $add_to_existing_line_item |
|
1119 | + * if true, and a duplicate line item with the same code is found, |
|
1120 | + * $amount will be added onto it; otherwise will simply set the taxes to match $amount |
|
1121 | + * @return EE_Line_Item the new tax line item created |
|
1122 | + * @throws EE_Error |
|
1123 | + * @throws InvalidArgumentException |
|
1124 | + * @throws InvalidDataTypeException |
|
1125 | + * @throws InvalidInterfaceException |
|
1126 | + * @throws ReflectionException |
|
1127 | + */ |
|
1128 | + public static function set_total_tax_to( |
|
1129 | + EE_Line_Item $total_line_item, |
|
1130 | + $amount, |
|
1131 | + $name = null, |
|
1132 | + $description = null, |
|
1133 | + $code = null, |
|
1134 | + $add_to_existing_line_item = false |
|
1135 | + ) { |
|
1136 | + $tax_subtotal = self::get_taxes_subtotal($total_line_item); |
|
1137 | + $taxable_total = $total_line_item->taxable_total(); |
|
1138 | + |
|
1139 | + if ($add_to_existing_line_item) { |
|
1140 | + $new_tax = $tax_subtotal->get_child_line_item($code); |
|
1141 | + EEM_Line_Item::instance()->delete( |
|
1142 | + array(array('LIN_code' => array('!=', $code), 'LIN_parent' => $tax_subtotal->ID())) |
|
1143 | + ); |
|
1144 | + } else { |
|
1145 | + $new_tax = null; |
|
1146 | + $tax_subtotal->delete_children_line_items(); |
|
1147 | + } |
|
1148 | + if ($new_tax) { |
|
1149 | + $new_tax->set_total($new_tax->total() + $amount); |
|
1150 | + $new_tax->set_percent($taxable_total ? $new_tax->total() / $taxable_total * 100 : 0); |
|
1151 | + } else { |
|
1152 | + // no existing tax item. Create it |
|
1153 | + $new_tax = EE_Line_Item::new_instance(array( |
|
1154 | + 'TXN_ID' => $total_line_item->TXN_ID(), |
|
1155 | + 'LIN_name' => $name ? $name : esc_html__('Tax', 'event_espresso'), |
|
1156 | + 'LIN_desc' => $description ? $description : '', |
|
1157 | + 'LIN_percent' => $taxable_total ? ($amount / $taxable_total * 100) : 0, |
|
1158 | + 'LIN_total' => $amount, |
|
1159 | + 'LIN_parent' => $tax_subtotal->ID(), |
|
1160 | + 'LIN_type' => EEM_Line_Item::type_tax, |
|
1161 | + 'LIN_code' => $code, |
|
1162 | + )); |
|
1163 | + } |
|
1164 | + |
|
1165 | + $new_tax = apply_filters( |
|
1166 | + 'FHEE__EEH_Line_Item__set_total_tax_to__new_tax_subtotal', |
|
1167 | + $new_tax, |
|
1168 | + $total_line_item |
|
1169 | + ); |
|
1170 | + $new_tax->save(); |
|
1171 | + $tax_subtotal->set_total($new_tax->total()); |
|
1172 | + $tax_subtotal->save(); |
|
1173 | + $total_line_item->recalculate_total_including_taxes(); |
|
1174 | + return $new_tax; |
|
1175 | + } |
|
1176 | + |
|
1177 | + |
|
1178 | + /** |
|
1179 | + * Makes all the line items which are children of $line_item taxable (or not). |
|
1180 | + * Does NOT save the line items |
|
1181 | + * |
|
1182 | + * @param EE_Line_Item $line_item |
|
1183 | + * @param boolean $taxable |
|
1184 | + * @param string $code_substring_for_whitelist if this string is part of the line item's code |
|
1185 | + * it will be whitelisted (ie, except from becoming taxable) |
|
1186 | + * @throws EE_Error |
|
1187 | + */ |
|
1188 | + public static function set_line_items_taxable( |
|
1189 | + EE_Line_Item $line_item, |
|
1190 | + $taxable = true, |
|
1191 | + $code_substring_for_whitelist = null |
|
1192 | + ) { |
|
1193 | + $whitelisted = false; |
|
1194 | + if ($code_substring_for_whitelist !== null) { |
|
1195 | + $whitelisted = strpos($line_item->code(), $code_substring_for_whitelist) !== false; |
|
1196 | + } |
|
1197 | + if (! $whitelisted && $line_item->is_line_item()) { |
|
1198 | + $line_item->set_is_taxable($taxable); |
|
1199 | + } |
|
1200 | + foreach ($line_item->children() as $child_line_item) { |
|
1201 | + EEH_Line_Item::set_line_items_taxable( |
|
1202 | + $child_line_item, |
|
1203 | + $taxable, |
|
1204 | + $code_substring_for_whitelist |
|
1205 | + ); |
|
1206 | + } |
|
1207 | + } |
|
1208 | + |
|
1209 | + |
|
1210 | + /** |
|
1211 | + * Gets all descendants that are event subtotals |
|
1212 | + * |
|
1213 | + * @uses EEH_Line_Item::get_subtotals_of_object_type() |
|
1214 | + * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1215 | + * @return EE_Line_Item[] |
|
1216 | + * @throws EE_Error |
|
1217 | + */ |
|
1218 | + public static function get_event_subtotals(EE_Line_Item $parent_line_item) |
|
1219 | + { |
|
1220 | + return self::get_subtotals_of_object_type($parent_line_item, EEM_Line_Item::OBJ_TYPE_EVENT); |
|
1221 | + } |
|
1222 | + |
|
1223 | + |
|
1224 | + /** |
|
1225 | + * Gets all descendants subtotals that match the supplied object type |
|
1226 | + * |
|
1227 | + * @uses EEH_Line_Item::_get_descendants_by_type_and_object_type() |
|
1228 | + * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1229 | + * @param string $obj_type |
|
1230 | + * @return EE_Line_Item[] |
|
1231 | + * @throws EE_Error |
|
1232 | + */ |
|
1233 | + public static function get_subtotals_of_object_type(EE_Line_Item $parent_line_item, $obj_type = '') |
|
1234 | + { |
|
1235 | + return self::_get_descendants_by_type_and_object_type( |
|
1236 | + $parent_line_item, |
|
1237 | + EEM_Line_Item::type_sub_total, |
|
1238 | + $obj_type |
|
1239 | + ); |
|
1240 | + } |
|
1241 | + |
|
1242 | + |
|
1243 | + /** |
|
1244 | + * Gets all descendants that are tickets |
|
1245 | + * |
|
1246 | + * @uses EEH_Line_Item::get_line_items_of_object_type() |
|
1247 | + * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1248 | + * @return EE_Line_Item[] |
|
1249 | + * @throws EE_Error |
|
1250 | + */ |
|
1251 | + public static function get_ticket_line_items(EE_Line_Item $parent_line_item) |
|
1252 | + { |
|
1253 | + return self::get_line_items_of_object_type( |
|
1254 | + $parent_line_item, |
|
1255 | + EEM_Line_Item::OBJ_TYPE_TICKET |
|
1256 | + ); |
|
1257 | + } |
|
1258 | + |
|
1259 | + |
|
1260 | + /** |
|
1261 | + * Gets all descendants subtotals that match the supplied object type |
|
1262 | + * |
|
1263 | + * @uses EEH_Line_Item::_get_descendants_by_type_and_object_type() |
|
1264 | + * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1265 | + * @param string $obj_type |
|
1266 | + * @return EE_Line_Item[] |
|
1267 | + * @throws EE_Error |
|
1268 | + */ |
|
1269 | + public static function get_line_items_of_object_type(EE_Line_Item $parent_line_item, $obj_type = '') |
|
1270 | + { |
|
1271 | + return self::_get_descendants_by_type_and_object_type( |
|
1272 | + $parent_line_item, |
|
1273 | + EEM_Line_Item::type_line_item, |
|
1274 | + $obj_type |
|
1275 | + ); |
|
1276 | + } |
|
1277 | + |
|
1278 | + |
|
1279 | + /** |
|
1280 | + * Gets all the descendants (ie, children or children of children etc) that are of the type 'tax' |
|
1281 | + * |
|
1282 | + * @uses EEH_Line_Item::get_descendants_of_type() |
|
1283 | + * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1284 | + * @return EE_Line_Item[] |
|
1285 | + * @throws EE_Error |
|
1286 | + */ |
|
1287 | + public static function get_tax_descendants(EE_Line_Item $parent_line_item) |
|
1288 | + { |
|
1289 | + return EEH_Line_Item::get_descendants_of_type( |
|
1290 | + $parent_line_item, |
|
1291 | + EEM_Line_Item::type_tax |
|
1292 | + ); |
|
1293 | + } |
|
1294 | + |
|
1295 | + |
|
1296 | + /** |
|
1297 | + * Gets all the real items purchased which are children of this item |
|
1298 | + * |
|
1299 | + * @uses EEH_Line_Item::get_descendants_of_type() |
|
1300 | + * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1301 | + * @return EE_Line_Item[] |
|
1302 | + * @throws EE_Error |
|
1303 | + */ |
|
1304 | + public static function get_line_item_descendants(EE_Line_Item $parent_line_item) |
|
1305 | + { |
|
1306 | + return EEH_Line_Item::get_descendants_of_type( |
|
1307 | + $parent_line_item, |
|
1308 | + EEM_Line_Item::type_line_item |
|
1309 | + ); |
|
1310 | + } |
|
1311 | + |
|
1312 | + |
|
1313 | + /** |
|
1314 | + * Gets all descendants of supplied line item that match the supplied line item type |
|
1315 | + * |
|
1316 | + * @uses EEH_Line_Item::_get_descendants_by_type_and_object_type() |
|
1317 | + * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1318 | + * @param string $line_item_type one of the EEM_Line_Item constants |
|
1319 | + * @return EE_Line_Item[] |
|
1320 | + * @throws EE_Error |
|
1321 | + */ |
|
1322 | + public static function get_descendants_of_type(EE_Line_Item $parent_line_item, $line_item_type) |
|
1323 | + { |
|
1324 | + return self::_get_descendants_by_type_and_object_type( |
|
1325 | + $parent_line_item, |
|
1326 | + $line_item_type, |
|
1327 | + null |
|
1328 | + ); |
|
1329 | + } |
|
1330 | + |
|
1331 | + |
|
1332 | + /** |
|
1333 | + * Gets all descendants of supplied line item that match the supplied line item type and possibly the object type |
|
1334 | + * as well |
|
1335 | + * |
|
1336 | + * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1337 | + * @param string $line_item_type one of the EEM_Line_Item constants |
|
1338 | + * @param string | NULL $obj_type object model class name (minus prefix) or NULL to ignore object type when |
|
1339 | + * searching |
|
1340 | + * @return EE_Line_Item[] |
|
1341 | + * @throws EE_Error |
|
1342 | + */ |
|
1343 | + protected static function _get_descendants_by_type_and_object_type( |
|
1344 | + EE_Line_Item $parent_line_item, |
|
1345 | + $line_item_type, |
|
1346 | + $obj_type = null |
|
1347 | + ) { |
|
1348 | + $objects = array(); |
|
1349 | + foreach ($parent_line_item->children() as $child_line_item) { |
|
1350 | + if ($child_line_item instanceof EE_Line_Item) { |
|
1351 | + if ($child_line_item->type() === $line_item_type |
|
1352 | + && ( |
|
1353 | + $child_line_item->OBJ_type() === $obj_type || $obj_type === null |
|
1354 | + ) |
|
1355 | + ) { |
|
1356 | + $objects[] = $child_line_item; |
|
1357 | + } else { |
|
1358 | + // go-through-all-its children looking for more matches |
|
1359 | + $objects = array_merge( |
|
1360 | + $objects, |
|
1361 | + self::_get_descendants_by_type_and_object_type( |
|
1362 | + $child_line_item, |
|
1363 | + $line_item_type, |
|
1364 | + $obj_type |
|
1365 | + ) |
|
1366 | + ); |
|
1367 | + } |
|
1368 | + } |
|
1369 | + } |
|
1370 | + return $objects; |
|
1371 | + } |
|
1372 | + |
|
1373 | + |
|
1374 | + /** |
|
1375 | + * Gets all descendants subtotals that match the supplied object type |
|
1376 | + * |
|
1377 | + * @uses EEH_Line_Item::_get_descendants_by_type_and_object_type() |
|
1378 | + * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1379 | + * @param string $OBJ_type object type (like Event) |
|
1380 | + * @param array $OBJ_IDs array of OBJ_IDs |
|
1381 | + * @return EE_Line_Item[] |
|
1382 | + * @throws EE_Error |
|
1383 | + */ |
|
1384 | + public static function get_line_items_by_object_type_and_IDs( |
|
1385 | + EE_Line_Item $parent_line_item, |
|
1386 | + $OBJ_type = '', |
|
1387 | + $OBJ_IDs = array() |
|
1388 | + ) { |
|
1389 | + return self::_get_descendants_by_object_type_and_object_ID( |
|
1390 | + $parent_line_item, |
|
1391 | + $OBJ_type, |
|
1392 | + $OBJ_IDs |
|
1393 | + ); |
|
1394 | + } |
|
1395 | + |
|
1396 | + |
|
1397 | + /** |
|
1398 | + * Gets all descendants of supplied line item that match the supplied line item type and possibly the object type |
|
1399 | + * as well |
|
1400 | + * |
|
1401 | + * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1402 | + * @param string $OBJ_type object type (like Event) |
|
1403 | + * @param array $OBJ_IDs array of OBJ_IDs |
|
1404 | + * @return EE_Line_Item[] |
|
1405 | + * @throws EE_Error |
|
1406 | + */ |
|
1407 | + protected static function _get_descendants_by_object_type_and_object_ID( |
|
1408 | + EE_Line_Item $parent_line_item, |
|
1409 | + $OBJ_type, |
|
1410 | + $OBJ_IDs |
|
1411 | + ) { |
|
1412 | + $objects = array(); |
|
1413 | + foreach ($parent_line_item->children() as $child_line_item) { |
|
1414 | + if ($child_line_item instanceof EE_Line_Item) { |
|
1415 | + if ($child_line_item->OBJ_type() === $OBJ_type |
|
1416 | + && is_array($OBJ_IDs) |
|
1417 | + && in_array($child_line_item->OBJ_ID(), $OBJ_IDs) |
|
1418 | + ) { |
|
1419 | + $objects[] = $child_line_item; |
|
1420 | + } else { |
|
1421 | + // go-through-all-its children looking for more matches |
|
1422 | + $objects = array_merge( |
|
1423 | + $objects, |
|
1424 | + self::_get_descendants_by_object_type_and_object_ID( |
|
1425 | + $child_line_item, |
|
1426 | + $OBJ_type, |
|
1427 | + $OBJ_IDs |
|
1428 | + ) |
|
1429 | + ); |
|
1430 | + } |
|
1431 | + } |
|
1432 | + } |
|
1433 | + return $objects; |
|
1434 | + } |
|
1435 | + |
|
1436 | + |
|
1437 | + /** |
|
1438 | + * Uses a breadth-first-search in order to find the nearest descendant of |
|
1439 | + * the specified type and returns it, else NULL |
|
1440 | + * |
|
1441 | + * @uses EEH_Line_Item::_get_nearest_descendant() |
|
1442 | + * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1443 | + * @param string $type like one of the EEM_Line_Item::type_* |
|
1444 | + * @return EE_Line_Item |
|
1445 | + * @throws EE_Error |
|
1446 | + * @throws InvalidArgumentException |
|
1447 | + * @throws InvalidDataTypeException |
|
1448 | + * @throws InvalidInterfaceException |
|
1449 | + * @throws ReflectionException |
|
1450 | + */ |
|
1451 | + public static function get_nearest_descendant_of_type(EE_Line_Item $parent_line_item, $type) |
|
1452 | + { |
|
1453 | + return self::_get_nearest_descendant($parent_line_item, 'LIN_type', $type); |
|
1454 | + } |
|
1455 | + |
|
1456 | + |
|
1457 | + /** |
|
1458 | + * Uses a breadth-first-search in order to find the nearest descendant |
|
1459 | + * having the specified LIN_code and returns it, else NULL |
|
1460 | + * |
|
1461 | + * @uses EEH_Line_Item::_get_nearest_descendant() |
|
1462 | + * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1463 | + * @param string $code any value used for LIN_code |
|
1464 | + * @return EE_Line_Item |
|
1465 | + * @throws EE_Error |
|
1466 | + * @throws InvalidArgumentException |
|
1467 | + * @throws InvalidDataTypeException |
|
1468 | + * @throws InvalidInterfaceException |
|
1469 | + * @throws ReflectionException |
|
1470 | + */ |
|
1471 | + public static function get_nearest_descendant_having_code(EE_Line_Item $parent_line_item, $code) |
|
1472 | + { |
|
1473 | + return self::_get_nearest_descendant($parent_line_item, 'LIN_code', $code); |
|
1474 | + } |
|
1475 | + |
|
1476 | + |
|
1477 | + /** |
|
1478 | + * Uses a breadth-first-search in order to find the nearest descendant |
|
1479 | + * having the specified LIN_code and returns it, else NULL |
|
1480 | + * |
|
1481 | + * @param EE_Line_Item $parent_line_item - the line item to find descendants of |
|
1482 | + * @param string $search_field name of EE_Line_Item property |
|
1483 | + * @param string $value any value stored in $search_field |
|
1484 | + * @return EE_Line_Item |
|
1485 | + * @throws EE_Error |
|
1486 | + * @throws InvalidArgumentException |
|
1487 | + * @throws InvalidDataTypeException |
|
1488 | + * @throws InvalidInterfaceException |
|
1489 | + * @throws ReflectionException |
|
1490 | + */ |
|
1491 | + protected static function _get_nearest_descendant(EE_Line_Item $parent_line_item, $search_field, $value) |
|
1492 | + { |
|
1493 | + foreach ($parent_line_item->children() as $child) { |
|
1494 | + if ($child->get($search_field) == $value) { |
|
1495 | + return $child; |
|
1496 | + } |
|
1497 | + } |
|
1498 | + foreach ($parent_line_item->children() as $child) { |
|
1499 | + $descendant_found = self::_get_nearest_descendant( |
|
1500 | + $child, |
|
1501 | + $search_field, |
|
1502 | + $value |
|
1503 | + ); |
|
1504 | + if ($descendant_found) { |
|
1505 | + return $descendant_found; |
|
1506 | + } |
|
1507 | + } |
|
1508 | + return null; |
|
1509 | + } |
|
1510 | + |
|
1511 | + |
|
1512 | + /** |
|
1513 | + * if passed line item has a TXN ID, uses that to jump directly to the grand total line item for the transaction, |
|
1514 | + * else recursively walks up the line item tree until a parent of type total is found, |
|
1515 | + * |
|
1516 | + * @param EE_Line_Item $line_item |
|
1517 | + * @return EE_Line_Item |
|
1518 | + * @throws EE_Error |
|
1519 | + */ |
|
1520 | + public static function find_transaction_grand_total_for_line_item(EE_Line_Item $line_item) |
|
1521 | + { |
|
1522 | + if ($line_item->TXN_ID()) { |
|
1523 | + $total_line_item = $line_item->transaction()->total_line_item(false); |
|
1524 | + if ($total_line_item instanceof EE_Line_Item) { |
|
1525 | + return $total_line_item; |
|
1526 | + } |
|
1527 | + } else { |
|
1528 | + $line_item_parent = $line_item->parent(); |
|
1529 | + if ($line_item_parent instanceof EE_Line_Item) { |
|
1530 | + if ($line_item_parent->is_total()) { |
|
1531 | + return $line_item_parent; |
|
1532 | + } |
|
1533 | + return EEH_Line_Item::find_transaction_grand_total_for_line_item($line_item_parent); |
|
1534 | + } |
|
1535 | + } |
|
1536 | + throw new EE_Error( |
|
1537 | + sprintf( |
|
1538 | + esc_html__( |
|
1539 | + 'A valid grand total for line item %1$d was not found.', |
|
1540 | + 'event_espresso' |
|
1541 | + ), |
|
1542 | + $line_item->ID() |
|
1543 | + ) |
|
1544 | + ); |
|
1545 | + } |
|
1546 | + |
|
1547 | + |
|
1548 | + /** |
|
1549 | + * Prints out a representation of the line item tree |
|
1550 | + * |
|
1551 | + * @param EE_Line_Item $line_item |
|
1552 | + * @param int $indentation |
|
1553 | + * @return void |
|
1554 | + * @throws EE_Error |
|
1555 | + */ |
|
1556 | + public static function visualize(EE_Line_Item $line_item, $indentation = 0) |
|
1557 | + { |
|
1558 | + echo defined('EE_TESTS_DIR') ? "\n" : '<br />'; |
|
1559 | + if (! $indentation) { |
|
1560 | + echo defined('EE_TESTS_DIR') ? "\n" : '<br />'; |
|
1561 | + } |
|
1562 | + for ($i = 0; $i < $indentation; $i++) { |
|
1563 | + echo '. '; |
|
1564 | + } |
|
1565 | + $breakdown = ''; |
|
1566 | + if ($line_item->is_line_item()) { |
|
1567 | + if ($line_item->is_percent()) { |
|
1568 | + $breakdown = "{$line_item->percent()}%"; |
|
1569 | + } else { |
|
1570 | + $breakdown = '$' . "{$line_item->unit_price()} x {$line_item->quantity()}"; |
|
1571 | + } |
|
1572 | + } |
|
1573 | + echo $line_item->name(); |
|
1574 | + echo " [ ID:{$line_item->ID()} | qty:{$line_item->quantity()} ] {$line_item->type()} : "; |
|
1575 | + echo '$' . (string) $line_item->total(); |
|
1576 | + if ($breakdown) { |
|
1577 | + echo " ( {$breakdown} )"; |
|
1578 | + } |
|
1579 | + if ($line_item->is_taxable()) { |
|
1580 | + echo ' * taxable'; |
|
1581 | + } |
|
1582 | + if ($line_item->children()) { |
|
1583 | + foreach ($line_item->children() as $child) { |
|
1584 | + self::visualize($child, $indentation + 1); |
|
1585 | + } |
|
1586 | + } |
|
1587 | + } |
|
1588 | + |
|
1589 | + |
|
1590 | + /** |
|
1591 | + * Calculates the registration's final price, taking into account that they |
|
1592 | + * need to not only help pay for their OWN ticket, but also any transaction-wide surcharges and taxes, |
|
1593 | + * and receive a portion of any transaction-wide discounts. |
|
1594 | + * eg1, if I buy a $1 ticket and brent buys a $9 ticket, and we receive a $5 discount |
|
1595 | + * then I'll get 1/10 of that $5 discount, which is $0.50, and brent will get |
|
1596 | + * 9/10ths of that $5 discount, which is $4.50. So my final price should be $0.50 |
|
1597 | + * and brent's final price should be $5.50. |
|
1598 | + * In order to do this, we basically need to traverse the line item tree calculating |
|
1599 | + * the running totals (just as if we were recalculating the total), but when we identify |
|
1600 | + * regular line items, we need to keep track of their share of the grand total. |
|
1601 | + * Also, we need to keep track of the TAXABLE total for each ticket purchase, so |
|
1602 | + * we can know how to apply taxes to it. (Note: "taxable total" does not equal the "pretax total" |
|
1603 | + * when there are non-taxable items; otherwise they would be the same) |
|
1604 | + * |
|
1605 | + * @param EE_Line_Item $line_item |
|
1606 | + * @param array $billable_ticket_quantities array of EE_Ticket IDs and their corresponding quantity that |
|
1607 | + * can be included in price calculations at this moment |
|
1608 | + * @return array keys are line items for tickets IDs and values are their share of the running total, |
|
1609 | + * plus the key 'total', and 'taxable' which also has keys of all |
|
1610 | + * the ticket IDs. |
|
1611 | + * Eg array( |
|
1612 | + * 12 => 4.3 |
|
1613 | + * 23 => 8.0 |
|
1614 | + * 'total' => 16.6, |
|
1615 | + * 'taxable' => array( |
|
1616 | + * 12 => 10, |
|
1617 | + * 23 => 4 |
|
1618 | + * ). |
|
1619 | + * So to find which registrations have which final price, we need |
|
1620 | + * to find which line item is theirs, which can be done with |
|
1621 | + * `EEM_Line_Item::instance()->get_line_item_for_registration( |
|
1622 | + * $registration );` |
|
1623 | + * @throws EE_Error |
|
1624 | + * @throws InvalidArgumentException |
|
1625 | + * @throws InvalidDataTypeException |
|
1626 | + * @throws InvalidInterfaceException |
|
1627 | + * @throws ReflectionException |
|
1628 | + */ |
|
1629 | + public static function calculate_reg_final_prices_per_line_item( |
|
1630 | + EE_Line_Item $line_item, |
|
1631 | + $billable_ticket_quantities = array() |
|
1632 | + ) { |
|
1633 | + $running_totals = [ |
|
1634 | + 'total' => 0, |
|
1635 | + 'taxable' => ['total' => 0] |
|
1636 | + ]; |
|
1637 | + foreach ($line_item->children() as $child_line_item) { |
|
1638 | + switch ($child_line_item->type()) { |
|
1639 | + case EEM_Line_Item::type_sub_total: |
|
1640 | + $running_totals_from_subtotal = EEH_Line_Item::calculate_reg_final_prices_per_line_item( |
|
1641 | + $child_line_item, |
|
1642 | + $billable_ticket_quantities |
|
1643 | + ); |
|
1644 | + // combine arrays but preserve numeric keys |
|
1645 | + $running_totals = array_replace_recursive($running_totals_from_subtotal, $running_totals); |
|
1646 | + $running_totals['total'] += $running_totals_from_subtotal['total']; |
|
1647 | + $running_totals['taxable']['total'] += $running_totals_from_subtotal['taxable']['total']; |
|
1648 | + break; |
|
1649 | + |
|
1650 | + case EEM_Line_Item::type_tax_sub_total: |
|
1651 | + // find how much the taxes percentage is |
|
1652 | + if ($child_line_item->percent() !== 0) { |
|
1653 | + $tax_percent_decimal = $child_line_item->percent() / 100; |
|
1654 | + } else { |
|
1655 | + $tax_percent_decimal = EE_Taxes::get_total_taxes_percentage() / 100; |
|
1656 | + } |
|
1657 | + // and apply to all the taxable totals, and add to the pretax totals |
|
1658 | + foreach ($running_totals as $line_item_id => $this_running_total) { |
|
1659 | + // "total" and "taxable" array key is an exception |
|
1660 | + if ($line_item_id === 'taxable') { |
|
1661 | + continue; |
|
1662 | + } |
|
1663 | + $taxable_total = $running_totals['taxable'][ $line_item_id ]; |
|
1664 | + $running_totals[ $line_item_id ] += ($taxable_total * $tax_percent_decimal); |
|
1665 | + } |
|
1666 | + break; |
|
1667 | + |
|
1668 | + case EEM_Line_Item::type_line_item: |
|
1669 | + // ticket line items or ???? |
|
1670 | + if ($child_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET) { |
|
1671 | + // kk it's a ticket |
|
1672 | + if (isset($running_totals[ $child_line_item->ID() ])) { |
|
1673 | + // huh? that shouldn't happen. |
|
1674 | + $running_totals['total'] += $child_line_item->total(); |
|
1675 | + } else { |
|
1676 | + // its not in our running totals yet. great. |
|
1677 | + if ($child_line_item->is_taxable()) { |
|
1678 | + $taxable_amount = $child_line_item->unit_price(); |
|
1679 | + } else { |
|
1680 | + $taxable_amount = 0; |
|
1681 | + } |
|
1682 | + // are we only calculating totals for some tickets? |
|
1683 | + if (isset($billable_ticket_quantities[ $child_line_item->OBJ_ID() ])) { |
|
1684 | + $quantity = $billable_ticket_quantities[ $child_line_item->OBJ_ID() ]; |
|
1685 | + $running_totals[ $child_line_item->ID() ] = $quantity |
|
1686 | + ? $child_line_item->unit_price() |
|
1687 | + : 0; |
|
1688 | + $running_totals['taxable'][ $child_line_item->ID() ] = $quantity |
|
1689 | + ? $taxable_amount |
|
1690 | + : 0; |
|
1691 | + } else { |
|
1692 | + $quantity = $child_line_item->quantity(); |
|
1693 | + $running_totals[ $child_line_item->ID() ] = $child_line_item->unit_price(); |
|
1694 | + $running_totals['taxable'][ $child_line_item->ID() ] = $taxable_amount; |
|
1695 | + } |
|
1696 | + $running_totals['taxable']['total'] += $taxable_amount * $quantity; |
|
1697 | + $running_totals['total'] += $child_line_item->unit_price() * $quantity; |
|
1698 | + } |
|
1699 | + } else { |
|
1700 | + // it's some other type of item added to the cart |
|
1701 | + // it should affect the running totals |
|
1702 | + // basically we want to convert it into a PERCENT modifier. Because |
|
1703 | + // more clearly affect all registration's final price equally |
|
1704 | + $line_items_percent_of_running_total = $running_totals['total'] > 0 |
|
1705 | + ? ($child_line_item->total() / $running_totals['total']) + 1 |
|
1706 | + : 1; |
|
1707 | + foreach ($running_totals as $line_item_id => $this_running_total) { |
|
1708 | + // the "taxable" array key is an exception |
|
1709 | + if ($line_item_id === 'taxable') { |
|
1710 | + continue; |
|
1711 | + } |
|
1712 | + // update the running totals |
|
1713 | + // yes this actually even works for the running grand total! |
|
1714 | + $running_totals[ $line_item_id ] = |
|
1715 | + $line_items_percent_of_running_total * $this_running_total; |
|
1716 | + |
|
1717 | + if ($child_line_item->is_taxable()) { |
|
1718 | + $running_totals['taxable'][ $line_item_id ] = |
|
1719 | + $line_items_percent_of_running_total * $running_totals['taxable'][ $line_item_id ]; |
|
1720 | + } |
|
1721 | + } |
|
1722 | + } |
|
1723 | + break; |
|
1724 | + } |
|
1725 | + } |
|
1726 | + return $running_totals; |
|
1727 | + } |
|
1728 | + |
|
1729 | + |
|
1730 | + /** |
|
1731 | + * @param EE_Line_Item $total_line_item |
|
1732 | + * @param EE_Line_Item $ticket_line_item |
|
1733 | + * @return float | null |
|
1734 | + * @throws EE_Error |
|
1735 | + * @throws InvalidArgumentException |
|
1736 | + * @throws InvalidDataTypeException |
|
1737 | + * @throws InvalidInterfaceException |
|
1738 | + * @throws OutOfRangeException |
|
1739 | + * @throws ReflectionException |
|
1740 | + */ |
|
1741 | + public static function calculate_final_price_for_ticket_line_item( |
|
1742 | + EE_Line_Item $total_line_item, |
|
1743 | + EE_Line_Item $ticket_line_item |
|
1744 | + ) { |
|
1745 | + static $final_prices_per_ticket_line_item = array(); |
|
1746 | + if (empty($final_prices_per_ticket_line_item)) { |
|
1747 | + $final_prices_per_ticket_line_item = EEH_Line_Item::calculate_reg_final_prices_per_line_item( |
|
1748 | + $total_line_item |
|
1749 | + ); |
|
1750 | + } |
|
1751 | + // ok now find this new registration's final price |
|
1752 | + if (isset($final_prices_per_ticket_line_item[ $ticket_line_item->ID() ])) { |
|
1753 | + return $final_prices_per_ticket_line_item[ $ticket_line_item->ID() ]; |
|
1754 | + } |
|
1755 | + $message = sprintf( |
|
1756 | + esc_html__( |
|
1757 | + 'The final price for the ticket line item (ID:%1$d) could not be calculated.', |
|
1758 | + 'event_espresso' |
|
1759 | + ), |
|
1760 | + $ticket_line_item->ID() |
|
1761 | + ); |
|
1762 | + if (WP_DEBUG) { |
|
1763 | + $message .= '<br>' . print_r($final_prices_per_ticket_line_item, true); |
|
1764 | + throw new OutOfRangeException($message); |
|
1765 | + } |
|
1766 | + EE_Log::instance()->log(__CLASS__, __FUNCTION__, $message); |
|
1767 | + return null; |
|
1768 | + } |
|
1769 | + |
|
1770 | + |
|
1771 | + /** |
|
1772 | + * Creates a duplicate of the line item tree, except only includes billable items |
|
1773 | + * and the portion of line items attributed to billable things |
|
1774 | + * |
|
1775 | + * @param EE_Line_Item $line_item |
|
1776 | + * @param EE_Registration[] $registrations |
|
1777 | + * @return EE_Line_Item |
|
1778 | + * @throws EE_Error |
|
1779 | + * @throws InvalidArgumentException |
|
1780 | + * @throws InvalidDataTypeException |
|
1781 | + * @throws InvalidInterfaceException |
|
1782 | + * @throws ReflectionException |
|
1783 | + */ |
|
1784 | + public static function billable_line_item_tree(EE_Line_Item $line_item, $registrations) |
|
1785 | + { |
|
1786 | + $copy_li = EEH_Line_Item::billable_line_item($line_item, $registrations); |
|
1787 | + foreach ($line_item->children() as $child_li) { |
|
1788 | + $copy_li->add_child_line_item( |
|
1789 | + EEH_Line_Item::billable_line_item_tree($child_li, $registrations) |
|
1790 | + ); |
|
1791 | + } |
|
1792 | + // if this is the grand total line item, make sure the totals all add up |
|
1793 | + // (we could have duplicated this logic AS we copied the line items, but |
|
1794 | + // it seems DRYer this way) |
|
1795 | + if ($copy_li->type() === EEM_Line_Item::type_total) { |
|
1796 | + $copy_li->recalculate_total_including_taxes(); |
|
1797 | + } |
|
1798 | + return $copy_li; |
|
1799 | + } |
|
1800 | + |
|
1801 | + |
|
1802 | + /** |
|
1803 | + * Creates a new, unsaved line item from $line_item that factors in the |
|
1804 | + * number of billable registrations on $registrations. |
|
1805 | + * |
|
1806 | + * @param EE_Line_Item $line_item |
|
1807 | + * @param EE_Registration[] $registrations |
|
1808 | + * @return EE_Line_Item |
|
1809 | + * @throws EE_Error |
|
1810 | + * @throws InvalidArgumentException |
|
1811 | + * @throws InvalidDataTypeException |
|
1812 | + * @throws InvalidInterfaceException |
|
1813 | + * @throws ReflectionException |
|
1814 | + */ |
|
1815 | + public static function billable_line_item(EE_Line_Item $line_item, $registrations) |
|
1816 | + { |
|
1817 | + $new_li_fields = $line_item->model_field_array(); |
|
1818 | + if ($line_item->type() === EEM_Line_Item::type_line_item && |
|
1819 | + $line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET |
|
1820 | + ) { |
|
1821 | + $count = 0; |
|
1822 | + foreach ($registrations as $registration) { |
|
1823 | + if ($line_item->OBJ_ID() === $registration->ticket_ID() && |
|
1824 | + in_array( |
|
1825 | + $registration->status_ID(), |
|
1826 | + EEM_Registration::reg_statuses_that_allow_payment(), |
|
1827 | + true |
|
1828 | + ) |
|
1829 | + ) { |
|
1830 | + $count++; |
|
1831 | + } |
|
1832 | + } |
|
1833 | + $new_li_fields['LIN_quantity'] = $count; |
|
1834 | + } |
|
1835 | + // don't set the total. We'll leave that up to the code that calculates it |
|
1836 | + unset($new_li_fields['LIN_ID'], $new_li_fields['LIN_parent'], $new_li_fields['LIN_total']); |
|
1837 | + return EE_Line_Item::new_instance($new_li_fields); |
|
1838 | + } |
|
1839 | + |
|
1840 | + |
|
1841 | + /** |
|
1842 | + * Returns a modified line item tree where all the subtotals which have a total of 0 |
|
1843 | + * are removed, and line items with a quantity of 0 |
|
1844 | + * |
|
1845 | + * @param EE_Line_Item $line_item |null |
|
1846 | + * @return EE_Line_Item|null |
|
1847 | + * @throws EE_Error |
|
1848 | + * @throws InvalidArgumentException |
|
1849 | + * @throws InvalidDataTypeException |
|
1850 | + * @throws InvalidInterfaceException |
|
1851 | + * @throws ReflectionException |
|
1852 | + */ |
|
1853 | + public static function non_empty_line_items(EE_Line_Item $line_item) |
|
1854 | + { |
|
1855 | + $copied_li = EEH_Line_Item::non_empty_line_item($line_item); |
|
1856 | + if ($copied_li === null) { |
|
1857 | + return null; |
|
1858 | + } |
|
1859 | + // if this is an event subtotal, we want to only include it if it |
|
1860 | + // has a non-zero total and at least one ticket line item child |
|
1861 | + $ticket_children = 0; |
|
1862 | + foreach ($line_item->children() as $child_li) { |
|
1863 | + $child_li_copy = EEH_Line_Item::non_empty_line_items($child_li); |
|
1864 | + if ($child_li_copy !== null) { |
|
1865 | + $copied_li->add_child_line_item($child_li_copy); |
|
1866 | + if ($child_li_copy->type() === EEM_Line_Item::type_line_item && |
|
1867 | + $child_li_copy->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET |
|
1868 | + ) { |
|
1869 | + $ticket_children++; |
|
1870 | + } |
|
1871 | + } |
|
1872 | + } |
|
1873 | + // if this is an event subtotal with NO ticket children |
|
1874 | + // we basically want to ignore it |
|
1875 | + if ($ticket_children === 0 |
|
1876 | + && $line_item->type() === EEM_Line_Item::type_sub_total |
|
1877 | + && $line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_EVENT |
|
1878 | + && $line_item->total() === 0 |
|
1879 | + ) { |
|
1880 | + return null; |
|
1881 | + } |
|
1882 | + return $copied_li; |
|
1883 | + } |
|
1884 | + |
|
1885 | + |
|
1886 | + /** |
|
1887 | + * Creates a new, unsaved line item, but if it's a ticket line item |
|
1888 | + * with a total of 0, or a subtotal of 0, returns null instead |
|
1889 | + * |
|
1890 | + * @param EE_Line_Item $line_item |
|
1891 | + * @return EE_Line_Item |
|
1892 | + * @throws EE_Error |
|
1893 | + * @throws InvalidArgumentException |
|
1894 | + * @throws InvalidDataTypeException |
|
1895 | + * @throws InvalidInterfaceException |
|
1896 | + * @throws ReflectionException |
|
1897 | + */ |
|
1898 | + public static function non_empty_line_item(EE_Line_Item $line_item) |
|
1899 | + { |
|
1900 | + if ($line_item->type() === EEM_Line_Item::type_line_item |
|
1901 | + && $line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET |
|
1902 | + && $line_item->quantity() === 0 |
|
1903 | + ) { |
|
1904 | + return null; |
|
1905 | + } |
|
1906 | + $new_li_fields = $line_item->model_field_array(); |
|
1907 | + // don't set the total. We'll leave that up to the code that calculates it |
|
1908 | + unset($new_li_fields['LIN_ID'], $new_li_fields['LIN_parent']); |
|
1909 | + return EE_Line_Item::new_instance($new_li_fields); |
|
1910 | + } |
|
1911 | + |
|
1912 | + |
|
1913 | + /** |
|
1914 | + * Cycles through all of the ticket line items for the supplied total line item |
|
1915 | + * and ensures that the line item's "is_taxable" field matches that of its corresponding ticket |
|
1916 | + * |
|
1917 | + * @param EE_Line_Item $total_line_item |
|
1918 | + * @since 4.9.79.p |
|
1919 | + * @throws EE_Error |
|
1920 | + * @throws InvalidArgumentException |
|
1921 | + * @throws InvalidDataTypeException |
|
1922 | + * @throws InvalidInterfaceException |
|
1923 | + * @throws ReflectionException |
|
1924 | + */ |
|
1925 | + public static function resetIsTaxableForTickets(EE_Line_Item $total_line_item) |
|
1926 | + { |
|
1927 | + $ticket_line_items = self::get_ticket_line_items($total_line_item); |
|
1928 | + foreach ($ticket_line_items as $ticket_line_item) { |
|
1929 | + if ($ticket_line_item instanceof EE_Line_Item |
|
1930 | + && $ticket_line_item->OBJ_type() === EEM_Line_Item::OBJ_TYPE_TICKET |
|
1931 | + ) { |
|
1932 | + $ticket = $ticket_line_item->ticket(); |
|
1933 | + if ($ticket instanceof EE_Ticket && $ticket->taxable() !== $ticket_line_item->is_taxable()) { |
|
1934 | + $ticket_line_item->set_is_taxable($ticket->taxable()); |
|
1935 | + $ticket_line_item->save(); |
|
1936 | + } |
|
1937 | + } |
|
1938 | + } |
|
1939 | + } |
|
1940 | + |
|
1941 | + |
|
1942 | + |
|
1943 | + /**************************************** @DEPRECATED METHODS *************************************** */ |
|
1944 | + /** |
|
1945 | + * @deprecated |
|
1946 | + * @param EE_Line_Item $total_line_item |
|
1947 | + * @return EE_Line_Item |
|
1948 | + * @throws EE_Error |
|
1949 | + * @throws InvalidArgumentException |
|
1950 | + * @throws InvalidDataTypeException |
|
1951 | + * @throws InvalidInterfaceException |
|
1952 | + * @throws ReflectionException |
|
1953 | + */ |
|
1954 | + public static function get_items_subtotal(EE_Line_Item $total_line_item) |
|
1955 | + { |
|
1956 | + EE_Error::doing_it_wrong( |
|
1957 | + 'EEH_Line_Item::get_items_subtotal()', |
|
1958 | + sprintf( |
|
1959 | + esc_html__('Method replaced with %1$s', 'event_espresso'), |
|
1960 | + 'EEH_Line_Item::get_pre_tax_subtotal()' |
|
1961 | + ), |
|
1962 | + '4.6.0' |
|
1963 | + ); |
|
1964 | + return self::get_pre_tax_subtotal($total_line_item); |
|
1965 | + } |
|
1966 | + |
|
1967 | + |
|
1968 | + /** |
|
1969 | + * @deprecated |
|
1970 | + * @param EE_Transaction $transaction |
|
1971 | + * @return EE_Line_Item |
|
1972 | + * @throws EE_Error |
|
1973 | + * @throws InvalidArgumentException |
|
1974 | + * @throws InvalidDataTypeException |
|
1975 | + * @throws InvalidInterfaceException |
|
1976 | + * @throws ReflectionException |
|
1977 | + */ |
|
1978 | + public static function create_default_total_line_item($transaction = null) |
|
1979 | + { |
|
1980 | + EE_Error::doing_it_wrong( |
|
1981 | + 'EEH_Line_Item::create_default_total_line_item()', |
|
1982 | + sprintf( |
|
1983 | + esc_html__('Method replaced with %1$s', 'event_espresso'), |
|
1984 | + 'EEH_Line_Item::create_total_line_item()' |
|
1985 | + ), |
|
1986 | + '4.6.0' |
|
1987 | + ); |
|
1988 | + return self::create_total_line_item($transaction); |
|
1989 | + } |
|
1990 | + |
|
1991 | + |
|
1992 | + /** |
|
1993 | + * @deprecated |
|
1994 | + * @param EE_Line_Item $total_line_item |
|
1995 | + * @param EE_Transaction $transaction |
|
1996 | + * @return EE_Line_Item |
|
1997 | + * @throws EE_Error |
|
1998 | + * @throws InvalidArgumentException |
|
1999 | + * @throws InvalidDataTypeException |
|
2000 | + * @throws InvalidInterfaceException |
|
2001 | + * @throws ReflectionException |
|
2002 | + */ |
|
2003 | + public static function create_default_tickets_subtotal(EE_Line_Item $total_line_item, $transaction = null) |
|
2004 | + { |
|
2005 | + EE_Error::doing_it_wrong( |
|
2006 | + 'EEH_Line_Item::create_default_tickets_subtotal()', |
|
2007 | + sprintf( |
|
2008 | + esc_html__('Method replaced with %1$s', 'event_espresso'), |
|
2009 | + 'EEH_Line_Item::create_pre_tax_subtotal()' |
|
2010 | + ), |
|
2011 | + '4.6.0' |
|
2012 | + ); |
|
2013 | + return self::create_pre_tax_subtotal($total_line_item, $transaction); |
|
2014 | + } |
|
2015 | + |
|
2016 | + |
|
2017 | + /** |
|
2018 | + * @deprecated |
|
2019 | + * @param EE_Line_Item $total_line_item |
|
2020 | + * @param EE_Transaction $transaction |
|
2021 | + * @return EE_Line_Item |
|
2022 | + * @throws EE_Error |
|
2023 | + * @throws InvalidArgumentException |
|
2024 | + * @throws InvalidDataTypeException |
|
2025 | + * @throws InvalidInterfaceException |
|
2026 | + * @throws ReflectionException |
|
2027 | + */ |
|
2028 | + public static function create_default_taxes_subtotal(EE_Line_Item $total_line_item, $transaction = null) |
|
2029 | + { |
|
2030 | + EE_Error::doing_it_wrong( |
|
2031 | + 'EEH_Line_Item::create_default_taxes_subtotal()', |
|
2032 | + sprintf( |
|
2033 | + esc_html__('Method replaced with %1$s', 'event_espresso'), |
|
2034 | + 'EEH_Line_Item::create_taxes_subtotal()' |
|
2035 | + ), |
|
2036 | + '4.6.0' |
|
2037 | + ); |
|
2038 | + return self::create_taxes_subtotal($total_line_item, $transaction); |
|
2039 | + } |
|
2040 | + |
|
2041 | + |
|
2042 | + /** |
|
2043 | + * @deprecated |
|
2044 | + * @param EE_Line_Item $total_line_item |
|
2045 | + * @param EE_Transaction $transaction |
|
2046 | + * @return EE_Line_Item |
|
2047 | + * @throws EE_Error |
|
2048 | + * @throws InvalidArgumentException |
|
2049 | + * @throws InvalidDataTypeException |
|
2050 | + * @throws InvalidInterfaceException |
|
2051 | + * @throws ReflectionException |
|
2052 | + */ |
|
2053 | + public static function create_default_event_subtotal(EE_Line_Item $total_line_item, $transaction = null) |
|
2054 | + { |
|
2055 | + EE_Error::doing_it_wrong( |
|
2056 | + 'EEH_Line_Item::create_default_event_subtotal()', |
|
2057 | + sprintf( |
|
2058 | + esc_html__('Method replaced with %1$s', 'event_espresso'), |
|
2059 | + 'EEH_Line_Item::create_event_subtotal()' |
|
2060 | + ), |
|
2061 | + '4.6.0' |
|
2062 | + ); |
|
2063 | + return self::create_event_subtotal($total_line_item, $transaction); |
|
2064 | + } |
|
2065 | 2065 | } |
@@ -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.9.80.rc.007'); |
|
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.9.80.rc.007'); |
|
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 | } |