|
1
|
|
|
<?php |
|
2
|
|
|
if ( ! defined( 'ABSPATH' ) ) { |
|
3
|
|
|
exit; |
|
4
|
|
|
} |
|
5
|
|
|
|
|
6
|
|
|
/** |
|
7
|
|
|
* WC_Gateway_Stripe class. |
|
8
|
|
|
* |
|
9
|
|
|
* @extends WC_Payment_Gateway |
|
10
|
|
|
*/ |
|
11
|
|
|
class WC_Gateway_Stripe extends WC_Payment_Gateway_CC { |
|
12
|
|
|
|
|
13
|
|
|
/** |
|
14
|
|
|
* Should we capture Credit cards |
|
15
|
|
|
* |
|
16
|
|
|
* @var bool |
|
17
|
|
|
*/ |
|
18
|
|
|
public $capture; |
|
19
|
|
|
|
|
20
|
|
|
/** |
|
21
|
|
|
* Alternate credit card statement name |
|
22
|
|
|
* |
|
23
|
|
|
* @var bool |
|
24
|
|
|
*/ |
|
25
|
|
|
public $statement_descriptor; |
|
26
|
|
|
|
|
27
|
|
|
/** |
|
28
|
|
|
* Checkout enabled |
|
29
|
|
|
* |
|
30
|
|
|
* @var bool |
|
31
|
|
|
*/ |
|
32
|
|
|
public $stripe_checkout; |
|
33
|
|
|
|
|
34
|
|
|
/** |
|
35
|
|
|
* Checkout Locale |
|
36
|
|
|
* |
|
37
|
|
|
* @var string |
|
38
|
|
|
*/ |
|
39
|
|
|
public $stripe_checkout_locale; |
|
40
|
|
|
|
|
41
|
|
|
/** |
|
42
|
|
|
* Credit card image |
|
43
|
|
|
* |
|
44
|
|
|
* @var string |
|
45
|
|
|
*/ |
|
46
|
|
|
public $stripe_checkout_image; |
|
47
|
|
|
|
|
48
|
|
|
/** |
|
49
|
|
|
* Should we store the users credit cards? |
|
50
|
|
|
* |
|
51
|
|
|
* @var bool |
|
52
|
|
|
*/ |
|
53
|
|
|
public $saved_cards; |
|
54
|
|
|
|
|
55
|
|
|
/** |
|
56
|
|
|
* API access secret key |
|
57
|
|
|
* |
|
58
|
|
|
* @var string |
|
59
|
|
|
*/ |
|
60
|
|
|
public $secret_key; |
|
61
|
|
|
|
|
62
|
|
|
/** |
|
63
|
|
|
* Api access publishable key |
|
64
|
|
|
* |
|
65
|
|
|
* @var string |
|
66
|
|
|
*/ |
|
67
|
|
|
public $publishable_key; |
|
68
|
|
|
|
|
69
|
|
|
/** |
|
70
|
|
|
* Do we accept bitcoin? |
|
71
|
|
|
* |
|
72
|
|
|
* @var bool |
|
73
|
|
|
*/ |
|
74
|
|
|
public $bitcoin; |
|
75
|
|
|
|
|
76
|
|
|
/** |
|
77
|
|
|
* Do we accept Apple Pay? |
|
78
|
|
|
* |
|
79
|
|
|
* @var bool |
|
80
|
|
|
*/ |
|
81
|
|
|
public $apple_pay; |
|
82
|
|
|
|
|
83
|
|
|
/** |
|
84
|
|
|
* Apple Pay Domain Set. |
|
85
|
|
|
* |
|
86
|
|
|
* @var bool |
|
87
|
|
|
*/ |
|
88
|
|
|
public $apple_pay_domain_set; |
|
89
|
|
|
|
|
90
|
|
|
/** |
|
91
|
|
|
* Apple Pay button style. |
|
92
|
|
|
* |
|
93
|
|
|
* @var bool |
|
94
|
|
|
*/ |
|
95
|
|
|
public $apple_pay_button; |
|
96
|
|
|
|
|
97
|
|
|
/** |
|
98
|
|
|
* Is test mode active? |
|
99
|
|
|
* |
|
100
|
|
|
* @var bool |
|
101
|
|
|
*/ |
|
102
|
|
|
public $testmode; |
|
103
|
|
|
|
|
104
|
|
|
/** |
|
105
|
|
|
* Logging enabled? |
|
106
|
|
|
* |
|
107
|
|
|
* @var bool |
|
108
|
|
|
*/ |
|
109
|
|
|
public $logging; |
|
110
|
|
|
|
|
111
|
|
|
/** |
|
112
|
|
|
* Stores Apple Pay domain verification issues. |
|
113
|
|
|
* |
|
114
|
|
|
* @var string |
|
115
|
|
|
*/ |
|
116
|
|
|
public $apple_pay_verify_notice; |
|
117
|
|
|
|
|
118
|
|
|
/** |
|
119
|
|
|
* Constructor |
|
120
|
|
|
*/ |
|
121
|
|
|
public function __construct() { |
|
122
|
|
|
$this->id = 'stripe'; |
|
123
|
|
|
$this->method_title = __( 'Stripe', 'woocommerce-gateway-stripe' ); |
|
124
|
|
|
$this->method_description = __( 'Stripe works by adding credit card fields on the checkout and then sending the details to Stripe for verification.', 'woocommerce-gateway-stripe' ); |
|
125
|
|
|
$this->has_fields = true; |
|
126
|
|
|
$this->view_transaction_url = 'https://dashboard.stripe.com/payments/%s'; |
|
127
|
|
|
$this->supports = array( |
|
128
|
|
|
'subscriptions', |
|
129
|
|
|
'products', |
|
130
|
|
|
'refunds', |
|
131
|
|
|
'subscription_cancellation', |
|
132
|
|
|
'subscription_reactivation', |
|
133
|
|
|
'subscription_suspension', |
|
134
|
|
|
'subscription_amount_changes', |
|
135
|
|
|
'subscription_payment_method_change', // Subs 1.n compatibility. |
|
136
|
|
|
'subscription_payment_method_change_customer', |
|
137
|
|
|
'subscription_payment_method_change_admin', |
|
138
|
|
|
'subscription_date_changes', |
|
139
|
|
|
'multiple_subscriptions', |
|
140
|
|
|
'pre-orders', |
|
141
|
|
|
'tokenization', |
|
142
|
|
|
'add_payment_method', |
|
143
|
|
|
); |
|
144
|
|
|
|
|
145
|
|
|
// Load the form fields. |
|
146
|
|
|
$this->init_form_fields(); |
|
147
|
|
|
|
|
148
|
|
|
// Load the settings. |
|
149
|
|
|
$this->init_settings(); |
|
150
|
|
|
|
|
151
|
|
|
// Get setting values. |
|
152
|
|
|
$this->title = $this->get_option( 'title' ); |
|
153
|
|
|
$this->description = $this->get_option( 'description' ); |
|
154
|
|
|
$this->enabled = $this->get_option( 'enabled' ); |
|
155
|
|
|
$this->testmode = 'yes' === $this->get_option( 'testmode' ); |
|
156
|
|
|
$this->capture = 'yes' === $this->get_option( 'capture', 'yes' ); |
|
157
|
|
|
$this->statement_descriptor = $this->get_option( 'statement_descriptor', wp_specialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES ) ); |
|
158
|
|
|
$this->stripe_checkout = 'yes' === $this->get_option( 'stripe_checkout' ); |
|
159
|
|
|
$this->stripe_checkout_locale = $this->get_option( 'stripe_checkout_locale' ); |
|
160
|
|
|
$this->stripe_checkout_image = $this->get_option( 'stripe_checkout_image', '' ); |
|
161
|
|
|
$this->saved_cards = 'yes' === $this->get_option( 'saved_cards' ); |
|
162
|
|
|
$this->secret_key = $this->testmode ? $this->get_option( 'test_secret_key' ) : $this->get_option( 'secret_key' ); |
|
163
|
|
|
$this->publishable_key = $this->testmode ? $this->get_option( 'test_publishable_key' ) : $this->get_option( 'publishable_key' ); |
|
164
|
|
|
$this->bitcoin = 'USD' === strtoupper( get_woocommerce_currency() ) && 'yes' === $this->get_option( 'stripe_bitcoin' ); |
|
165
|
|
|
$this->apple_pay = 'yes' === $this->get_option( 'apple_pay', 'yes' ); |
|
166
|
|
|
$this->apple_pay_domain_set = 'yes' === $this->get_option( 'apple_pay_domain_set', 'no' ); |
|
167
|
|
|
$this->apple_pay_button = $this->get_option( 'apple_pay_button', 'black' ); |
|
168
|
|
|
$this->logging = 'yes' === $this->get_option( 'logging' ); |
|
169
|
|
|
$this->apple_pay_verify_notice = ''; |
|
170
|
|
|
|
|
171
|
|
|
if ( $this->stripe_checkout ) { |
|
172
|
|
|
$this->order_button_text = __( 'Continue to payment', 'woocommerce-gateway-stripe' ); |
|
173
|
|
|
} |
|
174
|
|
|
|
|
175
|
|
|
if ( $this->testmode ) { |
|
176
|
|
|
$this->description .= ' ' . sprintf( __( 'TEST MODE ENABLED. In test mode, you can use the card number 4242424242424242 with any CVC and a valid expiration date or check the documentation "<a href="%s">Testing Stripe</a>" for more card numbers.', 'woocommerce-gateway-stripe' ), 'https://stripe.com/docs/testing' ); |
|
177
|
|
|
$this->description = trim( $this->description ); |
|
178
|
|
|
} |
|
179
|
|
|
|
|
180
|
|
|
WC_Stripe_API::set_secret_key( $this->secret_key ); |
|
181
|
|
|
|
|
182
|
|
|
$this->init_apple_pay(); |
|
183
|
|
|
|
|
184
|
|
|
// Hooks. |
|
185
|
|
|
add_action( 'wp_enqueue_scripts', array( $this, 'payment_scripts' ) ); |
|
186
|
|
|
add_action( 'admin_enqueue_scripts', array( $this, 'admin_scripts' ) ); |
|
187
|
|
|
add_action( 'admin_notices', array( $this, 'admin_notices' ) ); |
|
188
|
|
|
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) ); |
|
189
|
|
|
} |
|
190
|
|
|
|
|
191
|
|
|
/** |
|
192
|
|
|
* Get_icon function. |
|
193
|
|
|
* |
|
194
|
|
|
* @access public |
|
195
|
|
|
* @return string |
|
196
|
|
|
*/ |
|
197
|
|
View Code Duplication |
public function get_icon() { |
|
|
|
|
|
|
198
|
|
|
$ext = version_compare( WC()->version, '2.6', '>=' ) ? '.svg' : '.png'; |
|
199
|
|
|
$style = version_compare( WC()->version, '2.6', '>=' ) ? 'style="margin-left: 0.3em"' : ''; |
|
200
|
|
|
|
|
201
|
|
|
$icon = '<img src="' . WC_HTTPS::force_https_url( WC()->plugin_url() . '/assets/images/icons/credit-cards/visa' . $ext ) . '" alt="Visa" width="32" ' . $style . ' />'; |
|
202
|
|
|
$icon .= '<img src="' . WC_HTTPS::force_https_url( WC()->plugin_url() . '/assets/images/icons/credit-cards/mastercard' . $ext ) . '" alt="Mastercard" width="32" ' . $style . ' />'; |
|
203
|
|
|
$icon .= '<img src="' . WC_HTTPS::force_https_url( WC()->plugin_url() . '/assets/images/icons/credit-cards/amex' . $ext ) . '" alt="Amex" width="32" ' . $style . ' />'; |
|
204
|
|
|
|
|
205
|
|
|
if ( 'USD' === get_woocommerce_currency() ) { |
|
206
|
|
|
$icon .= '<img src="' . WC_HTTPS::force_https_url( WC()->plugin_url() . '/assets/images/icons/credit-cards/discover' . $ext ) . '" alt="Discover" width="32" ' . $style . ' />'; |
|
207
|
|
|
$icon .= '<img src="' . WC_HTTPS::force_https_url( WC()->plugin_url() . '/assets/images/icons/credit-cards/jcb' . $ext ) . '" alt="JCB" width="32" ' . $style . ' />'; |
|
208
|
|
|
$icon .= '<img src="' . WC_HTTPS::force_https_url( WC()->plugin_url() . '/assets/images/icons/credit-cards/diners' . $ext ) . '" alt="Diners" width="32" ' . $style . ' />'; |
|
209
|
|
|
} |
|
210
|
|
|
|
|
211
|
|
|
if ( $this->bitcoin && $this->stripe_checkout ) { |
|
212
|
|
|
$icon .= '<img src="' . WC_HTTPS::force_https_url( plugins_url( '/assets/images/bitcoin' . $ext, WC_STRIPE_MAIN_FILE ) ) . '" alt="Bitcoin" width="24" ' . $style . ' />'; |
|
213
|
|
|
} |
|
214
|
|
|
|
|
215
|
|
|
return apply_filters( 'woocommerce_gateway_icon', $icon, $this->id ); |
|
216
|
|
|
} |
|
217
|
|
|
|
|
218
|
|
|
/** |
|
219
|
|
|
* Get Stripe amount to pay |
|
220
|
|
|
* |
|
221
|
|
|
* @param float $total Amount due. |
|
222
|
|
|
* @param string $currency Accepted currency. |
|
223
|
|
|
* |
|
224
|
|
|
* @return float|int |
|
225
|
|
|
*/ |
|
226
|
|
View Code Duplication |
public function get_stripe_amount( $total, $currency = '' ) { |
|
|
|
|
|
|
227
|
|
|
if ( ! $currency ) { |
|
228
|
|
|
$currency = get_woocommerce_currency(); |
|
229
|
|
|
} |
|
230
|
|
|
switch ( strtoupper( $currency ) ) { |
|
231
|
|
|
// Zero decimal currencies. |
|
232
|
|
|
case 'BIF' : |
|
233
|
|
|
case 'CLP' : |
|
234
|
|
|
case 'DJF' : |
|
235
|
|
|
case 'GNF' : |
|
236
|
|
|
case 'JPY' : |
|
237
|
|
|
case 'KMF' : |
|
238
|
|
|
case 'KRW' : |
|
239
|
|
|
case 'MGA' : |
|
240
|
|
|
case 'PYG' : |
|
241
|
|
|
case 'RWF' : |
|
242
|
|
|
case 'VND' : |
|
243
|
|
|
case 'VUV' : |
|
244
|
|
|
case 'XAF' : |
|
245
|
|
|
case 'XOF' : |
|
246
|
|
|
case 'XPF' : |
|
247
|
|
|
$total = absint( $total ); |
|
248
|
|
|
break; |
|
249
|
|
|
default : |
|
250
|
|
|
$total = round( $total, 2 ) * 100; // In cents. |
|
251
|
|
|
break; |
|
252
|
|
|
} |
|
253
|
|
|
return $total; |
|
254
|
|
|
} |
|
255
|
|
|
|
|
256
|
|
|
/** |
|
257
|
|
|
* Initializes Apple Pay process on settings page. |
|
258
|
|
|
* |
|
259
|
|
|
* @since 3.1.0 |
|
260
|
|
|
* @version 3.1.0 |
|
261
|
|
|
*/ |
|
262
|
|
|
public function init_apple_pay() { |
|
263
|
|
|
if ( |
|
264
|
|
|
is_admin() && |
|
265
|
|
|
isset( $_GET['page'] ) && 'wc-settings' === $_GET['page'] && |
|
266
|
|
|
isset( $_GET['tab'] ) && 'checkout' === $_GET['tab'] && |
|
267
|
|
|
isset( $_GET['section'] ) && 'stripe' === $_GET['section'] |
|
268
|
|
|
) { |
|
269
|
|
|
$this->process_apple_pay_verification(); |
|
270
|
|
|
} |
|
271
|
|
|
} |
|
272
|
|
|
|
|
273
|
|
|
/** |
|
274
|
|
|
* Registers the domain with Stripe/Apple Pay |
|
275
|
|
|
* |
|
276
|
|
|
* @since 3.1.0 |
|
277
|
|
|
* @version 3.1.0 |
|
278
|
|
|
* @param string $secret_key |
|
279
|
|
|
*/ |
|
280
|
|
|
private function register_apple_pay_domain( $secret_key = '' ) { |
|
281
|
|
|
if ( empty( $secret_key ) ) { |
|
282
|
|
|
throw new Exception( __( 'Unable to verify domain - missing secret key.', 'woocommerce-gateway-stripe' ) ); |
|
283
|
|
|
} |
|
284
|
|
|
|
|
285
|
|
|
$endpoint = 'https://api.stripe.com/v1/apple_pay/domains'; |
|
286
|
|
|
|
|
287
|
|
|
$data = array( |
|
288
|
|
|
'domain_name' => $_SERVER['HTTP_HOST'], |
|
289
|
|
|
); |
|
290
|
|
|
|
|
291
|
|
|
$headers = array( |
|
292
|
|
|
'User-Agent' => 'WooCommerce Stripe Apple Pay', |
|
293
|
|
|
'Authorization' => 'Bearer ' . $secret_key, |
|
294
|
|
|
); |
|
295
|
|
|
|
|
296
|
|
|
$response = wp_remote_post( $endpoint, array( |
|
297
|
|
|
'headers' => $headers, |
|
298
|
|
|
'body' => http_build_query( $data ), |
|
299
|
|
|
) ); |
|
300
|
|
|
|
|
301
|
|
|
if ( 200 !== $response['response']['code'] ) { |
|
302
|
|
|
$parsed_response = json_decode( $response['body'] ); |
|
303
|
|
|
|
|
304
|
|
|
$this->apple_pay_verify_notice = $parsed_response->error->message; |
|
305
|
|
|
|
|
306
|
|
|
throw new Exception( sprintf( __( 'Unable to verify domain - %s', 'woocommerce-gateway-stripe' ), $parsed_response->error->message ) ); |
|
307
|
|
|
} |
|
308
|
|
|
} |
|
309
|
|
|
|
|
310
|
|
|
/** |
|
311
|
|
|
* Processes the Apple Pay domain verification. |
|
312
|
|
|
* |
|
313
|
|
|
* @since 3.1.0 |
|
314
|
|
|
* @version 3.1.0 |
|
315
|
|
|
*/ |
|
316
|
|
|
public function process_apple_pay_verification() { |
|
317
|
|
|
$gateway_settings = get_option( 'woocommerce_stripe_settings', '' ); |
|
318
|
|
|
|
|
319
|
|
|
try { |
|
320
|
|
|
$path = untrailingslashit( preg_replace( "!${_SERVER['SCRIPT_NAME']}$!", '', $_SERVER['SCRIPT_FILENAME'] ) ); |
|
321
|
|
|
$dir = '.well-known'; |
|
322
|
|
|
$file = 'apple-developer-merchantid-domain-association'; |
|
323
|
|
|
$fullpath = $path . '/' . $dir . '/' . $file; |
|
324
|
|
|
|
|
325
|
|
|
if ( ! empty( $gateway_settings['apple_pay_domain_set'] ) && 'yes' === $gateway_settings['apple_pay_domain_set'] && file_exists( $fullpath ) ) { |
|
326
|
|
|
return; |
|
327
|
|
|
} |
|
328
|
|
|
|
|
329
|
|
|
if ( ! file_exists( $path . '/' . $dir ) ) { |
|
330
|
|
|
if ( ! @mkdir( $path . '/' . $dir, 0755 ) ) { |
|
331
|
|
|
throw new Exception( __( 'Unable to create domain association folder to domain root.', 'woocommerce-gateway-stripe' ) ); |
|
332
|
|
|
} |
|
333
|
|
|
} |
|
334
|
|
|
|
|
335
|
|
|
if ( ! file_exists( $fullpath ) ) { |
|
336
|
|
|
if ( ! @copy( WC_STRIPE_PLUGIN_PATH . '/' . $file, $fullpath ) ) { |
|
337
|
|
|
throw new Exception( __( 'Unable to copy domain association file to domain root.', 'woocommerce-gateway-stripe' ) ); |
|
338
|
|
|
} |
|
339
|
|
|
} |
|
340
|
|
|
|
|
341
|
|
|
// At this point then the domain association folder and file should be available. |
|
342
|
|
|
// Proceed to verify/and or verify again. |
|
343
|
|
|
$this->register_apple_pay_domain( $this->secret_key ); |
|
344
|
|
|
|
|
345
|
|
|
// No errors to this point, verification success! |
|
346
|
|
|
$gateway_settings['apple_pay_domain_set'] = 'yes'; |
|
347
|
|
|
$this->apple_pay_domain_set = true; |
|
348
|
|
|
|
|
349
|
|
|
update_option( 'woocommerce_stripe_settings', $gateway_settings ); |
|
350
|
|
|
|
|
351
|
|
|
$this->log( __( 'Your domain has been verified with Apple Pay!', 'woocommerce-gateway-stripe' ) ); |
|
352
|
|
|
|
|
353
|
|
|
} catch ( Exception $e ) { |
|
354
|
|
|
$gateway_settings['apple_pay_domain_set'] = 'no'; |
|
355
|
|
|
|
|
356
|
|
|
update_option( 'woocommerce_stripe_settings', $gateway_settings ); |
|
357
|
|
|
|
|
358
|
|
|
$this->log( sprintf( __( 'Error: %s', 'woocommerce-gateway-stripe' ), $e->getMessage() ) ); |
|
359
|
|
|
} |
|
360
|
|
|
} |
|
361
|
|
|
|
|
362
|
|
|
/** |
|
363
|
|
|
* Check if SSL is enabled and notify the user |
|
364
|
|
|
*/ |
|
365
|
|
|
public function admin_notices() { |
|
366
|
|
|
if ( 'no' === $this->enabled ) { |
|
367
|
|
|
return; |
|
368
|
|
|
} |
|
369
|
|
|
|
|
370
|
|
|
if ( $this->apple_pay && ! empty( $this->apple_pay_verify_notice ) ) { |
|
371
|
|
|
echo '<div class="error stripe-apple-pay-message"><p>' . wp_kses( make_clickable( $this->apple_pay_verify_notice ) ) . '</p></div>'; |
|
372
|
|
|
} |
|
373
|
|
|
|
|
374
|
|
|
/** |
|
375
|
|
|
* Apple pay is enabled by default and domain verification initializes |
|
376
|
|
|
* when setting screen is displayed. So if domain verification is not set, |
|
377
|
|
|
* something went wrong so lets notify user. |
|
378
|
|
|
*/ |
|
379
|
|
|
if ( ! empty( $this->secret_key ) && $this->apple_pay && ! $this->apple_pay_domain_set ) { |
|
380
|
|
|
echo '<div class="error stripe-apple-pay-message"><p>' . sprintf( __( 'Apple Pay domain verification failed. Please check the %1$slog%2$s to see the issue. (Logging must be enabled to see recorded logs)', 'woocommerce-gateway-stripe' ), '<a href="' . admin_url( 'admin.php?page=wc-status&tab=logs' ) . '">', '</a>' ) . '</p></div>'; |
|
381
|
|
|
} |
|
382
|
|
|
|
|
383
|
|
|
// Show message if enabled and FORCE SSL is disabled and WordpressHTTPS plugin is not detected. |
|
384
|
|
View Code Duplication |
if ( ( function_exists( 'wc_site_is_https' ) && ! wc_site_is_https() ) && ( 'no' === get_option( 'woocommerce_force_ssl_checkout' ) && ! class_exists( 'WordPressHTTPS' ) ) ) { |
|
|
|
|
|
|
385
|
|
|
echo '<div class="error stripe-ssl-message"><p>' . sprintf( __( 'Stripe is enabled, but the <a href="%s">force SSL option</a> is disabled; your checkout may not be secure! Please enable SSL and ensure your server has a valid SSL certificate - Stripe will only work in test mode.', 'woocommerce-gateway-stripe' ), admin_url( 'admin.php?page=wc-settings&tab=checkout' ) ) . '</p></div>'; |
|
386
|
|
|
} |
|
387
|
|
|
} |
|
388
|
|
|
|
|
389
|
|
|
/** |
|
390
|
|
|
* Check if this gateway is enabled |
|
391
|
|
|
*/ |
|
392
|
|
View Code Duplication |
public function is_available() { |
|
|
|
|
|
|
393
|
|
|
if ( 'yes' === $this->enabled ) { |
|
394
|
|
|
if ( ! $this->testmode && is_checkout() && ! is_ssl() ) { |
|
395
|
|
|
return false; |
|
396
|
|
|
} |
|
397
|
|
|
if ( ! $this->secret_key || ! $this->publishable_key ) { |
|
398
|
|
|
return false; |
|
399
|
|
|
} |
|
400
|
|
|
return true; |
|
401
|
|
|
} |
|
402
|
|
|
return false; |
|
403
|
|
|
} |
|
404
|
|
|
|
|
405
|
|
|
/** |
|
406
|
|
|
* Initialise Gateway Settings Form Fields |
|
407
|
|
|
*/ |
|
408
|
|
|
public function init_form_fields() { |
|
409
|
|
|
$this->form_fields = include( 'settings-stripe.php' ); |
|
410
|
|
|
} |
|
411
|
|
|
|
|
412
|
|
|
/** |
|
413
|
|
|
* Payment form on checkout page |
|
414
|
|
|
*/ |
|
415
|
|
|
public function payment_fields() { |
|
416
|
|
|
$user = wp_get_current_user(); |
|
417
|
|
|
$display_tokenization = $this->supports( 'tokenization' ) && is_checkout() && $this->saved_cards; |
|
418
|
|
|
$total = WC()->cart->total; |
|
419
|
|
|
|
|
420
|
|
|
// If paying from order, we need to get total from order not cart. |
|
421
|
|
|
if ( isset( $_GET['pay_for_order'] ) && ! empty( $_GET['key'] ) ) { |
|
422
|
|
|
$order = wc_get_order( wc_get_order_id_by_order_key( wc_clean( $_GET['key'] ) ) ); |
|
423
|
|
|
$total = $order->get_total(); |
|
424
|
|
|
} |
|
425
|
|
|
|
|
426
|
|
View Code Duplication |
if ( $user->ID ) { |
|
|
|
|
|
|
427
|
|
|
$user_email = get_user_meta( $user->ID, 'billing_email', true ); |
|
428
|
|
|
$user_email = $user_email ? $user_email : $user->user_email; |
|
429
|
|
|
} else { |
|
430
|
|
|
$user_email = ''; |
|
431
|
|
|
} |
|
432
|
|
|
|
|
433
|
|
|
if ( is_add_payment_method_page() ) { |
|
434
|
|
|
$pay_button_text = __( 'Add Card', 'woocommerce-gateway-stripe' ); |
|
435
|
|
|
} else { |
|
436
|
|
|
$pay_button_text = ''; |
|
437
|
|
|
} |
|
438
|
|
|
|
|
439
|
|
|
echo '<div |
|
440
|
|
|
id="stripe-payment-data" |
|
441
|
|
|
data-panel-label="' . esc_attr( $pay_button_text ) . '" |
|
442
|
|
|
data-description="" |
|
443
|
|
|
data-email="' . esc_attr( $user_email ) . '" |
|
444
|
|
|
data-amount="' . esc_attr( $this->get_stripe_amount( $total ) ) . '" |
|
445
|
|
|
data-name="' . esc_attr( $this->statement_descriptor ) . '" |
|
446
|
|
|
data-currency="' . esc_attr( strtolower( get_woocommerce_currency() ) ) . '" |
|
447
|
|
|
data-image="' . esc_attr( $this->stripe_checkout_image ) . '" |
|
448
|
|
|
data-bitcoin="' . esc_attr( $this->bitcoin ? 'true' : 'false' ) . '" |
|
449
|
|
|
data-locale="' . esc_attr( $this->stripe_checkout_locale ? $this->stripe_checkout_locale : 'en' ) . '" |
|
450
|
|
|
data-allow-remember-me="' . esc_attr( $this->saved_cards ? 'true' : 'false' ) . '">'; |
|
451
|
|
|
|
|
452
|
|
|
if ( $this->description ) { |
|
453
|
|
|
echo apply_filters( 'wc_stripe_description', wpautop( wp_kses_post( $this->description ) ) ); |
|
454
|
|
|
} |
|
455
|
|
|
|
|
456
|
|
|
if ( $display_tokenization ) { |
|
457
|
|
|
$this->tokenization_script(); |
|
458
|
|
|
$this->saved_payment_methods(); |
|
459
|
|
|
} |
|
460
|
|
|
|
|
461
|
|
|
if ( ! $this->stripe_checkout ) { |
|
462
|
|
|
$this->form(); |
|
463
|
|
|
|
|
464
|
|
|
if ( $display_tokenization ) { |
|
465
|
|
|
$this->save_payment_method_checkbox(); |
|
466
|
|
|
} |
|
467
|
|
|
} |
|
468
|
|
|
|
|
469
|
|
|
echo '</div>'; |
|
470
|
|
|
} |
|
471
|
|
|
|
|
472
|
|
|
/** |
|
473
|
|
|
* Localize Stripe messages based on code |
|
474
|
|
|
* |
|
475
|
|
|
* @since 3.0.6 |
|
476
|
|
|
* @version 3.0.6 |
|
477
|
|
|
* @return array |
|
478
|
|
|
*/ |
|
479
|
|
|
public function get_localized_messages() { |
|
480
|
|
|
return apply_filters( 'wc_stripe_localized_messages', array( |
|
481
|
|
|
'invalid_number' => __( 'The card number is not a valid credit card number.', 'woocommerce-gateway-stripe' ), |
|
482
|
|
|
'invalid_expiry_month' => __( 'The card\'s expiration month is invalid.', 'woocommerce-gateway-stripe' ), |
|
483
|
|
|
'invalid_expiry_year' => __( 'The card\'s expiration year is invalid.', 'woocommerce-gateway-stripe' ), |
|
484
|
|
|
'invalid_cvc' => __( 'The card\'s security code is invalid.', 'woocommerce-gateway-stripe' ), |
|
485
|
|
|
'incorrect_number' => __( 'The card number is incorrect.', 'woocommerce-gateway-stripe' ), |
|
486
|
|
|
'expired_card' => __( 'The card has expired.', 'woocommerce-gateway-stripe' ), |
|
487
|
|
|
'incorrect_cvc' => __( 'The card\'s security code is incorrect.', 'woocommerce-gateway-stripe' ), |
|
488
|
|
|
'incorrect_zip' => __( 'The card\'s zip code failed validation.', 'woocommerce-gateway-stripe' ), |
|
489
|
|
|
'card_declined' => __( 'The card was declined.', 'woocommerce-gateway-stripe' ), |
|
490
|
|
|
'missing' => __( 'There is no card on a customer that is being charged.', 'woocommerce-gateway-stripe' ), |
|
491
|
|
|
'processing_error' => __( 'An error occurred while processing the card.', 'woocommerce-gateway-stripe' ), |
|
492
|
|
|
'invalid_request_error' => __( 'Could not find payment information.', 'woocommerce-gateway-stripe' ), |
|
493
|
|
|
) ); |
|
494
|
|
|
} |
|
495
|
|
|
|
|
496
|
|
|
/** |
|
497
|
|
|
* Load admin scripts. |
|
498
|
|
|
* |
|
499
|
|
|
* @since 3.1.0 |
|
500
|
|
|
* @version 3.1.0 |
|
501
|
|
|
*/ |
|
502
|
|
|
public function admin_scripts() { |
|
503
|
|
|
if ( 'woocommerce_page_wc-settings' !== get_current_screen()->id ) { |
|
504
|
|
|
return; |
|
505
|
|
|
} |
|
506
|
|
|
|
|
507
|
|
|
$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; |
|
508
|
|
|
|
|
509
|
|
|
wp_enqueue_script( 'woocommerce_stripe_admin', plugins_url( 'assets/js/stripe-admin' . $suffix . '.js', WC_STRIPE_MAIN_FILE ), array(), WC_STRIPE_VERSION, true ); |
|
510
|
|
|
|
|
511
|
|
|
$stripe_admin_params = array( |
|
512
|
|
|
'localized_messages' => array( |
|
513
|
|
|
'not_valid_live_key_msg' => __( 'This is not a valid live key. Live keys start with "sk_live_" and "pk_live_".', 'woocommerce-gateway-stripe' ), |
|
514
|
|
|
'not_valid_test_key_msg' => __( 'This is not a valid test key. Test keys start with "sk_test_" and "pk_test_".', 'woocommerce-gateway-stripe' ), |
|
515
|
|
|
're_verify_button_text' => __( 'Re-verify Domain', 'woocommerce-gateway-stripe' ), |
|
516
|
|
|
'missing_secret_key' => __( 'Missing Secret Key. Please set the secret key field above and re-try.', 'woocommerce-gateway-stripe' ), |
|
517
|
|
|
), |
|
518
|
|
|
'ajaxurl' => admin_url( 'admin-ajax.php' ), |
|
519
|
|
|
'nonce' => array( |
|
520
|
|
|
'apple_pay_domain_nonce' => wp_create_nonce( '_wc_stripe_apple_pay_domain_nonce' ), |
|
521
|
|
|
), |
|
522
|
|
|
); |
|
523
|
|
|
|
|
524
|
|
|
wp_localize_script( 'woocommerce_stripe_admin', 'wc_stripe_admin_params', apply_filters( 'wc_stripe_admin_params', $stripe_admin_params ) ); |
|
525
|
|
|
} |
|
526
|
|
|
|
|
527
|
|
|
/** |
|
528
|
|
|
* payment_scripts function. |
|
529
|
|
|
* |
|
530
|
|
|
* Outputs scripts used for stripe payment |
|
531
|
|
|
* |
|
532
|
|
|
* @access public |
|
533
|
|
|
*/ |
|
534
|
|
|
public function payment_scripts() { |
|
535
|
|
|
if ( ! is_cart() && ! is_checkout() && ! isset( $_GET['pay_for_order'] ) && ! is_add_payment_method_page() ) { |
|
536
|
|
|
return; |
|
537
|
|
|
} |
|
538
|
|
|
|
|
539
|
|
|
$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; |
|
540
|
|
|
|
|
541
|
|
|
if ( $this->stripe_checkout ) { |
|
542
|
|
|
wp_enqueue_script( 'stripe_checkout', 'https://checkout.stripe.com/v2/checkout.js', '', '2.0', true ); |
|
543
|
|
|
wp_enqueue_script( 'woocommerce_stripe', plugins_url( 'assets/js/stripe-checkout' . $suffix . '.js', WC_STRIPE_MAIN_FILE ), array( 'stripe_checkout' ), WC_STRIPE_VERSION, true ); |
|
544
|
|
View Code Duplication |
} else { |
|
|
|
|
|
|
545
|
|
|
wp_enqueue_script( 'stripe', 'https://js.stripe.com/v2/', '', '1.0', true ); |
|
546
|
|
|
wp_enqueue_script( 'woocommerce_stripe', plugins_url( 'assets/js/stripe' . $suffix . '.js', WC_STRIPE_MAIN_FILE ), array( 'jquery-payment', 'stripe' ), WC_STRIPE_VERSION, true ); |
|
547
|
|
|
} |
|
548
|
|
|
|
|
549
|
|
|
$stripe_params = array( |
|
550
|
|
|
'key' => $this->publishable_key, |
|
551
|
|
|
'i18n_terms' => __( 'Please accept the terms and conditions first', 'woocommerce-gateway-stripe' ), |
|
552
|
|
|
'i18n_required_fields' => __( 'Please fill in required checkout fields first', 'woocommerce-gateway-stripe' ), |
|
553
|
|
|
); |
|
554
|
|
|
|
|
555
|
|
|
// If we're on the pay page we need to pass stripe.js the address of the order. |
|
556
|
|
|
if ( isset( $_GET['pay_for_order'] ) && 'true' === $_GET['pay_for_order'] ) { |
|
557
|
|
|
$order_id = wc_get_order_id_by_order_key( urldecode( $_GET['key'] ) ); |
|
558
|
|
|
$order = wc_get_order( $order_id ); |
|
559
|
|
|
|
|
560
|
|
|
$stripe_params['billing_first_name'] = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->billing_first_name : $order->get_billing_first_name(); |
|
561
|
|
|
$stripe_params['billing_last_name'] = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->billing_last_name : $order->get_billing_last_name(); |
|
562
|
|
|
$stripe_params['billing_address_1'] = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->billing_address_1 : $order->get_billing_address_1(); |
|
563
|
|
|
$stripe_params['billing_address_2'] = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->billing_address_2 : $order->get_billing_address_2(); |
|
564
|
|
|
$stripe_params['billing_state'] = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->billing_state : $order->get_billing_state(); |
|
565
|
|
|
$stripe_params['billing_city'] = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->billing_city : $order->get_billing_city(); |
|
566
|
|
|
$stripe_params['billing_postcode'] = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->billing_postcode : $order->get_billing_postcode(); |
|
567
|
|
|
$stripe_params['billing_country'] = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->billing_country : $order->get_billing_country(); |
|
568
|
|
|
} |
|
569
|
|
|
|
|
570
|
|
|
$stripe_params['no_prepaid_card_msg'] = __( 'Sorry, we\'re not accepting prepaid cards at this time.', 'woocommerce-gateway-stripe' ); |
|
571
|
|
|
$stripe_params['allow_prepaid_card'] = apply_filters( 'wc_stripe_allow_prepaid_card', true ) ? 'yes' : 'no'; |
|
572
|
|
|
$stripe_params['stripe_checkout_require_billing_address'] = apply_filters( 'wc_stripe_checkout_require_billing_address', false ) ? 'yes' : 'no'; |
|
573
|
|
|
|
|
574
|
|
|
// merge localized messages to be use in JS |
|
575
|
|
|
$stripe_params = array_merge( $stripe_params, $this->get_localized_messages() ); |
|
576
|
|
|
|
|
577
|
|
|
wp_localize_script( 'woocommerce_stripe', 'wc_stripe_params', apply_filters( 'wc_stripe_params', $stripe_params ) ); |
|
578
|
|
|
} |
|
579
|
|
|
|
|
580
|
|
|
/** |
|
581
|
|
|
* Generate the request for the payment. |
|
582
|
|
|
* @param WC_Order $order |
|
583
|
|
|
* @param object $source |
|
584
|
|
|
* @return array() |
|
|
|
|
|
|
585
|
|
|
*/ |
|
586
|
|
|
protected function generate_payment_request( $order, $source ) { |
|
587
|
|
|
$post_data = array(); |
|
588
|
|
|
$post_data['currency'] = strtolower( version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->get_order_currency() : $order->get_currency() ); |
|
589
|
|
|
$post_data['amount'] = $this->get_stripe_amount( $order->get_total(), $post_data['currency'] ); |
|
590
|
|
|
$post_data['description'] = sprintf( __( '%1$s - Order %2$s', 'woocommerce-gateway-stripe' ), $this->statement_descriptor, $order->get_order_number() ); |
|
591
|
|
|
$post_data['capture'] = $this->capture ? 'true' : 'false'; |
|
592
|
|
|
|
|
593
|
|
|
$billing_email = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->billing_email : $order->get_billing_email(); |
|
594
|
|
|
$billing_first_name = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->billing_first_name : $order->get_billing_first_name(); |
|
595
|
|
|
$billing_last_name = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->billing_last_name : $order->get_billing_last_name(); |
|
596
|
|
|
|
|
597
|
|
|
if ( ! empty( $billing_email ) && apply_filters( 'wc_stripe_send_stripe_receipt', false ) ) { |
|
598
|
|
|
$post_data['receipt_email'] = $billing_email; |
|
599
|
|
|
} |
|
600
|
|
|
|
|
601
|
|
|
$post_data['expand[]'] = 'balance_transaction'; |
|
602
|
|
|
|
|
603
|
|
|
$metadata = array( |
|
604
|
|
|
__( 'Customer Name', 'woocommerce-gateway-stripe' ) => sanitize_text_field( $billing_first_name ) . ' ' . sanitize_text_field( $billing_last_name ), |
|
605
|
|
|
__( 'Customer Email', 'woocommerce-gateway-stripe' ) => sanitize_email( $billing_email ), |
|
606
|
|
|
); |
|
607
|
|
|
|
|
608
|
|
|
$post_data['metadata'] = apply_filters( 'wc_stripe_payment_metadata', $metadata, $order, $source ); |
|
609
|
|
|
|
|
610
|
|
|
if ( $source->customer ) { |
|
611
|
|
|
$post_data['customer'] = $source->customer; |
|
612
|
|
|
} |
|
613
|
|
|
|
|
614
|
|
|
if ( $source->source ) { |
|
615
|
|
|
$post_data['source'] = $source->source; |
|
616
|
|
|
} |
|
617
|
|
|
|
|
618
|
|
|
/** |
|
619
|
|
|
* Filter the return value of the WC_Payment_Gateway_CC::generate_payment_request. |
|
620
|
|
|
* |
|
621
|
|
|
* @since 3.1.0 |
|
622
|
|
|
* @param array $post_data |
|
623
|
|
|
* @param WC_Order $order |
|
624
|
|
|
* @param object $source |
|
625
|
|
|
*/ |
|
626
|
|
|
return apply_filters( 'wc_stripe_generate_payment_request', $post_data, $order, $source ); |
|
627
|
|
|
} |
|
628
|
|
|
|
|
629
|
|
|
/** |
|
630
|
|
|
* Get payment source. This can be a new token or existing card. |
|
631
|
|
|
* |
|
632
|
|
|
* @param string $user_id |
|
633
|
|
|
* @param bool $force_customer Should we force customer creation. |
|
634
|
|
|
* |
|
635
|
|
|
* @throws Exception When card was not added or for and invalid card. |
|
636
|
|
|
* @return object |
|
637
|
|
|
*/ |
|
638
|
|
|
protected function get_source( $user_id, $force_customer = false ) { |
|
639
|
|
|
$stripe_customer = new WC_Stripe_Customer( $user_id ); |
|
640
|
|
|
$stripe_source = false; |
|
641
|
|
|
$token_id = false; |
|
642
|
|
|
|
|
643
|
|
|
// New CC info was entered and we have a new token to process |
|
644
|
|
|
if ( isset( $_POST['stripe_token'] ) ) { |
|
645
|
|
|
$stripe_token = wc_clean( $_POST['stripe_token'] ); |
|
646
|
|
|
$maybe_saved_card = isset( $_POST['wc-stripe-new-payment-method'] ) && ! empty( $_POST['wc-stripe-new-payment-method'] ); |
|
647
|
|
|
|
|
648
|
|
|
// This is true if the user wants to store the card to their account. |
|
649
|
|
View Code Duplication |
if ( ( $user_id && $this->saved_cards && $maybe_saved_card ) || $force_customer ) { |
|
|
|
|
|
|
650
|
|
|
$stripe_source = $stripe_customer->add_card( $stripe_token ); |
|
651
|
|
|
|
|
652
|
|
|
if ( is_wp_error( $stripe_source ) ) { |
|
653
|
|
|
throw new Exception( $stripe_source->get_error_message() ); |
|
654
|
|
|
} |
|
655
|
|
|
} else { |
|
656
|
|
|
// Not saving token, so don't define customer either. |
|
657
|
|
|
$stripe_source = $stripe_token; |
|
658
|
|
|
$stripe_customer = false; |
|
659
|
|
|
} |
|
660
|
|
|
} elseif ( isset( $_POST['wc-stripe-payment-token'] ) && 'new' !== $_POST['wc-stripe-payment-token'] ) { |
|
661
|
|
|
// Use an existing token, and then process the payment |
|
662
|
|
|
|
|
663
|
|
|
$token_id = wc_clean( $_POST['wc-stripe-payment-token'] ); |
|
664
|
|
|
$token = WC_Payment_Tokens::get( $token_id ); |
|
665
|
|
|
|
|
666
|
|
|
if ( ! $token || $token->get_user_id() !== get_current_user_id() ) { |
|
667
|
|
|
WC()->session->set( 'refresh_totals', true ); |
|
668
|
|
|
throw new Exception( __( 'Invalid payment method. Please input a new card number.', 'woocommerce-gateway-stripe' ) ); |
|
669
|
|
|
} |
|
670
|
|
|
|
|
671
|
|
|
$stripe_source = $token->get_token(); |
|
672
|
|
|
} |
|
673
|
|
|
|
|
674
|
|
|
return (object) array( |
|
675
|
|
|
'token_id' => $token_id, |
|
676
|
|
|
'customer' => $stripe_customer ? $stripe_customer->get_id() : false, |
|
677
|
|
|
'source' => $stripe_source, |
|
678
|
|
|
); |
|
679
|
|
|
} |
|
680
|
|
|
|
|
681
|
|
|
/** |
|
682
|
|
|
* Get payment source from an order. This could be used in the future for |
|
683
|
|
|
* a subscription as an example, therefore using the current user ID would |
|
684
|
|
|
* not work - the customer won't be logged in :) |
|
685
|
|
|
* |
|
686
|
|
|
* Not using 2.6 tokens for this part since we need a customer AND a card |
|
687
|
|
|
* token, and not just one. |
|
688
|
|
|
* |
|
689
|
|
|
* @param object $order |
|
690
|
|
|
* @return object |
|
691
|
|
|
*/ |
|
692
|
|
|
protected function get_order_source( $order = null ) { |
|
693
|
|
|
$stripe_customer = new WC_Stripe_Customer(); |
|
694
|
|
|
$stripe_source = false; |
|
695
|
|
|
$token_id = false; |
|
696
|
|
|
|
|
697
|
|
|
if ( $order ) { |
|
698
|
|
|
$order_id = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->id : $order->get_id(); |
|
699
|
|
|
|
|
700
|
|
|
if ( $meta_value = get_post_meta( $order_id, '_stripe_customer_id', true ) ) { |
|
701
|
|
|
$stripe_customer->set_id( $meta_value ); |
|
702
|
|
|
} |
|
703
|
|
|
|
|
704
|
|
|
if ( $meta_value = get_post_meta( $order_id, '_stripe_card_id', true ) ) { |
|
705
|
|
|
$stripe_source = $meta_value; |
|
706
|
|
|
} |
|
707
|
|
|
} |
|
708
|
|
|
|
|
709
|
|
|
return (object) array( |
|
710
|
|
|
'token_id' => $token_id, |
|
711
|
|
|
'customer' => $stripe_customer ? $stripe_customer->get_id() : false, |
|
712
|
|
|
'source' => $stripe_source, |
|
713
|
|
|
); |
|
714
|
|
|
} |
|
715
|
|
|
|
|
716
|
|
|
/** |
|
717
|
|
|
* Process the payment |
|
718
|
|
|
* |
|
719
|
|
|
* @param int $order_id Reference. |
|
720
|
|
|
* @param bool $retry Should we retry on fail. |
|
721
|
|
|
* @param bool $force_customer Force user creation. |
|
722
|
|
|
* |
|
723
|
|
|
* @throws Exception If payment will not be accepted. |
|
724
|
|
|
* |
|
725
|
|
|
* @return array|void |
|
726
|
|
|
*/ |
|
727
|
|
|
public function process_payment( $order_id, $retry = true, $force_customer = false ) { |
|
728
|
|
|
try { |
|
729
|
|
|
$order = wc_get_order( $order_id ); |
|
730
|
|
|
$source = $this->get_source( get_current_user_id(), $force_customer ); |
|
731
|
|
|
|
|
732
|
|
View Code Duplication |
if ( empty( $source->source ) && empty( $source->customer ) ) { |
|
|
|
|
|
|
733
|
|
|
$error_msg = __( 'Please enter your card details to make a payment.', 'woocommerce-gateway-stripe' ); |
|
734
|
|
|
$error_msg .= ' ' . __( 'Developers: Please make sure that you are including jQuery and there are no JavaScript errors on the page.', 'woocommerce-gateway-stripe' ); |
|
735
|
|
|
throw new Exception( $error_msg ); |
|
736
|
|
|
} |
|
737
|
|
|
|
|
738
|
|
|
// Store source to order meta. |
|
739
|
|
|
$this->save_source( $order, $source ); |
|
740
|
|
|
|
|
741
|
|
|
// Handle payment. |
|
742
|
|
|
if ( $order->get_total() > 0 ) { |
|
743
|
|
|
|
|
744
|
|
View Code Duplication |
if ( $order->get_total() * 100 < WC_Stripe::get_minimum_amount() ) { |
|
|
|
|
|
|
745
|
|
|
throw new Exception( sprintf( __( 'Sorry, the minimum allowed order total is %1$s to use this payment method.', 'woocommerce-gateway-stripe' ), wc_price( WC_Stripe::get_minimum_amount() / 100 ) ) ); |
|
746
|
|
|
} |
|
747
|
|
|
|
|
748
|
|
|
$this->log( "Info: Begin processing payment for order $order_id for the amount of {$order->get_total()}" ); |
|
749
|
|
|
|
|
750
|
|
|
// Make the request. |
|
751
|
|
|
$response = WC_Stripe_API::request( $this->generate_payment_request( $order, $source ) ); |
|
752
|
|
|
|
|
753
|
|
|
if ( is_wp_error( $response ) ) { |
|
754
|
|
|
// Customer param wrong? The user may have been deleted on stripe's end. Remove customer_id. Can be retried without. |
|
755
|
|
|
if ( 'customer' === $response->get_error_code() && $retry ) { |
|
756
|
|
|
delete_user_meta( get_current_user_id(), '_stripe_customer_id' ); |
|
757
|
|
|
return $this->process_payment( $order_id, false, $force_customer ); |
|
758
|
|
|
// Source param wrong? The CARD may have been deleted on stripe's end. Remove token and show message. |
|
759
|
|
|
} elseif ( 'source' === $response->get_error_code() && $source->token_id ) { |
|
760
|
|
|
$token = WC_Payment_Tokens::get( $source->token_id ); |
|
761
|
|
|
$token->delete(); |
|
762
|
|
|
$message = __( 'This card is no longer available and has been removed.', 'woocommerce-gateway-stripe' ); |
|
763
|
|
|
$order->add_order_note( $message ); |
|
764
|
|
|
throw new Exception( $message ); |
|
765
|
|
|
} |
|
766
|
|
|
|
|
767
|
|
|
$localized_messages = $this->get_localized_messages(); |
|
768
|
|
|
|
|
769
|
|
|
$message = isset( $localized_messages[ $response->get_error_code() ] ) ? $localized_messages[ $response->get_error_code() ] : $response->get_error_message(); |
|
770
|
|
|
|
|
771
|
|
|
$order->add_order_note( $message ); |
|
772
|
|
|
|
|
773
|
|
|
throw new Exception( $message ); |
|
774
|
|
|
} |
|
775
|
|
|
|
|
776
|
|
|
// Process valid response. |
|
777
|
|
|
$this->process_response( $response, $order ); |
|
778
|
|
|
} else { |
|
779
|
|
|
$order->payment_complete(); |
|
780
|
|
|
} |
|
781
|
|
|
|
|
782
|
|
|
// Remove cart. |
|
783
|
|
|
WC()->cart->empty_cart(); |
|
784
|
|
|
|
|
785
|
|
|
do_action( 'wc_gateway_stripe_process_payment', $response, $order ); |
|
|
|
|
|
|
786
|
|
|
|
|
787
|
|
|
// Return thank you page redirect. |
|
788
|
|
|
return array( |
|
789
|
|
|
'result' => 'success', |
|
790
|
|
|
'redirect' => $this->get_return_url( $order ), |
|
791
|
|
|
); |
|
792
|
|
|
|
|
793
|
|
|
} catch ( Exception $e ) { |
|
794
|
|
|
wc_add_notice( $e->getMessage(), 'error' ); |
|
795
|
|
|
$this->log( sprintf( __( 'Error: %s', 'woocommerce-gateway-stripe' ), $e->getMessage() ) ); |
|
796
|
|
|
|
|
797
|
|
|
if ( $order->has_status( array( 'pending', 'failed' ) ) ) { |
|
798
|
|
|
$this->send_failed_order_email( $order_id ); |
|
799
|
|
|
} |
|
800
|
|
|
|
|
801
|
|
|
do_action( 'wc_gateway_stripe_process_payment_error', $e, $order ); |
|
802
|
|
|
|
|
803
|
|
|
return array( |
|
804
|
|
|
'result' => 'fail', |
|
805
|
|
|
'redirect' => '', |
|
806
|
|
|
); |
|
807
|
|
|
} |
|
808
|
|
|
} |
|
809
|
|
|
|
|
810
|
|
|
/** |
|
811
|
|
|
* Save source to order. |
|
812
|
|
|
* |
|
813
|
|
|
* @param WC_Order $order For to which the source applies. |
|
814
|
|
|
* @param stdClass $source Source information. |
|
815
|
|
|
*/ |
|
816
|
|
|
protected function save_source( $order, $source ) { |
|
817
|
|
|
$order_id = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->id : $order->get_id(); |
|
818
|
|
|
|
|
819
|
|
|
// Store source in the order. |
|
820
|
|
|
if ( $source->customer ) { |
|
821
|
|
|
update_post_meta( $order_id, '_stripe_customer_id', $source->customer ); |
|
822
|
|
|
} |
|
823
|
|
|
if ( $source->source ) { |
|
824
|
|
|
update_post_meta( $order_id, '_stripe_card_id', $source->source ); |
|
825
|
|
|
} |
|
826
|
|
|
} |
|
827
|
|
|
|
|
828
|
|
|
/** |
|
829
|
|
|
* Store extra meta data for an order from a Stripe Response. |
|
830
|
|
|
*/ |
|
831
|
|
|
public function process_response( $response, $order ) { |
|
832
|
|
|
$this->log( 'Processing response: ' . print_r( $response, true ) ); |
|
833
|
|
|
|
|
834
|
|
|
$order_id = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->id : $order->get_id(); |
|
835
|
|
|
|
|
836
|
|
|
// Store charge data |
|
837
|
|
|
update_post_meta( $order_id, '_stripe_charge_id', $response->id ); |
|
838
|
|
|
update_post_meta( $order_id, '_stripe_charge_captured', $response->captured ? 'yes' : 'no' ); |
|
839
|
|
|
|
|
840
|
|
|
// Store other data such as fees |
|
841
|
|
View Code Duplication |
if ( isset( $response->balance_transaction ) && isset( $response->balance_transaction->fee ) ) { |
|
|
|
|
|
|
842
|
|
|
// Fees and Net needs to both come from Stripe to be accurate as the returned |
|
843
|
|
|
// values are in the local currency of the Stripe account, not from WC. |
|
844
|
|
|
$fee = ! empty( $response->balance_transaction->fee ) ? WC_Stripe::format_number( $response->balance_transaction, 'fee' ) : 0; |
|
845
|
|
|
$net = ! empty( $response->balance_transaction->net ) ? WC_Stripe::format_number( $response->balance_transaction, 'net' ) : 0; |
|
846
|
|
|
update_post_meta( $order_id, 'Stripe Fee', $fee ); |
|
847
|
|
|
update_post_meta( $order_id, 'Net Revenue From Stripe', $net ); |
|
848
|
|
|
} |
|
849
|
|
|
|
|
850
|
|
|
if ( $response->captured ) { |
|
851
|
|
|
$order->payment_complete( $response->id ); |
|
852
|
|
|
|
|
853
|
|
|
$message = sprintf( __( 'Stripe charge complete (Charge ID: %s)', 'woocommerce-gateway-stripe' ), $response->id ); |
|
854
|
|
|
$order->add_order_note( $message ); |
|
855
|
|
|
$this->log( 'Success: ' . $message ); |
|
856
|
|
|
|
|
857
|
|
|
} else { |
|
858
|
|
|
add_post_meta( $order_id, '_transaction_id', $response->id, true ); |
|
859
|
|
|
|
|
860
|
|
|
if ( $order->has_status( array( 'pending', 'failed' ) ) ) { |
|
861
|
|
|
version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->reduce_order_stock() : wc_reduce_stock_levels( $order_id ); |
|
862
|
|
|
} |
|
863
|
|
|
|
|
864
|
|
|
$order->update_status( 'on-hold', sprintf( __( 'Stripe charge authorized (Charge ID: %s). Process order to take payment, or cancel to remove the pre-authorization.', 'woocommerce-gateway-stripe' ), $response->id ) ); |
|
865
|
|
|
$this->log( "Successful auth: $response->id" ); |
|
866
|
|
|
} |
|
867
|
|
|
|
|
868
|
|
|
return $response; |
|
869
|
|
|
} |
|
870
|
|
|
|
|
871
|
|
|
/** |
|
872
|
|
|
* Add payment method via account screen. |
|
873
|
|
|
* We don't store the token locally, but to the Stripe API. |
|
874
|
|
|
* @since 3.0.0 |
|
875
|
|
|
*/ |
|
876
|
|
|
public function add_payment_method() { |
|
877
|
|
|
if ( empty( $_POST['stripe_token'] ) || ! is_user_logged_in() ) { |
|
878
|
|
|
wc_add_notice( __( 'There was a problem adding the card.', 'woocommerce-gateway-stripe' ), 'error' ); |
|
879
|
|
|
return; |
|
880
|
|
|
} |
|
881
|
|
|
|
|
882
|
|
|
$stripe_customer = new WC_Stripe_Customer( get_current_user_id() ); |
|
883
|
|
|
$card = $stripe_customer->add_card( wc_clean( $_POST['stripe_token'] ) ); |
|
884
|
|
|
|
|
885
|
|
|
if ( is_wp_error( $card ) ) { |
|
886
|
|
|
$localized_messages = $this->get_localized_messages(); |
|
887
|
|
|
$error_msg = __( 'There was a problem adding the card.', 'woocommerce-gateway-stripe' ); |
|
888
|
|
|
|
|
889
|
|
|
// loop through the errors to find matching localized message |
|
890
|
|
|
foreach ( $card->errors as $error => $msg ) { |
|
891
|
|
|
if ( isset( $localized_messages[ $error ] ) ) { |
|
892
|
|
|
$error_msg = $localized_messages[ $error ]; |
|
893
|
|
|
} |
|
894
|
|
|
} |
|
895
|
|
|
|
|
896
|
|
|
wc_add_notice( $error_msg, 'error' ); |
|
897
|
|
|
return; |
|
898
|
|
|
} |
|
899
|
|
|
|
|
900
|
|
|
return array( |
|
901
|
|
|
'result' => 'success', |
|
902
|
|
|
'redirect' => wc_get_endpoint_url( 'payment-methods' ), |
|
903
|
|
|
); |
|
904
|
|
|
} |
|
905
|
|
|
|
|
906
|
|
|
/** |
|
907
|
|
|
* Refund a charge |
|
908
|
|
|
* @param int $order_id |
|
909
|
|
|
* @param float $amount |
|
910
|
|
|
* @return bool |
|
911
|
|
|
*/ |
|
912
|
|
|
public function process_refund( $order_id, $amount = null, $reason = '' ) { |
|
913
|
|
|
$order = wc_get_order( $order_id ); |
|
914
|
|
|
|
|
915
|
|
|
if ( ! $order || ! $order->get_transaction_id() ) { |
|
916
|
|
|
return false; |
|
917
|
|
|
} |
|
918
|
|
|
|
|
919
|
|
|
$body = array(); |
|
920
|
|
|
|
|
921
|
|
|
if ( ! is_null( $amount ) ) { |
|
922
|
|
|
$body['amount'] = $this->get_stripe_amount( $amount ); |
|
923
|
|
|
} |
|
924
|
|
|
|
|
925
|
|
|
if ( $reason ) { |
|
926
|
|
|
$body['metadata'] = array( |
|
927
|
|
|
'reason' => $reason, |
|
928
|
|
|
); |
|
929
|
|
|
} |
|
930
|
|
|
|
|
931
|
|
|
$this->log( "Info: Beginning refund for order $order_id for the amount of {$amount}" ); |
|
932
|
|
|
|
|
933
|
|
|
$response = WC_Stripe_API::request( $body, 'charges/' . $order->get_transaction_id() . '/refunds' ); |
|
934
|
|
|
|
|
935
|
|
|
if ( is_wp_error( $response ) ) { |
|
936
|
|
|
$this->log( 'Error: ' . $response->get_error_message() ); |
|
937
|
|
|
return $response; |
|
938
|
|
|
} elseif ( ! empty( $response->id ) ) { |
|
939
|
|
|
$refund_message = sprintf( __( 'Refunded %1$s - Refund ID: %2$s - Reason: %3$s', 'woocommerce-gateway-stripe' ), wc_price( $response->amount / 100 ), $response->id, $reason ); |
|
940
|
|
|
$order->add_order_note( $refund_message ); |
|
941
|
|
|
$this->log( 'Success: ' . html_entity_decode( strip_tags( $refund_message ) ) ); |
|
942
|
|
|
return true; |
|
943
|
|
|
} |
|
944
|
|
|
} |
|
945
|
|
|
|
|
946
|
|
|
/** |
|
947
|
|
|
* Sends the failed order email to admin |
|
948
|
|
|
* |
|
949
|
|
|
* @version 3.1.0 |
|
950
|
|
|
* @since 3.1.0 |
|
951
|
|
|
* @param int $order_id |
|
952
|
|
|
* @return null |
|
953
|
|
|
*/ |
|
954
|
|
|
public function send_failed_order_email( $order_id ) { |
|
955
|
|
|
$emails = WC()->mailer()->get_emails(); |
|
956
|
|
|
if ( ! empty( $emails ) && ! empty( $order_id ) ) { |
|
957
|
|
|
$emails['WC_Email_Failed_Order']->trigger( $order_id ); |
|
958
|
|
|
} |
|
959
|
|
|
} |
|
960
|
|
|
|
|
961
|
|
|
/** |
|
962
|
|
|
* Logs |
|
963
|
|
|
* |
|
964
|
|
|
* @since 3.1.0 |
|
965
|
|
|
* @version 3.1.0 |
|
966
|
|
|
* |
|
967
|
|
|
* @param string $message |
|
968
|
|
|
*/ |
|
969
|
|
|
public function log( $message ) { |
|
970
|
|
|
if ( $this->logging ) { |
|
971
|
|
|
WC_Stripe::log( $message ); |
|
972
|
|
|
} |
|
973
|
|
|
} |
|
974
|
|
|
} |
|
975
|
|
|
|
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.