Passed
Push — master ( d57dff...81fed3 )
by Brian
05:18
created

GetPaid_Payment_Gateway::get_confirm_payment()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 18
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 7
c 1
b 0
f 0
dl 0
loc 18
rs 10
cc 4
nc 3
nop 1
1
<?php
2
/**
3
 * Abstract payment gateway
4
 *
5
 */
6
7
defined( 'ABSPATH' ) || exit;
8
9
/**
10
 * Abstaract Payment Gateway class.
11
 *
12
 * Extended by individual payment gateways to handle payments.
13
 */
14
abstract class GetPaid_Payment_Gateway {
15
16
	/**
17
	 * Set if the place checkout button should be renamed on selection.
18
	 *
19
	 * @var string
20
	 */
21
	public $checkout_button_text;
22
23
	/**
24
	 * Boolean whether the method is enabled.
25
	 *
26
	 * @var bool
27
	 */
28
	public $enabled = true;
29
30
	/**
31
	 * Payment method id.
32
	 *
33
	 * @var string
34
	 */
35
	public $id;
36
37
	/**
38
	 * Payment method order.
39
	 *
40
	 * @var int
41
	 */
42
	public $order = 10;
43
44
	/**
45
	 * Payment method title for the frontend.
46
	 *
47
	 * @var string
48
	 */
49
	public $title;
50
51
	/**
52
	 * Payment method description for the frontend.
53
	 *
54
	 * @var string
55
	 */
56
	public $description;
57
58
	/**
59
	 * Gateway title.
60
	 *
61
	 * @var string
62
	 */
63
	public $method_title = '';
64
65
	/**
66
	 * Gateway description.
67
	 *
68
	 * @var string
69
	 */
70
	public $method_description = '';
71
72
	/**
73
	 * Countries this gateway is allowed for.
74
	 *
75
	 * @var array
76
	 */
77
	public $countries;
78
79
	/**
80
	 * Currencies this gateway is allowed for.
81
	 *
82
	 * @var array
83
	 */
84
	public $currencies;
85
86
	/**
87
	 * Currencies this gateway is not allowed for.
88
	 *
89
	 * @var array
90
	 */
91
	public $exclude_currencies;
92
93
	/**
94
	 * Maximum transaction amount, zero does not define a maximum.
95
	 *
96
	 * @var int
97
	 */
98
	public $max_amount = 0;
99
100
	/**
101
	 * Optional URL to view a transaction.
102
	 *
103
	 * @var string
104
	 */
105
	public $view_transaction_url = '';
106
107
	/**
108
	 * Optional URL to view a subscription.
109
	 *
110
	 * @var string
111
	 */
112
	public $view_subscription_url = '';
113
114
	/**
115
	 * Optional label to show for "new payment method" in the payment
116
	 * method/token selection radio selection.
117
	 *
118
	 * @var string
119
	 */
120
	public $new_method_label = '';
121
122
	/**
123
	 * Contains a user's saved tokens for this gateway.
124
	 *
125
	 * @var array
126
	 */
127
	protected $tokens = array();
128
129
	/**
130
	 * An array of features that this gateway supports.
131
	 *
132
	 * @var array
133
	 */
134
	protected $supports = array();
135
136
	/**
137
	 * Class constructor.
138
	 */
139
	public function __construct() {
140
		$this->enabled = wpinv_is_gateway_active( $this->id );
141
142
		// Register gateway.
143
		add_filter( 'wpinv_payment_gateways', array( $this, 'register_gateway' ) );
144
145
		// Enable Subscriptions.
146
		if ( $this->supports( 'subscription' ) ) {
147
			add_filter( "wpinv_{$this->id}_support_subscription", '__return_true' );
148
		}
149
150
		// Enable sandbox.
151
		if ( $this->supports( 'sandbox' ) ) {
152
			add_filter( "wpinv_{$this->id}_supports_sandbox", '__return_true' );
153
		}
154
155
		// Gateway settings.
156
		add_filter( "wpinv_gateway_settings_{$this->id}", array( $this, 'admin_settings' ) );
157
		
158
159
		// Gateway checkout fiellds.
160
		add_action( "wpinv_{$this->id}_cc_form", array( $this, 'payment_fields' ), 10, 2 );
161
162
		// Process payment.
163
		add_action( "getpaid_gateway_{$this->id}", array( $this, 'process_payment' ), 10, 3 );
164
165
		// Change the checkout button text.
166
		if ( ! empty( $this->checkout_button_text ) ) {
167
			add_filter( "getpaid_gateway_{$this->id}_checkout_button_label", array( $this, 'rename_checkout_button' ) );
168
		}
169
170
		// Check if a gateway is valid for a given currency.
171
		add_filter( "getpaid_gateway_{$this->id}_is_valid_for_currency", array( $this, 'validate_currency' ), 10, 2 );
172
173
		// Generate the transaction url.
174
		add_filter( "getpaid_gateway_{$this->id}_transaction_url", array( $this, 'filter_transaction_url' ), 10, 2 );
175
176
		// Generate the subscription url.
177
		add_filter( "getpaid_gateway_{$this->id}_subscription_url", array( $this, 'filter_subscription_url' ), 10, 2 );
178
179
		// Confirm payments.
180
		add_filter( "wpinv_payment_confirm_{$this->id}", array( $this, 'confirm_payment' ), 10, 2 );
181
182
		// Verify IPNs.
183
		add_action( "wpinv_verify_{$this->id}_ipn", array( $this, 'verify_ipn' ) );
184
185
	}
186
187
	/**
188
	 * Checks if this gateway is a given gateway.
189
	 *
190
	 * @since 1.0.19
191
	 * @return bool
192
	 */
193
	public function is( $gateway ) {
194
		return $gateway == $this->id;
195
	}
196
197
	/**
198
	 * Returns a users saved tokens for this gateway.
199
	 *
200
	 * @since 1.0.19
201
	 * @return array
202
	 */
203
	public function get_tokens( $sandbox = null ) {
204
205
		if ( is_user_logged_in() && $this->supports( 'tokens' ) && 0 == count( $this->tokens ) ) {
206
			$tokens = get_user_meta( get_current_user_id(), "getpaid_{$this->id}_tokens", true );
207
208
			if ( is_array( $tokens ) ) {
209
				$this->tokens = $tokens;
210
			}
211
212
		}
213
214
		if ( ! is_bool( $sandbox ) ) {
215
			return $this->tokens;
216
		}
217
218
		$args = array( 'type' => $sandbox ? 'sandbox' : 'live' );
219
		return wp_list_filter( $this->tokens, $args );
220
221
	}
222
223
	/**
224
	 * Saves a token for this gateway.
225
	 *
226
	 * @since 1.0.19
227
	 */
228
	public function save_token( $token ) {
229
230
		$tokens   = $this->get_tokens();
231
		$tokens[] = $token;
232
233
		update_user_meta( get_current_user_id(), "getpaid_{$this->id}_tokens", $tokens );
234
235
		$this->tokens = $tokens;
236
237
	}
238
239
	/**
240
	 * Return the title for admin screens.
241
	 *
242
	 * @return string
243
	 */
244
	public function get_method_title() {
245
		return apply_filters( 'getpaid_gateway_method_title', $this->method_title, $this );
246
	}
247
248
	/**
249
	 * Return the description for admin screens.
250
	 *
251
	 * @return string
252
	 */
253
	public function get_method_description() {
254
		return apply_filters( 'getpaid_gateway_method_description', $this->method_description, $this );
255
	}
256
257
	/**
258
	 * Get the success url.
259
	 *
260
	 * @param WPInv_Invoice $invoice Invoice object.
261
	 * @return string
262
	 */
263
	public function get_return_url( $invoice ) {
264
265
		// Payment success url
266
		$return_url = add_query_arg(
267
			array(
268
				'payment-confirm' => $this->id,
269
				'invoice_key'     => $invoice->get_key(),
270
				'utm_nooverride'  => 1
271
			),
272
			wpinv_get_success_page_uri()
273
		);
274
275
		return apply_filters( 'getpaid_gateway_success_url', $return_url, $invoice, $this );
276
	}
277
278
	/**
279
	 * Confirms payments when rendering the success page.
280
	 *
281
	 * @param string $content Success page content.
282
	 * @return string
283
	 */
284
	public function confirm_payment( $content ) {
285
286
		// Retrieve the invoice.
287
		$invoice_id = getpaid_get_current_invoice_id();
288
		$invoice    = wpinv_get_invoice( $invoice_id );
289
290
		// Ensure that it exists and that it is pending payment.
291
		if ( empty( $invoice_id ) || ! $invoice->needs_payment() ) {
292
			return $content;
293
		}
294
295
		// Can the user view this invoice??
296
		if ( ! wpinv_user_can_view_invoice( $invoice ) ) {
297
			return $content;
298
		}
299
300
		// Show payment processing indicator.
301
		return wpinv_get_template_html( 'wpinv-payment-processing.php', compact( 'invoice' ) );
302
	}
303
304
	/**
305
	 * Processes ipns and marks payments as complete.
306
	 *
307
	 * @return void
308
	 */
309
	public function verify_ipn() {}
310
311
	/**
312
	 * Get a link to the transaction on the 3rd party gateway site (if applicable).
313
	 *
314
	 * @param string $transaction_url transaction url.
315
	 * @param WPInv_Invoice $invoice Invoice object.
316
	 * @return string transaction URL, or empty string.
317
	 */
318
	public function filter_transaction_url( $transaction_url, $invoice ) {
319
320
		$transaction_id  = $invoice->get_transaction_id();
321
322
		if ( ! empty( $this->view_transaction_url ) && ! empty( $transaction_id ) ) {
323
			$transaction_url = sprintf( $this->view_transaction_url, $transaction_id );
324
			$replace         = $this->is_sandbox( $invoice ) ? 'sandbox' : '';
325
			$transaction_url = str_replace( '{sandbox}', $replace, $transaction_url );
326
		}
327
328
		return $transaction_url;
329
	}
330
331
	/**
332
	 * Get a link to the subscription on the 3rd party gateway site (if applicable).
333
	 *
334
	 * @param string $subscription_url transaction url.
335
	 * @param WPInv_Invoice $invoice Invoice object.
336
	 * @return string subscription URL, or empty string.
337
	 */
338
	public function filter_subscription_url( $subscription_url, $invoice ) {
339
340
		$profile_id      = $invoice->get_subscription_id();
341
342
		if ( ! empty( $this->view_subscription_url ) && ! empty( $profile_id ) ) {
343
344
			$subscription_url = sprintf( $this->view_subscription_url, $profile_id );
345
			$replace          = $this->is_sandbox( $invoice ) ? 'sandbox' : '';
346
			$subscription_url = str_replace( '{sandbox}', $replace, $subscription_url );
347
348
		}
349
350
		return $subscription_url;
351
	}
352
353
	/**
354
	 * Check if the gateway is available for use.
355
	 *
356
	 * @return bool
357
	 */
358
	public function is_available() {
359
		return ! empty( $this->enabled );
360
	}
361
362
	/**
363
	 * Return the gateway's title.
364
	 *
365
	 * @return string
366
	 */
367
	public function get_title() {
368
		return apply_filters( 'getpaid_gateway_title', $this->title, $this );
369
	}
370
371
	/**
372
	 * Return the gateway's description.
373
	 *
374
	 * @return string
375
	 */
376
	public function get_description() {
377
		return apply_filters( 'getpaid_gateway_description', $this->description, $this );
378
	}
379
380
	/**
381
	 * Process Payment.
382
	 *
383
	 *
384
	 * @param WPInv_Invoice $invoice Invoice.
385
	 * @param array $submission_data Posted checkout fields.
386
	 * @param GetPaid_Payment_Form_Submission $submission Checkout submission.
387
	 * @return void
388
	 */
389
	public function process_payment( $invoice, $submission_data, $submission ) {
390
		// Process the payment then either redirect to the success page or the gateway.
391
		do_action( 'getpaid_process_invoice_payment_' . $this->id, $invoice, $submission_data, $submission );
392
	}
393
394
	/**
395
	 * Process refund.
396
	 *
397
	 * If the gateway declares 'refunds' support, this will allow it to refund.
398
	 * a passed in amount.
399
	 *
400
	 * @param WPInv_Invoice $invoice Invoice.
401
	 * @param  float  $amount Refund amount.
402
	 * @param  string $reason Refund reason.
403
	 * @return WP_Error|bool True or false based on success, or a WP_Error object.
404
	 */
405
	public function process_refund( $invoice, $amount = null, $reason = '' ) {
406
		return apply_filters( 'getpaid_process_invoice_refund_' . $this->id, false, $invoice, $amount, $reason );
407
	}
408
409
	/**
410
	 * Displays the payment fields, credit cards etc.
411
	 * 
412
	 * @param int $invoice_id 0 or invoice id.
413
	 * @param GetPaid_Payment_Form $form Current payment form.
414
	 */
415
	public function payment_fields( $invoice_id, $form ) {
416
		do_action( 'getpaid_getpaid_gateway_payment_fields_' . $this->id, $invoice_id, $form );
417
	}
418
419
	/**
420
	 * Filters the gateway settings.
421
	 * 
422
	 * @param array $admin_settings
423
	 */
424
	public function admin_settings( $admin_settings ) {
425
		return $admin_settings;
426
	}
427
428
	/**
429
	 * Retrieves the value of a gateway setting.
430
	 * 
431
	 * @param string $option
432
	 */
433
	public function get_option( $option, $default = false ) {
434
		return wpinv_get_option( $this->id . '_' . $option, $default );
435
	}
436
437
	/**
438
	 * Check if a gateway supports a given feature.
439
	 *
440
	 * Gateways should override this to declare support (or lack of support) for a feature.
441
	 * For backward compatibility, gateways support 'products' by default, but nothing else.
442
	 *
443
	 * @param string $feature string The name of a feature to test support for.
444
	 * @return bool True if the gateway supports the feature, false otherwise.
445
	 * @since 1.0.19
446
	 */
447
	public function supports( $feature ) {
448
		return apply_filters( 'getpaid_payment_gateway_supports', in_array( $feature, $this->supports ), $feature, $this );
449
	}
450
451
	/**
452
	 * Returns the credit card form html.
453
	 * 
454
	 * @param bool $save whether or not to display the save button.
455
	 */
456
    public function get_cc_form( $save = false ) {
457
458
		ob_start();
459
460
        $id_prefix = esc_attr( uniqid( $this->id ) );
461
462
        $months = array(
463
            '01' => __( 'January', 'invoicing' ),
464
            '02' => __( 'February', 'invoicing' ),
465
            '03' => __( 'March', 'invoicing' ),
466
            '04' => __( 'April', 'invoicing' ),
467
            '05' => __( 'May', 'invoicing' ),
468
            '06' => __( 'June', 'invoicing' ),
469
            '07' => __( 'July', 'invoicing' ),
470
            '08' => __( 'August', 'invoicing' ),
471
            '09' => __( 'September', 'invoicing' ),
472
            '10' => __( 'October', 'invoicing' ),
473
            '11' => __( 'November', 'invoicing' ),
474
            '12' => __( 'December', 'invoicing' ),
475
        );
476
477
        $year  = (int) date( 'Y', current_time( 'timestamp' ) );
478
        $years = array();
479
480
        for ( $i = 0; $i <= 10; $i++ ) {
481
            $years[ $year + $i ] = $year + $i;
482
        }
483
484
        ?>
485
            <div class="<?php echo esc_attr( $this->id );?>-cc-form getpaid-cc-form card  mt-4">
486
487
488
                <div class="card-body">
489
                    <div class="row">
490
491
                        <div class="col-12 col-sm-6">
492
493
                            <?php
494
495
                                echo aui()->input(
496
                                    array(
497
                                        'name'              => $this->id . '[cc_number]',
498
                                        'id'                => "$id_prefix-cc-number",
499
                                        'label'             => __( 'Card number', 'invoicing' ),
500
                                        'label_type'        => 'vertical',
501
                                        'input_group_left'  => '<span class="input-group-text"><i class="fa fa-credit-card"></i></span>',
502
                                    )
503
                                );
504
                            ?>
505
506
                        </div>
507
508
                        <div class="col-12 col-sm-4">
509
                            <div class="form-group">
510
                                <label><?php _e( 'Expiration', 'invoicing' ); ?></label>
511
                                <div class="form-row">
512
513
                                    <div class="col">
514
                                        <select class="form-control" name="<?php echo esc_attr( $this->id );?>[cc_expire_month]">
515
                                            <option disabled selected="selected"><?php _e( 'MM', 'invoicing' ); ?></option>
516
517
                                            <?php
518
                                                foreach ( $months as $key => $month ) {
519
                                                    $key   = esc_attr( $key );
520
                                                    $month = wpinv_clean( $month );
521
                                                    echo "<option value='$key'>$month</option>" . PHP_EOL;
522
                                                }
523
                                            ?>
524
525
                                        </select>
526
                                    </div>
527
528
                                    <div class="col">
529
                                        <select class="form-control" name="<?php echo esc_attr( $this->id );?>[cc_expire_year]">
530
                                            <option disabled selected="selected"><?php _e( 'YY', 'invoicing' ); ?></option>
531
532
                                            <?php
533
                                                foreach ( $years as $key => $year ) {
534
                                                    $key   = esc_attr( $key );
535
                                                    $year  = wpinv_clean( $year );
536
                                                    echo "<option value='$key'>$year</option>" . PHP_EOL;
537
                                                }
538
                                            ?>
539
540
                                        </select>
541
                                    </div>
542
            
543
                                </div>
544
                            </div>
545
                        </div>
546
547
                        <div class="col-12 col-sm-2">
548
                            <?php
549
                                echo aui()->input(
550
                                    array(
551
                                        'name'              => $this->id . '[cc_cvv2]',
552
                                        'id'                => "$id_prefix-cc-cvv2",
553
                                        'label'             => __( 'CCV', 'invoicing' ),
554
                                        'label_type'        => 'vertical',
555
                                    )
556
                                );
557
                            ?>
558
                        </div>
559
560
					</div>
561
					
562
					<?php
563
564
						if ( $save ) {
565
							echo $this->save_payment_method_checkbox();
566
						}
567
568
					?>
569
                </div>
570
571
            </div>
572
		<?php
573
		
574
		return ob_get_clean();
575
576
    }
577
578
	/**
579
	 * Displays a new payment method entry form.
580
	 *
581
	 * @since 1.0.19
582
	 */
583
	public function new_payment_method_entry( $form ) {
584
		echo "<div class='getpaid-new-payment-method-form' style='display:none;'>$form</div>";
585
	}
586
587
	/**
588
	 * Grab and display our saved payment methods.
589
	 *
590
	 * @since 1.0.19
591
	 */
592
	public function saved_payment_methods() {
593
		$html = '<ul class="getpaid-saved-payment-methods m-0 mt-2" data-count="' . esc_attr( count( $this->get_tokens( $this->is_sandbox() ) ) ) . '">';
594
595
		foreach ( $this->get_tokens( $this->is_sandbox() ) as $token ) {
596
			$html .= $this->get_saved_payment_method_option_html( $token );
597
		}
598
599
		$html .= $this->get_new_payment_method_option_html();
600
		$html .= '</ul>';
601
602
		echo apply_filters( 'getpaid_payment_gateway_form_saved_payment_methods_html', $html, $this );
603
	}
604
605
	/**
606
	 * Gets saved payment method HTML from a token.
607
	 *
608
	 * @since 1.0.19
609
	 * @param  array $token Payment Token.
610
	 * @return string Generated payment method HTML
611
	 */
612
	public function get_saved_payment_method_option_html( $token ) {
613
614
		return sprintf(
615
			'<li class="getpaid-payment-method form-group">
616
				<label>
617
					<input name="getpaid-%1$s-payment-method" type="radio" value="%2$s" style="width:auto;" class="getpaid-saved-payment-method-token-input" %4$s />
618
					<span>%3$s</span>
619
				</label>
620
			</li>',
621
			esc_attr( $this->id ),
622
			esc_attr( $token['id'] ),
623
			esc_html( $token['name'] ),
624
			checked( empty( $token['default'] ), false, false )
625
		);
626
627
	}
628
629
	/**
630
	 * Displays a radio button for entering a new payment method (new CC details) instead of using a saved method.
631
	 *
632
	 * @since 1.0.19
633
	 */
634
	public function get_new_payment_method_option_html() {
635
636
		$label = apply_filters( 'getpaid_new_payment_method_label', $this->new_method_label ? $this->new_method_label : __( 'Use a new payment method', 'invoicing' ), $this );
637
638
		return sprintf(
639
			'<li class="getpaid-new-payment-method">
640
				<label>
641
					<input name="getpaid-%1$s-payment-method" type="radio" value="new" style="width:auto;" />
642
					<span>%2$s</span>
643
				</label>
644
			</li>',
645
			esc_attr( $this->id ),
646
			esc_html( $label )
647
		);
648
649
	}
650
651
	/**
652
	 * Outputs a checkbox for saving a new payment method to the database.
653
	 *
654
	 * @since 1.0.19
655
	 */
656
	public function save_payment_method_checkbox() {
657
658
		return sprintf(
659
			'<p class="form-group getpaid-save-payment-method">
660
				<label>
661
					<input name="getpaid-%1$s-new-payment-method" type="checkbox" value="true" style="width:auto;" />
662
					<span>%2$s</span>
663
				</label>
664
			</p>',
665
			esc_attr( $this->id ),
666
			esc_html__( 'Save payment method', 'invoicing' )
667
		);
668
669
	}
670
671
	/**
672
	 * Registers the gateway.
673
	 *
674
	 * @return array
675
	 */
676
	public function register_gateway( $gateways ) {
677
678
		$gateways[ $this->id ] = array(
679
680
			'admin_label'    => $this->method_title,
681
            'checkout_label' => $this->title,
682
			'ordering'       => $this->order,
683
684
		);
685
686
		return $gateways;
687
688
	}
689
690
	/**
691
	 * Checks whether or not this is a sandbox request.
692
	 *
693
	 * @param  WPInv_Invoice|null $invoice Invoice object or null.
694
	 * @return bool
695
	 */
696
	public function is_sandbox( $invoice = null ) {
697
698
		if ( ! empty( $invoice ) && ! $invoice->needs_payment() ) {
699
			return $invoice->get_mode() == 'test';
700
		}
701
702
		return wpinv_is_test_mode( $this->id );
703
704
	}
705
706
	/**
707
	 * Renames the checkout button
708
	 *
709
	 * @return string
710
	 */
711
	public function rename_checkout_button() {
712
		return $this->checkout_button_text;
713
	}
714
715
	/**
716
	 * Validate gateway currency
717
	 *
718
	 * @return bool
719
	 */
720
	public function validate_currency( $validation, $currency ) {
721
722
		// Required currencies.
723
		if ( ! empty( $this->currencies ) && ! in_array( $currency, $this->currencies ) ) {
724
			return false;
725
		}
726
727
		// Excluded currencies.
728
		if ( ! empty( $this->exclude_currencies ) && in_array( $currency, $this->exclude_currencies ) ) {
729
			return false;
730
		}
731
732
		return $validation;
733
	}
734
735
}
736