Issues (4296)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

includes/payments/class-give-payment.php (28 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Payments
4
 *
5
 * @package     Give
6
 * @subpackage  Classes/Give_Payment
7
 * @copyright   Copyright (c) 2016, WordImpress
8
 * @license     https://opensource.org/licenses/gpl-license GNU Public License
9
 * @since       1.5
10
 */
11
12
// Exit if accessed directly.
13
if ( ! defined( 'ABSPATH' ) ) {
14
	exit;
15
}
16
17
/**
18
 * Give_Payment Class
19
 *
20
 * This class is for working with payments in Give.
21
 *
22
 * @property int        $ID
23
 * @property bool       $new
24
 * @property string     $number
25
 * @property string     $mode
26
 * @property string     $import
27
 * @property string     $key
28
 * @property string     $form_title
29
 * @property string|int $form_id
30
 * @property string|int $price_id
31
 * @property string|int $total
32
 * @property string|int $subtotal
33
 * @property string|int $fees
34
 * @property string|int $fees_total
35
 * @property string     $post_status
36
 * @property string     $date
37
 * @property string     $post_date
38
 * @property string     $status
39
 * @property string     $email
40
 * @property array      $payment_meta
41
 * @property string     $customer_id
42
 * @property string     $donor_id
43
 * @property string     $completed_date
44
 * @property string     $currency
45
 * @property string     $ip
46
 * @property array      $user_info
47
 * @property string     $gateway
48
 * @property string     $user_id
49
 * @property string     $title_prefix
50
 * @property string     $first_name
51
 * @property string     $last_name
52
 * @property string     $parent_payment
53
 * @property string     $transaction_id
54
 * @property string     $old_status
55
 *
56
 * @since 1.5
57
 */
58
final class Give_Payment {
59
60
	/**
61
	 * The Payment ID.
62
	 *
63
	 * @since  1.5
64
	 *
65
	 * @var    int
66
	 */
67
	public $ID = 0;
68
69
	/**
70
	 * Protected non-read $_ID.
71
	 *
72
	 * @var int
73
	 */
74
	protected $_ID = 0;
75
76
	/**
77
	 * Identify if the payment is a new one or existing.
78
	 *
79
	 * @since  1.5
80
	 * @access protected
81
	 *
82
	 * @var    boolean
83
	 */
84
	protected $new = false;
85
86
	/**
87
	 * The Payment number (for use with sequential payments).
88
	 *
89
	 * @since  1.5
90
	 * @access protected
91
	 *
92
	 * @var    string
93
	 */
94
	protected $number = '';
95
96
	/**
97
	 * The Gateway mode the payment was made in.
98
	 *
99
	 * @since  1.5
100
	 * @access protected
101
	 *
102
	 * @var    string
103
	 */
104
	protected $mode = 'live';
105
106
	/**
107
	 * Is donations is Import or not.
108
	 *
109
	 * @since  1.8.13
110
	 * @access protected
111
	 *
112
	 * @var    bool
113
	 */
114
	protected $import = false;
115
116
	/**
117
	 * The unique donation payment key.
118
	 *
119
	 * @since  1.5
120
	 * @access protected
121
	 *
122
	 * @var    string
123
	 */
124
	protected $key = '';
125
126
	/**
127
	 * The Donation Form Title
128
	 *
129
	 * @since  1.5
130
	 * @access protected
131
	 *
132
	 * @var    string
133
	 */
134
	protected $form_title = 0;
135
136
	/**
137
	 * The Donation Form ID
138
	 *
139
	 * @since  1.5
140
	 * @access protected
141
	 *
142
	 * @var    string
143
	 */
144
	protected $form_id = 0;
145
146
	/**
147
	 * The Donation Form Price ID
148
	 *
149
	 * @since  1.5
150
	 * @access protected
151
	 *
152
	 * @var    string|int
153
	 */
154
	protected $price_id = 0;
155
156
	/**
157
	 * The total amount of the donation payment.
158
	 *
159
	 * @since  1.5
160
	 * @access protected
161
	 *
162
	 * @var    float
163
	 */
164
	protected $total = 0.00;
165
166
	/**
167
	 * The Subtotal fo the payment.
168
	 *
169
	 * @since  1.5
170
	 * @access protected
171
	 *
172
	 * @var    float
173
	 */
174
	protected $subtotal = 0;
175
176
	/**
177
	 * The date the payment was created
178
	 *
179
	 * @since  1.5
180
	 * @access protected
181
	 *
182
	 * @var    string
183
	 */
184
	protected $date = '';
185
186
	/**
187
	 * The date the payment post was created.
188
	 *
189
	 * @var string
190
	 */
191
	protected $post_date = '';
192
193
	/**
194
	 * The date the payment was marked as 'complete'.
195
	 *
196
	 * @since  1.5
197
	 * @access protected
198
	 *
199
	 * @var    string
200
	 */
201
	protected $completed_date = '';
202
203
	/**
204
	 * The status of the donation payment.
205
	 *
206
	 * @since  1.5
207
	 * @access protected
208
	 *
209
	 * @var    string
210
	 */
211
	protected $status = 'pending';
212
213
	/**
214
	 * Donation Status.
215
	 *
216
	 * @var string
217
	 */
218
	protected $post_status = 'pending'; // Same as $status but here for backwards compat.
219
220
	/**
221
	 * When updating, the old status prior to the change
222
	 *
223
	 * @since  1.5
224
	 * @access protected
225
	 *
226
	 * @var    string
227
	 */
228
	protected $old_status = '';
229
230
	/**
231
	 * The display name of the current payment status.
232
	 *
233
	 * @since  1.5
234
	 * @access protected
235
	 *
236
	 * @var    string
237
	 */
238
	protected $status_nicename = '';
239
240
	/**
241
	 * The donor ID that made the payment.
242
	 *
243
	 * @since  1.5
244
	 * @access protected
245
	 *
246
	 * @var    integer
247
	 */
248
	protected $customer_id = null;
249
250
	/**
251
	 * The Donor ID (if logged in) that made the payment
252
	 *
253
	 * @since  1.8.13
254
	 * @access protected
255
	 *
256
	 * @var    integer
257
	 */
258
	protected $donor_id = 0;
259
260
	/**
261
	 * The User ID (if logged in) that made the payment
262
	 *
263
	 * @since  1.5
264
	 * @access protected
265
	 *
266
	 * @var    integer
267
	 */
268
	protected $user_id = 0;
269
270
	/**
271
	 * The Title Prefix/Salutation of the Donor.
272
	 *
273
	 * @since 2.2
274
	 *
275
	 * @var string
276
	 */
277
	protected $title_prefix = '';
278
279
	/**
280
	 * The first name of the payee
281
	 *
282
	 * @since  1.5
283
	 * @access protected
284
	 *
285
	 * @var    string
286
	 */
287
	protected $first_name = '';
288
289
	/**
290
	 * The last name of the payee
291
	 *
292
	 * @since  1.5
293
	 * @access protected
294
	 *
295
	 * @var    string
296
	 */
297
	protected $last_name = '';
298 52
299
	/**
300 52
	 * The email used for the payment
301 52
	 *
302
	 * @since  1.5
303
	 * @access protected
304 52
	 *
305 52
	 * @var    string
306
	 */
307
	protected $email = '';
308
309
	/**
310
	 * Legacy (not to be accessed) array of user information
311
	 *
312
	 * @since  1.5
313
	 * @access private
314
	 *
315
	 * @var    array
316 52
	 */
317
	private $user_info = array();
318 52
319
	/**
320 52
	 * Legacy (not to be accessed) payment meta array
321
	 *
322 52
	 * @since  1.5
323
	 * @access private
324 52
	 *
325
	 * @var    array
326
	 */
327
	private $payment_meta = array();
328 52
329
	/**
330
	 * The physical address used for the payment if provided
331
	 *
332
	 * @since  1.5
333
	 * @access protected
334
	 *
335
	 * @var    array
336
	 */
337
	protected $address = array();
338
339
	/**
340
	 * The transaction ID returned by the gateway
341 52
	 *
342 52
	 * @since  1.5
343
	 * @access protected
344 52
	 *
345 52
	 * @var    string
346 52
	 */
347
	protected $transaction_id = '';
348 52
349 52
	/**
350 52
	 * IP Address payment was made from
351
	 *
352 52
	 * @since  1.5
353 52
	 * @access protected
354 52
	 *
355 52
	 * @var    string
356
	 */
357
	protected $ip = '';
358
359
	/**
360
	 * The gateway used to process the payment
361
	 *
362
	 * @since  1.5
363
	 * @access protected
364
	 *
365
	 * @var    string
366 42
	 */
367 42
	protected $gateway = '';
368 42
369
	/**
370
	 * The the payment was made with
371
	 *
372
	 * @since  1.5
373
	 * @access protected
374
	 *
375
	 * @var    string
376
	 */
377
	protected $currency = '';
378
379
	/**
380
	 * Array of items that have changed since the last save() was run.
381
	 * This is for internal use, to allow fewer update_payment_meta calls to be run.
382
	 *
383 52
	 * @since  1.5
384 52
	 * @access private
385
	 *
386 52
	 * @var    array
387
	 */
388
	private $pending;
389
390 52
	/**
391
	 * The parent payment (if applicable)
392 52
	 *
393 7
	 * @since  1.5
394
	 * @access protected
395
	 *
396 52
	 * @var    integer
397
	 */
398
	protected $parent_payment = 0;
399
400
	/**
401 52
	 * Setup the Give Payments class
402
	 *
403
	 * @since  1.5
404 52
	 * @access public
405
	 *
406
	 * @param  int|bool $payment_id A given payment.
407 52
	 *
408
	 * @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...
409
	 */
410 52
	public function __construct( $payment_id = false ) {
411
412
		if ( empty( $payment_id ) ) {
413 52
			return false;
0 ignored issues
show
Constructors do not have meaningful return values, anything that is returned from here is discarded. Are you sure this is correct?
Loading history...
414 52
		}
415 52
416 52
		$this->setup_payment( $payment_id );
0 ignored issues
show
It seems like $payment_id defined by parameter $payment_id on line 410 can also be of type boolean; however, Give_Payment::setup_payment() does only seem to accept integer, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
417 52
	}
418 52
419 52
	/**
420
	 * Magic GET function.
421 52
	 *
422 52
	 * @since  1.5
423
	 * @access public
424
	 *
425 52
	 * @param  string $key The property.
426
	 *
427
	 * @return mixed        The value.
428 52
	 */
429 52
	public function __get( $key ) {
430 52
431 52
		if ( method_exists( $this, 'get_' . $key ) ) {
432
433
			$value = call_user_func( array( $this, 'get_' . $key ) );
434 52
435 52
		} else {
436
437
			$value = $this->$key;
438 52
439 52
		}
440 52
441 52
		return $value;
442 52
	}
443 52
444 52
	/**
445 52
	 * Magic SET function
446
	 *
447
	 * Sets up the pending array for the save method
448 52
	 *
449 52
	 * @since  1.5
450 52
	 * @access public
451 52
	 *
452 52
	 * @param  string $key   The property name.
453
	 * @param  mixed  $value The value of the property.
454
	 */
455 52
	public function __set( $key, $value ) {
456
		$ignore = array( '_ID' );
457 52
458
		if ( 'status' === $key ) {
459
			$this->old_status = $this->status;
460
		}
461
462
		if ( ! in_array( $key, $ignore ) ) {
463
			$this->pending[ $key ] = $value;
464
		}
465
466 52
		if ( '_ID' !== $key ) {
467
			$this->$key = $value;
468
		}
469 52
	}
470 52
471 31
	/**
472 52
	 * Magic ISSET function, which allows empty checks on protected elements
473
	 *
474 22
	 * @since  1.5
475 21
	 * @access public
476 21
	 *
477
	 * @param  string $name The attribute to get.
478
	 *
479 52
	 * @return boolean|null       If the item is set or not
480
	 */
481 1
	public function __isset( $name ) {
482 1
		if ( property_exists( $this, $name ) ) {
483 1
			return false === empty( $this->$name );
484 1
		} else {
485
			return null;
486
		}
487 52
	}
488
489 1
	/**
490 1
	 * Setup payment properties
491
	 *
492 1
	 * @since  1.5
493
	 * @access private
494
	 *
495 52
	 * @param  int $payment_id The payment ID.
496 52
	 *
497 52
	 * @return bool            If the setup was successful or not
498 52
	 */
499 52
	private function setup_payment( $payment_id ) {
500 52
		$this->pending = array();
501 52
502 52
		if ( empty( $payment_id ) ) {
503
			return false;
504 52
		}
505 52
506 52
		$payment = get_post( absint( $payment_id ) );
507 52
508 52
		if ( ! $payment || is_wp_error( $payment ) ) {
509 52
			return false;
510 52
		}
511 52
512 52
		if ( 'give_payment' !== $payment->post_type ) {
513
			return false;
514 52
		}
515 52
516 52
		/**
517 52
		 * Fires before payment setup.
518 52
		 *
519 52
		 * Allow extensions to perform actions before the payment is loaded.
520 52
		 *
521 52
		 * @since 1.5
522
		 *
523
		 * @param Give_Payment $this       Payment object.
524 52
		 * @param int          $payment_id The ID of the payment.
525
		 */
526 52
		do_action( 'give_pre_setup_payment', $this, $payment_id );
527
528 52
		// Get payment from cache.
529 52
		$donation_vars = Give_Cache::get_group( $payment_id, 'give-donations' );
530
531 52
		if ( is_null( $donation_vars ) ) {
532
			// Primary Identifier.
533 52
			$this->ID = absint( $payment_id );
534
535
			// Protected ID that can never be changed.
536
			$this->_ID = absint( $payment_id );
537 52
538 52
			// We have a payment, get the generic payment_meta item to reduce calls to it.
539 52
			$this->payment_meta = $this->get_meta();
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->get_meta() of type * is incompatible with the declared type array of property $payment_meta.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

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

Loading history...
540
541 52
			// Status and Dates.
542
			$this->date           = $payment->post_date;
543
			$this->post_date      = $payment->post_date;
544 52
			$this->completed_date = $this->setup_completed_date();
545 52
			$this->status         = $payment->post_status;
546 52
			$this->post_status    = $this->status;
547 52
			$this->mode           = $this->setup_mode();
548
			$this->import         = $this->setup_import();
549 52
			$this->parent_payment = $payment->post_parent;
550
551 52
			$all_payment_statuses  = give_get_payment_statuses();
552
			$this->status_nicename = array_key_exists( $this->status, $all_payment_statuses ) ? $all_payment_statuses[ $this->status ] : ucfirst( $this->status );
553 52
554 52
			// Currency Based.
555 52
			$this->total    = $this->setup_total();
556
			$this->subtotal = $this->setup_subtotal();
557 52
			$this->currency = $this->setup_currency();
558 52
559
			// Gateway based.
560
			$this->gateway        = $this->setup_gateway();
561
			$this->transaction_id = $this->setup_transaction_id();
562
563
			// User based.
564
			$this->ip           = $this->setup_ip();
565 52
			$this->customer_id  = $this->setup_donor_id(); // Backward compatibility.
566 52
			$this->donor_id     = $this->setup_donor_id();
567 52
			$this->user_id      = $this->setup_user_id();
568
			$this->email        = $this->setup_email();
569 52
			$this->user_info    = $this->setup_user_info();
570
			$this->address      = $this->setup_address();
571
			$this->first_name   = $this->user_info['first_name'];
572
			$this->last_name    = $this->user_info['last_name'];
573
			$this->title_prefix = isset( $this->user_info['title'] ) ? $this->user_info['title'] : '';
574
575
			// Other Identifiers.
576
			$this->form_title = $this->setup_form_title();
577
			$this->form_id    = $this->setup_form_id();
0 ignored issues
show
Documentation Bug introduced by
The property $form_id was declared of type string, but $this->setup_form_id() is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
578
			$this->price_id   = $this->setup_price_id();
579
			$this->key        = $this->setup_payment_key();
580 52
			$this->number     = $this->setup_payment_number();
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->setup_payment_number() can also be of type integer. However, the property $number is declared as type string. 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...
581
582 52
			Give_Cache::set_group( $this->ID, get_object_vars( $this ), 'give-donations' );
583
		} else {
584
585 52
			foreach ( $donation_vars as $donation_var => $value ) {
0 ignored issues
show
The expression $donation_vars of type object|integer|double|string|array|boolean is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
586
				$this->$donation_var = $value;
587 52
			}
588
		} // End if().
589 52
590
		/**
591
		 * Fires after payment setup.
592 52
		 *
593
		 * Allow extensions to add items to this object via hook.
594
		 *
595 52
		 * @since 1.5
596
		 *
597
		 * @param Give_Payment $this       Payment object.
598 52
		 * @param int          $payment_id The ID of the payment.
599 1
		 */
600 1
		do_action( 'give_setup_payment', $this, $payment_id );
601
602
		return true;
603 52
	}
604
605 52
606 52
	/**
607
	 * Payment class object is storing various meta value in object parameter.
608 52
	 * So if user is updating payment meta but not updating payment object, then payment meta values will not reflect/changes on payment meta automatically
609
	 * and you can still access payment meta old value in any old payment object ( previously created ) which can cause to show or save wrong payment data.
610
	 * To prevent that user can use this function after updating any payment meta value ( in bulk or single update ).
611
	 *
612 52
	 * @since  1.6
613
	 * @access public
614 52
	 *
615
	 * @param  int $payment_id Payment ID.
616 52
	 *
617 52
	 * @return void
618
	 */
619 52
	public function update_payment_setup( $payment_id ) {
620
		// Delete cache.
621 52
		Give_Cache::delete_group( $this->ID,'give-donations' );
622
623 52
		$this->setup_payment( $payment_id );
624
	}
625 52
626
	/**
627
	 * Create the base of a payment.
628 1
	 *
629
	 * @since  1.5
630 1
	 * @access private
631 1
	 *
632
	 * @return int|bool False on failure, the payment ID on success.
633 1
	 */
634 1
	private function insert_payment() {
635 1
636
		// Construct the payment title.
637 1
		$payment_title = '';
638 1
		if ( ! empty( $this->first_name ) && ! empty( $this->last_name ) ) {
639 1
			$payment_title = $this->first_name . ' ' . $this->last_name;
640
		} elseif ( ! empty( $this->first_name ) && empty( $this->last_name ) ) {
641 1
			$payment_title = $this->first_name;
642 1
		} elseif ( ! empty( $this->email ) && is_email( $this->email ) ) {
643 52
			$payment_title = $this->email;
644
		}
645 2
646
		// Set Key.
647 2
		if ( empty( $this->key ) ) {
648 2
649 2
			$auth_key             = defined( 'AUTH_KEY' ) ? AUTH_KEY : '';
650
			$this->key            = strtolower( md5( $this->email . date( 'Y-m-d H:i:s' ) . $auth_key . uniqid( 'give', true ) ) );  // Unique key.
651
			$this->pending['key'] = $this->key;
652 2
		}
653 2
654 2
		// Set IP.
655 2
		if ( empty( $this->ip ) ) {
656
657 2
			$this->ip            = give_get_ip();
0 ignored issues
show
Documentation Bug introduced by
It seems like give_get_ip() can also be of type array. However, the property $ip is declared as type string. 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...
658 2
			$this->pending['ip'] = $this->ip;
659
660 2
		}
661 2
662 2
		// @todo: payment data exist here only for backward compatibility
663
		// issue: https://github.com/WordImpress/Give/issues/1132
664 2
		$payment_data = array(
665 2
			'price'        => $this->total,
666 1
			'date'         => $this->date,
667 2
			'user_email'   => $this->email,
668
			'purchase_key' => $this->key,
669 2
			'form_title'   => $this->form_title,
670 1
			'form_id'      => $this->form_id,
671 1
			'donor_id'     => $this->donor_id,
672 1
			'price_id'     => $this->price_id,
673
			'currency'     => $this->currency,
674 1
			'user_info'    => array(
675 1
				'id'         => $this->user_id,
676 2
				'title'      => $this->title_prefix,
677
				'email'      => $this->email,
678 52
				'first_name' => $this->first_name,
679
				'last_name'  => $this->last_name,
680 52
				'address'    => $this->address,
681 52
			),
682
			'status'       => $this->status,
683 52
		);
684
685
		$args = apply_filters( 'give_insert_payment_args', array(
686
			'post_title'    => $payment_title,
687
			'post_status'   => $this->status,
688
			'post_type'     => 'give_payment',
689
			'post_date'     => ! empty( $this->date ) ? $this->date : null,
690
			'post_date_gmt' => ! empty( $this->date ) ? get_gmt_from_date( $this->date ) : null,
691
			'post_parent'   => $this->parent_payment,
692
		), $payment_data );
693
694
		// Create a blank payment.
695
		$payment_id = wp_insert_post( $args );
696
697
		if ( ! empty( $payment_id ) ) {
698
699
			$this->ID  = $payment_id;
700
			$this->_ID = $payment_id;
701
702
			$donor = new stdClass;
703
704
			/**
705
			 * Filter donor class after the donation is completed and before customer table is updated.
706
			 *
707
			 * @since 1.8.13
708
			 */
709
			$donor = apply_filters( 'give_update_donor_information', $donor, $payment_id, $payment_data, $args );
710
711 52
			if ( did_action( 'give_pre_process_donation' ) && is_user_logged_in() ) {
712 52
				$donor = new Give_Donor( get_current_user_id(), true );
713 52
714
				// Donor is logged in but used a different email to purchase with so assign to their donor record.
715 52
				if ( ! empty( $donor->id ) && $this->email !== $donor->email ) {
716 52
					$donor->add_email( $this->email );
717 52
				}
718
			}
719 52
720 52
			if ( empty( $donor->id ) ) {
721 52
				$donor = new Give_Donor( $this->email );
722
			}
723 52
724 20
			if ( empty( $donor->id ) ) {
725 20
726
				$donor_data = array(
727 52
					'name'    => ! is_email( $payment_title ) ? $this->first_name . ' ' . $this->last_name : '',
728 52
					'email'   => $this->email,
729 52
					'user_id' => $this->user_id,
730
				);
731 52
732 52
				$donor->create( $donor_data );
733 52
734
			}
735 52
736 52
			// Update Donor Meta once donor is created.
737 52
			$donor->update_meta( '_give_donor_first_name', $this->first_name );
738
			$donor->update_meta( '_give_donor_last_name', $this->last_name );
739 52
			$donor->update_meta( '_give_donor_title_prefix', $this->title_prefix );
740 52
741 52
			$this->customer_id            = $donor->id;
742
			$this->pending['customer_id'] = $this->customer_id;
743 52
			$donor->attach_payment( $this->ID, false );
744 52
745 52
			$this->payment_meta = apply_filters( 'give_payment_meta', $this->payment_meta, $payment_data );
746
747 52
			/*
748 52
			 * _give_payment_meta backward compatibility.
749 52
			 *
750
			 * @since 2.0.1
751 52
			 */
752 52
			$custom_payment_meta = array_diff(
753 52
				array_map( 'maybe_serialize', $this->payment_meta ),
754
				array_map( 'maybe_serialize', $payment_data )
755 52
			);
756 52
757 52
			if ( ! empty( $custom_payment_meta ) ) {
758
				give_doing_it_wrong( '_give_payment_meta', __( 'This custom meta key deprecated. We are not using this meta key for storing payment meta but your custom meta data will be store because we added backward compatibility. Please change your logic because in future we can remove it.', 'give' ), '2.0.0' );
759 52
760
				$this->update_meta( '_give_payment_meta', array_map( 'maybe_unserialize', $custom_payment_meta ) );
0 ignored issues
show
array_map('maybe_unseria..., $custom_payment_meta) is of type array, but the function expects a string.

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...
761
			}
762
763 52
			$give_company = ( ! empty( $_REQUEST['give_company_name'] ) ? give_clean( $_REQUEST['give_company_name'] ) : '' );
0 ignored issues
show
Detected access of super global var $_REQUEST, probably need manual inspection.
Loading history...
Detected usage of a non-sanitized input variable: $_REQUEST
Loading history...
764 52
765 52
			// Check $page_url is not empty.
766
			if ( $give_company ) {
767 52
				give_update_meta( $payment_id, '_give_donation_company', $give_company );
768 52
769 52
				$donor_id = absint( $donor->id );
770
				if ( ! empty( $donor_id ) ) {
771 52
					Give()->donor_meta->update_meta( $donor_id, '_give_donor_company', $give_company );
772 20
				}
773 20
			}
774
775 52
			$this->new = true;
776
		} // End if().
777 2
778 2
		return $this->ID;
779 2
780 2
	}
781
782 2
	/**
783 2
	 * Save
784
	 *
785 52
	 * Once items have been set, an update is needed to save them to the database.
786 42
	 *
787 42
	 * @access public
788
	 *
789 52
	 * @return bool  True of the save occurred, false if it failed or wasn't needed
790
	 */
791 52
	public function save() {
792 52
		$saved = false;
793 52
794
		// Must have an ID.
795 52
		if ( empty( $this->ID ) ) {
796 52
797
			$payment_id = $this->insert_payment();
798 52
799 52
			if ( false === $payment_id ) {
800 52
				$saved = false;
801 52
			} else {
802 52
				$this->ID = $payment_id;
0 ignored issues
show
Documentation Bug introduced by
It seems like $payment_id can also be of type boolean. However, the property $ID is declared as type integer. 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...
803
			}
804 52
		}
805
806 42
		// Set ID if not matching.
807
		if ( $this->ID !== $this->_ID ) {
808 42
			$this->ID = $this->_ID;
809 42
		}
810
811 1
		// If we have something pending, let's save it.
812
		if ( ! empty( $this->pending ) ) {
813 1
814 1
			$total_increase = 0;
815
			$total_decrease = 0;
816 42
817
			foreach ( $this->pending as $key => $value ) {
818
819 1
				switch ( $key ) {
820 1
821
					case 'donations':
822 1
						// Update totals for pending donations.
823
						foreach ( $this->pending[ $key ] as $item ) {
824 42
825
							$quantity = isset( $item['quantity'] ) ? $item['quantity'] : 1;
826 52
							$price_id = isset( $item['price_id'] ) ? $item['price_id'] : 0;
827
828
							switch ( $item['action'] ) {
829 52
830 52
								case 'add':
831 52
832 52
									$price = $item['price'];
833 52
834 52
									if ( 'publish' === $this->status || 'complete' === $this->status ) {
835 52
836
										// Add donation to logs.
837 52
										$log_date = date_i18n( 'Y-m-d G:i:s', current_time( 'timestamp' ) );
838 52
										give_record_donation_in_log( $item['id'], $this->ID, $price_id, $log_date );
839
840
										$form = new Give_Donate_Form( $item['id'] );
841 52
										$form->increase_sales( $quantity );
842 52
										$form->increase_earnings( $price, $this->ID );
843 52
844 52
										$total_increase += $price;
845 52
									}
846 52
									break;
847
848 52
								case 'remove':
849 52
									$this->delete_sales_logs();
850 52
									if ( 'publish' === $this->status || 'complete' === $this->status ) {
851
										$form = new Give_Donate_Form( $item['id'] );
852 52
										$form->decrease_sales( $quantity );
853 52
										$form->decrease_earnings( $item['amount'], $this->ID );
854 52
855
										$total_decrease += $item['amount'];
856 52
									}
857
									break;
858
859
							}// End switch().
860
						}// End foreach().
861
						break;
862
863
					case 'status':
864
						$this->update_status( $this->status );
865
						break;
866
867
					case 'gateway':
868
						$this->update_meta( '_give_payment_gateway', $this->gateway );
869
						break;
870 52
871
					case 'mode':
872 52
						$this->update_meta( '_give_payment_mode', $this->mode );
873
						break;
874
875 52
					case 'transaction_id':
876
						$this->update_meta( '_give_payment_transaction_id', $this->transaction_id );
877
						break;
878
879
					case 'ip':
880
						$this->update_meta( '_give_payment_donor_ip', $this->ip );
881 52
						break;
882 52
883 52
					case 'customer_id':
884 52
						$this->update_meta( '_give_payment_donor_id', $this->customer_id );
885
						break;
886 52
887
					case 'form_title':
888
						$this->update_meta( '_give_payment_form_title', $this->form_title );
889 52
						break;
890 52
891 52
					case 'form_id':
892
						$this->update_meta( '_give_payment_form_id', $this->form_id );
893
						break;
894 2
895 1
					case 'price_id':
896 1
						$this->update_meta( '_give_payment_price_id', $this->price_id );
897
						break;
898 1
899
					case 'first_name':
900
						$this->update_meta( '_give_donor_billing_first_name', $this->first_name );
901 1
						break;
902 1
903 1
					case 'last_name':
904 1
						$this->update_meta( '_give_donor_billing_last_name', $this->last_name );
905 1
						break;
906 1
907
					case 'currency':
908 1
						$this->update_meta( '_give_payment_currency', $this->currency );
909
						break;
910
911
					case 'address':
912 1
						if ( ! empty( $this->address ) ) {
913
							foreach ( $this->address as $address_name => $address ) {
914 1
								switch ( $address_name ) {
915
									case 'line1':
916
										$this->update_meta( '_give_donor_billing_address1', $address );
917
										break;
918
919
									case 'line2':
920 52
										$this->update_meta( '_give_donor_billing_address2', $address );
921 52
										break;
922
923
									default:
924 52
										$this->update_meta( "_give_donor_billing_{$address_name}", $address );
925 52
								}
926 52
							}
927 52
						}
928 52
						break;
929
930
					case 'email':
931 52
						$this->update_meta( '_give_payment_donor_email', $this->email );
932
						break;
933
934
					case 'title_prefix':
935
						$this->update_meta( '_give_payment_donor_title_prefix', $this->title_prefix );
936 52
						break;
937 52
938 52
					case 'key':
939 52
						$this->update_meta( '_give_payment_purchase_key', $this->key );
940 52
						break;
941 52
942 52
					case 'number':
943
						// @todo: remove unused meta data.
944 52
						// Core is using post_title to store donation serial code ( fi enabled ) instead this meta key.
945
						// Do not use this meta key in your logic, can be remove in future
946 52
						$this->update_meta( '_give_payment_number', $this->number );
947
						break;
948 52
949
					case 'date':
950 52
						$args = array(
951
							'ID'        => $this->ID,
952
							'post_date' => date( 'Y-m-d H:i:s', strtotime( $this->date ) ),
953
							'edit_date' => true,
954
						);
955
956
						wp_update_post( $args );
957
						break;
958
959
					case 'completed_date':
960
						$this->update_meta( '_give_completed_date', $this->completed_date );
961
						break;
962
963
					case 'parent_payment':
964 2
						$args = array(
965
							'ID'          => $this->ID,
966
							'post_parent' => $this->parent_payment,
967
						);
968 2
969 2
						wp_update_post( $args );
970 2
						break;
971 2
972 2
					case 'total':
973
						$this->update_meta( '_give_payment_total', give_sanitize_amount_for_db( $this->total ) );
974 2
						break;
975
976
					default:
977 2
						/**
978
						 * Fires while saving payment.
979
						 *
980
						 * @since 1.7
981 2
						 *
982 2
						 * @param Give_Payment $this Payment object.
983 2
						 */
984 2
						do_action( 'give_payment_save', $this, $key );
985 2
						break;
986 2
				} // End switch().
987
			} // End foreach().
988 2
989
			if ( 'pending' !== $this->status ) {
990 2
991
				$donor = new Give_Donor( $this->customer_id );
992 2
993
				$total_change = $total_increase - $total_decrease;
994
				if ( $total_change < 0 ) {
995
996
					$total_change = - ( $total_change );
997
998
					// Decrease the donor's donation stats.
999
					$donor->decrease_value( $total_change );
1000
					give_decrease_total_earnings( $total_change );
1001
1002
					$donor->decrease_donation_count();
1003
1004
				} elseif ( $total_change > 0 ) {
1005
1006
					// Increase the donor's donation stats.
1007
					$donor->increase_value( $total_change );
1008
					give_increase_total_earnings( $total_change );
1009
1010
					$donor->increase_purchase_count();
1011
1012
				}
1013
1014
				// Verify and update form meta based on the form status.
1015
				give_set_form_closed_status( $this->form_id );
1016
			}
1017
1018
			$this->pending = array();
1019
			$saved         = true;
1020
		} // End if().
1021
1022
		if ( true === $saved ) {
1023
			$this->setup_payment( $this->ID );
1024
		}
1025
1026
		return $saved;
1027
	}
1028
1029
	/**
1030
	 * Add a donation to a given payment
1031
	 *
1032
	 * @since  1.5
1033
	 * @access public
1034
	 *
1035
	 * @param  int   $form_id The donation form to add.
1036
	 * @param  array $args    Other arguments to pass to the function.
1037
	 * @param  array $options List of donation options.
1038
	 *
1039
	 * @return bool           True when successful, false otherwise
1040
	 */
1041
	public function add_donation( $form_id = 0, $args = array(), $options = array() ) {
1042
1043
		$donation = new Give_Donate_Form( $form_id );
1044
1045
		// Bail if this post isn't a give donation form.
1046
		if ( ! $donation || 'give_forms' !== $donation->post_type ) {
1047
			return false;
1048
		}
1049
1050
		// Set some defaults.
1051
		$defaults = array(
1052
			'price'    => false,
1053
			'price_id' => false,
1054
		);
1055
1056
		$args = wp_parse_args( apply_filters( 'give_payment_add_donation_args', $args, $donation->ID ), $defaults );
1057
1058
		// Allow overriding the price.
1059
		if ( false !== $args['price'] ) {
1060
			$donation_amount = $args['price'];
1061
		} else {
1062
1063
			// Deal with variable pricing.
1064
			if ( give_has_variable_prices( $donation->ID ) ) {
1065
				$prices          = give_get_meta( $form_id, '_give_donation_levels', true );
1066
				$donation_amount = '';
1067
1068
				// Loop through prices.
1069 View Code Duplication
				foreach ( $prices as $price ) {
0 ignored issues
show
This code seems to be duplicated across 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...
1070
					// Find a match between price_id and level_id.
1071
					// First verify array keys exists THEN make the match.
1072
					if (
1073
						isset( $args['price_id'] ) &&
1074
						isset( $price['_give_id']['level_id'] ) &&
1075
						$args['price_id'] === (int) $price['_give_id']['level_id']
1076
					) {
1077
						$donation_amount = $price['_give_amount'];
1078
					}
1079
				}
1080
1081
				// Fallback to the lowest price point.
1082
				if ( '' === $donation_amount ) {
1083
					$donation_amount  = give_get_lowest_price_option( $donation->ID );
1084
					$args['price_id'] = give_get_lowest_price_id( $donation->ID );
1085
				}
1086
			} else {
1087
				// Simple form price.
1088
				$donation_amount = give_get_form_price( $donation->ID );
1089
			}
1090
		}
1091
1092
		// Sanitizing the price here so we don't have a dozen calls later.
1093
		$donation_amount = give_maybe_sanitize_amount( $donation_amount );
1094
		$total           = round( $donation_amount, give_get_price_decimals( $this->ID ) );
1095
1096
		// Add Options.
1097
		$default_options = array();
1098
		if ( false !== $args['price_id'] ) {
1099
			$default_options['price_id'] = (int) $args['price_id'];
1100
		}
1101
		$options = wp_parse_args( $options, $default_options );
1102
1103
		// Do not allow totals to go negative.
1104
		if ( $total < 0 ) {
1105
			$total = 0;
1106
		}
1107
1108
		$donation = array(
1109
			'name'     => $donation->post_title,
1110
			'id'       => $donation->ID,
1111
			'price'    => round( $total, give_get_price_decimals( $this->ID ) ),
1112
			'subtotal' => round( $total, give_get_price_decimals( $this->ID ) ),
1113
			'price_id' => $args['price_id'],
1114
			'action'   => 'add',
1115
			'options'  => $options,
1116
		);
1117
1118
		$this->pending['donations'][] = $donation;
1119
1120
		$this->increase_subtotal( $total );
1121
1122
		return true;
1123
1124
	}
1125
1126
	/**
1127
	 * Remove a donation from the payment
1128
	 *
1129
	 * @since  1.5
1130
	 * @access public
1131
	 *
1132
	 * @param  int   $form_id The form ID to remove.
1133
	 * @param  array $args    Arguments to pass to identify (quantity, amount, price_id).
1134
	 *
1135
	 * @return bool           If the item was removed or not
1136
	 */
1137
	public function remove_donation( $form_id, $args = array() ) {
1138
1139
		// Set some defaults.
1140
		$defaults = array(
1141
			'quantity' => 1,
1142
			'price'    => false,
1143
			'price_id' => false,
1144
		);
1145
		$args     = wp_parse_args( $args, $defaults );
1146
1147
		$form = new Give_Donate_Form( $form_id );
1148
1149
		// Bail if this post isn't a valid give donation form.
1150
		if ( ! $form || 'give_forms' !== $form->post_type ) {
1151
			return false;
1152
		}
1153
1154
		$pending_args             = $args;
1155
		$pending_args['id']       = $form_id;
1156
		$pending_args['amount']   = $this->total;
1157
		$pending_args['price_id'] = false !== $args['price_id'] ? (int) $args['price_id'] : false;
1158
		$pending_args['quantity'] = $args['quantity'];
1159
		$pending_args['action']   = 'remove';
1160
1161
		$this->pending['donations'][] = $pending_args;
1162
1163
		$this->decrease_subtotal( $this->total );
1164
1165
		return true;
1166
	}
1167
1168
1169
	/**
1170
	 * Add a note to a payment
1171
	 *
1172 52
	 * @since  1.5
1173 52
	 * @access public
1174 52
	 *
1175
	 * @param  string|bool $note The note to add.
1176 52
	 *
1177 52
	 * @return bool           If the note was specified or not
1178
	 */
1179
	public function add_note( $note = false ) {
1180
		// Bail if no note specified.
1181
		if ( ! $note ) {
1182
			return false;
1183
		}
1184
1185
		give_insert_payment_note( $this->ID, $note );
0 ignored issues
show
It seems like $note defined by parameter $note on line 1179 can also be of type boolean; however, give_insert_payment_note() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
1186
	}
1187
1188 2
	/**
1189 2
	 * Increase the payment's subtotal
1190 2
	 *
1191
	 * @since  1.5
1192 2
	 * @access private
1193
	 *
1194
	 * @param  float $amount The amount to increase the payment subtotal by.
1195
	 *
1196 2
	 * @return void
1197 2
	 */
1198
	private function increase_subtotal( $amount = 0.00 ) {
1199
		$amount         = (float) $amount;
1200
		$this->subtotal += $amount;
1201
1202
		$this->recalculate_total();
1203
	}
1204
1205
	/**
1206
	 * Decrease the payment's subtotal.
1207
	 *
1208
	 * @since  1.5
1209
	 * @access private
1210
	 *
1211
	 * @param  float $amount The amount to decrease the payment subtotal by.
1212
	 *
1213
	 * @return void
1214
	 */
1215
	private function decrease_subtotal( $amount = 0.00 ) {
1216
		$amount         = (float) $amount;
1217
		$this->subtotal -= $amount;
1218
1219
		if ( $this->subtotal < 0 ) {
1220
			$this->subtotal = 0;
0 ignored issues
show
Documentation Bug introduced by
The property $subtotal was declared of type double, but 0 is of type integer. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
1221
		}
1222
1223
		$this->recalculate_total();
1224
	}
1225
1226
	/**
1227
	 * Set or update the total for a payment.
1228
	 *
1229
	 * @since  1.5
1230
	 * @since  2.1.4 reset total in pending property
1231
	 * @access private
1232
	 *
1233
	 * @return void
1234
	 */
1235
	private function recalculate_total() {
1236
		$this->pending['total'] = $this->total = $this->subtotal;
1237
	}
1238
1239
	/**
1240
	 * Set the payment status and run any status specific changes necessary.
1241 52
	 *
1242 52
	 * @since  1.5
1243 52
	 * @access public
1244
	 *
1245
	 * @param  string|bool $status The status to set the payment to.
1246
	 *
1247
	 * @return bool   $updated Returns if the status was successfully updated.
1248
	 */
1249
	public function update_status( $status = false ) {
1250
1251
		// standardize the 'complete(d)' status.
1252
		if ( 'completed' === $status || 'complete' === $status ) {
1253
			$status = 'publish';
1254 52
		}
1255
1256
		$old_status = ! empty( $this->old_status ) ? $this->old_status : false;
1257 52
1258 39
		if ( $old_status === $status ) {
1259 39
			return false; // Don't permit status changes that aren't changes.
1260
		}
1261 52
1262
		$do_change = apply_filters( 'give_should_update_payment_status', true, $this->ID, $status, $old_status );
1263 52
1264 52
		$updated = false;
1265
1266
		if ( $do_change ) {
1267 42
1268
			/**
1269 42
			 * Fires before changing payment status.
1270
			 *
1271
			 * @since 1.5
1272 42
			 *
1273
			 * @param int    $payment_id Payments ID.
1274 42
			 * @param string $status     The new status.
1275
			 * @param string $old_status The old status.
1276
			 */
1277 42
			do_action( 'give_before_payment_status_change', $this->ID, $status, $old_status );
1278 42
1279 42
			$update_fields = array(
1280 42
				'ID'          => $this->ID,
1281
				'post_status' => $status,
1282 42
				'edit_date'   => current_time( 'mysql' ),
1283
			);
1284 42
1285 42
			$updated = wp_update_post( apply_filters( 'give_update_payment_status_fields', $update_fields ) );
1286
1287
			$all_payment_statuses  = give_get_payment_statuses();
1288
			$this->status_nicename = array_key_exists( $status, $all_payment_statuses ) ? $all_payment_statuses[ $status ] : ucfirst( $status );
1289 42
1290 4
			// Process any specific status functions.
1291 4
			$this->process_status( $status );
0 ignored issues
show
It seems like $status defined by parameter $status on line 1249 can also be of type boolean; however, Give_Payment::process_status() does only seem to accept string, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
1292 42
1293
			/**
1294
			 * Fires after changing payment status.
1295 42
			 *
1296 3
			 * @since 1.5
1297 3
			 *
1298
			 * @param int    $payment_id Payment ID.
1299
			 * @param string $status     The new status.
1300 42
			 * @param string $old_status The old status.
1301
			 */
1302 42
			do_action( 'give_update_payment_status', $this->ID, $status, $old_status );
1303
1304 42
		} // End if().
1305
1306
		return $updated;
1307
1308
	}
1309
1310
	/**
1311
	 * Change the status of the payment to refunded, and run the necessary changes
1312
	 *
1313
	 * @since  1.5
1314 4
	 * @access public
1315 4
	 *
1316 4
	 * @return void
1317 4
	 */
1318
	public function refund() {
1319 4
		$this->old_status        = $this->status;
1320 4
		$this->status            = 'refunded';
1321
		$this->pending['status'] = $this->status;
1322
1323
		$this->save();
1324
	}
1325
1326
	/**
1327
	 * Get a post meta item for the payment
1328
	 *
1329
	 * @since  1.5
1330
	 * @access public
1331
	 *
1332 52
	 * @param  string  $meta_key The Meta Key.
1333
	 * @param  boolean $single   Return single item or array.
1334 52
	 *
1335
	 * @return mixed             The value from the post meta
1336 52
	 */
1337
	public function get_meta( $meta_key = '_give_payment_meta', $single = true ) {
1338 52
		if (
1339 52
			! has_filter( 'get_post_metadata', 'give_bc_v20_get_payment_meta' ) &&
1340 52
			! doing_filter( 'get_post_metadata' )
1341
		) {
1342 52
			add_filter( 'get_post_metadata', 'give_bc_v20_get_payment_meta', 999, 4 );
1343 52
		}
1344 52
1345
		$meta = give_get_meta( $this->ID, $meta_key, $single );
1346 52
1347 52
		/**
1348 52
		 * Filter the specific meta key value.
1349
		 *
1350 52
		 * @since 1.5
1351 52
		 */
1352 52
		$meta = apply_filters( "give_get_payment_meta_{$meta_key}", $meta, $this->ID );
1353 52
1354
		// Security check.
1355 52 View Code Duplication
		if ( is_serialized( $meta ) ) {
0 ignored issues
show
This code seems to be duplicated across 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...
1356
			preg_match( '/[oO]\s*:\s*\d+\s*:\s*"\s*(?!(?i)(stdClass))/', $meta, $matches );
1357 52
			if ( ! empty( $matches ) ) {
1358
				$meta = array();
1359
			}
1360
		}
1361
1362
		/**
1363
		 * Filter the all meta keys.
1364
		 *
1365
		 * @since 1.5
1366
		 */
1367
		return apply_filters( 'give_get_payment_meta', $meta, $this->ID, $meta_key );
1368
	}
1369
1370
	/**
1371 52
	 * Update the post meta
1372 52
	 *
1373
	 * @since  1.5
1374
	 * @access public
1375
	 *
1376 52
	 * @param  string $meta_key   The meta key to update.
1377
	 * @param  string $meta_value The meta value.
1378
	 * @param  string $prev_value Previous meta value.
1379
	 *
1380
	 * @return int|bool           Meta ID if the key didn't exist, true on successful update, false on failure
1381
	 */
1382
	public function update_meta( $meta_key = '', $meta_value = '', $prev_value = '' ) {
1383
		if ( empty( $meta_key ) ) {
1384 52
			return false;
1385
		}
1386 52
0 ignored issues
show
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
1387 52
1388
		/**
1389 52
		 * Filter the single meta key while updating
1390 52
		 *
1391
		 * @since 1.5
1392 52
		 */
1393 52
		$meta_value = apply_filters( "give_update_payment_meta_{$meta_key}", $meta_value, $this->ID );
1394
1395 52
		return give_update_meta( $this->ID, $meta_key, $meta_value, $prev_value );
1396
	}
1397 52
1398
	/**
1399 52
	 * Process Donation Status.
1400
	 *
1401
	 * @param string $status Donation Status.
1402
	 *
1403
	 * @since  2.0.2
1404
	 * @access private
1405
	 *
1406
	 * @return void
1407
	 */
1408
	private function process_status( $status ) {
1409 4
		$process = true;
1410 4
1411
		// Bailout, if changed from completed to preapproval/processing.
1412
		// Bailout, if current status = previous status or status is publish.
1413 4
		if (
1414
			'preapproval' === $status ||
1415
			'processing' === $status ||
1416
			'publish' !== $this->old_status ||
1417
			$status !== $this->status
1418 4
		) {
1419
			$process = false;
1420 4
		}
1421
1422
		// Allow extensions to filter for their own payment types, Example: Recurring Payments.
1423
		$process = apply_filters( "give_should_process_{$status}", $process, $this );
1424 4
1425
		if ( false === $process ) {
1426 4
			return;
1427 4
		}
1428 4
1429
		/**
1430 4
		 * Fires before processing donation status.
1431 4
		 *
1432
		 * @param Give_Payment $this Payment object.
1433
		 *
1434 4
		 * @since 1.5
1435
		 */
1436 4
		do_action( "give_pre_{$status}_payment", $this );
1437 4
1438
		$decrease_earnings       = apply_filters( "give_decrease_earnings_on_{$status}", true, $this );
1439
		$decrease_donor_value    = apply_filters( "give_decrease_donor_value_on_{$status}", true, $this );
1440
		$decrease_donation_count = apply_filters( "give_decrease_donors_donation_count_on_{$status}", true, $this );
1441
1442
		$this->maybe_alter_stats( $decrease_earnings, $decrease_donor_value, $decrease_donation_count );
1443
		$this->delete_sales_logs();
1444
1445
		// @todo: Refresh only range related stat cache
1446
		give_delete_donation_stats();
1447
1448
		/**
1449
		 * Fires after processing donation status.
1450
		 *
1451
		 * @param Give_Payment $this Payment object.
1452
		 *
1453
		 * @since 1.5
1454
		 */
1455
		do_action( "give_post_{$status}_payment", $this );
1456 3
	}
1457 3
1458
	/**
1459
	 * Used during the process of moving to refunded or pending, to decrement stats
1460 3
	 *
1461 1
	 * @since  1.5
1462 1
	 * @access private
1463
	 *
1464
	 * @param  bool $alter_store_earnings          If the method should alter the store earnings.
1465 3
	 * @param  bool $alter_customer_value          If the method should reduce the donor value.
1466
	 * @param  bool $alter_customer_purchase_count If the method should reduce the donor's purchase count.
1467 3
	 *
1468 1
	 * @return void
1469
	 */
1470
	private function maybe_alter_stats( $alter_store_earnings, $alter_customer_value, $alter_customer_purchase_count ) {
1471 2
1472 2
		give_undo_donation( $this->ID );
1473 2
1474
		// Decrease store earnings.
1475 2
		if ( true === $alter_store_earnings ) {
1476 2
			give_decrease_total_earnings( $this->total );
1477
		}
1478 2
1479 2
		// Decrement the stats for the donor.
1480
		if ( ! empty( $this->customer_id ) ) {
1481
1482 2
			$donor = new Give_Donor( $this->customer_id );
1483 2
1484
			if ( true === $alter_customer_value ) {
1485
				$donor->decrease_value( $this->total );
1486
			}
1487
1488
			if ( true === $alter_customer_purchase_count ) {
1489
				$donor->decrease_donation_count();
1490
			}
1491
		}
1492
1493
	}
1494
1495
	/**
1496 6
	 * Delete sales logs for this donation
1497
	 *
1498 6
	 * @since  1.5
1499
	 * @access private
1500
	 *
1501 6
	 * @return void
1502 4
	 */
1503 4
	private function delete_sales_logs() {
1504
		// Remove related sale log entries.
1505
		Give()->logs->delete_logs( $this->ID );
1506 6
	}
1507
1508 6
	/**
1509
	 * Setup functions only, these are not to be used by developers.
1510 6
	 * These functions exist only to allow the setup routine to be backwards compatible with our old
1511 4
	 * helper functions.
1512 4
	 *
1513
	 * These will run whenever setup_payment is called, which should only be called once.
1514 6
	 * To update an attribute, update it directly instead of re-running the setup routine
1515 4
	 */
1516 4
1517
	/**
1518 6
	 * Setup the payment completed date
1519
	 *
1520 6
	 * @since  1.5
1521
	 * @access private
1522
	 *
1523
	 * @return string The date the payment was completed
1524
	 */
1525
	private function setup_completed_date() {
1526
		$payment = get_post( $this->ID );
1527
1528 6
		if ( 'pending' === $payment->post_status || 'preapproved' === $payment->post_status ) {
1529 6
			return false; // This payment was never completed.
1530
		}
1531
1532 6
		$date = ( $date = $this->get_meta( '_give_completed_date', true ) ) ? $date : $payment->modified_date;
1533 6
1534 6
		return $date;
1535
	}
1536
1537 6
	/**
1538 6
	 * Setup the payment mode
1539 6
	 *
1540
	 * @since  1.5
1541 6
	 * @access private
1542 6
	 *
1543
	 * @return string The payment mode
1544
	 */
1545
	private function setup_mode() {
1546
		return $this->get_meta( '_give_payment_mode' );
1547
	}
1548
1549
	/**
1550
	 * Setup the payment import data
1551
	 *
1552
	 * @since  1.8.13
1553
	 * @access private
1554
	 *
1555
	 * @return bool The payment import
1556
	 */
1557
	private function setup_import() {
1558
		return (bool) $this->get_meta( '_give_payment_import' );
1559 52
	}
1560 52
1561
	/**
1562 52
	 * Setup the payment total
1563 52
	 *
1564
	 * @since  1.5
1565
	 * @access private
1566 42
	 *
1567
	 * @return float The payment total
1568 42
	 */
1569
	private function setup_total() {
1570
		$amount = $this->get_meta( '_give_payment_total', true );
1571
1572
		return round( floatval( $amount ), give_get_price_decimals( $this->ID ) );
1573
	}
1574
1575
	/**
1576
	 * Setup the payment subtotal
1577 52
	 *
1578 52
	 * @since  1.5
1579
	 * @access private
1580
	 *
1581
	 * @return float The subtotal of the payment
1582
	 */
1583
	private function setup_subtotal() {
1584
		$subtotal = $this->total;
1585
1586
		return $subtotal;
1587 52
	}
1588 52
1589
	/**
1590 52
	 * Setup the currency code
1591 2
	 *
1592 2
	 * @since  1.5
1593
	 * @since  2.0 Set currency from _give_payment_currency meta key
1594 2
	 * @access private
1595
	 *
1596
	 * @return string The currency for the payment
1597 2
	 */
1598 View Code Duplication
	private function setup_currency() {
0 ignored issues
show
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...
1599 52
		$currency = $this->get_meta( '_give_payment_currency', true );
1600
		$currency = ! empty( $currency ) ?
1601
			$currency :
1602
			/**
1603
			 * Filter the default donation currency
1604
			 *
1605
			 * @since 1.5
1606
			 */
1607
			apply_filters(
1608 52
				'give_payment_currency_default',
1609 52
				give_get_currency( $this->form_id, $this ),
1610
				$this
1611 52
			);
1612
1613
		return $currency;
1614
	}
1615
1616
	/**
1617
	 * Setup the gateway used for the payment
1618
	 *
1619
	 * @since  1.5
1620 52
	 * @access private
1621 52
	 *
1622
	 * @return string The gateway
1623 52
	 */
1624 52
	private function setup_gateway() {
1625
		$gateway = $this->get_meta( '_give_payment_gateway', true );
1626
1627
		return $gateway;
1628
	}
1629
1630 52
	/**
1631
	 * Setup the donation ID
1632
	 *
1633
	 * @since  1.5
1634
	 * @access private
1635
	 *
1636
	 * @return string The donation ID
1637
	 */
1638 View Code Duplication
	private function setup_transaction_id() {
0 ignored issues
show
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...
1639
		$transaction_id = $this->get_meta( '_give_payment_transaction_id', true );
1640 52
1641 52
		if ( empty( $transaction_id ) ) {
1642
			$gateway        = $this->gateway;
1643 52
			$transaction_id = apply_filters( "give_get_payment_transaction_id-{$gateway}", $this->ID );
1644
		}
1645
1646
		return $transaction_id;
1647
	}
1648
1649
	/**
1650
	 * Setup the IP Address for the payment
1651
	 *
1652 52
	 * @since  1.5
1653 52
	 * @since  2.0 Set ip address from _give_payment_donor_ip meta key
1654
	 * @access private
1655 52
	 *
1656
	 * @return string The IP address for the payment
1657
	 */
1658
	private function setup_ip() {
1659
		$ip = $this->get_meta( '_give_payment_donor_ip', true );
1660
1661
		return $ip;
1662
	}
1663
1664 52
	/**
1665 52
	 * Setup the donor ID.
1666
	 *
1667 52
	 * @since  1.5
1668
	 * @since  2.0 Set id from _give_payment_donor_id meta key
1669
	 * @access private
1670
	 *
1671
	 * @return int The Donor ID.
1672
	 */
1673
	private function setup_donor_id() {
1674
		$donor_id = $this->get_meta( '_give_payment_donor_id', true );
1675
1676 52
		return $donor_id;
1677 52
	}
1678
1679 52
	/**
1680
	 * Setup the User ID associated with the donation
1681 52
	 *
1682 52
	 * @since  1.5
1683
	 * @since  2.0 Get user id connect to donor from donor table instead of payment meta.
1684 52
	 *
1685
	 * @access private
1686 52
	 *
1687
	 * @return int The User ID
1688
	 */
1689
	private function setup_user_id() {
1690
1691
		$donor   = Give()->customers->get_customer_by( 'id', $this->customer_id );
1692
		$user_id = $donor ? absint( $donor->user_id ) : 0;
1693
0 ignored issues
show
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
1694
1695 52
		return $user_id;
1696 52
	}
1697
1698 52
	/**
1699
	 * Setup the email address for the donation.
1700
	 *
1701
	 * @since  1.5
1702
	 * @since  2.0 Set email from _give_payment_donor_email meta key
1703
	 *
1704
	 * @access private
1705
	 *
1706
	 * @return string The email address for the payment.
1707 52
	 */
1708 52
	private function setup_email() {
1709
		$email = $this->get_meta( '_give_payment_donor_email', true );
1710 52
1711
		if ( empty( $email ) && $this->customer_id ) {
1712
			$email = Give()->donors->get_column( 'email', $this->customer_id );
1713
		}
1714
1715
		return $email;
1716
	}
1717
1718
	/**
1719 52
	 * Setup the user info.
1720 52
	 *
1721
	 * @since  1.5
1722 52
	 * @access private
1723
	 *
1724
	 * @return array The user info associated with the payment.
1725
	 */
1726
	private function setup_user_info() {
1727
		$defaults = array(
1728
			'title'      => $this->title_prefix,
1729
			'first_name' => $this->first_name,
1730
			'last_name'  => $this->last_name,
1731 52
		);
1732 52
1733
		$user_info = isset( $this->payment_meta['user_info'] ) ? $this->payment_meta['user_info'] : array();
1734 52
1735 2 View Code Duplication
		if ( is_serialized( $user_info ) ) {
0 ignored issues
show
This code seems to be duplicated across 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...
1736 2
			preg_match( '/[oO]\s*:\s*\d+\s*:\s*"\s*(?!(?i)(stdClass))/', $user_info, $matches );
1737
			if ( ! empty( $matches ) ) {
1738 52
				$user_info = array();
1739
			}
1740
		}
1741
1742
		$user_info = wp_parse_args( $user_info, $defaults );
1743
1744
		if ( empty( $user_info ) ) {
1745
			// Get the donor, but only if it's been created.
1746
			$donor = new Give_Donor( $this->customer_id );
1747 52
1748
			if ( $donor->id > 0 ) {
1749 52
				$user_info = array(
1750 52
					'first_name' => $donor->get_first_name(),
1751 52
					'last_name'  => $donor->get_last_name(),
1752
					'email'      => $donor->email,
1753 52
					'discount'   => 'none',
1754 52
				);
1755
			}
1756 52
		} else {
1757
			// Get the donor, but only if it's been created.
1758
			$donor = new Give_Donor( $this->customer_id );
1759
1760
			if ( $donor->id > 0 ) {
1761
				foreach ( $user_info as $key => $value ) {
1762
					if ( ! empty( $value ) ) {
1763
						continue;
1764
					}
1765
1766
					switch ( $key ) {
1767
						case 'title':
1768
							$user_info[ $key ] = Give()->donor_meta->get_meta( $donor->id, '_give_donor_title_prefix', true );
1769
							break;
1770
1771 52
						case 'first_name':
1772 52
							$user_info[ $key ] = $donor->get_first_name();
1773 52
							break;
1774 52
1775 52
						case 'last_name':
1776
							$user_info[ $key ] = $donor->get_last_name();
1777
							break;
1778
1779 21
						case 'email':
1780 21
							$user_info[ $key ] = $donor->email;
1781
							break;
1782 21
					}
1783 21
				}
1784
			}
1785 21
		}// End if().
1786 21
1787 21
		return $user_info;
1788
1789 21
	}
1790 21
1791
	/**
1792
	 * Setup the Address for the payment.
1793
	 *
1794
	 * @since  1.5
1795
	 * @access private
1796 52
	 *
1797
	 * @return array The Address information for the payment.
1798 52
	 */
1799
	private function setup_address() {
1800
		$address['line1']   = give_get_meta( $this->ID, '_give_donor_billing_address1', true, '' );
0 ignored issues
show
'' is of type string, but the function expects a boolean.

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...
1801 52
		$address['line2']   = give_get_meta( $this->ID, '_give_donor_billing_address2', true, '' );
0 ignored issues
show
'' is of type string, but the function expects a boolean.

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...
1802
		$address['city']    = give_get_meta( $this->ID, '_give_donor_billing_city', true, '' );
0 ignored issues
show
'' is of type string, but the function expects a boolean.

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...
1803
		$address['state']   = give_get_meta( $this->ID, '_give_donor_billing_state', true, '' );
0 ignored issues
show
'' is of type string, but the function expects a boolean.

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...
1804
		$address['zip']     = give_get_meta( $this->ID, '_give_donor_billing_zip', true, '' );
0 ignored issues
show
'' is of type string, but the function expects a boolean.

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...
1805
		$address['country'] = give_get_meta( $this->ID, '_give_donor_billing_country', true, '' );
0 ignored issues
show
'' is of type string, but the function expects a boolean.

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...
1806
1807
		return $address;
1808
	}
1809
1810
	/**
1811 52
	 * Setup the form title.
1812
	 *
1813 52
	 * @since  1.5
1814 52
	 * @access private
1815 52
	 *
1816 52
	 * @return string The Form Title.
1817 52
	 */
1818 52
	private function setup_form_title() {
1819
1820 52
		$form_id = $this->get_meta( '_give_payment_form_title', true );
1821
1822 52
		return $form_id;
1823
	}
1824
1825
	/**
1826
	 * Setup the form ID.
1827
	 *
1828
	 * @since  1.5
1829
	 * @access private
1830
	 *
1831 52
	 * @return int The Form ID
1832
	 */
1833 52
	private function setup_form_id() {
1834
1835 52
		$form_id = $this->get_meta( '_give_payment_form_id', true );
1836
1837
		return $form_id;
1838
	}
1839
1840
	/**
1841
	 * Setup the price ID.
1842
	 *
1843
	 * @since  1.5
1844 52
	 * @access private
1845
	 *
1846 52
	 * @return int The Form Price ID.
1847
	 */
1848 52
	private function setup_price_id() {
1849
		$price_id = $this->get_meta( '_give_payment_price_id', true );
1850
1851
		return $price_id;
1852
	}
1853
1854
	/**
1855
	 * Setup the payment key.
1856
	 *
1857 52
	 * @since  1.5
1858 52
	 * @access private
1859
	 *
1860 52
	 * @return string The Payment Key.
1861
	 */
1862
	private function setup_payment_key() {
1863
		$key = $this->get_meta( '_give_payment_purchase_key', true );
1864
1865
		return $key;
1866
	}
1867
1868
	/**
1869 52
	 * Setup the payment number.
1870 52
	 *
1871
	 * @since  1.5
1872 52
	 * @access private
1873
	 *
1874
	 * @return int|string Integer by default, or string if sequential order numbers is enabled.
1875
	 */
1876
	private function setup_payment_number() {
1877
		return $this->get_serial_code();
1878
	}
1879
1880
	/**
1881 52
	 * Converts this object into an array for special cases.
1882 52
	 *
1883
	 * @access public
1884 52
	 *
1885
	 * @return array The payment object as an array.
1886 20
	 */
1887
	public function array_convert() {
1888 20
		return get_object_vars( $this );
1889
	}
1890 2
1891
1892 2
	/**
1893
	 * Flag to check if donation is completed or not.
1894 20
	 *
1895
	 * @since  1.8
1896 52
	 * @access public
1897
	 *
1898
	 * @return bool
1899
	 */
1900
	public function is_completed() {
1901
		return ( 'publish' === $this->status && $this->completed_date );
1902
	}
1903
1904
	/**
1905
	 * Retrieve payment completion date.
1906
	 *
1907
	 * @since  1.5
1908
	 * @access private
1909
	 *
1910
	 * @return string Date payment was completed.
1911
	 */
1912
	private function get_completed_date() {
1913
		return apply_filters( 'give_payment_completed_date', $this->completed_date, $this->ID, $this );
1914 42
	}
1915 42
1916
	/**
1917
	 * Retrieve payment subtotal.
1918
	 *
1919
	 * @since  1.5
1920
	 * @access private
1921
	 *
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
	 * @access private
1933
	 *
1934 42
	 * @return string Payment currency code.
1935 42
	 */
1936
	private function get_currency() {
1937
		return apply_filters( 'give_payment_currency_code', $this->currency, $this->ID, $this );
1938
	}
1939
1940
	/**
1941
	 * Retrieve payment gateway.
1942
	 *
1943
	 * @since  1.5
1944 42
	 * @access private
1945 42
	 *
1946
	 * @return string Gateway used.
1947
	 */
1948
	private function get_gateway() {
1949
		return apply_filters( 'give_payment_gateway', $this->gateway, $this->ID, $this );
1950
	}
1951
1952
	/**
1953
	 * Retrieve donation ID.
1954 11
	 *
1955 11
	 * @since  1.5
1956
	 * @access private
1957
	 *
1958
	 * @return string Donation ID from merchant processor.
1959
	 */
1960
	private function get_transaction_id() {
1961
		return apply_filters( 'give_get_payment_transaction_id', $this->transaction_id, $this->ID, $this );
1962
	}
1963
1964
	/**
1965
	 * Retrieve payment IP
1966
	 *
1967
	 * @since  1.5
1968
	 * @access private
1969
	 *
1970
	 * @return string Payment IP address
1971
	 */
1972
	private function get_ip() {
1973
		return apply_filters( 'give_payment_user_ip', $this->ip, $this->ID, $this );
1974 52
	}
1975 52
1976
	/**
1977
	 * Retrieve payment donor ID.
1978
	 *
1979
	 * @since  1.5
1980
	 * @access private
1981
	 *
1982
	 * @return int Payment donor ID.
1983
	 */
1984 41
	private function get_donor_id() {
1985 41
		return apply_filters( 'give_payment_customer_id', $this->customer_id, $this->ID, $this );
1986
	}
1987
1988
	/**
1989
	 * Retrieve payment user ID.
1990
	 *
1991
	 * @since  1.5
1992
	 * @access private
1993
	 *
1994 42
	 * @return int Payment user ID.
1995 42
	 */
1996
	private function get_user_id() {
1997
		return apply_filters( 'give_payment_user_id', $this->user_id, $this->ID, $this );
1998
	}
1999
2000
	/**
2001
	 * Retrieve payment email.
2002
	 *
2003
	 * @since  1.5
2004 43
	 * @access private
2005 43
	 *
2006
	 * @return string Payment donor email.
2007
	 */
2008
	private function get_email() {
2009
		return apply_filters( 'give_payment_user_email', $this->email, $this->ID, $this );
2010
	}
2011
2012
	/**
2013
	 * Retrieve payment user info.
2014
	 *
2015
	 * @since  1.5
2016
	 * @access private
2017
	 *
2018
	 * @return array Payment user info.
2019
	 */
2020
	private function get_user_info() {
2021
		return apply_filters( 'give_payment_meta_user_info', $this->user_info, $this->ID, $this );
2022
	}
2023
2024 52
	/**
2025 52
	 * Retrieve payment billing address.
2026
	 *
2027
	 * @since  1.5
2028
	 * @access private
2029
	 *
2030
	 * @return array Payment billing address.
2031
	 */
2032
	private function get_address() {
2033
		return apply_filters( 'give_payment_address', $this->address, $this->ID, $this );
2034 52
	}
2035 52
2036
	/**
2037
	 * Retrieve payment key.
2038
	 *
2039
	 * @since  1.5
2040
	 * @access private
2041
	 *
2042
	 * @return string Payment key.
2043
	 */
2044 42
	private function get_key() {
2045 42
		return apply_filters( 'give_payment_key', $this->key, $this->ID, $this );
2046
	}
2047
2048
	/**
2049
	 * Retrieve payment form id
2050
	 *
2051
	 * @since  1.5
2052
	 * @access private
2053
	 *
2054
	 * @return string Payment form id
2055
	 */
2056
	private function get_form_id() {
2057
		return apply_filters( 'give_payment_form_id', $this->form_id, $this->ID, $this );
2058
	}
2059
2060
	/**
2061
	 * Retrieve payment number
2062
	 *
2063
	 * @since  1.5
2064
	 * @access private
2065
	 *
2066
	 * @return int|string Payment number
2067
	 */
2068
	private function get_number() {
2069
		return apply_filters( 'give_payment_number', $this->number, $this->ID, $this );
2070
	}
2071
2072
	/**
2073
	 * Get serial code
2074
	 *
2075
	 * @since 2.1
2076
	 *
2077
	 * @param array $args List of arguments.
2078
	 *
2079
	 * @return string
2080
	 */
2081
	public function get_serial_code( $args = array() ) {
2082
		return Give()->seq_donation_number->get_serial_code( $this, $args );
2083
	}
2084
}
2085