Give_Payment::setup_user_info()   C
last analyzed

Complexity

Conditions 13
Paths 24

Size

Total Lines 64

Duplication

Lines 6
Ratio 9.38 %

Importance

Changes 0
Metric Value
cc 13
nc 24
nop 0
dl 6
loc 64
rs 6.0787
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Payments
4
 *
5
 * @package     Give
6
 * @subpackage  Classes/Give_Payment
7
 * @copyright   Copyright (c) 2016, GiveWP
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
299
	/**
300
	 * The email used for the payment
301
	 *
302
	 * @since  1.5
303
	 * @access protected
304
	 *
305
	 * @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
	 */
317
	private $user_info = array();
318
319
	/**
320
	 * Legacy (not to be accessed) payment meta array
321
	 *
322
	 * @since  1.5
323
	 * @access private
324
	 *
325
	 * @var    array
326
	 */
327
	private $payment_meta = array();
328
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
	 *
342
	 * @since  1.5
343
	 * @access protected
344
	 *
345
	 * @var    string
346
	 */
347
	protected $transaction_id = '';
348
349
	/**
350
	 * IP Address payment was made from
351
	 *
352
	 * @since  1.5
353
	 * @access protected
354
	 *
355
	 * @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
	 */
367
	protected $gateway = '';
368
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
	 * @since  1.5
384
	 * @access private
385
	 *
386
	 * @var    array
387
	 */
388
	private $pending;
389
390
	/**
391
	 * The parent payment (if applicable)
392
	 *
393
	 * @since  1.5
394
	 * @access protected
395
	 *
396
	 * @var    integer
397
	 */
398
	protected $parent_payment = 0;
399
400
	/**
401
	 * Setup the Give Payments class
402
	 *
403
	 * @since  1.5
404
	 * @access public
405
	 *
406
	 * @param  int|bool $payment_id A given payment.
407
	 *
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
	public function __construct( $payment_id = false ) {
411
412
		if ( empty( $payment_id ) ) {
413
			return false;
0 ignored issues
show
Bug introduced by
Constructors do not have meaningful return values, anything that is returned from here is discarded. Are you sure this is correct?
Loading history...
414
		}
415
416
		$this->setup_payment( $payment_id );
0 ignored issues
show
Bug introduced by
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
	}
418
419
	/**
420
	 * Magic GET function.
421
	 *
422
	 * @since  1.5
423
	 * @access public
424
	 *
425
	 * @param  string $key The property.
426
	 *
427
	 * @return mixed        The value.
428
	 */
429
	public function __get( $key ) {
430
431
		if ( method_exists( $this, 'get_' . $key ) ) {
432
433
			$value = call_user_func( array( $this, 'get_' . $key ) );
434
435
		} else {
436
437
			$value = $this->$key;
438
439
		}
440
441
		return $value;
442
	}
443
444
	/**
445
	 * Magic SET function
446
	 *
447
	 * Sets up the pending array for the save method
448
	 *
449
	 * @since  1.5
450
	 * @access public
451
	 *
452
	 * @param  string $key   The property name.
453
	 * @param  mixed  $value The value of the property.
454
	 */
455
	public function __set( $key, $value ) {
456
		$ignore = array( '_ID' );
457
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
		if ( '_ID' !== $key ) {
467
			$this->$key = $value;
468
		}
469
	}
470
471
	/**
472
	 * Magic ISSET function, which allows empty checks on protected elements
473
	 *
474
	 * @since  1.5
475
	 * @access public
476
	 *
477
	 * @param  string $name The attribute to get.
478
	 *
479
	 * @return boolean|null       If the item is set or not
480
	 */
481
	public function __isset( $name ) {
482
		if ( property_exists( $this, $name ) ) {
483
			return false === empty( $this->$name );
484
		} else {
485
			return null;
486
		}
487
	}
488
489
	/**
490
	 * Setup payment properties
491
	 *
492
	 * @since  1.5
493
	 * @access private
494
	 *
495
	 * @param  int $payment_id The payment ID.
496
	 *
497
	 * @return bool            If the setup was successful or not
498
	 */
499
	private function setup_payment( $payment_id ) {
500
		$this->pending = array();
501
502
		if ( empty( $payment_id ) ) {
503
			return false;
504
		}
505
506
		$payment = get_post( absint( $payment_id ) );
507
508
		if ( ! $payment || is_wp_error( $payment ) ) {
509
			return false;
510
		}
511
512
		if ( 'give_payment' !== $payment->post_type ) {
513
			return false;
514
		}
515
516
		/**
517
		 * Fires before payment setup.
518
		 *
519
		 * Allow extensions to perform actions before the payment is loaded.
520
		 *
521
		 * @since 1.5
522
		 *
523
		 * @param Give_Payment $this       Payment object.
524
		 * @param int          $payment_id The ID of the payment.
525
		 */
526
		do_action( 'give_pre_setup_payment', $this, $payment_id );
527
528
		// Get payment from cache.
529
		$donation_vars = Give_Cache::get_group( $payment_id, 'give-donations' );
530
531
		if ( is_null( $donation_vars ) ) {
532
			// Primary Identifier.
533
			$this->ID = absint( $payment_id );
534
535
			// Protected ID that can never be changed.
536
			$this->_ID = absint( $payment_id );
537
538
			// We have a payment, get the generic payment_meta item to reduce calls to it.
539
			$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
			// Status and Dates.
542
			$this->date           = $payment->post_date;
543
			$this->post_date      = $payment->post_date;
544
			$this->completed_date = $this->setup_completed_date();
545
			$this->status         = $payment->post_status;
546
			$this->post_status    = $this->status;
547
			$this->mode           = $this->setup_mode();
548
			$this->import         = $this->setup_import();
549
			$this->parent_payment = $payment->post_parent;
550
551
			$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
554
			// Currency Based.
555
			$this->total    = $this->setup_total();
556
			$this->subtotal = $this->setup_subtotal();
557
			$this->currency = $this->setup_currency();
558
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
			$this->customer_id  = $this->setup_donor_id(); // Backward compatibility.
566
			$this->donor_id     = $this->setup_donor_id();
567
			$this->user_id      = $this->setup_user_id();
568
			$this->email        = $this->setup_email();
569
			$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
			$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
			Give_Cache::set_group( $this->ID, get_object_vars( $this ), 'give-donations' );
583
		} else {
584
585
			foreach ( $donation_vars as $donation_var => $value ) {
0 ignored issues
show
Bug introduced by
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
			}
588
		} // End if().
589
590
		/**
591
		 * Fires after payment setup.
592
		 *
593
		 * Allow extensions to add items to this object via hook.
594
		 *
595
		 * @since 1.5
596
		 *
597
		 * @param Give_Payment $this       Payment object.
598
		 * @param int          $payment_id The ID of the payment.
599
		 */
600
		do_action( 'give_setup_payment', $this, $payment_id );
601
602
		return true;
603
	}
604
605
606
	/**
607
	 * Payment class object is storing various meta value in object parameter.
608
	 * 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
	 * @since  1.6
613
	 * @access public
614
	 *
615
	 * @param  int $payment_id Payment ID.
616
	 *
617
	 * @return void
618
	 */
619
	public function update_payment_setup( $payment_id ) {
620
		// Delete cache.
621
		Give_Cache::delete_group( $this->ID,'give-donations' );
622
623
		$this->setup_payment( $payment_id );
624
	}
625
626
	/**
627
	 * Create the base of a payment.
628
	 *
629
	 * @since  1.5
630
	 * @access private
631
	 *
632
	 * @return int|bool False on failure, the payment ID on success.
633
	 */
634
	private function insert_payment() {
635
636
		// Construct the payment title.
637
		$payment_title = '';
638
		if ( ! empty( $this->first_name ) && ! empty( $this->last_name ) ) {
639
			$payment_title = $this->first_name . ' ' . $this->last_name;
640
		} elseif ( ! empty( $this->first_name ) && empty( $this->last_name ) ) {
641
			$payment_title = $this->first_name;
642
		} elseif ( ! empty( $this->email ) && is_email( $this->email ) ) {
643
			$payment_title = $this->email;
644
		}
645
646
		// Set Key.
647
		if ( empty( $this->key ) ) {
648
649
			$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
		}
653
654
		// Set IP.
655
		if ( empty( $this->ip ) ) {
656
657
			$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
			$this->pending['ip'] = $this->ip;
659
660
		}
661
662
		// @todo: payment data exist here only for backward compatibility
663
		// issue: https://github.com/impress-org/give/issues/1132
664
		$payment_data = array(
665
			'price'        => $this->total,
666
			'date'         => $this->date,
667
			'user_email'   => $this->email,
668
			'purchase_key' => $this->key,
669
			'form_title'   => $this->form_title,
670
			'form_id'      => $this->form_id,
671
			'donor_id'     => $this->donor_id,
672
			'price_id'     => $this->price_id,
673
			'currency'     => $this->currency,
674
			'user_info'    => array(
675
				'id'         => $this->user_id,
676
				'title'      => $this->title_prefix,
677
				'email'      => $this->email,
678
				'first_name' => $this->first_name,
679
				'last_name'  => $this->last_name,
680
				'address'    => $this->address,
681
			),
682
			'status'       => $this->status,
683
		);
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
			if ( did_action( 'give_pre_process_donation' ) && is_user_logged_in() ) {
712
				$donor = new Give_Donor( get_current_user_id(), true );
713
714
				// Donor is logged in but used a different email to purchase with so assign to their donor record.
715
				if ( ! empty( $donor->id ) && $this->email !== $donor->email ) {
716
					$donor->add_email( $this->email );
717
				}
718
			}
719
720
			if ( empty( $donor->id ) ) {
721
				$donor = new Give_Donor( $this->email );
722
			}
723
724
			if ( empty( $donor->id ) ) {
725
726
				$donor_data = array(
727
					'name'    => ! is_email( $payment_title ) ? $this->first_name . ' ' . $this->last_name : '',
728
					'email'   => $this->email,
729
					'user_id' => $this->user_id,
730
				);
731
732
				$donor->create( $donor_data );
733
734
			}
735
736
			// Update Donor Meta once donor is created.
737
			$donor->update_meta( '_give_donor_first_name', $this->first_name );
738
			$donor->update_meta( '_give_donor_last_name', $this->last_name );
739
			$donor->update_meta( '_give_donor_title_prefix', $this->title_prefix );
740
741
			$this->customer_id            = $donor->id;
742
			$this->pending['customer_id'] = $this->customer_id;
743
			$donor->attach_payment( $this->ID, false );
744
745
			$this->payment_meta = apply_filters( 'give_payment_meta', $this->payment_meta, $payment_data );
746
747
			/**
748
			 * _give_payment_meta backward compatibility.
749
			 *
750
			 * @since 2.0.1
751
			 */
752
			$custom_payment_meta = array_diff(
753
				array_map( 'maybe_serialize', $this->payment_meta ),
754
				array_map( 'maybe_serialize', $payment_data )
755
			);
756
757
			if ( ! empty( $custom_payment_meta ) ) {
758
				give_doing_it_wrong( '_give_payment_meta', __( 'This custom meta key has been deprecated for performance reasons. Your custom meta data will still be stored but we recommend updating your code to store meta keys individually.', 'give' ), '2.0.0' );
759
760
				$this->update_meta( '_give_payment_meta', array_map( 'maybe_unserialize', $custom_payment_meta ) );
0 ignored issues
show
Documentation introduced by
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
			$give_company = ( ! empty( $_REQUEST['give_company_name'] ) ? give_clean( $_REQUEST['give_company_name'] ) : '' );
0 ignored issues
show
introduced by
Detected access of super global var $_REQUEST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_REQUEST
Loading history...
764
765
			// Check $page_url is not empty.
766
			if ( $give_company ) {
767
				give_update_meta( $payment_id, '_give_donation_company', $give_company );
768
769
				$donor_id = absint( $donor->id );
770
				if ( ! empty( $donor_id ) ) {
771
					Give()->donor_meta->update_meta( $donor_id, '_give_donor_company', $give_company );
772
				}
773
			}
774
775
			$this->new = true;
776
		} // End if().
777
778
		return $this->ID;
779
780
	}
781
782
	/**
783
	 * Save
784
	 *
785
	 * Once items have been set, an update is needed to save them to the database.
786
	 *
787
	 * @access public
788
	 *
789
	 * @return bool  True of the save occurred, false if it failed or wasn't needed
790
	 */
791
	public function save() {
792
		$saved = false;
793
794
		// Must have an ID.
795
		if ( empty( $this->ID ) ) {
796
797
			$payment_id = $this->insert_payment();
798
799
			if ( false === $payment_id ) {
800
				$saved = false;
801
			} else {
802
				$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
		}
805
806
		// Set ID if not matching.
807
		if ( $this->ID !== $this->_ID ) {
808
			$this->ID = $this->_ID;
809
		}
810
811
		// If we have something pending, let's save it.
812
		if ( ! empty( $this->pending ) ) {
813
814
			$total_increase = 0;
815
			$total_decrease = 0;
816
817
			foreach ( $this->pending as $key => $value ) {
818
819
				switch ( $key ) {
820
821
					case 'donations':
822
						// Update totals for pending donations.
823
						foreach ( $this->pending[ $key ] as $item ) {
824
825
							$quantity = isset( $item['quantity'] ) ? $item['quantity'] : 1;
826
							$price_id = isset( $item['price_id'] ) ? $item['price_id'] : 0;
827
828
							switch ( $item['action'] ) {
829
830
								case 'add':
831
832
									$price = $item['price'];
833
834
									if ( 'publish' === $this->status || 'complete' === $this->status ) {
835
836
										// Add donation to logs.
837
										$log_date = date_i18n( 'Y-m-d G:i:s', current_time( 'timestamp' ) );
838
										give_record_donation_in_log( $item['id'], $this->ID, $price_id, $log_date );
839
840
										$form = new Give_Donate_Form( $item['id'] );
841
										$form->increase_sales( $quantity );
842
										$form->increase_earnings( $price, $this->ID );
843
844
										$total_increase += $price;
845
									}
846
									break;
847
848
								case 'remove':
849
									$this->delete_sales_logs();
850
									if ( 'publish' === $this->status || 'complete' === $this->status ) {
851
										$form = new Give_Donate_Form( $item['id'] );
852
										$form->decrease_sales( $quantity );
853
										$form->decrease_earnings( $item['amount'], $this->ID );
854
855
										$total_decrease += $item['amount'];
856
									}
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
871
					case 'mode':
872
						$this->update_meta( '_give_payment_mode', $this->mode );
873
						break;
874
875
					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
						break;
882
883
					case 'customer_id':
884
						$this->update_meta( '_give_payment_donor_id', $this->customer_id );
885
						break;
886
887
					case 'form_title':
888
						$this->update_meta( '_give_payment_form_title', $this->form_title );
889
						break;
890
891
					case 'form_id':
892
						$this->update_meta( '_give_payment_form_id', $this->form_id );
893
						break;
894
895
					case 'price_id':
896
						$this->update_meta( '_give_payment_price_id', $this->price_id );
897
						break;
898
899
					case 'first_name':
900
						$this->update_meta( '_give_donor_billing_first_name', $this->first_name );
901
						break;
902
903
					case 'last_name':
904
						$this->update_meta( '_give_donor_billing_last_name', $this->last_name );
905
						break;
906
907
					case 'currency':
908
						$this->update_meta( '_give_payment_currency', $this->currency );
909
						break;
910
911
					case 'address':
912
						if ( ! empty( $this->address ) ) {
913
							foreach ( $this->address as $address_name => $address ) {
914
								switch ( $address_name ) {
915
									case 'line1':
916
										$this->update_meta( '_give_donor_billing_address1', $address );
917
										break;
918
919
									case 'line2':
920
										$this->update_meta( '_give_donor_billing_address2', $address );
921
										break;
922
923
									default:
924
										$this->update_meta( "_give_donor_billing_{$address_name}", $address );
925
								}
926
							}
927
						}
928
						break;
929
930
					case 'email':
931
						$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
						break;
937
938
					case 'key':
939
						$this->update_meta( '_give_payment_purchase_key', $this->key );
940
						break;
941
942
					case 'number':
943
						// @todo: remove unused meta data.
944
						// 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
						$this->update_meta( '_give_payment_number', $this->number );
947
						break;
948
949
					case 'date':
950
						$args = array(
951
							'ID'            => $this->ID,
952
							'post_date'     => date( 'Y-m-d H:i:s', strtotime( $this->date ) ),
953
							'post_date_gmt' => get_gmt_from_date( $this->date ),
954
							'edit_date'     => true,
955
						);
956
957
						wp_update_post( $args );
958
						break;
959
960
					case 'completed_date':
961
						$this->update_meta( '_give_completed_date', $this->completed_date );
962
						break;
963
964
					case 'parent_payment':
965
						$args = array(
966
							'ID'          => $this->ID,
967
							'post_parent' => $this->parent_payment,
968
						);
969
970
						wp_update_post( $args );
971
						break;
972
973
					case 'total':
974
						$this->update_meta( '_give_payment_total', give_sanitize_amount_for_db( $this->total ) );
975
						break;
976
977
					default:
978
						/**
979
						 * Fires while saving payment.
980
						 *
981
						 * @since 1.7
982
						 *
983
						 * @param Give_Payment $this Payment object.
984
						 */
985
						do_action( 'give_payment_save', $this, $key );
986
						break;
987
				} // End switch().
988
			} // End foreach().
989
990
			if ( 'pending' !== $this->status ) {
991
992
				$donor = new Give_Donor( $this->customer_id );
993
994
				$total_change = $total_increase - $total_decrease;
995
				if ( $total_change < 0 ) {
996
997
					$total_change = - ( $total_change );
998
999
					// Decrease the donor's donation stats.
1000
					$donor->decrease_value( $total_change );
1001
					give_decrease_total_earnings( $total_change );
1002
1003
					$donor->decrease_donation_count();
1004
1005
				} elseif ( $total_change > 0 ) {
1006
1007
					// Increase the donor's donation stats.
1008
					$donor->increase_value( $total_change );
1009
					give_increase_total_earnings( $total_change );
1010
1011
					$donor->increase_purchase_count();
1012
1013
				}
1014
1015
				// Verify and update form meta based on the form status.
1016
				give_set_form_closed_status( $this->form_id );
1017
			}
1018
1019
			$this->pending = array();
1020
			$saved         = true;
1021
		} // End if().
1022
1023
		if ( true === $saved ) {
1024
			$this->setup_payment( $this->ID );
1025
		}
1026
1027
		return $saved;
1028
	}
1029
1030
	/**
1031
	 * Add a donation to a given payment
1032
	 *
1033
	 * @since  1.5
1034
	 * @access public
1035
	 *
1036
	 * @param  int   $form_id The donation form to add.
1037
	 * @param  array $args    Other arguments to pass to the function.
1038
	 * @param  array $options List of donation options.
1039
	 *
1040
	 * @return bool           True when successful, false otherwise
1041
	 */
1042
	public function add_donation( $form_id = 0, $args = array(), $options = array() ) {
1043
1044
		$donation = new Give_Donate_Form( $form_id );
1045
1046
		// Bail if this post isn't a give donation form.
1047
		if ( ! $donation || 'give_forms' !== $donation->post_type ) {
1048
			return false;
1049
		}
1050
1051
		// Set some defaults.
1052
		$defaults = array(
1053
			'price'    => false,
1054
			'price_id' => false,
1055
		);
1056
1057
		$args = wp_parse_args( apply_filters( 'give_payment_add_donation_args', $args, $donation->ID ), $defaults );
1058
1059
		// Allow overriding the price.
1060
		if ( false !== $args['price'] ) {
1061
			$donation_amount = $args['price'];
1062
		} else {
1063
1064
			// Deal with variable pricing.
1065
			if ( give_has_variable_prices( $donation->ID ) ) {
1066
				$prices          = give_get_meta( $form_id, '_give_donation_levels', true );
1067
				$donation_amount = '';
1068
1069
				// Loop through prices.
1070 View Code Duplication
				foreach ( $prices as $price ) {
0 ignored issues
show
Duplication introduced by
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...
1071
					// Find a match between price_id and level_id.
1072
					// First verify array keys exists THEN make the match.
1073
					if (
1074
						isset( $args['price_id'] ) &&
1075
						isset( $price['_give_id']['level_id'] ) &&
1076
						$args['price_id'] === (int) $price['_give_id']['level_id']
1077
					) {
1078
						$donation_amount = $price['_give_amount'];
1079
					}
1080
				}
1081
1082
				// Fallback to the lowest price point.
1083
				if ( '' === $donation_amount ) {
1084
					$donation_amount  = give_get_lowest_price_option( $donation->ID );
1085
					$args['price_id'] = give_get_lowest_price_id( $donation->ID );
1086
				}
1087
			} else {
1088
				// Simple form price.
1089
				$donation_amount = give_get_form_price( $donation->ID );
1090
			}
1091
		}
1092
1093
		// Sanitizing the price here so we don't have a dozen calls later.
1094
		$donation_amount = give_maybe_sanitize_amount( $donation_amount );
1095
		$total           = round( $donation_amount, give_get_price_decimals( $this->ID ) );
1096
1097
		// Add Options.
1098
		$default_options = array();
1099
		if ( false !== $args['price_id'] ) {
1100
			$default_options['price_id'] = (int) $args['price_id'];
1101
		}
1102
		$options = wp_parse_args( $options, $default_options );
1103
1104
		// Do not allow totals to go negative.
1105
		if ( $total < 0 ) {
1106
			$total = 0;
1107
		}
1108
1109
		$donation = array(
1110
			'name'     => $donation->post_title,
1111
			'id'       => $donation->ID,
1112
			'price'    => round( $total, give_get_price_decimals( $this->ID ) ),
1113
			'subtotal' => round( $total, give_get_price_decimals( $this->ID ) ),
1114
			'price_id' => $args['price_id'],
1115
			'action'   => 'add',
1116
			'options'  => $options,
1117
		);
1118
1119
		$this->pending['donations'][] = $donation;
1120
1121
		$this->increase_subtotal( $total );
1122
1123
		return true;
1124
1125
	}
1126
1127
	/**
1128
	 * Remove a donation from the payment
1129
	 *
1130
	 * @since  1.5
1131
	 * @access public
1132
	 *
1133
	 * @param  int   $form_id The form ID to remove.
1134
	 * @param  array $args    Arguments to pass to identify (quantity, amount, price_id).
1135
	 *
1136
	 * @return bool           If the item was removed or not
1137
	 */
1138
	public function remove_donation( $form_id, $args = array() ) {
1139
1140
		// Set some defaults.
1141
		$defaults = array(
1142
			'quantity' => 1,
1143
			'price'    => false,
1144
			'price_id' => false,
1145
		);
1146
		$args     = wp_parse_args( $args, $defaults );
1147
1148
		$form = new Give_Donate_Form( $form_id );
1149
1150
		// Bail if this post isn't a valid give donation form.
1151
		if ( ! $form || 'give_forms' !== $form->post_type ) {
1152
			return false;
1153
		}
1154
1155
		$pending_args             = $args;
1156
		$pending_args['id']       = $form_id;
1157
		$pending_args['amount']   = $this->total;
1158
		$pending_args['price_id'] = false !== $args['price_id'] ? (int) $args['price_id'] : false;
1159
		$pending_args['quantity'] = $args['quantity'];
1160
		$pending_args['action']   = 'remove';
1161
1162
		$this->pending['donations'][] = $pending_args;
1163
1164
		$this->decrease_subtotal( $this->total );
1165
1166
		return true;
1167
	}
1168
1169
1170
	/**
1171
	 * Add a note to a payment
1172
	 *
1173
	 * @since  1.5
1174
	 * @access public
1175
	 *
1176
	 * @param  string|bool $note The note to add.
1177
	 *
1178
	 * @return bool           If the note was specified or not
1179
	 */
1180
	public function add_note( $note = false ) {
1181
		// Bail if no note specified.
1182
		if ( ! $note ) {
1183
			return false;
1184
		}
1185
1186
		give_insert_payment_note( $this->ID, $note );
0 ignored issues
show
Bug introduced by
It seems like $note defined by parameter $note on line 1180 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...
1187
	}
1188
1189
	/**
1190
	 * Increase the payment's subtotal
1191
	 *
1192
	 * @since  1.5
1193
	 * @access private
1194
	 *
1195
	 * @param  float $amount The amount to increase the payment subtotal by.
1196
	 *
1197
	 * @return void
1198
	 */
1199
	private function increase_subtotal( $amount = 0.00 ) {
1200
		$amount         = (float) $amount;
1201
		$this->subtotal += $amount;
1202
1203
		$this->recalculate_total();
1204
	}
1205
1206
	/**
1207
	 * Decrease the payment's subtotal.
1208
	 *
1209
	 * @since  1.5
1210
	 * @access private
1211
	 *
1212
	 * @param  float $amount The amount to decrease the payment subtotal by.
1213
	 *
1214
	 * @return void
1215
	 */
1216
	private function decrease_subtotal( $amount = 0.00 ) {
1217
		$amount         = (float) $amount;
1218
		$this->subtotal -= $amount;
1219
1220
		if ( $this->subtotal < 0 ) {
1221
			$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...
1222
		}
1223
1224
		$this->recalculate_total();
1225
	}
1226
1227
	/**
1228
	 * Set or update the total for a payment.
1229
	 *
1230
	 * @since  1.5
1231
	 * @since  2.1.4 reset total in pending property
1232
	 * @access private
1233
	 *
1234
	 * @return void
1235
	 */
1236
	private function recalculate_total() {
1237
		$this->pending['total'] = $this->total = $this->subtotal;
1238
	}
1239
1240
	/**
1241
	 * Set the payment status and run any status specific changes necessary.
1242
	 *
1243
	 * @since  1.5
1244
	 * @access public
1245
	 *
1246
	 * @param  string|bool $status The status to set the payment to.
1247
	 *
1248
	 * @return bool   $updated Returns if the status was successfully updated.
1249
	 */
1250
	public function update_status( $status = false ) {
1251
1252
		// standardize the 'complete(d)' status.
1253
		if ( 'completed' === $status || 'complete' === $status ) {
1254
			$status = 'publish';
1255
		}
1256
1257
		$old_status = ! empty( $this->old_status ) ? $this->old_status : false;
1258
1259
		if ( $old_status === $status ) {
1260
			return false; // Don't permit status changes that aren't changes.
1261
		}
1262
1263
		$do_change = apply_filters( 'give_should_update_payment_status', true, $this->ID, $status, $old_status );
1264
1265
		$updated = false;
1266
1267
		if ( $do_change ) {
1268
1269
			/**
1270
			 * Fires before changing payment status.
1271
			 *
1272
			 * @since 1.5
1273
			 *
1274
			 * @param int    $payment_id Payments ID.
1275
			 * @param string $status     The new status.
1276
			 * @param string $old_status The old status.
1277
			 */
1278
			do_action( 'give_before_payment_status_change', $this->ID, $status, $old_status );
1279
1280
			$update_fields = array(
1281
				'ID'          => $this->ID,
1282
				'post_status' => $status,
1283
				'edit_date'   => current_time( 'mysql' ),
1284
			);
1285
1286
			$updated = wp_update_post( apply_filters( 'give_update_payment_status_fields', $update_fields ) );
1287
1288
			$all_payment_statuses  = give_get_payment_statuses();
1289
			$this->status_nicename = array_key_exists( $status, $all_payment_statuses ) ? $all_payment_statuses[ $status ] : ucfirst( $status );
1290
1291
			// Process any specific status functions.
1292
			$this->process_status( $status );
0 ignored issues
show
Bug introduced by
It seems like $status defined by parameter $status on line 1250 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...
1293
1294
			/**
1295
			 * Fires after changing payment status.
1296
			 *
1297
			 * @since 1.5
1298
			 *
1299
			 * @param int    $payment_id Payment ID.
1300
			 * @param string $status     The new status.
1301
			 * @param string $old_status The old status.
1302
			 */
1303
			do_action( 'give_update_payment_status', $this->ID, $status, $old_status );
1304
1305
		} // End if().
1306
1307
		return $updated;
1308
1309
	}
1310
1311
	/**
1312
	 * Change the status of the payment to refunded, and run the necessary changes
1313
	 *
1314
	 * @since  1.5
1315
	 * @access public
1316
	 *
1317
	 * @return void
1318
	 */
1319
	public function refund() {
1320
		$this->old_status        = $this->status;
1321
		$this->status            = 'refunded';
1322
		$this->pending['status'] = $this->status;
1323
1324
		$this->save();
1325
	}
1326
1327
	/**
1328
	 * Get a post meta item for the payment
1329
	 *
1330
	 * @since  1.5
1331
	 * @access public
1332
	 *
1333
	 * @param  string  $meta_key The Meta Key.
1334
	 * @param  boolean $single   Return single item or array.
1335
	 *
1336
	 * @return mixed             The value from the post meta
1337
	 */
1338
	public function get_meta( $meta_key = '_give_payment_meta', $single = true ) {
1339
		if (
1340
			! has_filter( 'get_post_metadata', 'give_bc_v20_get_payment_meta' ) &&
1341
			! doing_filter( 'get_post_metadata' )
1342
		) {
1343
			add_filter( 'get_post_metadata', 'give_bc_v20_get_payment_meta', 999, 4 );
1344
		}
1345
1346
		$meta = give_get_meta( $this->ID, $meta_key, $single );
1347
1348
		/**
1349
		 * Filter the specific meta key value.
1350
		 *
1351
		 * @since 1.5
1352
		 */
1353
		$meta = apply_filters( "give_get_payment_meta_{$meta_key}", $meta, $this->ID );
1354
1355
		// Security check.
1356 View Code Duplication
		if ( is_serialized( $meta ) ) {
0 ignored issues
show
Duplication introduced by
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...
1357
			preg_match( '/[oO]\s*:\s*\d+\s*:\s*"\s*(?!(?i)(stdClass))/', $meta, $matches );
1358
			if ( ! empty( $matches ) ) {
1359
				$meta = array();
1360
			}
1361
		}
1362
1363
		/**
1364
		 * Filter the all meta keys.
1365
		 *
1366
		 * @since 1.5
1367
		 */
1368
		return apply_filters( 'give_get_payment_meta', $meta, $this->ID, $meta_key );
1369
	}
1370
1371
	/**
1372
	 * Update the post meta
1373
	 *
1374
	 * @since  1.5
1375
	 * @access public
1376
	 *
1377
	 * @param  string $meta_key   The meta key to update.
1378
	 * @param  string $meta_value The meta value.
1379
	 * @param  string $prev_value Previous meta value.
1380
	 *
1381
	 * @return int|bool           Meta ID if the key didn't exist, true on successful update, false on failure
1382
	 */
1383
	public function update_meta( $meta_key = '', $meta_value = '', $prev_value = '' ) {
1384
		if ( empty( $meta_key ) ) {
1385
			return false;
1386
		}
1387
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
1388
1389
		/**
1390
		 * Filter the single meta key while updating
1391
		 *
1392
		 * @since 1.5
1393
		 */
1394
		$meta_value = apply_filters( "give_update_payment_meta_{$meta_key}", $meta_value, $this->ID );
1395
1396
		return give_update_meta( $this->ID, $meta_key, $meta_value, $prev_value );
1397
	}
1398
1399
	/**
1400
	 * Process Donation Status.
1401
	 *
1402
	 * @param string $status Donation Status.
1403
	 *
1404
	 * @since  2.0.2
1405
	 * @access private
1406
	 *
1407
	 * @return void
1408
	 */
1409
	private function process_status( $status ) {
1410
		$process = true;
1411
1412
		// Bailout, if changed from completed to preapproval/processing.
1413
		// Bailout, if current status = previous status or status is publish.
1414
		if (
1415
			'preapproval' === $status ||
1416
			'processing' === $status ||
1417
			'publish' !== $this->old_status ||
1418
			$status !== $this->status
1419
		) {
1420
			$process = false;
1421
		}
1422
1423
		// Allow extensions to filter for their own payment types, Example: Recurring Payments.
1424
		$process = apply_filters( "give_should_process_{$status}", $process, $this );
1425
1426
		if ( false === $process ) {
1427
			return;
1428
		}
1429
1430
		/**
1431
		 * Fires before processing donation status.
1432
		 *
1433
		 * @param Give_Payment $this Payment object.
1434
		 *
1435
		 * @since 1.5
1436
		 */
1437
		do_action( "give_pre_{$status}_payment", $this );
1438
1439
		$decrease_earnings       = apply_filters( "give_decrease_earnings_on_{$status}", true, $this );
1440
		$decrease_donor_value    = apply_filters( "give_decrease_donor_value_on_{$status}", true, $this );
1441
		$decrease_donation_count = apply_filters( "give_decrease_donors_donation_count_on_{$status}", true, $this );
1442
1443
		$this->maybe_alter_stats( $decrease_earnings, $decrease_donor_value, $decrease_donation_count );
1444
		$this->delete_sales_logs();
1445
1446
		// @todo: Refresh only range related stat cache
1447
		give_delete_donation_stats();
1448
1449
		/**
1450
		 * Fires after processing donation status.
1451
		 *
1452
		 * @param Give_Payment $this Payment object.
1453
		 *
1454
		 * @since 1.5
1455
		 */
1456
		do_action( "give_post_{$status}_payment", $this );
1457
	}
1458
1459
	/**
1460
	 * Used during the process of moving to refunded or pending, to decrement stats
1461
	 *
1462
	 * @since  1.5
1463
	 * @access private
1464
	 *
1465
	 * @param  bool $alter_store_earnings          If the method should alter the store earnings.
1466
	 * @param  bool $alter_customer_value          If the method should reduce the donor value.
1467
	 * @param  bool $alter_customer_purchase_count If the method should reduce the donor's purchase count.
1468
	 *
1469
	 * @return void
1470
	 */
1471
	private function maybe_alter_stats( $alter_store_earnings, $alter_customer_value, $alter_customer_purchase_count ) {
1472
1473
		give_undo_donation( $this->ID );
1474
1475
		// Decrease store earnings.
1476
		if ( true === $alter_store_earnings ) {
1477
			give_decrease_total_earnings( $this->total );
1478
		}
1479
1480
		// Decrement the stats for the donor.
1481
		if ( ! empty( $this->customer_id ) ) {
1482
1483
			$donor = new Give_Donor( $this->customer_id );
1484
1485
			if ( true === $alter_customer_value ) {
1486
				$donor->decrease_value( $this->total );
1487
			}
1488
1489
			if ( true === $alter_customer_purchase_count ) {
1490
				$donor->decrease_donation_count();
1491
			}
1492
		}
1493
1494
	}
1495
1496
	/**
1497
	 * Delete sales logs for this donation
1498
	 *
1499
	 * @since  1.5
1500
	 * @access private
1501
	 *
1502
	 * @return void
1503
	 */
1504
	private function delete_sales_logs() {
1505
		// Remove related sale log entries.
1506
		Give()->logs->delete_logs( $this->ID );
1507
	}
1508
1509
	/**
1510
	 * Setup functions only, these are not to be used by developers.
1511
	 * These functions exist only to allow the setup routine to be backwards compatible with our old
1512
	 * helper functions.
1513
	 *
1514
	 * These will run whenever setup_payment is called, which should only be called once.
1515
	 * To update an attribute, update it directly instead of re-running the setup routine
1516
	 */
1517
1518
	/**
1519
	 * Setup the payment completed date
1520
	 *
1521
	 * @since  1.5
1522
	 * @access private
1523
	 *
1524
	 * @return string The date the payment was completed
1525
	 */
1526
	private function setup_completed_date() {
1527
		$payment = get_post( $this->ID );
1528
1529
		if ( 'pending' === $payment->post_status || 'preapproved' === $payment->post_status ) {
1530
			return false; // This payment was never completed.
1531
		}
1532
1533
		$date = ( $date = $this->get_meta( '_give_completed_date', true ) ) ? $date : $payment->modified_date;
1534
1535
		return $date;
1536
	}
1537
1538
	/**
1539
	 * Setup the payment mode
1540
	 *
1541
	 * @since  1.5
1542
	 * @access private
1543
	 *
1544
	 * @return string The payment mode
1545
	 */
1546
	private function setup_mode() {
1547
		return $this->get_meta( '_give_payment_mode' );
1548
	}
1549
1550
	/**
1551
	 * Setup the payment import data
1552
	 *
1553
	 * @since  1.8.13
1554
	 * @access private
1555
	 *
1556
	 * @return bool The payment import
1557
	 */
1558
	private function setup_import() {
1559
		return (bool) $this->get_meta( '_give_payment_import' );
1560
	}
1561
1562
	/**
1563
	 * Setup the payment total
1564
	 *
1565
	 * @since  1.5
1566
	 * @access private
1567
	 *
1568
	 * @return float The payment total
1569
	 */
1570
	private function setup_total() {
1571
		$amount = $this->get_meta( '_give_payment_total', true );
1572
1573
		return round( floatval( $amount ), give_get_price_decimals( $this->ID ) );
1574
	}
1575
1576
	/**
1577
	 * Setup the payment subtotal
1578
	 *
1579
	 * @since  1.5
1580
	 * @access private
1581
	 *
1582
	 * @return float The subtotal of the payment
1583
	 */
1584
	private function setup_subtotal() {
1585
		$subtotal = $this->total;
1586
1587
		return $subtotal;
1588
	}
1589
1590
	/**
1591
	 * Setup the currency code
1592
	 *
1593
	 * @since  1.5
1594
	 * @since  2.0 Set currency from _give_payment_currency meta key
1595
	 * @access private
1596
	 *
1597
	 * @return string The currency for the payment
1598
	 */
1599 View Code Duplication
	private function setup_currency() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1600
		$currency = $this->get_meta( '_give_payment_currency', true );
1601
		$currency = ! empty( $currency ) ?
1602
			$currency :
1603
			/**
1604
			 * Filter the default donation currency
1605
			 *
1606
			 * @since 1.5
1607
			 */
1608
			apply_filters(
1609
				'give_payment_currency_default',
1610
				give_get_currency( $this->form_id, $this ),
1611
				$this
1612
			);
1613
1614
		return $currency;
1615
	}
1616
1617
	/**
1618
	 * Setup the gateway used for the payment
1619
	 *
1620
	 * @since  1.5
1621
	 * @access private
1622
	 *
1623
	 * @return string The gateway
1624
	 */
1625
	private function setup_gateway() {
1626
		$gateway = $this->get_meta( '_give_payment_gateway', true );
1627
1628
		return $gateway;
1629
	}
1630
1631
	/**
1632
	 * Setup the donation ID
1633
	 *
1634
	 * @since  1.5
1635
	 * @access private
1636
	 *
1637
	 * @return string The donation ID
1638
	 */
1639 View Code Duplication
	private function setup_transaction_id() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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

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

Loading history...
1640
		$transaction_id = $this->get_meta( '_give_payment_transaction_id', true );
1641
1642
		if ( empty( $transaction_id ) ) {
1643
			$gateway        = $this->gateway;
1644
			$transaction_id = apply_filters( "give_get_payment_transaction_id-{$gateway}", $this->ID );
1645
		}
1646
1647
		return $transaction_id;
1648
	}
1649
1650
	/**
1651
	 * Setup the IP Address for the payment
1652
	 *
1653
	 * @since  1.5
1654
	 * @since  2.0 Set ip address from _give_payment_donor_ip meta key
1655
	 * @access private
1656
	 *
1657
	 * @return string The IP address for the payment
1658
	 */
1659
	private function setup_ip() {
1660
		$ip = $this->get_meta( '_give_payment_donor_ip', true );
1661
1662
		return $ip;
1663
	}
1664
1665
	/**
1666
	 * Setup the donor ID.
1667
	 *
1668
	 * @since  1.5
1669
	 * @since  2.0 Set id from _give_payment_donor_id meta key
1670
	 * @access private
1671
	 *
1672
	 * @return int The Donor ID.
1673
	 */
1674
	private function setup_donor_id() {
1675
		$donor_id = $this->get_meta( '_give_payment_donor_id', true );
1676
1677
		return $donor_id;
1678
	}
1679
1680
	/**
1681
	 * Setup the User ID associated with the donation
1682
	 *
1683
	 * @since  1.5
1684
	 * @since  2.0 Get user id connect to donor from donor table instead of payment meta.
1685
	 *
1686
	 * @access private
1687
	 *
1688
	 * @return int The User ID
1689
	 */
1690
	private function setup_user_id() {
1691
1692
		$donor   = Give()->customers->get_customer_by( 'id', $this->customer_id );
1693
		$user_id = $donor ? absint( $donor->user_id ) : 0;
1694
0 ignored issues
show
Coding Style introduced by
Functions must not contain multiple empty lines in a row; found 2 empty lines
Loading history...
1695
1696
		return $user_id;
1697
	}
1698
1699
	/**
1700
	 * Setup the email address for the donation.
1701
	 *
1702
	 * @since  1.5
1703
	 * @since  2.0 Set email from _give_payment_donor_email meta key
1704
	 *
1705
	 * @access private
1706
	 *
1707
	 * @return string The email address for the payment.
1708
	 */
1709
	private function setup_email() {
1710
		$email = $this->get_meta( '_give_payment_donor_email', true );
1711
1712
		if ( empty( $email ) && $this->customer_id ) {
1713
			$email = Give()->donors->get_column( 'email', $this->customer_id );
1714
		}
1715
1716
		return $email;
1717
	}
1718
1719
	/**
1720
	 * Setup the user info.
1721
	 *
1722
	 * @since  1.5
1723
	 * @access private
1724
	 *
1725
	 * @return array The user info associated with the payment.
1726
	 */
1727
	private function setup_user_info() {
1728
		$defaults = array(
1729
			'title'      => $this->title_prefix,
1730
			'first_name' => $this->first_name,
1731
			'last_name'  => $this->last_name,
1732
		);
1733
1734
		$user_info = isset( $this->payment_meta['user_info'] ) ? $this->payment_meta['user_info'] : array();
1735
1736 View Code Duplication
		if ( is_serialized( $user_info ) ) {
0 ignored issues
show
Duplication introduced by
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...
1737
			preg_match( '/[oO]\s*:\s*\d+\s*:\s*"\s*(?!(?i)(stdClass))/', $user_info, $matches );
1738
			if ( ! empty( $matches ) ) {
1739
				$user_info = array();
1740
			}
1741
		}
1742
1743
		$user_info = wp_parse_args( $user_info, $defaults );
1744
1745
		if ( empty( $user_info ) ) {
1746
			// Get the donor, but only if it's been created.
1747
			$donor = new Give_Donor( $this->customer_id );
1748
1749
			if ( $donor->id > 0 ) {
1750
				$user_info = array(
1751
					'first_name' => $donor->get_first_name(),
1752
					'last_name'  => $donor->get_last_name(),
1753
					'email'      => $donor->email,
1754
					'discount'   => 'none',
1755
				);
1756
			}
1757
		} else {
1758
			// Get the donor, but only if it's been created.
1759
			$donor = new Give_Donor( $this->customer_id );
1760
1761
			if ( $donor->id > 0 ) {
1762
				foreach ( $user_info as $key => $value ) {
1763
					if ( ! empty( $value ) ) {
1764
						continue;
1765
					}
1766
1767
					switch ( $key ) {
1768
						case 'title':
1769
							$user_info[ $key ] = Give()->donor_meta->get_meta( $donor->id, '_give_donor_title_prefix', true );
1770
							break;
1771
1772
						case 'first_name':
1773
							$user_info[ $key ] = $donor->get_first_name();
1774
							break;
1775
1776
						case 'last_name':
1777
							$user_info[ $key ] = $donor->get_last_name();
1778
							break;
1779
1780
						case 'email':
1781
							$user_info[ $key ] = $donor->email;
1782
							break;
1783
					}
1784
				}
1785
			}
1786
		}// End if().
1787
1788
		return $user_info;
1789
1790
	}
1791
1792
	/**
1793
	 * Setup the Address for the payment.
1794
	 *
1795
	 * @since  1.5
1796
	 * @access private
1797
	 *
1798
	 * @return array The Address information for the payment.
1799
	 */
1800
	private function setup_address() {
1801
		$address['line1']   = give_get_meta( $this->ID, '_give_donor_billing_address1', true, '' );
0 ignored issues
show
Documentation introduced by
'' 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['line2']   = give_get_meta( $this->ID, '_give_donor_billing_address2', true, '' );
0 ignored issues
show
Documentation introduced by
'' 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['city']    = give_get_meta( $this->ID, '_give_donor_billing_city', true, '' );
0 ignored issues
show
Documentation introduced by
'' 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['state']   = give_get_meta( $this->ID, '_give_donor_billing_state', true, '' );
0 ignored issues
show
Documentation introduced by
'' 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['zip']     = give_get_meta( $this->ID, '_give_donor_billing_zip', true, '' );
0 ignored issues
show
Documentation introduced by
'' 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
		$address['country'] = give_get_meta( $this->ID, '_give_donor_billing_country', true, '' );
0 ignored issues
show
Documentation introduced by
'' 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...
1807
1808
		return $address;
1809
	}
1810
1811
	/**
1812
	 * Setup the form title.
1813
	 *
1814
	 * @since  1.5
1815
	 * @access private
1816
	 *
1817
	 * @return string The Form Title.
1818
	 */
1819
	private function setup_form_title() {
1820
1821
		$form_id = $this->get_meta( '_give_payment_form_title', true );
1822
1823
		return $form_id;
1824
	}
1825
1826
	/**
1827
	 * Setup the form ID.
1828
	 *
1829
	 * @since  1.5
1830
	 * @access private
1831
	 *
1832
	 * @return int The Form ID
1833
	 */
1834
	private function setup_form_id() {
1835
1836
		$form_id = $this->get_meta( '_give_payment_form_id', true );
1837
1838
		return $form_id;
1839
	}
1840
1841
	/**
1842
	 * Setup the price ID.
1843
	 *
1844
	 * @since  1.5
1845
	 * @access private
1846
	 *
1847
	 * @return int The Form Price ID.
1848
	 */
1849
	private function setup_price_id() {
1850
		$price_id = $this->get_meta( '_give_payment_price_id', true );
1851
1852
		return $price_id;
1853
	}
1854
1855
	/**
1856
	 * Setup the payment key.
1857
	 *
1858
	 * @since  1.5
1859
	 * @access private
1860
	 *
1861
	 * @return string The Payment Key.
1862
	 */
1863
	private function setup_payment_key() {
1864
		$key = $this->get_meta( '_give_payment_purchase_key', true );
1865
1866
		return $key;
1867
	}
1868
1869
	/**
1870
	 * Setup the payment number.
1871
	 *
1872
	 * @since  1.5
1873
	 * @access private
1874
	 *
1875
	 * @return int|string Integer by default, or string if sequential order numbers is enabled.
1876
	 */
1877
	private function setup_payment_number() {
1878
		return $this->get_serial_code();
1879
	}
1880
1881
	/**
1882
	 * Converts this object into an array for special cases.
1883
	 *
1884
	 * @access public
1885
	 *
1886
	 * @return array The payment object as an array.
1887
	 */
1888
	public function array_convert() {
1889
		return get_object_vars( $this );
1890
	}
1891
1892
1893
	/**
1894
	 * Flag to check if donation is completed or not.
1895
	 *
1896
	 * @since  1.8
1897
	 * @access public
1898
	 *
1899
	 * @return bool
1900
	 */
1901
	public function is_completed() {
1902
		return ( 'publish' === $this->status && $this->completed_date );
1903
	}
1904
1905
	/**
1906
	 * Retrieve payment completion date.
1907
	 *
1908
	 * @since  1.5
1909
	 * @access private
1910
	 *
1911
	 * @return string Date payment was completed.
1912
	 */
1913
	private function get_completed_date() {
1914
		return apply_filters( 'give_payment_completed_date', $this->completed_date, $this->ID, $this );
1915
	}
1916
1917
	/**
1918
	 * Retrieve payment subtotal.
1919
	 *
1920
	 * @since  1.5
1921
	 * @access private
1922
	 *
1923
	 * @return float Payment subtotal.
1924
	 */
1925
	private function get_subtotal() {
1926
		return apply_filters( 'give_get_payment_subtotal', $this->subtotal, $this->ID, $this );
1927
	}
1928
1929
	/**
1930
	 * Retrieve payment currency.
1931
	 *
1932
	 * @since  1.5
1933
	 * @access private
1934
	 *
1935
	 * @return string Payment currency code.
1936
	 */
1937
	private function get_currency() {
1938
		return apply_filters( 'give_payment_currency_code', $this->currency, $this->ID, $this );
1939
	}
1940
1941
	/**
1942
	 * Retrieve payment gateway.
1943
	 *
1944
	 * @since  1.5
1945
	 * @access private
1946
	 *
1947
	 * @return string Gateway used.
1948
	 */
1949
	private function get_gateway() {
1950
		return apply_filters( 'give_payment_gateway', $this->gateway, $this->ID, $this );
1951
	}
1952
1953
	/**
1954
	 * Retrieve donation ID.
1955
	 *
1956
	 * @since  1.5
1957
	 * @access private
1958
	 *
1959
	 * @return string Donation ID from merchant processor.
1960
	 */
1961
	private function get_transaction_id() {
1962
		return apply_filters( 'give_get_payment_transaction_id', $this->transaction_id, $this->ID, $this );
1963
	}
1964
1965
	/**
1966
	 * Retrieve payment IP
1967
	 *
1968
	 * @since  1.5
1969
	 * @access private
1970
	 *
1971
	 * @return string Payment IP address
1972
	 */
1973
	private function get_ip() {
1974
		return apply_filters( 'give_payment_user_ip', $this->ip, $this->ID, $this );
1975
	}
1976
1977
	/**
1978
	 * Retrieve payment donor ID.
1979
	 *
1980
	 * @since  1.5
1981
	 * @access private
1982
	 *
1983
	 * @return int Payment donor ID.
1984
	 */
1985
	private function get_donor_id() {
1986
		return apply_filters( 'give_payment_customer_id', $this->customer_id, $this->ID, $this );
1987
	}
1988
1989
	/**
1990
	 * Retrieve payment user ID.
1991
	 *
1992
	 * @since  1.5
1993
	 * @access private
1994
	 *
1995
	 * @return int Payment user ID.
1996
	 */
1997
	private function get_user_id() {
1998
		return apply_filters( 'give_payment_user_id', $this->user_id, $this->ID, $this );
1999
	}
2000
2001
	/**
2002
	 * Retrieve payment email.
2003
	 *
2004
	 * @since  1.5
2005
	 * @access private
2006
	 *
2007
	 * @return string Payment donor email.
2008
	 */
2009
	private function get_email() {
2010
		return apply_filters( 'give_payment_user_email', $this->email, $this->ID, $this );
2011
	}
2012
2013
	/**
2014
	 * Retrieve payment user info.
2015
	 *
2016
	 * @since  1.5
2017
	 * @access private
2018
	 *
2019
	 * @return array Payment user info.
2020
	 */
2021
	private function get_user_info() {
2022
		return apply_filters( 'give_payment_meta_user_info', $this->user_info, $this->ID, $this );
2023
	}
2024
2025
	/**
2026
	 * Retrieve payment billing address.
2027
	 *
2028
	 * @since  1.5
2029
	 * @access private
2030
	 *
2031
	 * @return array Payment billing address.
2032
	 */
2033
	private function get_address() {
2034
		return apply_filters( 'give_payment_address', $this->address, $this->ID, $this );
2035
	}
2036
2037
	/**
2038
	 * Retrieve payment key.
2039
	 *
2040
	 * @since  1.5
2041
	 * @access private
2042
	 *
2043
	 * @return string Payment key.
2044
	 */
2045
	private function get_key() {
2046
		return apply_filters( 'give_payment_key', $this->key, $this->ID, $this );
2047
	}
2048
2049
	/**
2050
	 * Retrieve payment form id
2051
	 *
2052
	 * @since  1.5
2053
	 * @access private
2054
	 *
2055
	 * @return string Payment form id
2056
	 */
2057
	private function get_form_id() {
2058
		return apply_filters( 'give_payment_form_id', $this->form_id, $this->ID, $this );
2059
	}
2060
2061
	/**
2062
	 * Retrieve payment number
2063
	 *
2064
	 * @since  1.5
2065
	 * @access private
2066
	 *
2067
	 * @return int|string Payment number
2068
	 */
2069
	private function get_number() {
2070
		return apply_filters( 'give_payment_number', $this->number, $this->ID, $this );
2071
	}
2072
2073
	/**
2074
	 * Get serial code
2075
	 *
2076
	 * @since 2.1
2077
	 *
2078
	 * @param array $args List of arguments.
2079
	 *
2080
	 * @return string
2081
	 */
2082
	public function get_serial_code( $args = array() ) {
2083
		return Give()->seq_donation_number->get_serial_code( $this, $args );
2084
	}
2085
}
2086