Completed
Pull Request — master (#627)
by Devin
04:26
created

Give_Payment::setup_price_id()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
c 3
b 0
f 0
nc 1
nop 0
dl 0
loc 5
rs 9.4285
ccs 3
cts 3
cp 1
crap 1
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 26 and the first side effect is on line 17.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * Payments
4
 *
5
 * This class is for working with payments in Give.
6
 *
7
 * @package     Give
8
 * @subpackage  Classes/Payment
9
 * @copyright   Copyright (c) 2016, WordImpress
10
 * @license     http://opensource.org/licenses/gpl-2.0.php GNU Public License
11
 * @since       1.5
12
 */
13
14
15
// Exit if accessed directly
16
if ( ! defined( 'ABSPATH' ) ) {
17
	exit;
18
}
19
20
21
/**
22
 * Give_Payment Class
23
 *
24
 * @since 1.5
25
 */
26
final class Give_Payment {
27
28
	/**
29
	 * The Payment we are working with
30
	 *
31
	 * @var int
32
	 * @access private
33
	 * @since 1.0
34
	 */
35
36
	/**
37
	 * The Payment ID
38
	 *
39
	 * @since  1.5
40
	 * @var    integer
41
	 */
42
	public $ID = 0;
43
	protected $_ID = 0;
44
45
	/**
46
	 * Identify if the payment is a new one or existing
47
	 *
48
	 * @since  1.5
49
	 * @var boolean
50
	 */
51
	protected $new = false;
52
53
	/**
54
	 * The Payment number (for use with sequential payments)
55
	 *
56
	 * @since  1.5
57
	 * @var string
58
	 */
59
	protected $number = '';
60
61
	/**
62
	 * The Gateway mode the payment was made in
63
	 *
64
	 * @since  1.5
65
	 * @var string
66
	 */
67
	protected $mode = 'live';
68
69
	/**
70
	 * The Unique Payment Key
71
	 *
72
	 * @since  1.5
73
	 * @var string
74
	 */
75
	protected $key = '';
76
77
	/**
78
	 * The Donation Form Title
79
	 *
80
	 * @since  1.5
81
	 * @var string
82
	 */
83
	protected $form_title = 0;
84
85
	/**
86
	 * The Donation Form ID
87
	 *
88
	 * @since  1.5
89
	 * @var string
90
	 */
91
	protected $form_id = 0;
92
93
	/**
94
	 * The Donation Form Price ID
95
	 *
96
	 * @since  1.5
97
	 * @var string
98
	 */
99
	protected $price_id = 0;
100
101
	/**
102
	 * The total amount the payment is for
103
	 * Includes donation amount and fees
104
	 *
105
	 * @since  1.5
106
	 * @var float
107
	 */
108
	protected $total = 0.00;
109
110
	/**
111
	 * The Subtotal fo the payment before fees
112
	 *
113
	 * @since  1.5
114
	 * @var float
115
	 */
116
	protected $subtotal = 0;
117
118
	/**
119
	 * Array of global fees for this payment
120
	 *
121
	 * @since  1.5
122
	 * @var array
123
	 */
124
	protected $fees = array();
125
126
	/**
127
	 * The sum of the fee amounts
128
	 *
129
	 * @since  1.5
130
	 * @var float
131
	 */
132
	protected $fees_total = 0;
133
134
	/**
135
	 * The date the payment was created
136
	 *
137
	 * @since  1.5
138
	 * @var string
139
	 */
140
	protected $date = '';
141
	protected $post_date = '';
142
143
	/**
144
	 * The date the payment was marked as 'complete'
145
	 *
146
	 * @since  1.5
147
	 * @var string
148
	 */
149
	protected $completed_date = '';
150
151
	/**
152
	 * The status of the payment
153
	 *
154
	 * @since  1.5
155
	 * @var string
156
	 */
157
	protected $status = 'pending';
158
	protected $post_status = 'pending'; // Same as $status but here for backwards compat
159
160
	/**
161
	 * When updating, the old status prior to the change
162
	 *
163
	 * @since  1.5
164
	 * @var string
165
	 */
166
	protected $old_status = '';
167
168
	/**
169
	 * The display name of the current payment status
170
	 *
171
	 * @since  1.5
172
	 * @var string
173
	 */
174
	protected $status_nicename = '';
175
176
	/**
177
	 * The customer ID that made the payment
178
	 *
179
	 * @since  1.5
180
	 * @var integer
181
	 */
182
	protected $customer_id = null;
183
184
	/**
185
	 * The User ID (if logged in) that made the payment
186
	 *
187
	 * @since  1.5
188
	 * @var integer
189
	 */
190
	protected $user_id = 0;
191
192
	/**
193
	 * The first name of the payee
194
	 *
195
	 * @since  1.5
196
	 * @var string
197
	 */
198
	protected $first_name = '';
199
200
	/**
201
	 * The last name of the payee
202
	 *
203
	 * @since  1.5
204
	 * @var string
205
	 */
206
	protected $last_name = '';
207
208
	/**
209
	 * The email used for the payment
210
	 *
211
	 * @since  1.5
212
	 * @var string
213
	 */
214
	protected $email = '';
215
216
	/**
217
	 * Legacy (not to be accessed) array of user information
218
	 *
219
	 * @since  1.5
220
	 * @var array
221
	 */
222
	private $user_info = array();
223
224
	/**
225
	 * Legacy (not to be accessed) payment meta array
226
	 *
227
	 * @since  1.5
228
	 * @var array
229
	 */
230
	private $payment_meta = array();
231
232
	/**
233
	 * The physical address used for the payment if provided
234
	 *
235
	 * @since  1.5
236
	 * @var array
237
	 */
238
	protected $address = array();
239
240
	/**
241
	 * The transaction ID returned by the gateway
242
	 *
243
	 * @since  1.5
244
	 * @var string
245
	 */
246
	protected $transaction_id = '';
247
248
	/**
249
	 * IP Address payment was made from
250
	 *
251
	 * @since  1.5
252
	 * @var string
253
	 */
254
	protected $ip = '';
255
256
	/**
257
	 * The gateway used to process the payment
258
	 *
259
	 * @since  1.5
260
	 * @var string
261
	 */
262
	protected $gateway = '';
263
264
	/**
265
	 * The the payment was made with
266
	 *
267
	 * @since  1.5
268
	 * @var string
269
	 */
270
	protected $currency = '';
271
272
	/**
273
	 * Array of items that have changed since the last save() was run
274
	 * This is for internal use, to allow fewer update_payment_meta calls to be run
275
	 *
276
	 * @since  1.5
277
	 * @var array
278
	 */
279
	private $pending;
280
281
	/**
282
	 * The parent payment (if applicable)
283
	 *
284
	 * @since  1.5
285
	 * @var integer
286
	 */
287
	protected $parent_payment = 0;
288
289
	/**
290
	 * Setup the Give Payments class
291
	 *
292
	 * @since 1.0
293
	 *
294
	 * @param int $payment_id A given payment
295
	 *
296
	 * @return mixed void|false
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...
297
	 */
298 52
	public function __construct( $payment_id = false ) {
299
300 52
		if ( empty( $payment_id ) ) {
301 52
			return false;
302 6
		}
303
304 52
		$this->setup_payment( $payment_id );
305 52
	}
306
307
	/**
308
	 * Magic GET function
309
	 *
310
	 * @since  1.5
311
	 *
312
	 * @param  string $key The property
313
	 *
314
	 * @return mixed        The value
315
	 */
316 52
	public function __get( $key ) {
317
318 52
		if ( method_exists( $this, 'get_' . $key ) ) {
319
320 52
			$value = call_user_func( array( $this, 'get_' . $key ) );
321
322 52
		} else {
323
324 52
			$value = $this->$key;
325
326
		}
327
328 52
		return $value;
329
	}
330
331
	/**
332
	 * Magic SET function
333
	 *
334
	 * Sets up the pending array for the save method
335
	 *
336
	 * @since  1.5
337
	 *
338
	 * @param string $key The property name
339
	 * @param mixed $value The value of the property
340
	 */
341 52
	public function __set( $key, $value ) {
342 52
		$ignore = array( '_ID' );
343
344 52
		if ( $key === 'status' ) {
345 52
			$this->old_status = $this->status;
346 52
		}
347
348 52
		if ( ! in_array( $key, $ignore ) ) {
349 52
			$this->pending[ $key ] = $value;
350 52
		}
351
352 52
		if ( '_ID' !== $key ) {
353 52
			$this->$key = $value;
354 52
		}
355 52
	}
356
357
	/**
358
	 * Magic ISSET function, which allows empty checks on protected elements
359
	 *
360
	 * @since  1.5
361
	 *
362
	 * @param  string $name The attribute to get
363
	 *
364
	 * @return boolean       If the item is set or not
365
	 */
366 42
	public function __isset( $name ) {
367 42
		if ( property_exists( $this, $name ) ) {
368 42
			return false === empty( $this->$name );
369
		} else {
370
			return null;
371
		}
372
	}
373
374
	/**
375
	 * Setup payment properties
376
	 *
377
	 * @since  1.5
378
	 *
379
	 * @param  int $payment_id The payment ID
380
	 *
381
	 * @return bool            If the setup was successful or not
382
	 */
383 52
	private function setup_payment( $payment_id ) {
384 52
		$this->pending = array();
385
386 52
		if ( empty( $payment_id ) ) {
387
			return false;
388
		}
389
390 52
		$payment = get_post( $payment_id );
391
392 52
		if ( ! $payment || is_wp_error( $payment ) ) {
393 5
			return false;
394
		}
395
396 52
		if ( 'give_payment' !== $payment->post_type ) {
397
			return false;
398
		}
399
400
		// Allow extensions to perform actions before the payment is loaded
401 52
		do_action( 'give_pre_setup_payment', $this, $payment_id );
402
403
		// Primary Identifier
404 52
		$this->ID = absint( $payment_id );
405
406
		// Protected ID that can never be changed
407 52
		$this->_ID = absint( $payment_id );
408
409
		// We have a payment, get the generic payment_meta item to reduce calls to it
410 52
		$this->payment_meta = $this->get_meta();
411
412
		// Status and Dates
413 52
		$this->date           = $payment->post_date;
414 52
		$this->post_date      = $payment->post_date;
415 52
		$this->completed_date = $this->setup_completed_date();
416 52
		$this->status         = $payment->post_status;
417 52
		$this->post_status    = $this->status;
418 52
		$this->mode           = $this->setup_mode();
419 52
		$this->parent_payment = $payment->post_parent;
420
421 52
		$all_payment_statuses  = give_get_payment_statuses();
422 52
		$this->status_nicename = array_key_exists( $this->status, $all_payment_statuses ) ? $all_payment_statuses[ $this->status ] : ucfirst( $this->status );
423
424
		// Items
425 52
		$this->fees = $this->setup_fees();
426
427
		// Currency Based
428 52
		$this->total      = $this->setup_total();
429 52
		$this->fees_total = $this->setup_fees_total();
430 52
		$this->subtotal   = $this->setup_subtotal();
431 52
		$this->currency   = $this->setup_currency();
432
433
		// Gateway based
434 52
		$this->gateway        = $this->setup_gateway();
435 52
		$this->transaction_id = $this->setup_transaction_id();
436
437
		// User based
438 52
		$this->ip          = $this->setup_ip();
439 52
		$this->customer_id = $this->setup_customer_id();
440 52
		$this->user_id     = $this->setup_user_id();
441 52
		$this->email       = $this->setup_email();
442 52
		$this->user_info   = $this->setup_user_info();
443 52
		$this->address     = $this->setup_address();
444 52
		$this->first_name  = $this->user_info['first_name'];
445 52
		$this->last_name   = $this->user_info['last_name'];
446
447
		// Other Identifiers
448 52
		$this->form_title = $this->setup_form_title();
449 52
		$this->form_id    = $this->setup_form_id();
450 52
		$this->price_id   = $this->setup_price_id();
451 52
		$this->key        = $this->setup_payment_key();
452 52
		$this->number     = $this->setup_payment_number();
453
454
		// Allow extensions to add items to this object via hook
455 52
		do_action( 'give_setup_payment', $this, $payment_id );
456
457 52
		return true;
458
	}
459
460
	/**
461
	 * Create the base of a payment.
462
	 *
463
	 * @since  1.5
464
	 * @return int|bool False on failure, the payment ID on success.
465
	 */
466 52
	private function insert_payment() {
467
468
		// Construct the payment title
469 52
		$payment_title = '';
470 52
		if ( ! empty( $this->first_name ) && ! empty( $this->last_name ) ) {
471 31
			$payment_title = $this->first_name . ' ' . $this->last_name;
472 52
		} else if ( ! empty( $this->first_name ) && empty( $this->last_name ) ) {
473
			$payment_title = $this->first_name;
474 22
		} else if ( ! empty( $this->email ) && is_email( $this->email ) ) {
475 21
			$payment_title = $this->email;
476 21
		}
477
478
		//Set Key
479 52
		if ( empty( $this->key ) ) {
480
481 1
			$auth_key             = defined( 'AUTH_KEY' ) ? AUTH_KEY : '';
482 1
			$this->key            = strtolower( md5( $this->email . date( 'Y-m-d H:i:s' ) . $auth_key . uniqid( 'give', true ) ) );  // Unique key
483 1
			$this->pending['key'] = $this->key;
484 1
		}
485
486
		//Set IP
487 52
		if ( empty( $this->ip ) ) {
488
489 1
			$this->ip            = give_get_ip();
490 1
			$this->pending['ip'] = $this->ip;
491
492 1
		}
493
494
		$payment_data = array(
495 52
			'price'        => $this->total,
496 52
			'date'         => $this->date,
497 52
			'user_email'   => $this->email,
498 52
			'purchase_key' => $this->key,
499 52
			'form_title'   => $this->form_title,
500 52
			'form_id'      => $this->form_id,
501 52
			'price_id'     => $this->price_id,
502 52
			'currency'     => $this->currency,
503
			'user_info'    => array(
504 52
				'id'         => $this->user_id,
505 52
				'email'      => $this->email,
506 52
				'first_name' => $this->first_name,
507 52
				'last_name'  => $this->last_name,
508 52
				'address'    => $this->address,
509 52
			),
510 52
			'status'       => $this->status,
511 52
			'fees'         => $this->fees,
512 52
		);
513
514 52
		$args = apply_filters( 'give_insert_payment_args', array(
515 52
			'post_title'    => $payment_title,
516 52
			'post_status'   => $this->status,
517 52
			'post_type'     => 'give_payment',
518 52
			'post_date'     => ! empty( $this->date ) ? $this->date : null,
519 52
			'post_date_gmt' => ! empty( $this->date ) ? get_gmt_from_date( $this->date ) : null,
520 52
			'post_parent'   => $this->parent_payment,
521 52
		), $payment_data );
522
523
		// Create a blank payment
524 52
		$payment_id = wp_insert_post( $args );
525
526 52
		if ( ! empty( $payment_id ) ) {
527
528 52
			$this->ID  = $payment_id;
529 52
			$this->_ID = $payment_id;
530
531 52
			$customer = new stdClass;
532
533 52
			if ( did_action( 'give_pre_process_purchase' ) && is_user_logged_in() ) {
534
				$customer = new Give_Customer( get_current_user_id(), true );
535
			}
536
537 52
			if ( empty( $customer->id ) ) {
538 52
				$customer = new Give_Customer( $this->email );
539 52
			}
540
541 52
			if ( empty( $customer->id ) ) {
542
543
				$customer_data = array(
544 52
					'name'    => ! is_email( $payment_title ) ? $this->first_name . ' ' . $this->last_name : '',
545 52
					'email'   => $this->email,
546 52
					'user_id' => $this->user_id,
547 52
				);
548
549 52
				$customer->create( $customer_data );
0 ignored issues
show
Bug introduced by
The method create does only exist in Give_Customer, but not in stdClass.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
550
551 52
			}
552
553 52
			$this->customer_id            = $customer->id;
554 52
			$this->pending['customer_id'] = $this->customer_id;
555 52
			$customer->attach_payment( $this->ID, false );
0 ignored issues
show
Bug introduced by
The method attach_payment does only exist in Give_Customer, but not in stdClass.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
556
557 52
			$this->payment_meta = apply_filters( 'give_payment_meta', $this->payment_meta, $payment_data );
558 52
			if ( ! empty( $this->payment_meta['fees'] ) ) {
559
				$this->fees = array_merge( $this->fees, $this->payment_meta['fees'] );
560
				foreach ( $this->fees as $fee ) {
561
					$this->increase_fees( $fee['amount'] );
562
				}
563
			}
564
565 52
			$this->update_meta( '_give_payment_meta', $this->payment_meta );
566 52
			$this->new = true;
567 52
		}
568
569 52
		return $this->ID;
570
571
	}
572
573
	/**
574
	 * Save
575
	 *
576
	 * @description: Once items have been set, an update is needed to save them to the database.
577
	 *
578
	 * @return bool  True of the save occurred, false if it failed or wasn't needed
579
	 */
580 52
	public function save() {
581
582 52
		$saved = false;
583
584
		//Must have an ID 
585 52
		if ( empty( $this->ID ) ) {
586
587 52
			$payment_id = $this->insert_payment();
588
589 52
			if ( false === $payment_id ) {
590
				$saved = false;
591
			} else {
592 52
				$this->ID = $payment_id;
593
			}
594
595 52
		}
596
597
		//Set ID if not matching
598 52
		if ( $this->ID !== $this->_ID ) {
599 1
			$this->ID = $this->_ID;
600 1
		}
601
602
		// If we have something pending, let's save it
603 52
		if ( ! empty( $this->pending ) ) {
604
605 52
			$total_increase = 0;
606 52
			$total_decrease = 0;
607
608 52
			foreach ( $this->pending as $key => $value ) {
609
610
				switch ( $key ) {
611
612 52
					case 'donations':
613
						// Update totals for pending donations
614 52
						foreach ( $this->pending[ $key ] as $item ) {
615
616 52
							$quantity = isset( $item['quantity'] ) ? $item['quantity'] : 1;
617 52
							$price_id = isset( $item['price_id'] ) ? $item['price_id'] : 0;
618
619 52
							switch ( $item['action'] ) {
620
621 52
								case 'add':
622
623 52
									$price = $item['price'];
624
625 52
									if ( 'publish' === $this->status || 'complete' === $this->status || 'revoked' === $this->status ) {
626
627
										// Add sales logs
628 1
										$log_date = date_i18n( 'Y-m-d G:i:s', current_time( 'timestamp' ) );
629
630 1
										$y = 0;
631 1
										while ( $y < $quantity ) {
632
633 1
											give_record_sale_in_log( $item['id'], $this->ID, $price_id, $log_date );
634 1
											$y ++;
635 1
										}
636
637 1
										$form = new Give_Donate_Form( $item['id'] );
638 1
										$form->increase_sales( $quantity );
639 1
										$form->increase_earnings( $price );
640
641 1
										$total_increase += $price;
642 1
									}
643 52
									break;
644
645 2
								case 'remove':
646
									$log_args = array(
647 2
										'post_type'   => 'give_log',
648 2
										'post_parent' => $item['id'],
649 2
										'numberposts' => $quantity,
650
										'meta_query'  => array(
651
											array(
652 2
												'key'     => '_give_log_payment_id',
653 2
												'value'   => $this->ID,
654 2
												'compare' => '=',
655 2
											),
656
											array(
657 2
												'key'     => '_give_log_price_id',
658 2
												'value'   => $price_id,
659
												'compare' => '='
660 2
											)
661 2
										)
662 2
									);
663
664 2
									$found_logs = get_posts( $log_args );
665 2
									foreach ( $found_logs as $log ) {
666 1
										wp_delete_post( $log->ID, true );
667 2
									}
668
669 2
									if ( 'publish' === $this->status || 'complete' === $this->status || 'revoked' === $this->status ) {
670 1
										$form = new Give_Donate_Form( $item['id'] );
671 1
										$form->decrease_sales( $quantity );
672 1
										$form->decrease_earnings( $item['amount'] );
673
674 1
										$total_decrease += $item['amount'];
675 1
									}
676 2
									break;
677
678 52
							}
679
680 52
						}
681 52
						break;
682
683 52
					case 'fees':
684
685
						if ( 'publish' !== $this->status && 'complete' !== $this->status && 'revoked' !== $this->status ) {
686
							break;
687
						}
688
689
						if ( empty( $this->pending[ $key ] ) ) {
690
							break;
691
						}
692
693
						foreach ( $this->pending[ $key ] as $fee ) {
694
695
							switch ( $fee['action'] ) {
696
697
								case 'add':
698
									$total_increase += $fee['amount'];
699
									break;
700
701
								case 'remove':
702
									$total_decrease += $fee['amount'];
703
									break;
704
705
							}
706
707
						}
708
709
						break;
710
711 52
					case 'status':
712 52
						$this->update_status( $this->status );
713 52
						break;
714
715 52
					case 'gateway':
716 52
						$this->update_meta( '_give_payment_gateway', $this->gateway );
717 52
						break;
718
719 52
					case 'mode':
720 52
						$this->update_meta( '_give_payment_mode', $this->mode );
721 52
						break;
722
723 52
					case 'transaction_id':
724 20
						$this->update_meta( '_give_payment_transaction_id', $this->transaction_id );
725 20
						break;
726
727 52
					case 'ip':
728 52
						$this->update_meta( '_give_payment_user_ip', $this->ip );
729 52
						break;
730
731 52
					case 'customer_id':
732 52
						$this->update_meta( '_give_payment_customer_id', $this->customer_id );
733 52
						break;
734
735 52
					case 'user_id':
736 52
						$this->update_meta( '_give_payment_user_id', $this->user_id );
737 52
						break;
738
739 52
					case 'form_title':
740 52
						$this->update_meta( '_give_payment_form_title', $this->form_title );
741 52
						break;
742
743 52
					case 'form_id':
744 52
						$this->update_meta( '_give_payment_form_id', $this->form_id );
745 52
						break;
746
747 52
					case 'price_id':
748 52
						$this->update_meta( '_give_payment_price_id', $this->price_id );
749 52
						break;
750
751 52
					case 'first_name':
752 52
						$this->user_info['first_name'] = $this->first_name;
753 52
						break;
754
755 52
					case 'last_name':
756 52
						$this->user_info['last_name'] = $this->last_name;
757 52
						break;
758
759 52
					case 'address':
760
						$this->user_info['address'] = $this->address;
761
						break;
762
763 52
					case 'email':
764 52
						$this->update_meta( '_give_payment_user_email', $this->email );
765 52
						break;
766
767 52
					case 'key':
768 52
						$this->update_meta( '_give_payment_purchase_key', $this->key );
769 52
						break;
770
771 52
					case 'number':
772 20
						$this->update_meta( '_give_payment_number', $this->number );
773 20
						break;
774
775 52
					case 'date':
776
						$args = array(
777 2
							'ID'        => $this->ID,
778 2
							'post_date' => $this->date,
779 2
							'edit_date' => true,
780 2
						);
781
782 2
						wp_update_post( $args );
783 2
						break;
784
785 52
					case 'completed_date':
786 42
						$this->update_meta( '_give_completed_date', $this->completed_date );
787 42
						break;
788
789 52
					case 'parent_payment':
790
						$args = array(
791 52
							'ID'          => $this->ID,
792 52
							'post_parent' => $this->parent_payment,
793 52
						);
794
795 52
						wp_update_post( $args );
796 52
						break;
797
798 52
					default:
799 52
						do_action( 'give_payment_save', $this, $key );
800 52
						break;
801 52
				}
802 52
			}
803
804 52
			if ( 'pending' !== $this->status ) {
805
806 42
				$customer = new Give_Customer( $this->customer_id );
807
808 42
				$total_change = $total_increase - $total_decrease;
809 42
				if ( $total_change < 0 ) {
810
811 1
					$total_change = - ( $total_change );
812
					// Decrease the customer's purchase stats
813 1
					$customer->decrease_value( $total_change );
814 1
					give_decrease_total_earnings( $total_change );
815
816 42
				} else if ( $total_change > 0 ) {
817
818
					// Increase the customer's purchase stats
819 1
					$customer->increase_value( $total_change );
820 1
					give_increase_total_earnings( $total_change );
821
822 1
				}
823
824 42
			}
825
826 52
			$this->update_meta( '_give_payment_total', $this->total );
827
828
			$new_meta = array(
829 52
				'form_title' => $this->form_title,
830 52
				'form_id'    => $this->form_id,
831 52
				'price_id'   => $this->price_id,
832 52
				'fees'       => $this->fees,
833 52
				'currency'   => $this->currency,
834 52
				'user_info'  => $this->user_info,
835 52
			);
836
837 52
			$meta        = $this->get_meta();
838 52
			$merged_meta = array_merge( $meta, $new_meta );
839
840
			// Only save the payment meta if it's changed
841 52
			if ( md5( serialize( $meta ) ) !== md5( serialize( $merged_meta ) ) ) {
842 52
				$updated = $this->update_meta( '_give_payment_meta', $merged_meta );
843 52
				if ( false !== $updated ) {
844 52
					$saved = true;
845 52
				}
846 52
			}
847
848 52
			$this->pending = array();
849 52
			$saved         = true;
850 52
		}
851
852 52
		if ( true === $saved ) {
853 52
			$this->setup_payment( $this->ID );
854 52
		}
855
856 52
		return $saved;
857
	}
858
859
	/**
860
	 * Add a donation to a given payment
861
	 *
862
	 * @since 1.5
863
	 *
864
	 * @param int $form_id The donation form to add
865
	 * @param array $args Other arguments to pass to the function
866
	 * @param array $options List of donation options
867
	 *
868
	 * @return bool True when successful, false otherwise
869
	 */
870 52
	public function add_donation( $form_id = 0, $args = array(), $options = array() ) {
871
872 52
		$donation = new Give_Donate_Form( $form_id );
873
874
		// Bail if this post isn't a give donation form
875 52
		if ( ! $donation || $donation->post_type !== 'give_forms' ) {
0 ignored issues
show
Documentation introduced by
The property post_type does not exist on object<Give_Donate_Form>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
876
			return false;
877
		}
878
879
		// Set some defaults
880
		$defaults = array(
881 52
			'price'    => false,
882 52
			'price_id' => false,
883 52
			'fees'     => array(),
884 52
		);
885
886 52
		$args = wp_parse_args( apply_filters( 'give_payment_add_donation_args', $args, $donation->ID ), $defaults );
887
888
		// Allow overriding the price
889 52
		if ( false !== $args['price'] ) {
890 52
			$item_price = $args['price'];
891 52
		} else {
892
893
			// Deal with variable pricing
894 2
			if ( give_has_variable_prices( $donation->ID ) ) {
895 1
				$prices     = maybe_unserialize( get_post_meta( $form_id, '_give_donation_levels', true ) );
896 1
				$item_price = '';
897
				//Loop through prices
898 1
				foreach ( $prices as $price ) {
899
					//Find a match between price_id and level_id
900
					//First verify array keys exists THEN make the match
901 1
					if ( ( isset( $args['price_id'] ) && isset( $price['_give_id']['level_id'] ) )
902 1
					     && $args['price_id'] == $price['_give_id']['level_id']
903 1
					) {
904 1
						$item_price = $price['_give_amount'];
905 1
					}
906 1
				}
907
				//Fallback to the lowest price point
908 1
				if ( $item_price == '' ) {
909
					$item_price       = give_get_lowest_price_option( $donation->ID );
910
					$args['price_id'] = give_get_lowest_price_id( $donation->ID );
911
				}
912 1
			} else {
913
				//Simple form price
914 1
				$item_price = give_get_form_price( $donation->ID );
915
			}
916
917
		}
918
919
		// Sanitizing the price here so we don't have a dozen calls later
920 52
		$item_price = give_sanitize_amount( $item_price );
921 52
		$total      = round( $item_price, give_currency_decimal_filter() );
922
923
		//Add Options
924 52
		$default_options = array();
925 52
		if ( false !== $args['price_id'] ) {
926 52
			$default_options['price_id'] = (int) $args['price_id'];
927 52
		}
928 52
		$options = wp_parse_args( $options, $default_options );
929
930
		// Do not allow totals to go negative
931 52
		if ( $total < 0 ) {
932
			$total = 0;
933
		}
934
935
		$donation = array(
936 52
			'name'     => $donation->post_title,
937 52
			'id'       => $donation->ID,
938 52
			'price'    => round( $total, give_currency_decimal_filter() ),
939 52
			'subtotal' => round( $total, give_currency_decimal_filter() ),
940 52
			'fees'     => $args['fees'],
941 52
			'price_id' => $args['price_id'],
942 52
			'action'   => 'add',
943
			'options'  => $options
944 52
		);
945
946 52
		$this->pending['donations'][] = $donation;
947
948 52
		$this->increase_subtotal( $total );
949
950 52
		return true;
951
952
	}
953
954
	/**
955
	 * Remove a donation from the payment
956
	 *
957
	 * @since  1.5
958
	 *
959
	 * @param  int $form_id The form ID to remove
960
	 * @param  array $args Arguments to pass to identify (quantity, amount, price_id)
961
	 *
962
	 * @return bool If the item was removed or not
963
	 */
964 2
	public function remove_donation( $form_id, $args = array() ) {
965
966
		// Set some defaults
967
		$defaults = array(
968 2
			'quantity' => 1,
969 2
			'price'    => false,
970 2
			'price_id' => false,
971 2
		);
972 2
		$args     = wp_parse_args( $args, $defaults );
973
974 2
		$form = new Give_Donate_Form( $form_id );
975
976
		// Bail if this post isn't a valid give donation form
977 2
		if ( ! $form || $form->post_type !== 'give_forms' ) {
0 ignored issues
show
Documentation introduced by
The property post_type does not exist on object<Give_Donate_Form>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
978
			return false;
979
		}
980
981 2
		$pending_args             = $args;
982 2
		$pending_args['id']       = $form_id;
983 2
		$pending_args['amount']   = $this->total;
984 2
		$pending_args['price_id'] = false !== $args['price_id'] ? (int) $args['price_id'] : false;
985 2
		$pending_args['quantity'] = $args['quantity'];
986 2
		$pending_args['action']   = 'remove';
987
988 2
		$this->pending['donations'][] = $pending_args;
989
990 2
		$this->decrease_subtotal( $this->total );
991
992 2
		return true;
993
	}
994
995
	/**
996
	 * Add a fee to a given payment
997
	 *
998
	 * @since  1.5
999
	 *
1000
	 * @param  array $args Array of arguments for the fee to add
1001
	 * @param bool $global
1002
	 *
1003
	 * @return bool If the fee was added
1004
	 */
1005
	public function add_fee( $args, $global = true ) {
0 ignored issues
show
Unused Code introduced by
The parameter $global is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1006
1007
		$default_args = array(
1008
			'label'    => '',
1009
			'amount'   => 0,
1010
			'type'     => 'fee',
1011
			'id'       => '',
1012
			'price_id' => 0,
1013
		);
1014
1015
		$fee          = wp_parse_args( $args, $default_args );
1016
		$this->fees[] = $fee;
1017
1018
1019
		$added_fee               = $fee;
1020
		$added_fee['action']     = 'add';
1021
		$this->pending['fees'][] = $added_fee;
1022
		reset( $this->fees );
1023
1024
		$this->increase_fees( $fee['amount'] );
1025
1026
		return true;
1027
	}
1028
1029
	/**
1030
	 * Remove a fee from the payment
1031
	 *
1032
	 * @since  1.5
1033
	 *
1034
	 * @param  int $key The array key index to remove
1035
	 *
1036
	 * @return bool     If the fee was removed successfully
1037
	 */
1038
	public function remove_fee( $key ) {
1039
		$removed = false;
1040
1041
		if ( is_numeric( $key ) ) {
1042
			$removed = $this->remove_fee_by( 'index', $key );
1043
		}
1044
1045
		return $removed;
1046
	}
1047
1048
	/**
1049
	 * Remove a fee by the defined attributed
1050
	 *
1051
	 * @since  1.5
1052
	 *
1053
	 * @param  string $key The key to remove by
1054
	 * @param  int|string $value The value to search for
1055
	 * @param  boolean $global False - removes the first value it fines, True - removes all matches
1056
	 *
1057
	 * @return boolean             If the item is removed
1058
	 */
1059
	public function remove_fee_by( $key, $value, $global = false ) {
1060
1061
		$allowed_fee_keys = apply_filters( 'give_payment_fee_keys', array(
1062
			'index',
1063
			'label',
1064
			'amount',
1065
			'type',
1066
		) );
1067
1068
		if ( ! in_array( $key, $allowed_fee_keys ) ) {
1069
			return false;
1070
		}
1071
1072
		$removed = false;
1073
		if ( 'index' === $key && array_key_exists( $value, $this->fees ) ) {
1074
1075
			$removed_fee             = $this->fees[ $value ];
1076
			$removed_fee['action']   = 'remove';
1077
			$this->pending['fees'][] = $removed_fee;
1078
1079
			$this->decrease_fees( $removed_fee['amount'] );
1080
1081
			unset( $this->fees[ $value ] );
1082
			$removed = true;
1083
1084
		} else if ( 'index' !== $key ) {
1085
1086
			foreach ( $this->fees as $index => $fee ) {
1087
1088
				if ( isset( $fee[ $key ] ) && $fee[ $key ] == $value ) {
1089
1090
					$removed_fee             = $fee;
1091
					$removed_fee['action']   = 'remove';
1092
					$this->pending['fees'][] = $removed_fee;
1093
1094
					$this->decrease_fees( $removed_fee['amount'] );
1095
1096
					unset( $this->fees[ $index ] );
1097
					$removed = true;
1098
1099
					if ( false === $global ) {
1100
						break;
1101
					}
1102
1103
				}
1104
1105
			}
1106
1107
		}
1108
1109
		if ( true === $removed ) {
1110
			$this->fees = array_values( $this->fees );
1111
		}
1112
1113
		return $removed;
1114
	}
1115
1116
	/**
1117
	 * Get the fees, filterable by type
1118
	 *
1119
	 * @since  1.5
1120
	 *
1121
	 * @param  string $type All, item, fee
1122
	 *
1123
	 * @return array        The Fees for the type specified
1124
	 */
1125
	public function get_fees( $type = 'all' ) {
1126
		$fees = array();
1127
1128
		if ( ! empty( $this->fees ) && is_array( $this->fees ) ) {
1129
1130
			foreach ( $this->fees as $fee_id => $fee ) {
1131
1132
				if ( 'all' != $type && ! empty( $fee['type'] ) && $type != $fee['type'] ) {
1133
					continue;
1134
				}
1135
1136
				$fee['id'] = $fee_id;
1137
				$fees[]    = $fee;
1138
1139
			}
1140
		}
1141
1142
		return apply_filters( 'give_get_payment_fees', $fees, $this->ID, $this );
1143
	}
1144
1145
	/**
1146
	 * Add a note to a payment
1147
	 *
1148
	 * @since 1.0
1149
	 *
1150
	 * @param string $note The note to add
1151
	 *
1152
	 * @return void
1153
	 */
1154
	public function add_note( $note = false ) {
1155
		// Bail if no note specified
1156
		if ( ! $note ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $note of type false|string is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
1157
			return false;
1158
		}
1159
1160
		give_insert_payment_note( $this->ID, $note );
1161
	}
1162
1163
	/**
1164
	 * Increase the payment's subtotal
1165
	 *
1166
	 * @since  1.5
1167
	 *
1168
	 * @param  float $amount The amount to increase the payment subtotal by
1169
	 *
1170
	 * @return void
1171
	 */
1172 52
	private function increase_subtotal( $amount = 0.00 ) {
1173 52
		$amount = (float) $amount;
1174 52
		$this->subtotal += $amount;
1175
1176 52
		$this->recalculate_total();
1177 52
	}
1178
1179
	/**
1180
	 * Decrease the payment's subtotal
1181
	 *
1182
	 * @since  1.5
1183
	 *
1184
	 * @param  float $amount The amount to decrease the payment subtotal by
1185
	 *
1186
	 * @return void
1187
	 */
1188 2
	private function decrease_subtotal( $amount = 0.00 ) {
1189 2
		$amount = (float) $amount;
1190 2
		$this->subtotal -= $amount;
1191
1192 2
		if ( $this->subtotal < 0 ) {
1193
			$this->subtotal = 0;
1194
		}
1195
1196 2
		$this->recalculate_total();
1197 2
	}
1198
1199
	/**
1200
	 * Increase the payment's subtotal
1201
	 *
1202
	 * @since  1.5
1203
	 *
1204
	 * @param  float $amount The amount to increase the payment subtotal by
1205
	 *
1206
	 * @return void
1207
	 */
1208
	private function increase_fees( $amount = 0.00 ) {
1209
		$amount = (float) $amount;
1210
		$this->fees_total += $amount;
1211
1212
		$this->recalculate_total();
1213
	}
1214
1215
	/**
1216
	 * Decrease the payment's subtotal
1217
	 *
1218
	 * @since  1.5
1219
	 *
1220
	 * @param  float $amount The amount to decrease the payment subtotal by
1221
	 *
1222
	 * @return void
1223
	 */
1224
	private function decrease_fees( $amount = 0.00 ) {
1225
		$amount = (float) $amount;
1226
		$this->fees_total -= $amount;
1227
1228
		if ( $this->fees_total < 0 ) {
1229
			$this->fees_total = 0;
1230
		}
1231
1232
		$this->recalculate_total();
1233
	}
1234
1235
	/**
1236
	 * Set or update the total for a payment
1237
	 *
1238
	 * @since 1.0
1239
	 * @return void
1240
	 */
1241 52
	private function recalculate_total() {
1242 52
		$this->total = $this->subtotal + $this->fees_total;
1243 52
	}
1244
1245
	/**
1246
	 * Set the payment status and run any status specific changes necessary
1247
	 *
1248
	 * @since 1.0
1249
	 *
1250
	 * @param  string $status The status to set the payment to
1251
	 *
1252
	 * @return bool Returns if the status was successfully updated
1253
	 */
1254 52
	public function update_status( $status = false ) {
1255
1256
		//standardize the 'complete(d)' status
1257 52
		if ( $status == 'completed' || $status == 'complete' ) {
1258 39
			$status = 'publish';
1259 39
		}
1260
1261 52
		$old_status = ! empty( $this->old_status ) ? $this->old_status : false;
1262
1263 52
		if ( $old_status === $status ) {
1264 52
			return false; // Don't permit status changes that aren't changes
1265
		}
1266
1267 42
		$do_change = apply_filters( 'give_should_update_payment_status', true, $this->ID, $status, $old_status );
1268
1269 42
		$updated = false;
1270
1271
1272 42
		if ( $do_change ) {
1273
1274 42
			do_action( 'give_before_payment_status_change', $this->ID, $status, $old_status );
1275
1276
			$update_fields = array(
1277 42
				'ID'          => $this->ID,
1278 42
				'post_status' => $status,
1279 42
				'edit_date'   => current_time( 'mysql' )
1280 42
			);
1281
1282 42
			$updated = wp_update_post( apply_filters( 'give_update_payment_status_fields', $update_fields ) );
1283
1284 42
			$all_payment_statuses  = give_get_payment_statuses();
1285 42
			$this->status_nicename = array_key_exists( $status, $all_payment_statuses ) ? $all_payment_statuses[ $status ] : ucfirst( $status );
1286
1287
			// Process any specific status functions
1288
			switch ( $status ) {
1289 42
				case 'refunded':
1290 4
					$this->process_refund();
1291 4
					break;
1292 42
				case 'failed':
1293
					$this->process_failure();
0 ignored issues
show
Unused Code introduced by
The call to the method Give_Payment::process_failure() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
1294
					break;
1295 42
				case 'pending':
1296 3
					$this->process_pending();
1297 3
					break;
1298
			}
1299
1300 42
			do_action( 'give_update_payment_status', $this->ID, $status, $old_status );
1301
1302 42
		}
1303
1304 42
		return $updated;
1305
1306
	}
1307
1308
	/**
1309
	 * Change the status of the payment to refunded, and run the necessary changes
1310
	 *
1311
	 * @since  1.5
1312
	 * @return void
1313
	 */
1314 4
	public function refund() {
1315 4
		$this->old_status        = $this->status;
1316 4
		$this->status            = 'refunded';
1317 4
		$this->pending['status'] = $this->status;
1318
1319 4
		$this->save();
1320 4
	}
1321
1322
	/**
1323
	 * Get a post meta item for the payment
1324
	 *
1325
	 * @since  1.5
1326
	 *
1327
	 * @param  string $meta_key The Meta Key
1328
	 * @param  boolean $single Return single item or array
1329
	 *
1330
	 * @return mixed             The value from the post meta
1331
	 */
1332 52
	public function get_meta( $meta_key = '_give_payment_meta', $single = true ) {
1333
1334 52
		$meta = get_post_meta( $this->ID, $meta_key, $single );
1335
1336 52
		if ( $meta_key === '_give_payment_meta' ) {
1337
1338 52
			if ( empty( $meta['key'] ) ) {
1339 52
				$meta['key'] = $this->setup_payment_key();
1340 52
			}
1341
1342 52
			if ( empty( $meta['form_title'] ) ) {
1343 52
				$meta['form_title'] = $this->setup_form_title();
1344 52
			}
1345
1346 52
			if ( empty( $meta['email'] ) ) {
1347 52
				$meta['email'] = $this->setup_email();
1348 52
			}
1349
1350 52
			if ( empty( $meta['date'] ) ) {
1351 52
				$meta['date'] = get_post_field( 'post_date', $this->ID );
1352 52
			}
1353 52
		}
1354
1355 52
		$meta = apply_filters( 'give_get_payment_meta_' . $meta_key, $meta, $this->ID );
1356
1357 52
		return apply_filters( 'give_get_payment_meta', $meta, $this->ID, $meta_key );
1358
	}
1359
1360
	/**
1361
	 * Update the post meta
1362
	 *
1363
	 * @since  1.5
1364
	 *
1365
	 * @param  string $meta_key The meta key to update
1366
	 * @param  string $meta_value The meta value
1367
	 * @param  string $prev_value Previous meta value
1368
	 *
1369
	 * @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure
1370
	 */
1371 52
	public function update_meta( $meta_key = '', $meta_value = '', $prev_value = '' ) {
1372 52
		if ( empty( $meta_key ) ) {
1373
			return false;
1374
		}
1375
1376 52
		if ( $meta_key == 'key' || $meta_key == 'date' ) {
1377
1378
			$current_meta              = $this->get_meta();
1379
			$current_meta[ $meta_key ] = $meta_value;
1380
1381
			$meta_key   = '_give_payment_meta';
1382
			$meta_value = $current_meta;
1383
1384 52
		} else if ( $meta_key == 'email' || $meta_key == '_give_payment_user_email' ) {
1385
1386 52
			$meta_value = apply_filters( 'give_give_update_payment_meta_' . $meta_key, $meta_value, $this->ID );
1387 52
			update_post_meta( $this->ID, '_give_payment_user_email', $meta_value );
1388
1389 52
			$current_meta                       = $this->get_meta();
1390 52
			$current_meta['user_info']['email'] = $meta_value;
1391
1392 52
			$meta_key   = '_give_payment_meta';
1393 52
			$meta_value = $current_meta;
1394
1395 52
		}
1396
1397 52
		$meta_value = apply_filters( 'give_update_payment_meta_' . $meta_key, $meta_value, $this->ID );
1398
1399 52
		return update_post_meta( $this->ID, $meta_key, $meta_value, $prev_value );
1400
	}
1401
1402
	/**
1403
	 * When a payment is set to a status of 'refunded' process the necessary actions to reduce stats
1404
	 *
1405
	 * @since  1.5
1406
	 * @access private
1407
	 * @return void
1408
	 */
1409 4
	private function process_refund() {
1410 4
		$process_refund = true;
1411
1412
		// If the payment was not in publish or revoked status, don't decrement stats as they were never incremented
1413 4
		if ( ( 'publish' != $this->old_status && 'revoked' != $this->old_status ) || 'refunded' != $this->status ) {
1414
			$process_refund = false;
1415
		}
1416
1417
		// Allow extensions to filter for their own payment types, Example: Recurring Payments
1418 4
		$process_refund = apply_filters( 'give_should_process_refund', $process_refund, $this );
1419
1420 4
		if ( false === $process_refund ) {
1421
			return;
1422
		}
1423
1424 4
		do_action( 'give_pre_refund_payment', $this );
1425
1426 4
		$decrease_store_earnings = apply_filters( 'give_decrease_store_earnings_on_refund', true, $this );
1427 4
		$decrease_customer_value = apply_filters( 'give_decrease_customer_value_on_refund', true, $this );
1428 4
		$decrease_purchase_count = apply_filters( 'give_decrease_customer_purchase_count_on_refund', true, $this );
1429
1430 4
		$this->maybe_alter_stats( $decrease_store_earnings, $decrease_customer_value, $decrease_purchase_count );
1431 4
		$this->delete_sales_logs();
1432
1433
		// Clear the This Month earnings (this_monththis_month is NOT a typo)
1434 4
		delete_transient( md5( 'give_earnings_this_monththis_month' ) );
1435
1436 4
		do_action( 'give_post_refund_payment', $this );
1437 4
	}
1438
1439
	/**
1440
	 * Process when a payment is set to failed
1441
	 *
1442
	 * @since  1.5
1443
	 * @return void
1444
	 */
1445
	private function process_failure() {
1446
1447
1448
	}
1449
1450
	/**
1451
	 * Process when a payment moves to pending
1452
	 *
1453
	 * @since  1.5
1454
	 * @return void
1455
	 */
1456 3
	private function process_pending() {
1457 3
		$process_pending = true;
1458
1459
		// If the payment was not in publish or revoked status, don't decrement stats as they were never incremented
1460 3
		if ( ( 'publish' != $this->old_status && 'revoked' != $this->old_status ) || 'pending' != $this->status ) {
1461 1
			$process_pending = false;
1462 1
		}
1463
1464
		// Allow extensions to filter for their own payment types, Example: Recurring Payments
1465 3
		$process_pending = apply_filters( 'give_should_process_pending', $process_pending, $this );
1466
1467 3
		if ( false === $process_pending ) {
1468 1
			return;
1469
		}
1470
1471 2
		$decrease_store_earnings = apply_filters( 'give_decrease_store_earnings_on_pending', true, $this );
1472 2
		$decrease_customer_value = apply_filters( 'give_decrease_customer_value_on_pending', true, $this );
1473 2
		$decrease_purchase_count = apply_filters( 'give_decrease_customer_purchase_count_on_pending', true, $this );
1474
1475 2
		$this->maybe_alter_stats( $decrease_store_earnings, $decrease_customer_value, $decrease_purchase_count );
1476 2
		$this->delete_sales_logs();
1477
1478 2
		$this->completed_date = false;
1479 2
		$this->update_meta( '_give_completed_date', '' );
1480
1481
		// Clear the This Month earnings (this_monththis_month is NOT a typo)
1482 2
		delete_transient( md5( 'give_earnings_this_monththis_month' ) );
1483 2
	}
1484
1485
	/**
1486
	 * Used during the process of moving to refunded or pending, to decrement stats
1487
	 *
1488
	 * @since  1.5
1489
	 *
1490
	 * @param  bool $alter_store_earnings If the method should alter the store earnings
1491
	 * @param  bool $alter_customer_value If the method should reduce the customer value
1492
	 * @param  bool $alter_customer_purchase_count If the method should reduce the customer's purchase count
1493
	 *
1494
	 * @return void
1495
	 */
1496 6
	private function maybe_alter_stats( $alter_store_earnings, $alter_customer_value, $alter_customer_purchase_count ) {
1497
1498 6
		give_undo_purchase( false, $this->ID );
1499
1500
		// Decrease store earnings
1501 6
		if ( true === $alter_store_earnings ) {
1502 4
			give_decrease_total_earnings( $this->total );
1503 4
		}
1504
1505
		// Decrement the stats for the customer
1506 6
		if ( ! empty( $this->customer_id ) ) {
1507
1508 6
			$customer = new Give_Customer( $this->customer_id );
1509
1510 6
			if ( true === $alter_customer_value ) {
1511 4
				$customer->decrease_value( $this->total );
1512 4
			}
1513
1514 6
			if ( true === $alter_customer_purchase_count ) {
1515 4
				$customer->decrease_purchase_count();
1516 4
			}
1517
1518 6
		}
1519
1520 6
	}
1521
1522
	/**
1523
	 * Delete sales logs for this purchase
1524
	 *
1525
	 * @since  1.5
1526
	 * @return void
1527
	 */
1528 6
	private function delete_sales_logs() {
1529 6
		global $give_logs;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1530
1531
		// Remove related sale log entries
1532 6
		$give_logs->delete_logs(
1533 6
			null,
1534 6
			'sale',
1535
			array(
1536
				array(
1537 6
					'key'   => '_give_log_payment_id',
1538 6
					'value' => $this->ID,
1539 6
				),
1540
			)
1541 6
		);
1542 6
	}
1543
1544
	/**
1545
	 * Setup functions only, these are not to be used by developers.
1546
	 * These functions exist only to allow the setup routine to be backwards compatible with our old
1547
	 * helper functions.
1548
	 *
1549
	 * These will run whenever setup_payment is called, which should only be called once.
1550
	 * To update an attribute, update it directly instead of re-running the setup routine
1551
	 */
1552
1553
	/**
1554
	 * Setup the payment completed date
1555
	 *
1556
	 * @since  1.5
1557
	 * @return string The date the payment was completed
1558
	 */
1559 52
	private function setup_completed_date() {
1560 52
		$payment = get_post( $this->ID );
1561
1562 52
		if ( 'pending' == $payment->post_status || 'preapproved' == $payment->post_status ) {
1563 52
			return false; // This payment was never completed
1564
		}
1565
1566 42
		$date = ( $date = $this->get_meta( '_give_completed_date', true ) ) ? $date : $payment->modified_date;
1567
1568 42
		return $date;
1569
	}
1570
1571
	/**
1572
	 * Setup the payment mode
1573
	 *
1574
	 * @since  1.5
1575
	 * @return string The payment mode
1576
	 */
1577 52
	private function setup_mode() {
1578 52
		return $this->get_meta( '_give_payment_mode' );
1579
	}
1580
1581
	/**
1582
	 * Setup the payment total
1583
	 *
1584
	 * @since  1.5
1585
	 * @return float The payment total
1586
	 */
1587 52
	private function setup_total() {
1588 52
		$amount = $this->get_meta( '_give_payment_total', true );
1589
1590 52
		if ( empty( $amount ) && '0.00' != $amount ) {
1591 2
			$meta = $this->get_meta( '_give_payment_meta', true );
1592 2
			$meta = maybe_unserialize( $meta );
1593
1594 2
			if ( isset( $meta['amount'] ) ) {
1595
				$amount = $meta['amount'];
1596
			}
1597 2
		}
1598
1599 52
		return $amount;
1600
	}
1601
1602
	/**
1603
	 * Setup the payment subtotal
1604
	 *
1605
	 * @since  1.5
1606
	 * @return float The subtotal of the payment
1607
	 */
1608 52
	private function setup_subtotal() {
1609 52
		$subtotal = $this->total;
1610
1611 52
		return $subtotal;
1612
	}
1613
1614
	/**
1615
	 * Setup the payment fees
1616
	 *
1617
	 * @since  1.5
1618
	 * @return float The fees total for the payment
1619
	 */
1620 52
	private function setup_fees_total() {
1621 52
		$fees_total = (float) 0.00;
1622
1623 52
		$payment_fees = isset( $this->payment_meta['fees'] ) ? $this->payment_meta['fees'] : array();
1624 52
		if ( ! empty( $payment_fees ) ) {
1625
			foreach ( $payment_fees as $fee ) {
1626
				$fees_total += (float) $fee['amount'];
1627
			}
1628
		}
1629
1630 52
		return $fees_total;
1631
1632
	}
1633
1634
	/**
1635
	 * Setup the currency code
1636
	 *
1637
	 * @since  1.5
1638
	 * @return string              The currency for the payment
1639
	 */
1640 52
	private function setup_currency() {
1641 52
		$currency = isset( $this->payment_meta['currency'] ) ? $this->payment_meta['currency'] : apply_filters( 'give_payment_currency_default', give_get_currency(), $this );
1642
1643 52
		return $currency;
1644
	}
1645
1646
	/**
1647
	 * Setup any fees associated with the payment
1648
	 *
1649
	 * @since  1.5
1650
	 * @return array The Fees
1651
	 */
1652 52
	private function setup_fees() {
1653 52
		$payment_fees = isset( $this->payment_meta['fees'] ) ? $this->payment_meta['fees'] : array();
1654
1655 52
		return $payment_fees;
1656
	}
1657
1658
	/**
1659
	 * Setup the gateway used for the payment
1660
	 *
1661
	 * @since  1.5
1662
	 * @return string The gateway
1663
	 */
1664 52
	private function setup_gateway() {
1665 52
		$gateway = $this->get_meta( '_give_payment_gateway', true );
1666
1667 52
		return $gateway;
1668
	}
1669
1670
	/**
1671
	 * Setup the transaction ID
1672
	 *
1673
	 * @since  1.5
1674
	 * @return string The transaction ID for the payment
1675
	 */
1676 52
	private function setup_transaction_id() {
1677 52
		$transaction_id = $this->get_meta( '_give_payment_transaction_id', true );
1678
1679 52
		if ( empty( $transaction_id ) || (int) $transaction_id === (int) $this->ID ) {
1680
1681 52
			$gateway        = $this->gateway;
1682 52
			$transaction_id = apply_filters( 'give_get_payment_transaction_id-' . $gateway, $this->ID );
1683
1684 52
		}
1685
1686 52
		return $transaction_id;
1687
	}
1688
1689
	/**
1690
	 * Setup the IP Address for the payment
1691
	 *
1692
	 * @since  1.5
1693
	 * @return string The IP address for the payment
1694
	 */
1695 52
	private function setup_ip() {
1696 52
		$ip = $this->get_meta( '_give_payment_user_ip', true );
1697
1698 52
		return $ip;
1699
	}
1700
1701
	/**
1702
	 * Setup the customer ID
1703
	 *
1704
	 * @since  1.5
1705
	 * @return int The Customer ID
1706
	 */
1707 52
	private function setup_customer_id() {
1708 52
		$customer_id = $this->get_meta( '_give_payment_customer_id', true );
1709
1710 52
		return $customer_id;
1711
	}
1712
1713
	/**
1714
	 * Setup the User ID associated with the purchase
1715
	 *
1716
	 * @since  1.5
1717
	 * @return int The User ID
1718
	 */
1719 52
	private function setup_user_id() {
1720 52
		$user_id = $this->get_meta( '_give_payment_user_id', true );
1721
1722 52
		return $user_id;
1723
	}
1724
1725
	/**
1726
	 * Setup the email address for the purchase
1727
	 *
1728
	 * @since  1.5
1729
	 * @return string The email address for the payment
1730
	 */
1731 52
	private function setup_email() {
1732 52
		$email = $this->get_meta( '_give_payment_user_email', true );
1733
1734 52
		if ( empty( $email ) ) {
1735 2
			$email = Give()->customers->get_column( 'email', $this->customer_id );
1736 2
		}
1737
1738 52
		return $email;
1739
	}
1740
1741
	/**
1742
	 * Setup the user info
1743
	 *
1744
	 * @since  1.5
1745
	 * @return array               The user info associated with the payment
1746
	 */
1747 52
	private function setup_user_info() {
1748
		$defaults = array(
1749 52
			'first_name' => $this->first_name,
1750 52
			'last_name'  => $this->last_name,
1751 52
		);
1752
1753 52
		$user_info = isset( $this->payment_meta['user_info'] ) ? maybe_unserialize( $this->payment_meta['user_info'] ) : array();
1754 52
		$user_info = wp_parse_args( $user_info, $defaults );
1755
1756 52
		if ( empty( $user_info ) ) {
1757
			// Get the customer, but only if it's been created
1758
			$customer = new Give_Customer( $this->customer_id );
1759
1760
			if ( $customer->id > 0 ) {
1761
				$name      = explode( ' ', $customer->name, 2 );
1762
				$user_info = array(
1763
					'first_name' => $name[0],
1764
					'last_name'  => $name[1],
1765
					'email'      => $customer->email,
1766
					'discount'   => 'none',
1767
				);
1768
			}
1769
		} else {
1770
			// Get the customer, but only if it's been created
1771 52
			$customer = new Give_Customer( $this->customer_id );
1772 52
			if ( $customer->id > 0 ) {
1773 52
				foreach ( $user_info as $key => $value ) {
1774 52
					if ( ! empty( $value ) ) {
1775 52
						continue;
1776
					}
1777
1778
					switch ( $key ) {
1779 21
						case 'first_name':
1780 21
							$name = explode( ' ', $customer->name, 2 );
1781
1782 21
							$user_info[ $key ] = $name[0];
1783 21
							break;
1784
1785 21
						case 'last_name':
1786 21
							$name      = explode( ' ', $customer->name, 2 );
1787 21
							$last_name = ! empty( $name[1] ) ? $name[1] : '';
1788
1789 21
							$user_info[ $key ] = $last_name;
1790 21
							break;
1791
1792
						case 'email':
1793
							$user_info[ $key ] = $customer->email;
1794
							break;
1795
					}
1796 52
				}
1797
1798 52
			}
1799
		}
1800
1801 52
		return $user_info;
1802
1803
	}
1804
1805
	/**
1806
	 * Setup the Address for the payment
1807
	 *
1808
	 * @since  1.5
1809
	 * @return array               The Address information for the payment
1810
	 */
1811 52
	private function setup_address() {
1812
1813 52
		$address = ! empty( $this->payment_meta['user_info']['address'] ) ? $this->payment_meta['user_info']['address'] : array(
1814 52
			'line1'   => '',
1815 52
			'line2'   => '',
1816 52
			'city'    => '',
1817 52
			'country' => '',
1818 52
			'state'   => '',
1819
			'zip'     => ''
1820 52
		);
1821
1822 52
		return $address;
1823
	}
1824
1825
	/**
1826
	 * Setup the form title
1827
	 *
1828
	 * @since  1.5
1829
	 * @return string The Form Title
1830
	 */
1831 52
	private function setup_form_title() {
1832
1833 52
		$form_id = $this->get_meta( '_give_payment_form_title', true );
1834
1835 52
		return $form_id;
1836
	}
1837
1838
	/**
1839
	 * Setup the form ID
1840
	 *
1841
	 * @since  1.5
1842
	 * @return int The Form ID
1843
	 */
1844 52
	private function setup_form_id() {
1845
1846 52
		$form_id = $this->get_meta( '_give_payment_form_id', true );
1847
1848 52
		return $form_id;
1849
	}
1850
1851
	/**
1852
	 * Setup the price ID
1853
	 *
1854
	 * @since  1.5
1855
	 * @return int The Form Price ID
1856
	 */
1857 52
	private function setup_price_id() {
1858 52
		$price_id = $this->get_meta( '_give_payment_price_id', true );
1859
1860 52
		return $price_id;
1861
	}
1862
1863
	/**
1864
	 * Setup the payment key
1865
	 *
1866
	 * @since  1.5
1867
	 * @return string The Payment Key
1868
	 */
1869 52
	private function setup_payment_key() {
1870 52
		$key = $this->get_meta( '_give_payment_purchase_key', true );
1871
1872 52
		return $key;
1873
	}
1874
1875
	/**
1876
	 * Setup the payment number
1877
	 *
1878
	 * @since  1.5
1879
	 * @return int|string Integer by default, or string if sequential order numbers is enabled
1880
	 */
1881 52
	private function setup_payment_number() {
1882 52
		$number = $this->ID;
1883
1884 52
		if ( give_get_option( 'enable_sequential' ) ) {
1885
1886 20
			$number = $this->get_meta( '_give_payment_number', true );
1887
1888 20
			if ( ! $number ) {
1889
1890 2
				$number = $this->ID;
1891
1892 2
			}
1893
1894 20
		}
1895
1896 52
		return $number;
1897
	}
1898
1899
	/**
1900
	 * Converts this object into an array for special cases
1901
	 *
1902
	 * @return array The payment object as an array
1903
	 */
1904
	public function array_convert() {
1905
		return get_object_vars( $this );
1906
	}
1907
1908
	/**
1909
	 * Retrieve payment completion date
1910
	 *
1911
	 * @since  1.5
1912
	 * @return string Date payment was completed
1913
	 */
1914 42
	private function get_completed_date() {
1915 42
		return apply_filters( 'give_payment_completed_date', $this->completed_date, $this->ID, $this );
1916
	}
1917
1918
	/**
1919
	 * Retrieve payment subtotal
1920
	 *
1921
	 * @since  1.5
1922
	 * @return float Payment subtotal
1923
	 */
1924
	private function get_subtotal() {
1925
		return apply_filters( 'give_get_payment_subtotal', $this->subtotal, $this->ID, $this );
1926
	}
1927
1928
	/**
1929
	 * Retrieve payment currency
1930
	 *
1931
	 * @since  1.5
1932
	 * @return string Payment currency code
1933
	 */
1934 42
	private function get_currency() {
1935 42
		return apply_filters( 'give_payment_currency_code', $this->currency, $this->ID, $this );
1936
	}
1937
1938
	/**
1939
	 * Retrieve payment gateway
1940
	 *
1941
	 * @since  1.5
1942
	 * @return string Gateway used
1943
	 */
1944 42
	private function get_gateway() {
1945 42
		return apply_filters( 'give_payment_gateway', $this->gateway, $this->ID, $this );
1946
	}
1947
1948
	/**
1949
	 * Retrieve payment transaction ID
1950
	 *
1951
	 * @since  1.5
1952
	 * @return string Transaction ID from merchant processor
1953
	 */
1954 11
	private function get_transaction_id() {
1955 11
		return apply_filters( 'give_get_payment_transaction_id', $this->transaction_id, $this->ID, $this );
1956
	}
1957
1958
	/**
1959
	 * Retrieve payment IP
1960
	 *
1961
	 * @since  1.5
1962
	 * @return string Payment IP address
1963
	 */
1964
	private function get_ip() {
1965
		return apply_filters( 'give_payment_user_ip', $this->ip, $this->ID, $this );
1966
	}
1967
1968
	/**
1969
	 * Retrieve payment customer ID
1970
	 *
1971
	 * @since  1.5
1972
	 * @return int Payment customer ID
1973
	 */
1974 52
	private function get_customer_id() {
1975 52
		return apply_filters( 'give_payment_customer_id', $this->customer_id, $this->ID, $this );
1976
	}
1977
1978
	/**
1979
	 * Retrieve payment user ID
1980
	 *
1981
	 * @since  1.5
1982
	 * @return int Payment user ID
1983
	 */
1984 41
	private function get_user_id() {
1985 41
		return apply_filters( 'give_payment_user_id', $this->user_id, $this->ID, $this );
1986
	}
1987
1988
	/**
1989
	 * Retrieve payment email
1990
	 *
1991
	 * @since  1.5
1992
	 * @return string Payment customer email
1993
	 */
1994 42
	private function get_email() {
1995 42
		return apply_filters( 'give_payment_user_email', $this->email, $this->ID, $this );
1996
	}
1997
1998
	/**
1999
	 * Retrieve payment user info
2000
	 *
2001
	 * @since  1.5
2002
	 * @return array Payment user info
2003
	 */
2004 43
	private function get_user_info() {
2005 43
		return apply_filters( 'give_payment_meta_user_info', $this->user_info, $this->ID, $this );
2006
	}
2007
2008
	/**
2009
	 * Retrieve payment billing address
2010
	 *
2011
	 * @since  1.5
2012
	 * @return array Payment billing address
2013
	 */
2014
	private function get_address() {
2015
		return apply_filters( 'give_payment_address', $this->address, $this->ID, $this );
2016
	}
2017
2018
	/**
2019
	 * Retrieve payment key
2020
	 *
2021
	 * @since  1.5
2022
	 * @return string Payment key
2023
	 */
2024 52
	private function get_key() {
2025 52
		return apply_filters( 'give_payment_key', $this->key, $this->ID, $this );
2026
	}
2027
2028
	/**
2029
	 * Retrieve payment key
2030
	 *
2031
	 * @since  1.5
2032
	 * @return string Payment key
2033
	 */
2034 52
	private function get_form_id() {
2035 52
		return apply_filters( 'give_payment_form_id', $this->form_id, $this->ID, $this );
2036
	}
2037
2038
	/**
2039
	 * Retrieve payment number
2040
	 *
2041
	 * @since  1.5
2042
	 * @return int|string Payment number
2043
	 */
2044 42
	private function get_number() {
2045 42
		return apply_filters( 'give_payment_number', $this->number, $this->ID, $this );
2046
	}
2047
2048
}
2049