Completed
Branch BUG-9625-better-us-phone-valid... (e0ce21)
by
unknown
631:18 queued 616:37
created

Transactions_Admin_Page   F

Complexity

Total Complexity 194

Size/Duplication

Total Lines 1796
Duplicated Lines 2.95 %

Coupling/Cohesion

Components 2
Dependencies 39

Importance

Changes 0
Metric Value
dl 53
loc 1796
rs 0.5217
c 0
b 0
f 0
wmc 194
lcom 2
cbo 39

50 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A _init_page_props() 6 6 1
A _ajax_hooks() 0 5 1
A _define_page_props() 10 10 1
B _set_page_routes() 0 46 3
A _set_page_config() 0 63 2
A _add_screen_options() 0 1 1
A _add_feature_pointers() 0 1 1
A admin_init() 0 20 2
A admin_notices() 0 1 1
A admin_footer_scripts() 0 1 1
A _set_transaction_status_array() 0 3 1
A get_transaction_status_array() 0 3 1
A _get_payment_status_array() 0 5 1
A _add_screen_options_default() 0 3 1
A load_scripts_styles() 0 13 1
A load_scripts_styles_view_transaction() 0 4 1
A load_scripts_styles_default() 0 4 1
A _set_list_table_views_default() 0 19 1
B _set_transaction_object() 0 17 5
A _transaction_legend_items() 0 71 3
A _transactions_overview_list_table() 0 7 3
F _transaction_details() 8 173 21
A _transaction_details_metaboxes() 0 18 1
F txn_details_meta_box() 0 83 11
C _get_registration_payment_IDs() 0 27 8
C _get_registrations_to_apply_payment_to() 0 52 8
A _get_reg_status_selection() 0 10 1
A _get_payment_methods() 0 16 4
C txn_attendees_meta_box() 0 60 10
A txn_registrant_side_meta_box() 0 17 3
A txn_billing_info_side_meta_box() 0 11 1
B apply_payments_or_refunds() 0 44 4
C _validate_payment_request_data() 7 29 7
B _generate_payment_form_section() 0 93 1
B _create_payment_from_request_data() 0 38 5
A _process_transaction_payments() 0 13 2
A _get_REG_IDs_to_apply_payment_to() 0 14 4
A existing_reg_payment_REG_IDs() 0 3 1
A set_existing_reg_payment_REG_IDs() 0 3 1
A _get_existing_reg_payment_REG_IDs() 0 10 3
A _remove_existing_registration_payments() 0 21 3
A _update_registration_payments() 0 21 3
A _process_registration_status_change() 0 18 3
B _build_payment_json_response() 0 34 4
C delete_payment() 0 42 7
A _registration_payment_data_array() 0 17 4
C _maybe_send_notifications() 22 28 7
A _send_payment_reminder() 0 7 3
F get_transactions() 0 108 30

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Transactions_Admin_Page often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Transactions_Admin_Page, and based on these observations, apply Extract Interface, too.

1
<?php if ( ! defined('EVENT_ESPRESSO_VERSION')) exit('No direct script access allowed');
2
/**
3
 * Event Espresso
4
 *
5
 * Event Registration and Management Plugin for WordPress
6
 *
7
 * @ package			Event Espresso
8
 * @ author				Seth Shoultes
9
 * @ copyright		(c) 2008-2011 Event Espresso  All Rights Reserved.
10
 * @ license			{@link http://eventespresso.com/support/terms-conditions/}   * see Plugin Licensing *
11
 * @ link					{@link http://www.eventespresso.com}
12
 * @ since		 		4.0
13
 *
14
 * ------------------------------------------------------------------------
15
 *
16
 * EE_Admin_Transactions class
17
 *
18
 * @package			Event Espresso
19
 * @subpackage	includes/core/admin/transactions/Transactions_Admin_Page.core.php
20
 * @author				Brent Christensen
21
 *
22
 * ------------------------------------------------------------------------
23
 */
24
class Transactions_Admin_Page extends EE_Admin_Page {
25
26
	/**
27
	 * @var EE_Transaction
28
	 */
29
	private $_transaction;
30
31
	/**
32
	 * @var EE_Session
33
	 */
34
	private $_session;
35
36
	/**
37
	 * @var array $_txn_status
38
	 */
39
	private static $_txn_status;
40
41
	/**
42
	 * @var array $_pay_status
43
	 */
44
	private static $_pay_status;
45
46
	/**
47
	 * @var array $_existing_reg_payment_REG_IDs
48
	 */
49
	protected $_existing_reg_payment_REG_IDs = null;
50
51
52
53
	/**
54
	 * @Constructor
55
	 * @access public
56
	 * @param bool $routing
57
	 * @return Transactions_Admin_Page
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
58
	 */
59
	public function __construct( $routing = TRUE ) {
60
		parent::__construct( $routing );
61
	}
62
63
64
65
	/**
66
	 * 	_init_page_props
67
	 * @return void
68
	 */
69 View Code Duplication
	protected function _init_page_props() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
70
		$this->page_slug = TXN_PG_SLUG;
71
		$this->page_label = __('Transactions', 'event_espresso');
72
		$this->_admin_base_url = TXN_ADMIN_URL;
73
		$this->_admin_base_path = TXN_ADMIN;
74
	}
75
76
77
78
	/**
79
	 * 	_ajax_hooks
80
	 * @return void
81
	 */
82
	protected function _ajax_hooks() {
83
		add_action('wp_ajax_espresso_apply_payment', array( $this, 'apply_payments_or_refunds'));
84
		add_action('wp_ajax_espresso_apply_refund', array( $this, 'apply_payments_or_refunds'));
85
		add_action('wp_ajax_espresso_delete_payment', array( $this, 'delete_payment'));
86
	}
87
88
89
90
	/**
91
	 * 	_define_page_props
92
	 * @return void
93
	 */
94 View Code Duplication
	protected function  _define_page_props() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
95
		$this->_admin_page_title = $this->page_label;
96
		$this->_labels = array(
97
			'buttons' => array(
98
				'add' => __('Add New Transaction', 'event_espresso'),
99
				'edit' => __('Edit Transaction', 'event_espresso'),
100
				'delete' => __('Delete Transaction','event_espresso'),
101
			)
102
		);
103
	}
104
105
106
107
	/**
108
	 * 		grab url requests and route them
109
	*		@access private
110
	*		@return void
111
	*/
112
	public function _set_page_routes() {
113
114
		$this->_set_transaction_status_array();
115
116
		$txn_id = ! empty( $this->_req_data['TXN_ID'] ) && ! is_array( $this->_req_data['TXN_ID'] ) ? $this->_req_data['TXN_ID'] : 0;
117
118
		$this->_page_routes = array(
119
120
				'default' => array(
121
					'func' => '_transactions_overview_list_table',
122
					'capability' => 'ee_read_transactions'
123
					),
124
125
				'view_transaction' => array(
126
					'func' => '_transaction_details',
127
					'capability' => 'ee_read_transaction',
128
					'obj_id' => $txn_id
129
					),
130
131
				'send_payment_reminder'	=> array(
132
					'func' => '_send_payment_reminder',
133
					'noheader' => TRUE,
134
					'capability' => 'ee_send_message'
135
					),
136
137
				'espresso_apply_payment' => array(
138
				 	'func' => 'apply_payments_or_refunds',
139
				 	'noheader' => TRUE,
140
				 	'capability' => 'ee_edit_payments'
141
				 	),
142
143
				'espresso_apply_refund'	=> array(
144
					'func' => 'apply_payments_or_refunds',
145
					'noheader' => TRUE,
146
					'capability' => 'ee_edit_payments'
147
					),
148
149
				'espresso_delete_payment' => array(
150
					'func' => 'delete_payment',
151
					'noheader' => TRUE,
152
					'capability' => 'ee_delete_payments'
153
					),
154
155
		);
156
157
	}
158
159
160
161
162
163
164
165
166
	protected function _set_page_config() {
167
		$this->_page_config = array(
168
			'default' => array(
169
				'nav' => array(
170
					'label' => __('Overview', 'event_espresso'),
171
					'order' => 10
172
					),
173
				'list_table' => 'EE_Admin_Transactions_List_Table',
174
				'help_tabs' => array(
175
					'transactions_overview_help_tab' => array(
176
						'title' => __('Transactions Overview', 'event_espresso'),
177
						'filename' => 'transactions_overview'
178
					),
179
					'transactions_overview_table_column_headings_help_tab' => array(
180
						'title' => __('Transactions Table Column Headings', 'event_espresso'),
181
						'filename' => 'transactions_overview_table_column_headings'
182
					),
183
					'transactions_overview_views_filters_help_tab' => array(
184
						'title' => __('Transaction Views & Filters & Search', 'event_espresso'),
185
						'filename' => 'transactions_overview_views_filters_search'
186
					),
187
				),
188
				'help_tour' => array( 'Transactions_Overview_Help_Tour' ),
189
				/**
190
				 * commented out because currently we are not displaying tips for transaction list table status but this
191
				 * may change in a later iteration so want to keep the code for then.
192
				 */
193
				//'qtips' => array( 'Transactions_List_Table_Tips' ),
194
				'require_nonce' => FALSE
195
				),
196
			'view_transaction' => array(
197
				'nav' => array(
198
					'label' => __('View Transaction', 'event_espresso'),
199
					'order' => 5,
200
					'url' => isset($this->_req_data['TXN_ID']) ? add_query_arg(array('TXN_ID' => $this->_req_data['TXN_ID'] ), $this->_current_page_view_url )  : $this->_admin_base_url,
201
					'persistent' => FALSE
202
					),
203
				'help_tabs' => array(
204
					'transactions_view_transaction_help_tab' => array(
205
						'title' => __('View Transaction', 'event_espresso'),
206
						'filename' => 'transactions_view_transaction'
207
					),
208
					'transactions_view_transaction_transaction_details_table_help_tab' => array(
209
						'title' => __('Transaction Details Table', 'event_espresso'),
210
						'filename' => 'transactions_view_transaction_transaction_details_table'
211
					),
212
					'transactions_view_transaction_attendees_registered_help_tab' => array(
213
						'title' => __('Attendees Registered', 'event_espresso'),
214
						'filename' => 'transactions_view_transaction_attendees_registered'
215
					),
216
					'transactions_view_transaction_views_primary_registrant_billing_information_help_tab' => array(
217
						'title' => __('Primary Registrant & Billing Information', 'event_espresso'),
218
						'filename' => 'transactions_view_transaction_primary_registrant_billing_information'
219
					),
220
				),
221
				'qtips' => array( 'Transaction_Details_Tips' ),
222
				'help_tour' => array( 'Transaction_Details_Help_Tour' ),
223
				'metaboxes' => array('_transaction_details_metaboxes'),
224
225
				'require_nonce' => FALSE
226
				)
227
		);
228
	}
229
230
231
	/**
232
	 * The below methods aren't used by this class currently
233
	 */
234
	protected function _add_screen_options() {}
235
	protected function _add_feature_pointers() {}
236
	public function admin_init() {
237
		// IF a registration was JUST added via the admin...
238
		if (
239
		isset(
240
			$this->_req_data[ 'redirect_from' ],
241
			$this->_req_data[ 'EVT_ID' ],
242
			$this->_req_data[ 'event_name' ]
243
		)
244
		) {
245
			// then set a cookie so that we can block any attempts to use
246
			// the back button as a way to enter another registration.
247
			setcookie( 'ee_registration_added', $this->_req_data[ 'EVT_ID' ], time() + WEEK_IN_SECONDS, '/' );
248
			// and update the global
249
			$_COOKIE[ 'ee_registration_added' ] = $this->_req_data[ 'EVT_ID' ];
250
		}
251
		EE_Registry::$i18n_js_strings[ 'invalid_server_response' ] = __( 'An error occurred! Your request may have been processed, but a valid response from the server was not received. Please refresh the page and try again.', 'event_espresso' );
252
		EE_Registry::$i18n_js_strings[ 'error_occurred' ] = __( 'An error occurred! Please refresh the page and try again.', 'event_espresso' );
253
		EE_Registry::$i18n_js_strings[ 'txn_status_array' ] = self::$_txn_status;
254
		EE_Registry::$i18n_js_strings[ 'pay_status_array' ] = self::$_pay_status;
255
	}
256
	public function admin_notices() {}
257
	public function admin_footer_scripts() {}
258
259
260
261
	/**
262
	 * _set_transaction_status_array
263
	 * sets list of transaction statuses
264
	*
265
	 * @access private
266
	*	@return void
267
	*/
268
	private function _set_transaction_status_array() {
269
		self::$_txn_status = EEM_Transaction::instance()->status_array(TRUE);
270
	}
271
272
273
274
	/**
275
	 * get_transaction_status_array
276
	 * return the transaction status array for wp_list_table
277
	 *
278
	 * @access public
279
	 * @return array
280
	 */
281
	public function get_transaction_status_array() {
282
		return self::$_txn_status;
283
	}
284
285
286
287
	/**
288
	 * 	get list of payment statuses
289
	*
290
	 * @access private
291
	*	@return void
292
	*/
293
	private function _get_payment_status_array() {
294
		self::$_pay_status = EEM_Payment::instance()->status_array(TRUE);
295
		$this->_template_args['payment_status'] = self::$_pay_status;
296
297
	}
298
299
300
301
	/**
302
	 * 	_add_screen_options_default
303
	 *
304
	 * 	@access protected
305
	 *	@return void
306
	 */
307
	protected function _add_screen_options_default() {
308
		$this->_per_page_screen_option();
309
	}
310
311
312
313
	/**
314
	 * load_scripts_styles
315
	 *
316
	 * @access public
317
	 *	@return void
318
	 */
319
	public function load_scripts_styles() {
320
		//enqueue style
321
		wp_register_style( 'espresso_txn', TXN_ASSETS_URL . 'espresso_transactions_admin.css', array(), EVENT_ESPRESSO_VERSION );
322
		wp_enqueue_style('espresso_txn');
323
324
		//scripts
325
		add_filter('FHEE_load_accounting_js', '__return_true');
326
327
		//scripts
328
		wp_register_script('espresso_txn', TXN_ASSETS_URL . 'espresso_transactions_admin.js', array('ee_admin_js', 'ee-datepicker', 'jquery-ui-datepicker', 'jquery-ui-draggable', 'ee-dialog', 'ee-accounting', 'ee-serialize-full-array'), EVENT_ESPRESSO_VERSION, TRUE);
329
		wp_enqueue_script('espresso_txn');
330
331
	}
332
333
334
335
	/**
336
	 * 	load_scripts_styles_view_transaction
337
	 *
338
	 *	@access public
339
	 *	@return void
340
	 */
341
	public function load_scripts_styles_view_transaction() {
342
		//styles
343
		wp_enqueue_style('espresso-ui-theme');
344
	}
345
346
347
348
	/**
349
	 * 	load_scripts_styles_default
350
	 *
351
	 * @access public
352
	 *	@return void
353
	 */
354
	public function load_scripts_styles_default() {
355
		//styles
356
		wp_enqueue_style('espresso-ui-theme');
357
	}
358
359
360
361
	/**
362
	 * 	_set_list_table_views_default
363
	 *
364
	 *	@access protected
365
	 *	@return void
366
	 */
367
	protected function _set_list_table_views_default() {
368
		$this->_views = array (
369
			'all' => array (
370
				'slug' 		=> 'all',
371
				'label' 		=> __('View All Transactions', 'event_espresso'),
372
				'count' 	=> 0
373
				),
374
			'abandoned' => array(
375
				'slug' 		=> 'abandoned',
376
				'label' 		=> __('Abandoned Transactions', 'event_espresso'),
377
				'count' 	=> 0
378
			),
379
			'failed' => array(
380
				'slug' 		=> 'failed',
381
				'label' 		=> __('Failed Transactions', 'event_espresso'),
382
				'count' 	=> 0
383
			)
384
		);
385
	}
386
387
388
389
	/**
390
	 * _set_transaction_object
391
	 * This sets the _transaction property for the transaction details screen
392
	 *
393
	 *	@access private
394
	 *	@return void
395
	 */
396
	private function _set_transaction_object() {
397
		if ( is_object( $this->_transaction) )
398
			return; //get out we've already set the object
399
400
	    $TXN = EEM_Transaction::instance();
401
402
	    $TXN_ID = ( ! empty( $this->_req_data['TXN_ID'] )) ? absint( $this->_req_data['TXN_ID'] ) : FALSE;
403
404
	    //get transaction object
405
	    $this->_transaction = $TXN->get_one_by_ID($TXN_ID);
0 ignored issues
show
Documentation Bug introduced by
It seems like $TXN->get_one_by_ID($TXN_ID) can also be of type object<EE_Base_Class>. However, the property $_transaction is declared as type object<EE_Transaction>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
406
	    $this->_session = !empty( $this->_transaction ) ? $this->_transaction->get('TXN_session_data') : NULL;
0 ignored issues
show
Documentation Bug introduced by
It seems like !empty($this->_transacti...N_session_data') : NULL can also be of type boolean. However, the property $_session is declared as type object<EE_Session>. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
407
408
	 	if ( empty( $this->_transaction ) ) {
409
	    	$error_msg = __('An error occurred and the details for Transaction ID #', 'event_espresso') . $TXN_ID .  __(' could not be retrieved.', 'event_espresso');
410
			EE_Error::add_error( $error_msg, __FILE__, __FUNCTION__, __LINE__ );
411
	    }
412
	}
413
414
415
416
	/**
417
	 * 	_transaction_legend_items
418
	 *
419
	 *	@access protected
420
	 *	@return array
421
	 */
422
	protected function _transaction_legend_items() {
423
		$items = apply_filters(
424
			'FHEE__Transactions_Admin_Page___transaction_legend_items__items',
425
			array(
426
				'view_details' => array(
427
					'class' => 'dashicons dashicons-cart',
428
					'desc' => __('View Transaction Details', 'event_espresso')
429
				),
430
				'view_invoice' => array(
431
					'class' => 'dashicons dashicons-media-spreadsheet',
432
					'desc' => __('View Transaction Invoice', 'event_espresso')
433
				),
434
				'view_receipt' => array(
435
					'class' => 'dashicons dashicons-media-default',
436
					'desc' => __('View Transaction Receipt', 'event_espresso' )
437
				),
438
				'view_registration' => array(
439
					'class' => 'dashicons dashicons-clipboard',
440
					'desc' => __('View Registration Details', 'event_espresso')
441
				)
442
			)
443
		);
444
445
		if ( EE_Registry::instance()->CAP->current_user_can( 'ee_send_message', 'espresso_transactions_send_payment_reminder' ) ) {
446
447
			EE_Registry::instance()->load_helper( 'MSG_Template' );
448
			if ( EEH_MSG_Template::is_mt_active( 'payment_reminder' ) ) {
449
				$items['send_payment_reminder'] = array(
450
					'class' => 'dashicons dashicons-email-alt',
451
					'desc' => __('Send Payment Reminder', 'event_espresso')
452
					);
453
			} else {
454
				$items['blank*'] = array(
455
					'class'=> '',
456
					'desc' => ''
457
					);
458
			}
459
		} else {
460
			$items['blank*'] = array(
461
				'class'=> '',
462
				'desc' => ''
463
				);
464
		}
465
		$more_items = apply_filters(
466
			'FHEE__Transactions_Admin_Page___transaction_legend_items__more_items',
467
			array(
468
				'overpaid'   => array(
469
					'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::overpaid_status_code,
470
					'desc'  => EEH_Template::pretty_status( EEM_Transaction::overpaid_status_code, FALSE, 'sentence' )
471
				),
472
				'complete'   => array(
473
					'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::complete_status_code,
474
					'desc'  => EEH_Template::pretty_status( EEM_Transaction::complete_status_code, FALSE, 'sentence' )
475
				),
476
				'incomplete' => array(
477
					'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::incomplete_status_code,
478
					'desc'  => EEH_Template::pretty_status( EEM_Transaction::incomplete_status_code, FALSE, 'sentence' )
479
				),
480
				'abandoned'  => array(
481
					'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::abandoned_status_code,
482
					'desc'  => EEH_Template::pretty_status( EEM_Transaction::abandoned_status_code, FALSE, 'sentence' )
483
				),
484
				'failed'     => array(
485
					'class' => 'ee-status-legend ee-status-legend-' . EEM_Transaction::failed_status_code,
486
					'desc'  => EEH_Template::pretty_status( EEM_Transaction::failed_status_code, FALSE, 'sentence' )
487
				)
488
			)
489
		);
490
491
		return array_merge( $items, $more_items);
492
	}
493
494
495
496
	/**
497
	 * 	_transactions_overview_list_table
498
	 *
499
	 * @access protected
500
	 *	@return void
501
	 */
502
	protected function _transactions_overview_list_table() {
503
		$this->_admin_page_title = __('Transactions', 'event_espresso');
504
		$event = isset($this->_req_data['EVT_ID']) ? EEM_Event::instance()->get_one_by_ID($this->_req_data['EVT_ID'] ) : NULL;
505
		$this->_template_args['admin_page_header'] = $event instanceof EE_Event ? sprintf( __('%sViewing Transactions for the Event: %s%s', 'event_espresso'), '<h3>', '<a href="' . EE_Admin_Page::add_query_args_and_nonce(array('action' => 'edit', 'post' => $event->ID()), EVENTS_ADMIN_URL ) . '" title="' . esc_attr__('Click to Edit event', 'event_espresso') . '">' . $event->get('EVT_name') . '</a>', '</h3>' ) : '';
506
		$this->_template_args['after_list_table'] = $this->_display_legend( $this->_transaction_legend_items() );
507
		$this->display_admin_list_table_page_with_no_sidebar();
508
	}
509
510
511
512
	/**
513
	* 	_transaction_details
514
	 * generates HTML for the View Transaction Details Admin page
515
	*
516
	 * @access protected
517
	*	@return void
518
	*/
519
	protected function _transaction_details() {
520
		do_action( 'AHEE__Transactions_Admin_Page__transaction_details__start', $this->_transaction );
521
		EE_Registry::instance()->load_helper( 'MSG_Template' );
522
523
		$this->_set_transaction_status_array();
524
525
		$this->_template_args = array();
526
		$this->_template_args['transactions_page'] = $this->_wp_page_slug;
527
528
		$this->_set_transaction_object();
529
530
		$primary_registration = $this->_transaction->primary_registration();
531
		$attendee = $primary_registration instanceof EE_Registration ? $primary_registration->attendee() : NULL;
532
533
		$this->_template_args['txn_nmbr']['value'] = $this->_transaction->ID();
534
		$this->_template_args['txn_nmbr']['label'] = __( 'Transaction Number', 'event_espresso' );
535
536
		$this->_template_args['txn_datetime']['value'] = $this->_transaction->get_datetime('TXN_timestamp', 'l F j, Y', 'g:i:s a' );
537
		$this->_template_args['txn_datetime']['label'] = __( 'Date', 'event_espresso' );
538
539
		$this->_template_args['txn_status']['value'] = self::$_txn_status[ $this->_transaction->get('STS_ID') ];
540
		$this->_template_args['txn_status']['label'] = __( 'Transaction Status', 'event_espresso' );
541
		$this->_template_args['txn_status']['class'] = 'status-' . $this->_transaction->get('STS_ID');
542
543
		$this->_template_args['grand_total'] = $this->_transaction->get('TXN_total');
544
		$this->_template_args['total_paid'] = $this->_transaction->get('TXN_paid');
545
546
		if (
547
			$attendee instanceof EE_Attendee
548
			&& EE_Registry::instance()->CAP->current_user_can(
549
				'ee_send_message',
550
				'espresso_transactions_send_payment_reminder'
551
			)
552
		) {
553
			EE_Registry::instance()->load_helper( 'MSG_Template' );
554
			$this->_template_args['send_payment_reminder_button'] =
555
				EEH_MSG_Template::is_mt_active( 'payment_reminder' )
556
				&& $this->_transaction->get('STS_ID') != EEM_Transaction::complete_status_code
557
				&& $this->_transaction->get('STS_ID') != EEM_Transaction::overpaid_status_code
558
					? EEH_Template::get_button_or_link(
559
						EE_Admin_Page::add_query_args_and_nonce(
560
							array(
561
								'action'=>'send_payment_reminder',
562
								'TXN_ID'=>$this->_transaction->ID(),
563
								'redirect_to' => 'view_transaction'
564
							),
565
							TXN_ADMIN_URL
566
						),
567
						__(' Send Payment Reminder', 'event_espresso'),
568
						'button secondary-button right',
569
						'dashicons dashicons-email-alt'
570
					)
571
				    : '';
572
		} else {
573
			$this->_template_args['send_payment_reminder_button'] = '';
574
		}
575
576
		$amount_due = $this->_transaction->get('TXN_total') - $this->_transaction->get('TXN_paid');
577
		$this->_template_args['amount_due'] = EEH_Template::format_currency( $amount_due, TRUE );
578
		if ( EE_Registry::instance()->CFG->currency->sign_b4 ) {
579
			$this->_template_args['amount_due'] = EE_Registry::instance()->CFG->currency->sign . $this->_template_args['amount_due'];
580
		} else {
581
			$this->_template_args['amount_due'] = $this->_template_args['amount_due'] . EE_Registry::instance()->CFG->currency->sign;
582
		}
583
		$this->_template_args['amount_due_class'] =  '';
584
585
		if ( $this->_transaction->get('TXN_paid') == $this->_transaction->get('TXN_total') ) {
586
			// paid in full
587
			$this->_template_args['amount_due'] =  FALSE;
588 View Code Duplication
		} elseif ( $this->_transaction->get('TXN_paid') > $this->_transaction->get('TXN_total') ) {
589
			// overpaid
590
			$this->_template_args['amount_due_class'] =  'txn-overview-no-payment-spn';
591
		} elseif (( $this->_transaction->get('TXN_total') > 0 ) && ( $this->_transaction->get('TXN_paid') > 0 )) {
592
			// monies owing
593
			$this->_template_args['amount_due_class'] =  'txn-overview-part-payment-spn';
594 View Code Duplication
		} elseif (( $this->_transaction->get('TXN_total') > 0 ) && ( $this->_transaction->get('TXN_paid') == 0 )) {
595
			// no payments made yet
596
			$this->_template_args['amount_due_class'] =  'txn-overview-no-payment-spn';
597
		} elseif ( $this->_transaction->get('TXN_total') == 0 ) {
598
			// free event
599
			$this->_template_args['amount_due'] =  FALSE;
600
		}
601
602
		$payment_method = $this->_transaction->payment_method();
603
604
		$this->_template_args['method_of_payment_name'] = $payment_method instanceof EE_Payment_Method
605
			? $payment_method->admin_name()
606
			: __( 'Unknown', 'event_espresso' );
607
608
		$this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
609
		// link back to overview
610
		$this->_template_args['txn_overview_url'] = ! empty ( $_SERVER['HTTP_REFERER'] )
611
			? $_SERVER['HTTP_REFERER']
612
			: TXN_ADMIN_URL;
613
614
615
		// next link
616
		$next_txn = $this->_transaction->next(
617
			null,
618
			array( array( 'STS_ID' => array( '!=', EEM_Transaction::failed_status_code ) ) ),
619
			'TXN_ID'
620
		);
621
		$this->_template_args['next_transaction'] = $next_txn
622
			? $this->_next_link(
623
				EE_Admin_Page::add_query_args_and_nonce(
624
					array( 'action' => 'view_transaction', 'TXN_ID' => $next_txn['TXN_ID'] ),
625
					TXN_ADMIN_URL
626
				),
627
				'dashicons dashicons-arrow-right ee-icon-size-22'
628
			)
629
			: '';
630
		// previous link
631
		$previous_txn = $this->_transaction->previous(
632
			null,
633
			array( array( 'STS_ID' => array( '!=', EEM_Transaction::failed_status_code ) ) ),
634
			'TXN_ID'
635
		);
636
		$this->_template_args['previous_transaction'] = $previous_txn
637
			? $this->_previous_link(
638
				EE_Admin_Page::add_query_args_and_nonce(
639
					array( 'action' => 'view_transaction', 'TXN_ID' => $previous_txn['TXN_ID'] ),
640
					TXN_ADMIN_URL
641
				),
642
				'dashicons dashicons-arrow-left ee-icon-size-22'
643
			)
644
			: '';
645
646
		// were we just redirected here after adding a new registration ???
647
		if (
648
			isset(
649
				$this->_req_data[ 'redirect_from' ],
650
				$this->_req_data[ 'EVT_ID' ],
651
				$this->_req_data[ 'event_name' ]
652
			)
653
		) {
654
			if (
655
				EE_Registry::instance()->CAP->current_user_can(
656
					'ee_edit_registrations',
657
					'espresso_registrations_new_registration',
658
					$this->_req_data[ 'EVT_ID' ]
659
				)
660
			) {
661
				$this->_admin_page_title .= '<a id="add-new-registration" class="add-new-h2 button-primary" href="';
662
				$this->_admin_page_title .= EE_Admin_Page::add_query_args_and_nonce(
663
					array(
664
						'page'     => 'espresso_registrations',
665
						'action'   => 'new_registration',
666
						'return'   => 'default',
667
						'TXN_ID'   => $this->_transaction->ID(),
668
						'event_id' => $this->_req_data[ 'EVT_ID' ],
669
					),
670
					REG_ADMIN_URL
671
				);
672
				$this->_admin_page_title .= '">';
673
674
				$this->_admin_page_title .= sprintf(
675
					__('Add Another New Registration to Event: "%1$s" ?'),
676
					htmlentities( urldecode( $this->_req_data[ 'event_name' ] ), ENT_QUOTES, 'UTF-8' )
677
				);
678
				$this->_admin_page_title .= '</a>';
679
			}
680
			EE_Registry::instance()->SSN->clear_session( __CLASS__, __FUNCTION__ );
681
		}
682
		// grab messages at the last second
683
		$this->_template_args['notices'] = EE_Error::get_notices();
684
		// path to template
685
		$template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_header.template.php';
686
		$this->_template_args['admin_page_header'] = EEH_Template::display_template( $template_path, $this->_template_args, TRUE );
687
688
		// the details template wrapper
689
		$this->display_admin_page_with_sidebar();
690
691
	}
692
693
694
695
	/**
696
	 * 		_transaction_details_metaboxes
697
	 *
698
	 *		@access protected
699
	 *		@return void
700
	 */
701
	protected function _transaction_details_metaboxes() {
702
703
		$this->_set_transaction_object();
704
705
		add_meta_box( 'edit-txn-details-mbox', __( 'Transaction Details', 'event_espresso' ), array( $this, 'txn_details_meta_box' ), $this->_wp_page_slug, 'normal', 'high' );
706
		add_meta_box(
707
			'edit-txn-attendees-mbox',
708
			__( 'Attendees Registered in this Transaction', 'event_espresso' ),
709
			array( $this, 'txn_attendees_meta_box' ),
710
			$this->_wp_page_slug,
711
			'normal',
712
			'high',
713
			array( 'TXN_ID' => $this->_transaction->ID() )
714
		);
715
		add_meta_box( 'edit-txn-registrant-mbox', __( 'Primary Contact', 'event_espresso' ), array( $this, 'txn_registrant_side_meta_box' ), $this->_wp_page_slug, 'side', 'high' );
716
		add_meta_box( 'edit-txn-billing-info-mbox', __( 'Billing Information', 'event_espresso' ), array( $this, 'txn_billing_info_side_meta_box' ), $this->_wp_page_slug, 'side', 'high' );
717
718
	}
719
720
721
722
	/**
723
	 * txn_details_meta_box
724
	 * generates HTML for the Transaction main meta box
725
	*
726
	 * @access public
727
	*	@return void
728
	*/
729
	public function txn_details_meta_box() {
730
731
		$this->_set_transaction_object();
732
		$this->_template_args['TXN_ID'] = $this->_transaction->ID();
733
		$this->_template_args['attendee'] = $this->_transaction->primary_registration() instanceof EE_Registration ? $this->_transaction->primary_registration()->attendee() : null;
734
735
		//get line table
736
		EEH_Autoloader::register_line_item_display_autoloaders();
737
		$Line_Item_Display = new EE_Line_Item_Display( 'admin_table', 'EE_Admin_Table_Line_Item_Display_Strategy' );
738
		$this->_template_args['line_item_table'] = $Line_Item_Display->display_line_item( $this->_transaction->total_line_item() );
739
		$this->_template_args['REG_code'] = $this->_transaction->get_first_related('Registration')->get('REG_code');
740
741
		// process taxes
742
		$taxes = $this->_transaction->get_many_related( 'Line_Item', array( array( 'LIN_type' => EEM_Line_Item::type_tax )));
743
		$this->_template_args['taxes'] = ! empty( $taxes ) ? $taxes : FALSE;
744
745
		$this->_template_args['grand_total'] = EEH_Template::format_currency($this->_transaction->get('TXN_total'), FALSE, FALSE );
0 ignored issues
show
Documentation introduced by
$this->_transaction->get('TXN_total') is of type boolean, but the function expects a double|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
746
		$this->_template_args['grand_raw_total'] = $this->_transaction->get('TXN_total');
747
		$this->_template_args['TXN_status'] = $this->_transaction->get('STS_ID');
748
749
//		$txn_status_class = 'status-' . $this->_transaction->get('STS_ID');
750
751
		// process payment details
752
		$payments = $this->_transaction->get_many_related('Payment');
753
		if( ! empty(  $payments ) ) {
754
			$this->_template_args[ 'payments' ] = $payments;
755
			$this->_template_args[ 'existing_reg_payments' ] = $this->_get_registration_payment_IDs( $payments );
0 ignored issues
show
Documentation introduced by
$payments is of type array<integer,object<EE_Base_Class>>, but the function expects a array<integer,object<EE_Payment>>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
756
		} else {
757
			$this->_template_args[ 'payments' ] = false;
758
			$this->_template_args[ 'existing_reg_payments' ] = array();
759
		}
760
761
		$this->_template_args['edit_payment_url'] = add_query_arg( array( 'action' => 'edit_payment'  ), TXN_ADMIN_URL );
762
		$this->_template_args['delete_payment_url'] = add_query_arg( array( 'action' => 'espresso_delete_payment' ), TXN_ADMIN_URL );
763
764
		if ( isset( $txn_details['invoice_number'] )) {
0 ignored issues
show
Bug introduced by
The variable $txn_details seems to never exist, and therefore isset should always return false. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
765
			$this->_template_args['txn_details']['invoice_number']['value'] = $this->_template_args['REG_code'];
766
			$this->_template_args['txn_details']['invoice_number']['label'] = __( 'Invoice Number', 'event_espresso' );
767
		}
768
769
		$this->_template_args['txn_details']['registration_session']['value'] = $this->_transaction->get_first_related('Registration')->get('REG_session');
770
		$this->_template_args['txn_details']['registration_session']['label'] = __( 'Registration Session', 'event_espresso' );
771
772
		$this->_template_args['txn_details']['ip_address']['value'] = isset( $this->_session['ip_address'] ) ? $this->_session['ip_address'] : '';
773
		$this->_template_args['txn_details']['ip_address']['label'] = __( 'Transaction placed from IP', 'event_espresso' );
774
775
		$this->_template_args['txn_details']['user_agent']['value'] = isset( $this->_session['user_agent'] ) ? $this->_session['user_agent'] : '';
776
		$this->_template_args['txn_details']['user_agent']['label'] = __( 'Registrant User Agent', 'event_espresso' );
777
778
		$reg_steps = '<ul>';
779
		foreach ( $this->_transaction->reg_steps() as $reg_step => $reg_step_status ) {
780
			if ( $reg_step_status === true ) {
781
				$reg_steps .= '<li style="color:#70cc50">' . sprintf( __( '%1$s : Completed', 'event_espresso' ), ucwords( str_replace( '_', ' ', $reg_step ) ) ) . '</li>';
782
			} else if ( is_numeric( $reg_step_status ) && $reg_step_status !== false ) {
783
					$reg_steps .= '<li style="color:#2EA2CC">' . sprintf(
784
							__( '%1$s : Initiated %2$s', 'event_espresso' ),
785
							ucwords( str_replace( '_', ' ', $reg_step ) ),
786
							gmdate( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), ( $reg_step_status + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ) ) )
787
						) . '</li>';
788
				} else {
789
				$reg_steps .= '<li style="color:#E76700">' . sprintf( __( '%1$s : Never Initiated', 'event_espresso' ), ucwords( str_replace( '_', ' ', $reg_step ) ) ) . '</li>';
790
			}
791
		}
792
		$reg_steps .= '</ul>';
793
		$this->_template_args['txn_details']['reg_steps']['value'] = $reg_steps;
794
		$this->_template_args['txn_details']['reg_steps']['label'] = __( 'Registration Step Progress', 'event_espresso' );
795
796
797
		$this->_get_registrations_to_apply_payment_to();
798
		$this->_get_payment_methods( $payments );
799
		$this->_get_payment_status_array();
800
		$this->_get_reg_status_selection(); //sets up the template args for the reg status array for the transaction.
801
802
		$this->_template_args['transaction_form_url'] = add_query_arg( array( 'action' => 'edit_transaction', 'process' => 'transaction'  ), TXN_ADMIN_URL );
803
		$this->_template_args['apply_payment_form_url'] = add_query_arg( array( 'page' => 'espresso_transactions', 'action' => 'espresso_apply_payment' ), WP_AJAX_URL );
804
		$this->_template_args['delete_payment_form_url'] = add_query_arg( array( 'page' => 'espresso_transactions', 'action' => 'espresso_delete_payment' ), WP_AJAX_URL );
805
806
		// 'espresso_delete_payment_nonce'
807
808
		$template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_txn_details.template.php';
809
		echo EEH_Template::display_template( $template_path, $this->_template_args, TRUE );
810
811
	}
812
813
814
815
	/**
816
	 * _get_registration_payment_IDs
817
	 *
818
	 *    generates an array of Payment IDs and their corresponding Registration IDs
819
	 *
820
	 * @access protected
821
	 * @param EE_Payment[] $payments
822
	 * @return array
823
	 */
824
	protected function _get_registration_payment_IDs( $payments = array() ) {
825
		$existing_reg_payments = array();
826
		// get all reg payments for these payments
827
		$reg_payments = EEM_Registration_Payment::instance()->get_all( array(
828
			array(
829
				'PAY_ID' => array(
830
					'IN',
831
					array_keys( $payments )
832
				)
833
			)
834
		) );
835
		if ( ! empty( $reg_payments ) ) {
836
			foreach ( $payments as $payment ) {
837
				if ( ! $payment instanceof EE_Payment ) {
838
					continue;
839
				} else if ( ! isset( $existing_reg_payments[ $payment->ID() ] ) ) {
840
					$existing_reg_payments[ $payment->ID() ] = array();
841
				}
842
				foreach ( $reg_payments as $reg_payment ) {
843
					if ( $reg_payment instanceof EE_Registration_Payment && $reg_payment->payment_ID() === $payment->ID() ) {
844
						$existing_reg_payments[ $payment->ID() ][ ] = $reg_payment->registration_ID();
845
					}
846
				}
847
			}
848
		}
849
		return $existing_reg_payments;
850
	}
851
852
853
854
	/**
855
	 * _get_registrations_to_apply_payment_to
856
	 *
857
	 * 	generates HTML for displaying a series of checkboxes in the admin payment modal window
858
	 * which allows the admin to only apply the payment to the specific registrations
859
	 *
860
	 *	@access protected
861
	 * @return void
862
	 */
863
	protected function _get_registrations_to_apply_payment_to() {
864
		// we want any registration with an active status (ie: not deleted or cancelled)
865
		$query_params = array(
866
			array(
867
				'STS_ID' => array(
868
					'IN',
869
					array(
870
						EEM_Registration::status_id_approved,
871
						EEM_Registration::status_id_pending_payment,
872
						EEM_Registration::status_id_not_approved,
873
					)
874
				)
875
			)
876
		);
877
		$registrations_to_apply_payment_to = '<br /><div id="txn-admin-apply-payment-to-registrations-dv"  style="clear: both; margin: 1.5em 0 0; display: none;">';
878
		$registrations_to_apply_payment_to .= '<br /><div class="admin-primary-mbox-tbl-wrap">';
879
		$registrations_to_apply_payment_to .= '<table class="admin-primary-mbox-tbl">';
880
		$registrations_to_apply_payment_to .= '<thead><tr>';
881
		$registrations_to_apply_payment_to .= '<td>' . __( 'ID', 'event_espresso' ) . '</td>';
882
		$registrations_to_apply_payment_to .= '<td>' . __( 'Registrant', 'event_espresso' ) . '</td>';
883
		$registrations_to_apply_payment_to .= '<td>' . __( 'Ticket', 'event_espresso' ) . '</td>';
884
		$registrations_to_apply_payment_to .= '<td>' . __( 'Event', 'event_espresso' ) . '</td>';
885
		$registrations_to_apply_payment_to .= '<td class="txn-admin-payment-paid-td jst-cntr">' . __( 'Paid', 'event_espresso' ) . '</td>';
886
		$registrations_to_apply_payment_to .= '<td class="txn-admin-payment-owing-td jst-cntr">' . __( 'Owing', 'event_espresso' ) . '</td>';
887
		$registrations_to_apply_payment_to .= '<td class="jst-cntr">' . __( 'Apply', 'event_espresso' ) . '</td>';
888
		$registrations_to_apply_payment_to .= '</tr></thead><tbody>';
889
		// get registrations for TXN
890
		$registrations = $this->_transaction->registrations( $query_params );
891
		foreach ( $registrations as $registration ) {
892
			if ( $registration instanceof EE_Registration ) {
893
				$owing = $registration->final_price() - $registration->paid();
894
				$taxable = $registration->ticket()->taxable() ? ' <span class="smaller-text lt-grey-text"> ' . __( '+ tax', 'event_espresso' ) . '</span>' : '';
895
				$checked = empty( $existing_reg_payments ) || in_array( $registration->ID(), $existing_reg_payments ) ? ' checked="checked"' : '';
0 ignored issues
show
Bug introduced by
The variable $existing_reg_payments seems to never exist, and therefore empty should always return true. Did you maybe rename this variable?

This check looks for calls to isset(...) or empty() on variables that are yet undefined. These calls will always produce the same result and can be removed.

This is most likely caused by the renaming of a variable or the removal of a function/method parameter.

Loading history...
896
				$registrations_to_apply_payment_to .= '<tr id="apply-payment-registration-row-' . $registration->ID() . '">';
897
				// add html for checkbox input and label
898
				$registrations_to_apply_payment_to .= '<td>' . $registration->ID() . '</td>';
899
				$registrations_to_apply_payment_to .= '<td>' . $registration->attendee() instanceof EE_Attendee ? $registration->attendee()->full_name() : __( 'Unknown Attendee', 'event_espresso' ) . '</td>';
900
				$registrations_to_apply_payment_to .= '<td>' . $registration->ticket()->name() . ' : ' . $registration->ticket()->pretty_price() . $taxable . '</td>';
901
				$registrations_to_apply_payment_to .= '<td>' . $registration->event_name() . '</td>';
902
				$registrations_to_apply_payment_to .= '<td class="txn-admin-payment-paid-td jst-rght">' . $registration->pretty_paid() . '</td>';
903
				$registrations_to_apply_payment_to .= '<td class="txn-admin-payment-owing-td jst-rght">' . EEH_Template::format_currency( $owing ) . '</td>';
904
				$registrations_to_apply_payment_to .= '<td class="jst-cntr">';
905
				$disabled = $registration->final_price() > 0 ? '' : ' disabled';
906
				$registrations_to_apply_payment_to .= '<input type="checkbox" value="' . $registration->ID() . '" name="txn_admin_payment[registrations]"' . $checked . $disabled . '>';
907
				$registrations_to_apply_payment_to .= '</td>';
908
				$registrations_to_apply_payment_to .= '</tr>';
909
			}
910
		}
911
		$registrations_to_apply_payment_to .= '</tbody></table></div>';
912
		$registrations_to_apply_payment_to .= '<p class="clear description">' . __( 'The payment will only be applied to the registrations that have a check mark in their corresponding check box. Checkboxes for free registrations have been disabled.', 'event_espresso' ) . '</p></div>';
913
		$this->_template_args[ 'registrations_to_apply_payment_to' ] = $registrations_to_apply_payment_to;
914
	}
915
916
917
918
	/**
919
	 * _get_reg_status_selection
920
	 *
921
	 * @todo this will need to be adjusted either once MER comes along OR we move default reg status to tickets instead of events.
922
	 *	@access protected
923
	 * @return void
924
	 */
925
	protected function _get_reg_status_selection() {
926
		//first get all possible statuses
927
		$statuses = EEM_Registration::reg_status_array(array(), TRUE);
928
		//let's add a "don't change" option.
929
		$status_array['NAN'] = __('Leave the Same', 'event_espresso');
0 ignored issues
show
Coding Style Comprehensibility introduced by
$status_array was never initialized. Although not strictly required by PHP, it is generally a good practice to add $status_array = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
930
		$status_array = array_merge( $status_array, $statuses );
931
		$this->_template_args['status_change_select'] = EEH_Form_Fields::select_input( 'txn_reg_status_change[reg_status]', $status_array, 'NAN', 'id="txn-admin-payment-reg-status-inp"', 'txn-reg-status-change-reg-status' );
932
		$this->_template_args['delete_status_change_select'] = EEH_Form_Fields::select_input( 'delete_txn_reg_status_change[reg_status]', $status_array, 'NAN', 'delete-txn-admin-payment-reg-status-inp', 'delete-txn-reg-status-change-reg-status' );
933
934
	}
935
936
937
938
	/**
939
	 * 	_get_payment_methods
940
	 * Gets all the payment methods available generally, or the ones that are already
941
	 * selected on these payments (in case their payment methods are no longer active).
942
	 * Has the side-effect of updating the template args' payment_methods item
943
	 *	@access private
944
	 * @param EE_Payment[] to show on this page
945
	 *	@return void
946
	 */
947
	private function _get_payment_methods( $payments = array() ) {
948
		$payment_methods_of_payments = array();
949
		foreach( $payments as $payment ){
950
			if( $payment instanceof EE_Payment ){
951
				$payment_methods_of_payments[] = $payment->get( 'PMD_ID' );
952
			}
953
		}
954
		if( $payment_methods_of_payments ){
0 ignored issues
show
Bug Best Practice introduced by
The expression $payment_methods_of_payments of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
955
			$query_args = array( array( 'OR*payment_method_for_payment' => array(
956
					'PMD_ID' => array( 'IN', $payment_methods_of_payments ),
957
					'PMD_scope' => array( 'LIKE', '%' . EEM_Payment_Method::scope_admin . '%' ) ) ) );
958
		}else{
959
			$query_args = array( array( 'PMD_scope' => array( 'LIKE', '%' . EEM_Payment_Method::scope_admin . '%' ) ) );
960
		}
961
		$this->_template_args['payment_methods'] = EEM_Payment_Method::instance()->get_all( $query_args );
962
	}
963
964
965
966
	/**
967
	 * txn_attendees_meta_box
968
	 *    generates HTML for the Attendees Transaction main meta box
969
	 *
970
	 * @access public
971
	 * @param WP_Post $post
972
	 * @param array $metabox
973
	 * @return void
974
	 */
975
	public function txn_attendees_meta_box( $post, $metabox = array( 'args' => array() )) {
976
977
		extract( $metabox['args'] );
978
		$this->_template_args['post'] = $post;
979
		$this->_template_args['event_attendees'] = array();
980
		// process items in cart
981
		$line_items = $this->_transaction->get_many_related('Line_Item', array( array( 'LIN_type' => 'line-item' ) ) );
982
		if ( ! empty( $line_items )) {
983
			foreach ( $line_items as $item ) {
984
				if ( $item instanceof EE_Line_Item ) {
985
					switch( $item->OBJ_type() ) {
986
987
						case 'Event' :
988
							break;
989
990
						case 'Ticket' :
991
							$ticket = $item->ticket();
992
							if ( empty( $ticket )) {
993
								continue; //right now we're only handling tickets here.  Cause its expected that only tickets will have attendees right?
994
							}
995
							$ticket_price = EEH_Template::format_currency( $item->get( 'LIN_unit_price' ));
0 ignored issues
show
Documentation introduced by
$item->get('LIN_unit_price') is of type boolean, but the function expects a double|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
996
							$event = $ticket->get_first_related('Registration')->get_first_related('Event');
997
							$event_name = $event instanceof EE_Event ? $event->get('EVT_name') . ' - ' . $item->get('LIN_name') : '';
998
999
							$registrations = $ticket->get_many_related('Registration', array( array('TXN_ID' => $this->_transaction->ID() )));
1000
							foreach( $registrations as $registration ) {
1001
								$this->_template_args['event_attendees'][$registration->ID()]['att_num'] 						= $registration->get('REG_count');
1002
								$this->_template_args['event_attendees'][$registration->ID()]['event_ticket_name'] 	= $event_name;
1003
								$this->_template_args['event_attendees'][$registration->ID()]['ticket_price'] 				= $ticket_price;
1004
								// attendee info
1005
								$attendee = $registration->get_first_related('Attendee');
1006
								if ( $attendee instanceof EE_Attendee ) {
1007
									$this->_template_args['event_attendees'][$registration->ID()]['att_id'] 			= $attendee->ID();
1008
									$this->_template_args['event_attendees'][$registration->ID()]['attendee'] 	= $attendee->full_name();
1009
									$this->_template_args['event_attendees'][$registration->ID()]['email'] 			= '<a href="mailto:' . $attendee->email() . '?subject=' . $event->get('EVT_name') . __(' Event', 'event_espresso') . '">' . $attendee->email() . '</a>';
1010
									$this->_template_args['event_attendees'][$registration->ID()]['address'] 		=  implode(',<br>', $attendee->full_address_as_array() );
1011
								} else {
1012
									$this->_template_args['event_attendees'][$registration->ID()]['att_id'] 			= '';
1013
									$this->_template_args['event_attendees'][$registration->ID()]['attendee'] 	= '';
1014
									$this->_template_args['event_attendees'][$registration->ID()]['email'] 			= '';
1015
									$this->_template_args['event_attendees'][$registration->ID()]['address'] 		= '';
1016
								}
1017
							}
1018
							break;
1019
1020
					}
1021
				}
1022
			}
1023
1024
			$this->_template_args['transaction_form_url'] = add_query_arg( array( 'action' => 'edit_transaction', 'process' => 'attendees'  ), TXN_ADMIN_URL );
1025
			echo EEH_Template::display_template( TXN_TEMPLATE_PATH . 'txn_admin_details_main_meta_box_attendees.template.php', $this->_template_args, TRUE );
1026
1027
		} else {
1028
			echo sprintf(
1029
				__( '%1$sFor some reason, there are no attendees registered for this transaction. Likely the registration was abandoned in process.%2$s', 'event_espresso' ),
1030
				'<p class="important-notice">',
1031
				'</p>'
1032
			);
1033
		}
1034
	}
1035
1036
1037
1038
	/**
1039
	 * txn_registrant_side_meta_box
1040
	 * generates HTML for the Edit Transaction side meta box
1041
	 *
1042
	 * @access public
1043
	 * @throws \EE_Error
1044
	 * @return void
1045
	 */
1046
	public function txn_registrant_side_meta_box() {
1047
		$primary_att = $this->_transaction->primary_registration() instanceof EE_Registration ? $this->_transaction->primary_registration()->get_first_related('Attendee') : null;
1048
		if ( ! $primary_att instanceof EE_Attendee ) {
1049
			$this->_template_args['no_attendee_message'] = __('There is no attached contact for this transaction.  The transaction either failed due to an error or was abandoned.', 'event_espresso');
1050
			$primary_att = EEM_Attendee::instance()->create_default_object();
1051
		}
1052
		$this->_template_args['ATT_ID'] 						= $primary_att->ID();
1053
		$this->_template_args['prime_reg_fname']		= $primary_att->fname();
1054
		$this->_template_args['prime_reg_lname']		= $primary_att->lname();
1055
		$this->_template_args['prime_reg_email'] 		= $primary_att->email();
1056
		$this->_template_args['prime_reg_phone'] 	= $primary_att->phone();
1057
		$this->_template_args['edit_attendee_url'] 	= EE_Admin_Page::add_query_args_and_nonce( array( 'action' => 'edit_attendee', 'post' => $primary_att->ID()  ), REG_ADMIN_URL );
1058
		// get formatted address for registrant
1059
		EE_Registry::instance()->load_helper( 'Formatter' );
1060
		$this->_template_args[ 'formatted_address' ] = EEH_Address::format( $primary_att );
1061
		echo EEH_Template::display_template( TXN_TEMPLATE_PATH . 'txn_admin_details_side_meta_box_registrant.template.php', $this->_template_args, TRUE );
1062
	}
1063
1064
1065
1066
	/**
1067
	 * txn_billing_info_side_meta_box
1068
	 * 	generates HTML for the Edit Transaction side meta box
1069
	*
1070
	 * @access public
1071
	*	@return void
1072
	*/
1073
	public function txn_billing_info_side_meta_box() {
1074
1075
		$this->_template_args['billing_form'] = $this->_transaction->billing_info();
1076
		$this->_template_args['billing_form_url'] = add_query_arg(
1077
			array( 'action' => 'edit_transaction', 'process' => 'billing'  ),
1078
			TXN_ADMIN_URL
1079
		);
1080
1081
		$template_path = TXN_TEMPLATE_PATH . 'txn_admin_details_side_meta_box_billing_info.template.php';
1082
		echo EEH_Template::display_template( $template_path, $this->_template_args, TRUE );/**/
1083
	}
1084
1085
1086
1087
	/**
1088
	 * apply_payments_or_refunds
1089
	 * 	registers a payment or refund made towards a transaction
1090
	*
1091
	 * @access public
1092
	*	@return void
1093
	*/
1094
	public function apply_payments_or_refunds() {
1095
		$json_response_data = array( 'return_data' => FALSE );
1096
		$valid_data = $this->_validate_payment_request_data();
1097
		if ( ! empty( $valid_data ) ) {
1098
			$PAY_ID = $valid_data[ 'PAY_ID' ];
1099
			//save  the new payment
1100
			$payment = $this->_create_payment_from_request_data( $valid_data );
1101
			// get the TXN for this payment
1102
			$transaction = $payment->transaction();
1103
			// verify transaction
1104
			if ( $transaction instanceof EE_Transaction ) {
1105
				// calculate_total_payments_and_update_status
1106
				$this->_process_transaction_payments( $transaction );
1107
				$REG_IDs = $this->_get_REG_IDs_to_apply_payment_to( $payment );
1108
				$this->_remove_existing_registration_payments( $payment, $PAY_ID );
1109
				// apply payment to registrations (if applicable)
1110
				if ( ! empty( $REG_IDs ) ) {
1111
					$this->_update_registration_payments( $transaction, $payment, $REG_IDs );
1112
					$this->_maybe_send_notifications();
1113
					// now process status changes for the same registrations
1114
					$this->_process_registration_status_change( $transaction, $REG_IDs );
1115
				}
1116
				$this->_maybe_send_notifications( $payment );
1117
				//prepare to render page
1118
				$json_response_data[ 'return_data' ] = $this->_build_payment_json_response( $payment, $REG_IDs );
1119
				do_action( 'AHEE__Transactions_Admin_Page__apply_payments_or_refund__after_recording', $transaction, $payment );
1120
			} else {
1121
				EE_Error::add_error(
1122
					__( 'A valid Transaction for this payment could not be retrieved.', 'event_espresso' ),
1123
					__FILE__, __FUNCTION__, __LINE__
1124
				);
1125
			}
1126
		} else {
1127
			EE_Error::add_error( __( 'The payment form data could not be processed. Please try again.', 'event_espresso' ), __FILE__, __FUNCTION__, __LINE__ );
1128
		}
1129
1130
		$notices = EE_Error::get_notices( false, false, false );
1131
		$this->_template_args = array(
1132
			'data' => $json_response_data,
1133
			'error' => $notices['errors'],
1134
			'success' => $notices['success']
1135
		);
1136
		$this->_return_json();
1137
	}
1138
1139
1140
1141
	/**
1142
	 * _validate_payment_request_data
1143
	 *
1144
	 * @return array
1145
	 */
1146
	protected function _validate_payment_request_data() {
1147
		if ( ! isset( $this->_req_data[ 'txn_admin_payment' ] ) ) {
1148
			return false;
1149
		}
1150
		$payment_form = $this->_generate_payment_form_section();
1151
		try {
1152
			if ( $payment_form->was_submitted() ) {
1153
				$payment_form->receive_form_submission();
1154
				if ( ! $payment_form->is_valid() ) {
1155
					$submission_error_messages = array();
1156
					foreach ( $payment_form->get_validation_errors_accumulated() as $validation_error ) {
1157 View Code Duplication
						if ( $validation_error instanceof EE_Validation_Error ) {
1158
							$submission_error_messages[] = sprintf(
1159
								_x( '%s : %s', 'Form Section Name : Form Validation Error', 'event_espresso' ),
1160
								$validation_error->get_form_section()->html_label_text(),
1161
								$validation_error->getMessage()
1162
							);
1163
						}
1164
					}
1165
					EE_Error::add_error( join( '<br />', $submission_error_messages ), __FILE__, __FUNCTION__, __LINE__ );
1166
					return array();
1167
				}
1168
			}
1169
		} catch ( EE_Error $e ) {
1170
			EE_Error::add_error( $e->getMessage(), __FILE__, __FUNCTION__, __LINE__ );
1171
			return array();
1172
		}
1173
		return $payment_form->valid_data();
1174
	}
1175
1176
1177
1178
	/**
1179
	 * _generate_payment_form_section
1180
	 *
1181
	 * @return EE_Form_Section_Proper
1182
	 */
1183
	protected function _generate_payment_form_section() {
1184
		return new EE_Form_Section_Proper(
1185
			array(
1186
				'name' => 'txn_admin_payment',
1187
				'subsections'     => array(
1188
					'PAY_ID' => new EE_Text_Input(
1189
						array(
1190
							'default' => 0,
1191
							'required' => false,
1192
							'html_label_text' => __( 'Payment ID', 'event_espresso' ),
1193
							'validation_strategies' => array( new EE_Int_Normalization() )
1194
						)
1195
					),
1196
					'TXN_ID' => new EE_Text_Input(
1197
						array(
1198
							'default' => 0,
1199
							'required' => true,
1200
							'html_label_text' => __( 'Transaction ID', 'event_espresso' ),
1201
							'validation_strategies' => array( new EE_Int_Normalization() )
1202
						)
1203
					),
1204
					'type' => new EE_Text_Input(
1205
						array(
1206
							'default' => 1,
1207
							'required' => true,
1208
							'html_label_text' => __( 'Payment or Refund', 'event_espresso' ),
1209
							'validation_strategies' => array( new EE_Int_Normalization() )
1210
						)
1211
					),
1212
					'amount' => new EE_Text_Input(
1213
						array(
1214
							'default' => 0,
1215
							'required' => true,
1216
							'html_label_text' => __( 'Payment amount', 'event_espresso' ),
1217
							'validation_strategies' => array( new EE_Float_Normalization() )
1218
						)
1219
					),
1220
					'status' => new EE_Text_Input(
1221
						array(
1222
							'default' => EEM_Payment::status_id_approved,
1223
							'required' => true,
1224
							'html_label_text' => __( 'Payment status', 'event_espresso' ),
1225
						)
1226
					),
1227
					'PMD_ID' => new EE_Text_Input(
1228
						array(
1229
							'default' => 2,
1230
							'required' => true,
1231
							'html_label_text' => __( 'Payment Method', 'event_espresso' ),
1232
							'validation_strategies' => array( new EE_Int_Normalization() )
1233
						)
1234
					),
1235
					'date' => new EE_Text_Input(
1236
						array(
1237
							'default' => time(),
1238
							'required' => true,
1239
							'html_label_text' => __( 'Payment date', 'event_espresso' ),
1240
						)
1241
					),
1242
					'txn_id_chq_nmbr' => new EE_Text_Input(
1243
						array(
1244
							'default' => '',
1245
							'required' => false,
1246
							'html_label_text' => __( 'Transaction or Cheque Number', 'event_espresso' ),
1247
                                                        'validation_strategies' => array(
1248
                                                            new EE_Max_Length_Validation_Strategy( __('Input too long', 'event_espresso'), 100 ),
1249
                                                        )
1250
						)
1251
					),
1252
					'po_number' => new EE_Text_Input(
1253
						array(
1254
							'default' => '',
1255
							'required' => false,
1256
							'html_label_text' => __( 'Purchase Order Number', 'event_espresso' ),
1257
                                                        'validation_strategies' => array(
1258
                                                            new EE_Max_Length_Validation_Strategy( __('Input too long', 'event_espresso'), 100 ),
1259
                                                        )
1260
						)
1261
					),
1262
					'accounting' => new EE_Text_Input(
1263
						array(
1264
							'default' => '',
1265
							'required' => false,
1266
							'html_label_text' => __( 'Extra Field for Accounting', 'event_espresso' ),
1267
                                                        'validation_strategies' => array(
1268
                                                            new EE_Max_Length_Validation_Strategy( __('Input too long', 'event_espresso'), 100 ),
1269
                                                        )
1270
						)
1271
					),
1272
				)
1273
			)
1274
		);
1275
	}
1276
1277
1278
1279
	/**
1280
	 * _create_payment_from_request_data
1281
	 *
1282
	 * @param array $valid_data
1283
	 * @return EE_Payment
1284
	 */
1285
	protected function _create_payment_from_request_data( $valid_data ) {
1286
		$PAY_ID = $valid_data[ 'PAY_ID' ];
1287
		// get payment amount
1288
		$amount = $valid_data[ 'amount' ] ? abs( $valid_data[ 'amount' ] ) : 0;
1289
		// payments have a type value of 1 and refunds have a type value of -1
1290
		// so multiplying amount by type will give a positive value for payments, and negative values for refunds
1291
		$amount = $valid_data[ 'type' ] < 0 ? $amount * -1 : $amount;
1292
		// for some reason the date string coming in has extra spaces between the date and time.  This fixes that.
1293
		$date = $valid_data['date'] ? preg_replace( '/\s+/', ' ', $valid_data['date'] ) : date( 'Y-m-d g:i a', current_time( 'timestamp' ) );
1294
		$payment = EE_Payment::new_instance(
1295
			array(
1296
				'TXN_ID' 								=> $valid_data[ 'TXN_ID' ],
1297
				'STS_ID' 								=> $valid_data[ 'status' ],
1298
				'PAY_timestamp' 				=> $date,
1299
				'PAY_source'           			=> EEM_Payment_Method::scope_admin,
1300
				'PMD_ID'               				=> $valid_data[ 'PMD_ID' ],
1301
				'PAY_amount'           			=> $amount,
1302
				'PAY_txn_id_chq_nmbr'  	=> $valid_data[ 'txn_id_chq_nmbr' ],
1303
				'PAY_po_number'        		=> $valid_data[ 'po_number' ],
1304
				'PAY_extra_accntng'    		=> $valid_data[ 'accounting' ],
1305
				'PAY_details'          				=> $valid_data,
1306
				'PAY_ID'               				=> $PAY_ID
1307
			),
1308
			'',
1309
			array( 'Y-m-d', 'g:i a' )
1310
		);
1311
1312
		if ( ! $payment->save() ) {
1313
			EE_Error::add_error(
1314
				sprintf(
1315
					__( 'Payment %1$d has not been successfully saved to the database.', 'event_espresso' ),
1316
					$payment->ID()
1317
				),
1318
				__FILE__, __FUNCTION__, __LINE__
1319
			);
1320
		}
1321
		return $payment;
1322
	}
1323
1324
1325
1326
	/**
1327
	 * _process_transaction_payments
1328
	 *
1329
	 * @param \EE_Transaction $transaction
1330
	 * @return array
1331
	 */
1332
	protected function _process_transaction_payments( EE_Transaction $transaction ) {
1333
		/** @type EE_Transaction_Payments $transaction_payments */
1334
		$transaction_payments = EE_Registry::instance()->load_class( 'Transaction_Payments' );
1335
		//update the transaction with this payment
1336
		if ( $transaction_payments->calculate_total_payments_and_update_status( $transaction ) ) {
1337
			EE_Error::add_success( __( 'The payment has been processed successfully.', 'event_espresso' ), __FILE__, __FUNCTION__, __LINE__ );
1338
		} else {
1339
			EE_Error::add_error(
1340
				__( 'The payment was processed successfully but the amount paid for the transaction was not updated.', 'event_espresso' )
1341
				, __FILE__, __FUNCTION__, __LINE__
1342
			);
1343
		}
1344
	}
1345
1346
1347
1348
	/**
1349
	 * _get_REG_IDs_to_apply_payment_to
1350
	 *
1351
	 * returns a list of registration IDs that the payment will apply to
1352
	 *
1353
	 * @param \EE_Payment $payment
1354
	 * @return array
1355
	 */
1356
	protected function _get_REG_IDs_to_apply_payment_to( EE_Payment $payment ) {
1357
		$REG_IDs = array();
1358
		// grab array of IDs for specific registrations to apply changes to
1359
		if ( isset( $this->_req_data[ 'txn_admin_payment' ][ 'registrations' ] ) ) {
1360
			$REG_IDs = (array)$this->_req_data[ 'txn_admin_payment' ][ 'registrations' ];
1361
		}
1362
		//nothing specified ? then get all reg IDs
1363
		if ( empty( $REG_IDs ) ) {
1364
			$registrations = $payment->transaction()->registrations();
1365
			$REG_IDs = ! empty( $registrations ) ? array_keys( $registrations ) : $this->_get_existing_reg_payment_REG_IDs( $payment );
1366
		}
1367
		// ensure that REG_IDs are integers and NOT strings
1368
		return array_map( 'intval', $REG_IDs );
1369
	}
1370
1371
1372
1373
	/**
1374
	 * @return array
1375
	 */
1376
	public function existing_reg_payment_REG_IDs() {
1377
		return $this->_existing_reg_payment_REG_IDs;
1378
	}
1379
1380
1381
1382
	/**
1383
	 * @param array $existing_reg_payment_REG_IDs
1384
	 */
1385
	public function set_existing_reg_payment_REG_IDs( $existing_reg_payment_REG_IDs = null ) {
1386
		$this->_existing_reg_payment_REG_IDs = $existing_reg_payment_REG_IDs;
0 ignored issues
show
Documentation Bug introduced by
It seems like $existing_reg_payment_REG_IDs can be null. However, the property $_existing_reg_payment_REG_IDs is declared as array. Maybe change the type of the property to array|null or add a type check?

Our type inference engine has found an assignment of a scalar value (like a string, an integer or null) to a property which is an array.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property.

To type hint that a parameter can be either an array or null, you can set a type hint of array and a default value of null. The PHP interpreter will then accept both an array or null for that parameter.

function aContainsB(array $needle = null, array  $haystack) {
    if (!$needle) {
        return false;
    }

    return array_intersect($haystack, $needle) == $haystack;
}

The function can be called with either null or an array for the parameter $needle but will only accept an array as $haystack.

Loading history...
1387
	}
1388
1389
1390
1391
	/**
1392
	 * _get_existing_reg_payment_REG_IDs
1393
	 *
1394
	 * returns a list of registration IDs that the payment is currently related to
1395
	 * as recorded in the database
1396
	 *
1397
	 * @param \EE_Payment $payment
1398
	 * @return array
1399
	 */
1400
	protected function _get_existing_reg_payment_REG_IDs( EE_Payment $payment ) {
1401
		if ( $this->existing_reg_payment_REG_IDs() === null ) {
1402
			// let's get any existing reg payment records for this payment
1403
			$existing_reg_payment_REG_IDs = $payment->get_many_related( 'Registration' );
1404
			// but we only want the REG IDs, so grab the array keys
1405
			$existing_reg_payment_REG_IDs = ! empty( $existing_reg_payment_REG_IDs ) ? array_keys( $existing_reg_payment_REG_IDs ) : array();
1406
			$this->set_existing_reg_payment_REG_IDs( $existing_reg_payment_REG_IDs );
1407
		}
1408
		return $this->existing_reg_payment_REG_IDs();
1409
	}
1410
1411
1412
1413
	/**
1414
	 * _remove_existing_registration_payments
1415
	 *
1416
	 * this calculates the difference between existing relations
1417
	 * to the supplied payment and the new list registration IDs,
1418
	 * removes any related registrations that no longer apply,
1419
	 * and then updates the registration paid fields
1420
	 *
1421
	 * @param \EE_Payment $payment
1422
	 * @param int         $PAY_ID
1423
	 * @return bool;
0 ignored issues
show
Documentation introduced by
The doc-type bool; could not be parsed: Expected "|" or "end of type", but got ";" at position 4. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
1424
	 */
1425
	protected function _remove_existing_registration_payments( EE_Payment $payment, $PAY_ID = 0 ) {
1426
		// newly created payments will have nothing recorded for $PAY_ID
1427
		if ( $PAY_ID == 0 ) {
1428
			return false;
1429
		}
1430
		$existing_reg_payment_REG_IDs = $this->_get_existing_reg_payment_REG_IDs( $payment );
1431
		if ( empty( $existing_reg_payment_REG_IDs )) {
1432
			return false;
1433
		}
1434
		/** @type EE_Transaction_Payments $transaction_payments */
1435
		$transaction_payments = EE_Registry::instance()->load_class( 'Transaction_Payments' );
1436
		return $transaction_payments->delete_registration_payments_and_update_registrations(
1437
			$payment,
1438
			array(
1439
				array(
1440
					'PAY_ID' => $payment->ID(),
1441
					'REG_ID' => array( 'IN', $existing_reg_payment_REG_IDs ),
1442
				)
1443
			)
1444
		);
1445
	}
1446
1447
1448
1449
	/**
1450
	 * _update_registration_payments
1451
	 *
1452
	 * this applies the payments to the selected registrations
1453
	 * but only if they have not already been paid for
1454
	 *
1455
	 * @param  EE_Transaction $transaction
1456
	 * @param \EE_Payment $payment
1457
	 * @param array $REG_IDs
1458
	 * @return bool
1459
	 */
1460
	protected function _update_registration_payments( EE_Transaction $transaction, EE_Payment $payment, $REG_IDs = array() ) {
1461
		// we can pass our own custom set of registrations to EE_Payment_Processor::process_registration_payments()
1462
		// so let's do that using our set of REG_IDs from the form
1463
		$registration_query_where_params = array(
1464
			'REG_ID' => array( 'IN', $REG_IDs )
1465
		);
1466
		// but add in some conditions regarding payment,
1467
		// so that we don't apply payments to registrations that are free or have already been paid for
1468
		// but ONLY if the payment is NOT a refund ( ie: the payment amount is not negative )
1469
		if ( ! $payment->is_a_refund() ) {
1470
			$registration_query_where_params[ 'REG_final_price' ]  = array( '!=', 0 );
1471
			$registration_query_where_params[ 'REG_final_price*' ]  = array( '!=', 'REG_paid', true );
1472
		}
1473
		//EEH_Debug_Tools::printr( $registration_query_where_params, '$registration_query_where_params', __FILE__, __LINE__ );
1474
		$registrations = $transaction->registrations( array( $registration_query_where_params ) );
1475
		if ( ! empty( $registrations ) ) {
1476
			/** @type EE_Payment_Processor $payment_processor */
1477
			$payment_processor = EE_Registry::instance()->load_core( 'Payment_Processor' );
1478
			$payment_processor->process_registration_payments( $transaction, $payment, $registrations );
0 ignored issues
show
Documentation introduced by
$registrations is of type array<integer,object<EE_Base_Class>>, but the function expects a array<integer,object<EE_Registration>>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1479
		}
1480
	}
1481
1482
1483
1484
	/**
1485
	 * _process_registration_status_change
1486
	 *
1487
	 * This processes requested registration status changes for all the registrations
1488
	 * on a given transaction and (optionally) sends out notifications for the changes.
1489
	 *
1490
	 * @param  EE_Transaction $transaction
1491
	 * @param array $REG_IDs
1492
	 * @return bool
1493
	 */
1494
	protected function _process_registration_status_change( EE_Transaction $transaction, $REG_IDs = array() ) {
1495
		// first if there is no change in status then we get out.
1496
		if (
1497
			! isset( $this->_req_data['txn_reg_status_change'], $this->_req_data[ 'txn_reg_status_change' ][ 'reg_status' ] )
1498
			|| $this->_req_data['txn_reg_status_change']['reg_status'] == 'NAN'
1499
		) {
1500
			//no error message, no change requested, just nothing to do man.
1501
			return FALSE;
1502
		}
1503
		/** @type EE_Transaction_Processor $transaction_processor */
1504
		$transaction_processor = EE_Registry::instance()->load_class( 'Transaction_Processor' );
1505
		// made it here dude?  Oh WOW.  K, let's take care of changing the statuses
1506
		return $transaction_processor->manually_update_registration_statuses(
1507
			$transaction,
1508
			sanitize_text_field( $this->_req_data[ 'txn_reg_status_change' ][ 'reg_status' ] ),
1509
			array( array( 'REG_ID' => array( 'IN', $REG_IDs ) ) )
1510
		);
1511
	}
1512
1513
1514
1515
	/**
1516
	 * _build_payment_json_response
1517
	 *
1518
	 * @access public
1519
	 * @param \EE_Payment $payment
1520
	 * @param array       $REG_IDs
1521
	 * @param bool | null        $delete_txn_reg_status_change
1522
	 * @return array
1523
	 */
1524
	protected function _build_payment_json_response( EE_Payment $payment, $REG_IDs = array(), $delete_txn_reg_status_change = null ) {
1525
		// was the payment deleted ?
1526
		if ( is_bool( $delete_txn_reg_status_change )) {
1527
			return array(
1528
				'PAY_ID' 				=> $payment->ID(),
1529
				'amount' 			=> $payment->amount(),
1530
				'total_paid' 			=> $payment->transaction()->paid(),
1531
				'txn_status' 			=> $payment->transaction()->status_ID(),
1532
				'pay_status' 		=> $payment->STS_ID(),
1533
				'registrations' 	=> $this->_registration_payment_data_array( $REG_IDs ),
1534
				'delete_txn_reg_status_change' => $delete_txn_reg_status_change,
1535
			);
1536
		} else {
1537
			$this->_get_payment_status_array();
1538
			return array(
1539
				'amount' 		=> $payment->amount(),
1540
				'total_paid' 		=> $payment->transaction()->paid(),
1541
				'txn_status' 		=> $payment->transaction()->status_ID(),
1542
				'pay_status' 	=> $payment->STS_ID(),
1543
				'PAY_ID'           => $payment->ID(),
1544
				'STS_ID' 			=> $payment->STS_ID(),
1545
				'status' 			=> self::$_pay_status[ $payment->STS_ID() ],
1546
				'date' 				=> $payment->timestamp( 'Y-m-d', 'h:i a' ),
1547
				'method' 		=> strtoupper( $payment->source() ),
1548
				'PM_ID' 			=> $payment->payment_method() ? $payment->payment_method()->ID() : 1,
1549
				'gateway' 		=> $payment->payment_method() ? $payment->payment_method()->admin_name() : __( "Unknown", 'event_espresso' ),
1550
				'gateway_response' 	=> $payment->gateway_response(),
1551
				'txn_id_chq_nmbr'  	=> $payment->txn_id_chq_nmbr(),
1552
				'po_number'        		=> $payment->po_number(),
1553
				'extra_accntng'    		=> $payment->extra_accntng(),
1554
				'registrations'    			=> $this->_registration_payment_data_array( $REG_IDs ),
1555
			);
1556
		}
1557
	}
1558
1559
1560
1561
	/**
1562
	 * delete_payment
1563
	 * 	delete a payment or refund made towards a transaction
1564
	*
1565
	 * @access public
1566
	*	@return void
1567
	*/
1568
	public function delete_payment() {
1569
		$json_response_data = array( 'return_data' => FALSE );
1570
		$PAY_ID = isset( $this->_req_data['delete_txn_admin_payment'], $this->_req_data['delete_txn_admin_payment']['PAY_ID'] ) ? absint( $this->_req_data['delete_txn_admin_payment']['PAY_ID'] ) : 0;
1571
		if ( $PAY_ID ) {
1572
			$delete_txn_reg_status_change = isset( $this->_req_data[ 'delete_txn_reg_status_change' ] ) ? $this->_req_data[ 'delete_txn_reg_status_change' ] : false;
1573
			$payment = EEM_Payment::instance()->get_one_by_ID( $PAY_ID );
1574
			if ( $payment instanceof EE_Payment ) {
1575
				$REG_IDs = $this->_get_existing_reg_payment_REG_IDs( $payment );
1576
				/** @type EE_Transaction_Payments $transaction_payments */
1577
				$transaction_payments = EE_Registry::instance()->load_class( 'Transaction_Payments' );
1578
				if ( $transaction_payments->delete_payment_and_update_transaction( $payment )) {
1579
					$json_response_data['return_data'] = $this->_build_payment_json_response( $payment, $REG_IDs, $delete_txn_reg_status_change );
1580
					if ( $delete_txn_reg_status_change ) {
1581
						$this->_req_data['txn_reg_status_change'] = $delete_txn_reg_status_change;
1582
						//MAKE sure we also add the delete_txn_req_status_change to the
1583
						//$_REQUEST global because that's how messages will be looking for it.
1584
						$_REQUEST['txn_reg_status_change'] = $delete_txn_reg_status_change;
1585
						$this->_maybe_send_notifications();
1586
						$this->_process_registration_status_change( $payment->transaction(), $REG_IDs );
0 ignored issues
show
Bug introduced by
It seems like $payment->transaction() can be null; however, _process_registration_status_change() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
1587
					}
1588
				}
1589
			} else {
1590
				EE_Error::add_error(
1591
					__( 'Valid Payment data could not be retrieved from the database.', 'event_espresso' ),
1592
					__FILE__, __FUNCTION__, __LINE__
1593
				);
1594
			}
1595
		} else {
1596
			EE_Error::add_error(
1597
				__( 'A valid Payment ID was not received, therefore payment form data could not be loaded.', 'event_espresso' ),
1598
				__FILE__, __FUNCTION__, __LINE__
1599
			);
1600
		}
1601
		$notices = EE_Error::get_notices( false, false, false);
1602
		$this->_template_args = array(
1603
			'data' => $json_response_data,
1604
			'success' => $notices['success'],
1605
			'error' => $notices['errors'],
1606
			'attention' => $notices['attention']
1607
		);
1608
		$this->_return_json();
1609
	}
1610
1611
1612
1613
	/**
1614
	 * _registration_payment_data_array
1615
	 * adds info for 'owing' and 'paid' for each registration to the json response
1616
	 *
1617
	 * @access protected
1618
	 * @param array $REG_IDs
1619
	 * @return array
1620
	 */
1621
	protected function _registration_payment_data_array( $REG_IDs ) {
1622
		$registration_payment_data = array();
1623
		//if non empty reg_ids lets get an array of registrations and update the values for the apply_payment/refund rows.
1624
		if ( ! empty( $REG_IDs ) ) {
1625
			EE_Registry::instance()->load_helper( 'Template' );
1626
			$registrations = EEM_Registration::instance()->get_all( array( array( 'REG_ID' => array( 'IN', $REG_IDs ) ) ) );
1627
			foreach ( $registrations as $registration ) {
1628
				if ( $registration instanceof EE_Registration ) {
1629
					$registration_payment_data[ $registration->ID() ] = array(
1630
						'paid' => $registration->pretty_paid(),
1631
						'owing' => EEH_Template::format_currency( $registration->final_price() - $registration->paid() ),
1632
					);
1633
				}
1634
			}
1635
		}
1636
		return $registration_payment_data;
1637
	}
1638
1639
1640
1641
	/**
1642
	 * _maybe_send_notifications
1643
	 *
1644
	 * determines whether or not the admin has indicated that notifications should be sent.
1645
	 * If so, will toggle a filter switch for delivering registration notices.
1646
	 * If passed an EE_Payment object, then it will trigger payment notifications instead.
1647
	 *
1648
	 * @access protected
1649
	 * @param \EE_Payment | null $payment
1650
	 */
1651
	protected function _maybe_send_notifications( $payment = null ) {
1652
		switch ( $payment instanceof EE_Payment ) {
1653
			// payment notifications
1654 View Code Duplication
			case true :
1655
				if (
1656
					isset(
1657
						$this->_req_data[ 'txn_payments' ],
1658
						$this->_req_data[ 'txn_payments' ][ 'send_notifications' ]
1659
					) &&
1660
					filter_var( $this->_req_data[ 'txn_payments' ][ 'send_notifications' ], FILTER_VALIDATE_BOOLEAN )
1661
				) {
1662
					$this->_process_payment_notification( $payment );
1663
				}
1664
				break;
1665
			// registration notifications
1666 View Code Duplication
			case false :
1667
				if (
1668
					isset(
1669
						$this->_req_data[ 'txn_reg_status_change' ],
1670
						$this->_req_data[ 'txn_reg_status_change' ][ 'send_notifications' ]
1671
					) &&
1672
					filter_var( $this->_req_data[ 'txn_reg_status_change' ][ 'send_notifications' ], FILTER_VALIDATE_BOOLEAN )
1673
				) {
1674
					add_filter( 'FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true' );
1675
				}
1676
				break;
1677
		}
1678
	}
1679
1680
1681
1682
	/**
1683
	 * _send_payment_reminder
1684
	 * 	generates HTML for the View Transaction Details Admin page
1685
	*
1686
	 * @access protected
1687
	*	@return void
1688
	*/
1689
	protected function _send_payment_reminder() {
1690
	    $TXN_ID = ( ! empty( $this->_req_data['TXN_ID'] )) ? absint( $this->_req_data['TXN_ID'] ) : FALSE;
1691
		$transaction = EEM_Transaction::instance()->get_one_by_ID( $TXN_ID );
1692
		$query_args = isset($this->_req_data['redirect_to'] ) ? array('action' => $this->_req_data['redirect_to'], 'TXN_ID' => $this->_req_data['TXN_ID'] ) : array();
1693
		do_action( 'AHEE__Transactions_Admin_Page___send_payment_reminder__process_admin_payment_reminder', $transaction );
1694
		$this->_redirect_after_action( FALSE, __('payment reminder', 'event_espresso'), __('sent', 'event_espresso'), $query_args, TRUE );
0 ignored issues
show
Documentation introduced by
FALSE is of type boolean, but the function expects a integer.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1695
	}
1696
1697
1698
1699
	/**
1700
	 *  get_transactions
1701
	 *    get transactions for given parameters (used by list table)
1702
	 *
1703
	 * @param  int     $perpage how many transactions displayed per page
1704
	 * @param  boolean $count return the count or objects
1705
	 * @param string   $view
1706
	 * @return mixed int = count || array of transaction objects
1707
	 */
1708
	public function get_transactions( $perpage, $count = FALSE, $view = '' ) {
1709
1710
		$TXN = EEM_Transaction::instance();
1711
1712
	    $start_date = isset( $this->_req_data['txn-filter-start-date'] ) ? wp_strip_all_tags( $this->_req_data['txn-filter-start-date'] ) : date( 'm/d/Y', strtotime( '-10 year' ));
1713
	    $end_date = isset( $this->_req_data['txn-filter-end-date'] ) ? wp_strip_all_tags( $this->_req_data['txn-filter-end-date'] ) : date( 'm/d/Y' );
1714
1715
	    //make sure our timestamps start and end right at the boundaries for each day
1716
	    $start_date = date( 'Y-m-d', strtotime( $start_date ) ) . ' 00:00:00';
1717
	    $end_date = date( 'Y-m-d', strtotime( $end_date ) ) . ' 23:59:59';
1718
1719
1720
	    //convert to timestamps
1721
	    $start_date = strtotime( $start_date );
1722
	    $end_date = strtotime( $end_date );
1723
1724
	    //makes sure start date is the lowest value and vice versa
1725
	    $start_date = min( $start_date, $end_date );
1726
	    $end_date = max( $start_date, $end_date );
1727
1728
	    //convert to correct format for query
1729
	$start_date = EEM_Transaction::instance()->convert_datetime_for_query( 'TXN_timestamp', date( 'Y-m-d H:i:s', $start_date ), 'Y-m-d H:i:s' );
1730
	$end_date = EEM_Transaction::instance()->convert_datetime_for_query( 'TXN_timestamp', date( 'Y-m-d H:i:s', $end_date ), 'Y-m-d H:i:s' );
1731
1732
1733
1734
	    //set orderby
1735
		$this->_req_data['orderby'] = ! empty($this->_req_data['orderby']) ? $this->_req_data['orderby'] : '';
1736
1737
		switch ( $this->_req_data['orderby'] ) {
1738
			case 'TXN_ID':
1739
				$orderby = 'TXN_ID';
1740
				break;
1741
			case 'ATT_fname':
1742
				$orderby = 'Registration.Attendee.ATT_fname';
1743
				break;
1744
			case 'event_name':
1745
				$orderby = 'Registration.Event.EVT_name';
1746
				break;
1747
			default: //'TXN_timestamp'
1748
				$orderby = 'TXN_timestamp';
1749
		}
1750
1751
		$sort = ( isset( $this->_req_data['order'] ) && ! empty( $this->_req_data['order'] )) ? $this->_req_data['order'] : 'DESC';
1752
		$current_page = isset( $this->_req_data['paged'] ) && !empty( $this->_req_data['paged'] ) ? $this->_req_data['paged'] : 1;
1753
		$per_page = isset( $perpage ) && !empty( $perpage ) ? $perpage : 10;
1754
		$per_page = isset( $this->_req_data['perpage'] ) && !empty( $this->_req_data['perpage'] ) ? $this->_req_data['perpage'] : $per_page;
1755
1756
		$offset = ($current_page-1)*$per_page;
1757
		$limit = array( $offset, $per_page );
1758
1759
		$_where = array(
1760
			'TXN_timestamp' => array('BETWEEN', array($start_date, $end_date) ),
1761
			'Registration.REG_count' => 1
1762
		);
1763
1764
		if ( isset( $this->_req_data['EVT_ID'] ) ) {
1765
			$_where['Registration.EVT_ID'] = $this->_req_data['EVT_ID'];
1766
		}
1767
1768
		if ( isset( $this->_req_data['s'] ) ) {
1769
			$search_string = '%' . $this->_req_data['s'] . '%';
1770
			$_where['OR'] = array(
1771
				'Registration.Event.EVT_name' => array( 'LIKE', $search_string ),
1772
				'Registration.Event.EVT_desc' => array( 'LIKE', $search_string ),
1773
				'Registration.Event.EVT_short_desc' => array( 'LIKE' , $search_string ),
1774
				'Registration.Attendee.ATT_full_name' => array( 'LIKE', $search_string ),
1775
				'Registration.Attendee.ATT_fname' => array( 'LIKE', $search_string ),
1776
				'Registration.Attendee.ATT_lname' => array( 'LIKE', $search_string ),
1777
				'Registration.Attendee.ATT_short_bio' => array( 'LIKE', $search_string ),
1778
				'Registration.Attendee.ATT_email' => array('LIKE', $search_string ),
1779
				'Registration.Attendee.ATT_address' => array( 'LIKE', $search_string ),
1780
				'Registration.Attendee.ATT_address2' => array( 'LIKE', $search_string ),
1781
				'Registration.Attendee.ATT_city' => array( 'LIKE', $search_string ),
1782
				'Registration.REG_final_price' => array( 'LIKE', $search_string ),
1783
				'Registration.REG_code' => array( 'LIKE', $search_string ),
1784
				'Registration.REG_count' => array( 'LIKE' , $search_string ),
1785
				'Registration.REG_group_size' => array( 'LIKE' , $search_string ),
1786
				'Registration.Ticket.TKT_name' => array( 'LIKE', $search_string ),
1787
				'Registration.Ticket.TKT_description' => array( 'LIKE', $search_string ),
1788
				'Payment.PAY_source' => array('LIKE', $search_string ),
1789
				'Payment.Payment_Method.PMD_name' => array('LIKE', $search_string ),
1790
				'TXN_session_data' => array( 'LIKE', $search_string ),
1791
				'Payment.PAY_txn_id_chq_nmbr' => array( 'LIKE', $search_string )
1792
				);
1793
		}
1794
1795
		//failed transactions
1796
		$failed = ( ! empty( $this->_req_data['status'] ) && $this->_req_data['status'] == 'failed' && ! $count ) || ( $count && $view == 'failed' ) ? TRUE: FALSE;
1797
		$abandoned = ( ! empty( $this->_req_data['status'] ) && $this->_req_data['status'] == 'abandoned' && ! $count ) || ( $count && $view == 'abandoned' ) ? TRUE: FALSE;
1798
1799
		if ( $failed ) {
1800
			$_where[ 'STS_ID' ] = EEM_Transaction::failed_status_code;
1801
		} else if ( $abandoned ) {
1802
				$_where['STS_ID'] = EEM_Transaction::abandoned_status_code;
1803
		} else {
1804
				$_where['STS_ID'] = array( '!=', EEM_Transaction::failed_status_code );
1805
				$_where['STS_ID*'] = array( '!=', EEM_Transaction::abandoned_status_code );
1806
		}
1807
1808
		$query_params = array( $_where, 'order_by' => array( $orderby => $sort ), 'limit' => $limit );
1809
1810
		$transactions = $count ? $TXN->count( array($_where), 'TXN_ID', TRUE ) : $TXN->get_all($query_params);
1811
1812
1813
		return $transactions;
1814
1815
	}
1816
1817
1818
1819
}
1820