Test Failed
Push — travis/4010 ( cd7197 )
by Ravinder
12:19
created

Give_Stripe_Card   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 357
Duplicated Lines 4.2 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
dl 15
loc 357
rs 10
c 0
b 0
f 0
wmc 29
lcom 1
cbo 4

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
B check_for_source() 0 50 6
A prepare_card_data() 0 18 1
C process_payment() 15 143 11
C listen_stripe_3dsecure_payment() 0 79 10

How to fix   Duplicated Code   

Duplicated Code

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

Common duplication problems, and corresponding solutions are:

1
<?php
2
/**
3
 * Give - Stripe Card Payments
4
 *
5
 * @package    Give
6
 * @subpackage Stripe Core
7
 * @copyright  Copyright (c) 2019, GiveWP
8
 * @license    https://opensource.org/licenses/gpl-license GNU Public License
9
 */
10
11
// Exit if accessed directly.
12
if ( ! defined( 'ABSPATH' ) ) {
13
	exit;
14
}
15
16
/**
17
 * Check for Give_Stripe_Card existence.
18
 *
19
 * @since 2.5.0
20
 */
21
if ( ! class_exists( 'Give_Stripe_Card' ) ) {
22
23
	/**
24
	 * Class Give_Stripe_Card.
25
	 *
26
	 * @since 2.5.0
27
	 */
28
	class Give_Stripe_Card extends Give_Stripe_Gateway {
29
30
		/**
31
		 * Override Payment Method ID.
32
		 *
33
		 * @since  2.5.0
34
		 * @access public
35
		 *
36
		 * @var string
37
		 */
38
		public $id = 'stripe';
39
40
		/**
41
		 * Give_Stripe_Card constructor.
42
		 *
43
		 * @since  2.5.0
44
		 * @access public
45
		 */
46
		public function __construct() {
47
48
			parent::__construct();
49
50
			add_action( 'init', array( $this, 'listen_stripe_3dsecure_payment' ) );
51
		}
52
53
		/**
54
		 * Check for the Stripe Source.
55
		 *
56
		 * @param array $donation_data List of Donation Data.
57
		 *
58
		 * @since 2.0.6
59
		 *
60
		 * @return string
61
		 */
62
		public function check_for_source( $donation_data ) {
63
64
			$source_id          = $donation_data['post_data']['give_stripe_source'];
65
			$stripe_js_fallback = give_get_option( 'stripe_js_fallback' );
66
67
			if ( ! isset( $source_id ) ) {
68
69
				// check for fallback mode.
70
				if ( ! empty( $stripe_js_fallback ) ) {
71
72
					$card_data = $this->prepare_card_data( $donation_data );
73
74
					// Set Application Info.
75
					give_stripe_set_app_info();
76
77
					try {
78
79
						$source = \Stripe\Source::create( array(
80
							'card' => $card_data,
81
						) );
82
						$source_id = $source->id;
83
84
					} catch ( \Stripe\Error\Base $e ) {
85
						$this->log_error( $e );
86
87
					} catch ( Exception $e ) {
88
89
						give_record_gateway_error(
90
							__( 'Stripe Error', 'give-stripe' ),
91
							sprintf(
92
								/* translators: %s Exception Message Body */
93
								__( 'The Stripe Gateway returned an error while creating the customer payment source. Details: %s', 'give-stripe' ),
94
								$e->getMessage()
95
							)
96
						);
97
						give_set_error( 'stripe_error', __( 'An occurred while processing the donation with the gateway. Please try your donation again.', 'give-stripe' ) );
98
						give_send_back_to_checkout( "?payment-mode={$this->id}&form_id={$donation_data['post_data']['give-form-id']}" );
99
					}
100
				} elseif ( ! $this->is_stripe_popup_enabled() ) {
0 ignored issues
show
Bug introduced by
The method is_stripe_popup_enabled() does not seem to exist on object<Give_Stripe_Card>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
101
102
					// No Stripe source and fallback mode is disabled.
103
					give_set_error( 'no_token', __( 'Missing Stripe Source. Please contact support.', 'give-stripe' ) );
104
					give_record_gateway_error( __( 'Missing Stripe Source', 'give-stripe' ), __( 'A Stripe token failed to be generated. Please check Stripe logs for more information.', 'give-stripe' ) );
105
106
				}
107
			} // End if().
108
109
			return $source_id;
110
111
		}
112
113
		/**
114
		 * Process the POST Data for the Credit Card Form, if a source was not supplied.
115
		 *
116
		 * @since 2.5.0
117
		 *
118
		 * @param array $donation_data List of donation data.
119
		 *
120
		 * @return array The credit card data from the $_POST
121
		 */
122
		public function prepare_card_data( $donation_data ) {
123
124
			$card_data = array(
125
				'number'          => $donation_data['card_info']['card_number'],
126
				'name'            => $donation_data['card_info']['card_name'],
127
				'exp_month'       => $donation_data['card_info']['card_exp_month'],
128
				'exp_year'        => $donation_data['card_info']['card_exp_year'],
129
				'cvc'             => $donation_data['card_info']['card_cvc'],
130
				'address_line1'   => $donation_data['card_info']['card_address'],
131
				'address_line2'   => $donation_data['card_info']['card_address_2'],
132
				'address_city'    => $donation_data['card_info']['card_city'],
133
				'address_zip'     => $donation_data['card_info']['card_zip'],
134
				'address_state'   => $donation_data['card_info']['card_state'],
135
				'address_country' => $donation_data['card_info']['card_country'],
136
			);
137
138
			return $card_data;
139
		}
140
141
		/**
142
		 * This function will be used for donation processing.
143
		 *
144
		 * @param array $donation_data List of donation data.
145
		 *
146
		 * @since  2.5.0
147
		 * @access public
148
		 *
149
		 * @return void
150
		 */
151
		public function process_payment( $donation_data ) {
152
153
			// Bailout, if the current gateway and the posted gateway mismatched.
154
			if ( $this->id !== $donation_data['post_data']['give-gateway'] ) {
155
				return;
156
			}
157
158
			// Make sure we don't have any left over errors present.
159
			give_clear_errors();
160
161
			$source_id = ! empty( $donation_data['post_data']['give_stripe_source'] )
162
				? $donation_data['post_data']['give_stripe_source']
163
				: $this->check_for_source( $donation_data );
164
165
			// Any errors?
166
			$errors = give_get_errors();
167
168
			// No errors, proceed.
169
			if ( ! $errors ) {
170
171
				$form_id          = ! empty( $donation_data['post_data']['give-form-id'] ) ? intval( $donation_data['post_data']['give-form-id'] ) : 0;
172
				$price_id         = ! empty( $donation_data['post_data']['give-price-id'] ) ? $donation_data['post_data']['give-price-id'] : 0;
173
				$donor_email      = ! empty( $donation_data['post_data']['give_email'] ) ? $donation_data['post_data']['give_email'] : 0;
174
				$intent_id        = ! empty( $donation_data['post_data']['give_stripe_intent_id'] ) ? $donation_data['post_data']['give_stripe_intent_id'] : 0;
0 ignored issues
show
Unused Code introduced by
$intent_id is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
175
				$donation_summary = give_payment_gateway_donation_summary( $donation_data, false );
176
177
				// Get an existing Stripe customer or create a new Stripe Customer and attach the source to customer.
178
				$give_stripe_customer = new Give_Stripe_Customer( $donor_email, $source_id );
179
				$stripe_customer      = $give_stripe_customer->customer_data;
0 ignored issues
show
Unused Code introduced by
$stripe_customer is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
180
				$stripe_customer_id   = $give_stripe_customer->get_id();
181
182
				// We have a Stripe customer, charge them.
183
				if ( $stripe_customer_id ) {
184
185
					// Proceed to get stripe source details on if stripe checkout is not enabled.
186
					$source    = $give_stripe_customer->attached_source;
187
					$source_id = $source->id;
188
189
					// Setup the payment details.
190
					$payment_data = array(
191
						'price'           => $donation_data['price'],
192
						'give_form_title' => $donation_data['post_data']['give-form-title'],
193
						'give_form_id'    => $form_id,
194
						'give_price_id'   => $price_id,
195
						'date'            => $donation_data['date'],
196
						'user_email'      => $donation_data['user_email'],
197
						'purchase_key'    => $donation_data['purchase_key'],
198
						'currency'        => give_get_currency( $form_id ),
199
						'user_info'       => $donation_data['user_info'],
200
						'status'          => 'pending',
201
						'gateway'         => $this->id,
202
					);
203
204
					// Record the pending payment in Give.
205
					$donation_id = give_insert_payment( $payment_data );
206
207
					// Save Stripe Customer ID to Donation note, Donor and Donation for future reference.
208
					give_insert_payment_note( $donation_id, 'Stripe Customer ID: ' . $stripe_customer_id );
0 ignored issues
show
Security Bug introduced by
It seems like $donation_id defined by give_insert_payment($payment_data) on line 205 can also be of type false; however, give_insert_payment_note() does only seem to accept integer, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
209
					$this->save_stripe_customer_id( $stripe_customer_id, $donation_id );
0 ignored issues
show
Security Bug introduced by
It seems like $donation_id defined by give_insert_payment($payment_data) on line 205 can also be of type false; however, Give_Stripe_Gateway::save_stripe_customer_id() does only seem to accept integer, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
210
					give_update_meta( $donation_id, '_give_stripe_customer_id', $stripe_customer_id );
0 ignored issues
show
Security Bug introduced by
It seems like $donation_id defined by give_insert_payment($payment_data) on line 205 can also be of type false; however, give_update_meta() does only seem to accept integer, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
211
212
					// Save Source ID to donation note and DB.
213
					give_insert_payment_note( $donation_id, 'Stripe Source ID: ' . $source_id );
0 ignored issues
show
Security Bug introduced by
It seems like $donation_id defined by give_insert_payment($payment_data) on line 205 can also be of type false; however, give_insert_payment_note() does only seem to accept integer, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
214
					give_update_meta( $donation_id, '_give_stripe_source_id', $source_id );
0 ignored issues
show
Security Bug introduced by
It seems like $donation_id defined by give_insert_payment($payment_data) on line 205 can also be of type false; however, give_update_meta() does only seem to accept integer, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
215
216
					// Save donation summary to donation.
217
					give_update_meta( $donation_id, '_give_stripe_donation_summary', $donation_summary );
0 ignored issues
show
Security Bug introduced by
It seems like $donation_id defined by give_insert_payment($payment_data) on line 205 can also be of type false; however, give_update_meta() does only seem to accept integer, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
218
219
					/**
220
					 * This filter hook is used to update the payment intent arguments.
221
					 *
222
					 * @since 2.5.0
223
					 */
224
					$intent_args = apply_filters(
225
						'give_stripe_create_intent_args',
226
						array(
227
							'amount'               => $this->format_amount( $donation_data['price'] ),
228
							'currency'             => give_get_currency( $form_id ),
229
							'payment_method_types' => [ 'card' ],
230
							'statement_descriptor' => give_stripe_get_statement_descriptor(),
231
							'receipt_email'        => $donation_data['user_email'],
232
							'description'          => give_payment_gateway_donation_summary( $donation_data ),
233
							'metadata'             => $this->prepare_metadata( $donation_id ),
0 ignored issues
show
Security Bug introduced by
It seems like $donation_id defined by give_insert_payment($payment_data) on line 205 can also be of type false; however, Give_Stripe_Gateway::prepare_metadata() does only seem to accept integer, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
234
							'customer'             => $stripe_customer_id,
235
							'source'               => $source_id,
236
							'save_payment_method'  => true,
237
							'confirm'              => true,
238
							'return_url'           => give_get_success_page_uri(),
239
						)
240
					);
241
					$intent      = $this->payment_intent->create( $intent_args );
242
243
					// Save Payment Intent ID to donation note and DB.
244
					give_insert_payment_note( $donation_id, 'Stripe Payment Intent ID: ' . $intent->id );
0 ignored issues
show
Security Bug introduced by
It seems like $donation_id defined by give_insert_payment($payment_data) on line 205 can also be of type false; however, give_insert_payment_note() does only seem to accept integer, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
245
					give_update_meta( $donation_id, '_give_stripe_payment_intent_id', $intent->id );
0 ignored issues
show
Security Bug introduced by
It seems like $donation_id defined by give_insert_payment($payment_data) on line 205 can also be of type false; however, give_update_meta() does only seem to accept integer, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
246
247
					// Save Payment Intent Client Secret to donation note and DB.
248
					give_insert_payment_note( $donation_id, 'Stripe Payment Intent Client Secret: ' . $intent->client_secret );
0 ignored issues
show
Security Bug introduced by
It seems like $donation_id defined by give_insert_payment($payment_data) on line 205 can also be of type false; however, give_insert_payment_note() does only seem to accept integer, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
249
					give_update_meta( $donation_id, '_give_stripe_payment_intent_client_secret', $intent->client_secret );
0 ignored issues
show
Security Bug introduced by
It seems like $donation_id defined by give_insert_payment($payment_data) on line 205 can also be of type false; however, give_update_meta() does only seem to accept integer, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
250
251
					$charge_id = $intent->charges['data'][0]->id;
252
253
					if ( ! empty( $charge_id ) ) {
254
						// Set Charge ID as transaction ID for the donation.
255
						give_set_payment_transaction_id( $donation_id, $charge_id );
0 ignored issues
show
Security Bug introduced by
It seems like $donation_id defined by give_insert_payment($payment_data) on line 205 can also be of type false; however, give_set_payment_transaction_id() does only seem to accept integer, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
256
						give_insert_payment_note( $donation_id, 'Stripe Charge ID: ' . $charge_id );
0 ignored issues
show
Security Bug introduced by
It seems like $donation_id defined by give_insert_payment($payment_data) on line 205 can also be of type false; however, give_insert_payment_note() does only seem to accept integer, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
257
					}
258
259
					// Additional steps required when payment intent status is set to `requires_action`.
260
					if ( 'requires_action' === $intent->status ) {
261
262
						$action_url = $intent->next_action->redirect_to_url->url;
263
264
						// Save Payment Intent requires action related information to donation note and DB.
265
						give_insert_payment_note( $donation_id, 'Stripe requires additional action to be fulfilled.' );
0 ignored issues
show
Security Bug introduced by
It seems like $donation_id defined by give_insert_payment($payment_data) on line 205 can also be of type false; however, give_insert_payment_note() does only seem to accept integer, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
266
						give_update_meta( $donation_id, '_give_stripe_payment_intent_require_action_url', $action_url );
0 ignored issues
show
Security Bug introduced by
It seems like $donation_id defined by give_insert_payment($payment_data) on line 205 can also be of type false; however, give_update_meta() does only seem to accept integer, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
267
268
						wp_redirect( $action_url );
269
						exit;
270
					}
271
272
					// Send them to success page.
273
					give_send_to_success_page();
274
275 View Code Duplication
				} else {
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...
276
277
					// No customer, failed.
278
					give_record_gateway_error(
279
						__( 'Stripe Customer Creation Failed', 'give' ),
280
						sprintf(
281
							/* translators: %s Donation Data */
282
							__( 'Customer creation failed while processing the donation. Details: %s', 'give' ),
283
							wp_json_encode( $donation_data )
284
						)
285
					);
286
					give_set_error( 'stripe_error', __( 'The Stripe Gateway returned an error while processing the donation.', 'give' ) );
287
					give_send_back_to_checkout( "?payment-mode={$this->id}" );
288
289
				} // End if().
290
			} else {
291
				give_send_back_to_checkout( "?payment-mode={$this->id}" );
292
			} // End if().
293
		}
294
295
		/**
296
		 * Authorise Donation to successfully complete the donation.
297
		 *
298
		 * @since  1.6
299
		 * @access public
300
		 *
301
		 * @todo remove this function when payment intent is supported with subscriptions.
302
		 *
303
		 * @return void
304
		 */
305
		public function listen_stripe_3dsecure_payment() {
306
307
			// Sanitize the parameter received from query string.
308
			$data = give_clean( $_GET ); // WPCS: input var ok.
0 ignored issues
show
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
309
310
			// Must be a stripe three-d-secure listener to proceed.
311
			if ( ! isset( $data['give-listener'] ) || 'stripe_three_d_secure' !== $data['give-listener'] ) {
312
				return;
313
			}
314
315
			$donation_id = ! empty( $data['donation_id'] ) ? $data['donation_id'] : '';
316
			$source_id   = ! empty( $data['source'] ) ? $data['source'] : '';
317
			$description = give_get_meta( $donation_id, '_give_stripe_donation_summary', true );
318
			$customer_id = give_get_meta( $donation_id, '_give_stripe_customer_id', true );
319
320
			// Get Source Object from source id.
321
			$source_object = $this->get_source_details( $source_id );
322
323
			// Proceed to charge, if the 3D secure source is chargeable.
324
			if ( 'chargeable' === $source_object->status ) {
325
				$charge_args = array(
326
					'amount'               => $source_object->amount,
327
					'currency'             => $source_object->currency,
328
					'customer'             => $customer_id,
329
					'source'               => $source_object->id,
330
					'description'          => html_entity_decode( $description, ENT_COMPAT, 'UTF-8' ),
331
					'statement_descriptor' => $source_object->statement_descriptor,
332
					'metadata'             => $this->prepare_metadata( $donation_id ),
333
				);
334
335
				// If preapproval enabled, only capture the charge
336
				// @see: https://stripe.com/docs/api#create_charge-capture.
337
				if ( give_stripe_is_preapproved_enabled() ) {
338
					$charge_args['capture'] = false;
339
				}
340
341
				try {
342
					$charge = $this->create_charge( $donation_id, $charge_args );
343
344
					if ( $charge ) {
345
						/**
346
						 * This action hook will help to perform additional steps when 3D secure payments are processed.
347
						 *
348
						 * @since 2.1
349
						 *
350
						 * @param int            $donation_id Donation ID.
351
						 * @param \Stripe\Charge $charge      Stripe Charge Object.
352
						 * @param string         $customer_id Stripe Customer ID.
353
						 */
354
						do_action( 'give_stripe_verify_3dsecure_payment', $donation_id, $charge, $customer_id );
355
356
						// Verify Payment.
357
						$this->verify_payment( $donation_id, $customer_id, $charge );
358
					}
359
				} catch ( \Stripe\Error\Base $e ) {
360
					$this->log_error( $e );
361
				} catch ( Exception $e ) {
362
					give_update_payment_status( $donation_id, 'failed' );
363
364
					give_record_gateway_error(
365
						__( 'Stripe Error', 'give-stripe' ),
366
						sprintf(
367
							/* translators: Exception Message Body */
368
							__( 'The Stripe Gateway returned an error while processing a donation. Details: %s', 'give' ),
369
							$e->getMessage()
370
						)
371
					);
372
373
					wp_safe_redirect( give_get_failed_transaction_uri() );
374
				} // End try().
375
			} else {
376
377
				give_update_payment_status( $donation_id, 'failed' );
378
				give_record_gateway_error( __( 'Donor Error', 'give' ), sprintf( __( 'Donor has cancelled the payment during authorization process.', 'give' ) ) );
379
				wp_safe_redirect( give_get_failed_transaction_uri() );
380
			} // End if().
381
382
			give_die();
383
		}
384
	}
385
}
386
return new Give_Stripe_Card();
387