|
1
|
|
|
<?php |
|
2
|
|
|
if ( ! defined( 'ABSPATH' ) ) { |
|
3
|
|
|
exit; |
|
4
|
|
|
} |
|
5
|
|
|
|
|
6
|
|
|
/** |
|
7
|
|
|
* WC_Stripe_Apple_Pay class. |
|
8
|
|
|
* |
|
9
|
|
|
* @extends WC_Gateway_Stripe |
|
10
|
|
|
*/ |
|
11
|
|
|
class WC_Stripe_Apple_Pay extends WC_Gateway_Stripe { |
|
12
|
|
|
/** |
|
13
|
|
|
* This Instance. |
|
14
|
|
|
* |
|
15
|
|
|
* @var |
|
16
|
|
|
*/ |
|
17
|
|
|
private static $_this; |
|
18
|
|
|
|
|
19
|
|
|
/** |
|
20
|
|
|
* Statement Description |
|
21
|
|
|
* |
|
22
|
|
|
* @var |
|
23
|
|
|
*/ |
|
24
|
|
|
public $statement_descriptor; |
|
25
|
|
|
|
|
26
|
|
|
/** |
|
27
|
|
|
* Check if we capture the transaction immediately. |
|
28
|
|
|
* |
|
29
|
|
|
* @var bool |
|
30
|
|
|
*/ |
|
31
|
|
|
public $capture; |
|
32
|
|
|
|
|
33
|
|
|
/** |
|
34
|
|
|
* Do we accept Apple Pay? |
|
35
|
|
|
* |
|
36
|
|
|
* @var bool |
|
37
|
|
|
*/ |
|
38
|
|
|
public $apple_pay; |
|
39
|
|
|
|
|
40
|
|
|
/** |
|
41
|
|
|
* Apple Pay button style. |
|
42
|
|
|
* |
|
43
|
|
|
* @var bool |
|
44
|
|
|
*/ |
|
45
|
|
|
public $apple_pay_button; |
|
46
|
|
|
|
|
47
|
|
|
/** |
|
48
|
|
|
* Apple Pay button language. |
|
49
|
|
|
* |
|
50
|
|
|
* @var bool |
|
51
|
|
|
*/ |
|
52
|
|
|
public $apple_pay_button_lang; |
|
53
|
|
|
|
|
54
|
|
|
/** |
|
55
|
|
|
* Is test mode active? |
|
56
|
|
|
* |
|
57
|
|
|
* @var bool |
|
58
|
|
|
*/ |
|
59
|
|
|
public $testmode; |
|
60
|
|
|
|
|
61
|
|
|
/** |
|
62
|
|
|
* Logging enabled? |
|
63
|
|
|
* |
|
64
|
|
|
* @var bool |
|
65
|
|
|
*/ |
|
66
|
|
|
public $logging; |
|
67
|
|
|
|
|
68
|
|
|
/** |
|
69
|
|
|
* Should we store the users credit cards? |
|
70
|
|
|
* |
|
71
|
|
|
* @var bool |
|
72
|
|
|
*/ |
|
73
|
|
|
public $saved_cards; |
|
74
|
|
|
|
|
75
|
|
|
/** |
|
76
|
|
|
* Publishable key credentials. |
|
77
|
|
|
* |
|
78
|
|
|
* @var bool |
|
79
|
|
|
*/ |
|
80
|
|
|
public $publishable_key; |
|
81
|
|
|
|
|
82
|
|
|
/** |
|
83
|
|
|
* Is shipping enabled? |
|
84
|
|
|
* |
|
85
|
|
|
* @var bool |
|
86
|
|
|
*/ |
|
87
|
|
|
public $is_shipping_enabled; |
|
88
|
|
|
|
|
89
|
|
|
/** |
|
90
|
|
|
* Constructor. |
|
91
|
|
|
* |
|
92
|
|
|
* @access public |
|
93
|
|
|
* @since 3.1.0 |
|
94
|
|
|
* @version 3.1.0 |
|
95
|
|
|
*/ |
|
96
|
|
|
public function __construct() { |
|
97
|
|
|
self::$_this = $this; |
|
98
|
|
|
|
|
99
|
|
|
$gateway_settings = get_option( 'woocommerce_stripe_settings', '' ); |
|
100
|
|
|
|
|
101
|
|
|
$this->statement_descriptor = ! empty( $gateway_settings['statement_descriptor'] ) ? $gateway_settings['statement_descriptor'] : wp_specialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES ); |
|
102
|
|
|
|
|
103
|
|
|
// If both site title and statement descriptor is not set. Fallback. |
|
104
|
|
|
if ( empty( $this->statement_descriptor ) ) { |
|
105
|
|
|
$this->statement_descriptor = $_SERVER['SERVER_NAME']; |
|
106
|
|
|
} |
|
107
|
|
|
|
|
108
|
|
|
$this->enabled = ( ! empty( $gateway_settings['enabled'] ) && 'yes' === $gateway_settings['enabled'] ) ? true : false; |
|
109
|
|
|
$this->testmode = ( ! empty( $gateway_settings['testmode'] ) && 'yes' === $gateway_settings['testmode'] ) ? true : false; |
|
110
|
|
|
$this->capture = ( ! empty( $gateway_settings['capture'] ) && 'yes' === $gateway_settings['capture'] ) ? true : false; |
|
111
|
|
|
$this->saved_cards = ( ! empty( $gateway_settings['saved_cards'] ) && 'yes' === $gateway_settings['saved_cards'] ) ? true : false; |
|
112
|
|
|
$this->apple_pay = ( ! empty( $gateway_settings['apple_pay'] ) && 'yes' === $gateway_settings['apple_pay'] ) ? true : false; |
|
113
|
|
|
$this->apple_pay_button = ! empty( $gateway_settings['apple_pay_button'] ) ? $gateway_settings['apple_pay_button'] : 'black'; |
|
114
|
|
|
$this->apple_pay_button_lang = ! empty( $gateway_settings['apple_pay_button_lang'] ) ? $gateway_settings['apple_pay_button_lang'] : 'en'; |
|
115
|
|
|
$this->logging = ( ! empty( $gateway_settings['logging'] ) && 'yes' === $gateway_settings['logging'] ) ? true : false; |
|
116
|
|
|
$this->publishable_key = ! empty( $gateway_settings['publishable_key'] ) ? $gateway_settings['publishable_key'] : ''; |
|
117
|
|
|
$this->is_shipping_enabled = $this->is_shipping_enabled(); |
|
118
|
|
|
|
|
119
|
|
|
if ( $this->testmode ) { |
|
120
|
|
|
$this->publishable_key = ! empty( $gateway_settings['test_publishable_key'] ) ? $gateway_settings['test_publishable_key'] : ''; |
|
121
|
|
|
} |
|
122
|
|
|
|
|
123
|
|
|
$this->init(); |
|
124
|
|
|
} |
|
125
|
|
|
|
|
126
|
|
|
public function instance() { |
|
127
|
|
|
return self::$_this; |
|
128
|
|
|
} |
|
129
|
|
|
|
|
130
|
|
|
/** |
|
131
|
|
|
* Initialize. |
|
132
|
|
|
* |
|
133
|
|
|
* @access public |
|
134
|
|
|
* @since 3.1.0 |
|
135
|
|
|
* @version 3.1.4 |
|
136
|
|
|
*/ |
|
137
|
|
|
public function init() { |
|
138
|
|
|
// If Apple Pay is not enabled no need to proceed further. |
|
139
|
|
|
if ( ! $this->apple_pay ) { |
|
140
|
|
|
return; |
|
141
|
|
|
} |
|
142
|
|
|
|
|
143
|
|
|
add_action( 'wp_enqueue_scripts', array( $this, 'cart_scripts' ) ); |
|
144
|
|
|
add_action( 'wp_enqueue_scripts', array( $this, 'single_scripts' ) ); |
|
145
|
|
|
|
|
146
|
|
|
/** |
|
147
|
|
|
* In order to display the Apple Pay button in the correct position, |
|
148
|
|
|
* a new hook was added to WooCommerce 3.0. In older versions of WooCommerce, |
|
149
|
|
|
* CSS is used to position the button. |
|
150
|
|
|
*/ |
|
151
|
|
|
if ( version_compare( WC_VERSION, '3.0.0', '<' ) ) { |
|
152
|
|
|
add_action( 'woocommerce_after_add_to_cart_button', array( $this, 'display_apple_pay_button' ), 1 ); |
|
153
|
|
|
} else { |
|
154
|
|
|
add_action( 'woocommerce_after_add_to_cart_quantity', array( $this, 'display_apple_pay_button' ), 1 ); |
|
155
|
|
|
} |
|
156
|
|
|
|
|
157
|
|
|
add_action( 'woocommerce_proceed_to_checkout', array( $this, 'display_apple_pay_button' ), 1 ); |
|
158
|
|
|
add_action( 'woocommerce_proceed_to_checkout', array( $this, 'display_apple_pay_separator_html' ), 2 ); |
|
159
|
|
|
add_action( 'woocommerce_checkout_before_customer_details', array( $this, 'display_apple_pay_button' ), 1 ); |
|
160
|
|
|
add_action( 'woocommerce_checkout_before_customer_details', array( $this, 'display_apple_pay_separator_html' ), 2 ); |
|
161
|
|
|
add_action( 'wc_ajax_wc_stripe_log_apple_pay_errors', array( $this, 'log_apple_pay_errors' ) ); |
|
162
|
|
|
add_action( 'wc_ajax_wc_stripe_apple_pay', array( $this, 'process_apple_pay' ) ); |
|
163
|
|
|
add_action( 'wc_ajax_wc_stripe_generate_apple_pay_cart', array( $this, 'generate_apple_pay_cart' ) ); |
|
164
|
|
|
add_action( 'wc_ajax_wc_stripe_apple_pay_clear_cart', array( $this, 'clear_cart' ) ); |
|
165
|
|
|
add_action( 'wc_ajax_wc_stripe_generate_apple_pay_single', array( $this, 'generate_apple_pay_single' ) ); |
|
166
|
|
|
add_action( 'wc_ajax_wc_stripe_apple_pay_get_shipping_methods', array( $this, 'get_shipping_methods' ) ); |
|
167
|
|
|
add_action( 'wc_ajax_wc_stripe_apple_pay_update_shipping_method', array( $this, 'update_shipping_method' ) ); |
|
168
|
|
|
add_filter( 'woocommerce_gateway_title', array( $this, 'filter_gateway_title' ), 10, 2 ); |
|
169
|
|
|
add_filter( 'woocommerce_validate_postcode', array( $this, 'postal_code_validation' ), 10, 3 ); |
|
170
|
|
|
} |
|
171
|
|
|
|
|
172
|
|
|
/** |
|
173
|
|
|
* Filters the gateway title to reflect Apple Pay. |
|
174
|
|
|
* |
|
175
|
|
|
*/ |
|
176
|
|
|
public function filter_gateway_title( $title, $id ) { |
|
177
|
|
|
global $post; |
|
178
|
|
|
|
|
179
|
|
|
if ( ! is_object( $post ) ) { |
|
180
|
|
|
return $title; |
|
181
|
|
|
} |
|
182
|
|
|
|
|
183
|
|
|
$method_title = get_post_meta( $post->ID, '_payment_method_title', true ); |
|
184
|
|
|
|
|
185
|
|
|
if ( 'stripe' === $id && ! empty( $method_title ) && 'Apple Pay (Stripe)' === $method_title ) { |
|
186
|
|
|
return $method_title; |
|
187
|
|
|
} |
|
188
|
|
|
|
|
189
|
|
|
return $title; |
|
190
|
|
|
} |
|
191
|
|
|
|
|
192
|
|
|
/** |
|
193
|
|
|
* Log errors coming from Apple Pay. |
|
194
|
|
|
* |
|
195
|
|
|
* @since 3.1.4 |
|
196
|
|
|
* @version 3.1.4 |
|
197
|
|
|
*/ |
|
198
|
|
|
public function log_apple_pay_errors() { |
|
199
|
|
|
if ( ! wp_verify_nonce( $_POST['nonce'], '_wc_stripe_apple_pay_nonce' ) && ! wp_verify_nonce( $_POST['nonce'], '_wc_stripe_apple_pay_cart_nonce' ) ) { |
|
200
|
|
|
wp_die( __( 'Cheatin’ huh?', 'woocommerce-gateway-stripe' ) ); |
|
201
|
|
|
} |
|
202
|
|
|
|
|
203
|
|
|
$errors = wc_clean( stripslashes( $_POST['errors'] ) ); |
|
204
|
|
|
|
|
205
|
|
|
$this->log( $errors ); |
|
206
|
|
|
|
|
207
|
|
|
exit; |
|
208
|
|
|
} |
|
209
|
|
|
|
|
210
|
|
|
/** |
|
211
|
|
|
* Removes postal code validation from WC. |
|
212
|
|
|
* |
|
213
|
|
|
* @since 3.1.4 |
|
214
|
|
|
* @version 3.1.4 |
|
215
|
|
|
*/ |
|
216
|
|
|
public function postal_code_validation( $valid, $postcode, $country ) { |
|
217
|
|
|
$gateways = WC()->payment_gateways->get_available_payment_gateways(); |
|
218
|
|
|
|
|
219
|
|
|
if ( ! $this->apple_pay || ! isset( $gateways['stripe'] ) ) { |
|
220
|
|
|
return $valid; |
|
221
|
|
|
} |
|
222
|
|
|
|
|
223
|
|
|
/** |
|
224
|
|
|
* Currently Apple Pay truncates postal codes from UK and Canada to first 3 characters |
|
225
|
|
|
* when passing it back from the shippingcontactselected object. This causes WC to invalidate |
|
226
|
|
|
* the order and not let it go through. The remedy for now is just to remove this validation. |
|
227
|
|
|
*/ |
|
228
|
|
|
if ( 'GB' === $country || 'CA' === $country ) { |
|
229
|
|
|
return true; |
|
230
|
|
|
} |
|
231
|
|
|
|
|
232
|
|
|
return $valid; |
|
233
|
|
|
} |
|
234
|
|
|
|
|
235
|
|
|
/** |
|
236
|
|
|
* Checks if shipping is enabled for the store. |
|
237
|
|
|
* |
|
238
|
|
|
* @since 3.1.6 |
|
239
|
|
|
* @version 3.1.6 |
|
240
|
|
|
* @return bool |
|
241
|
|
|
*/ |
|
242
|
|
|
public function is_shipping_enabled() { |
|
243
|
|
|
$shipping_enabled = get_option( 'woocommerce_ship_to_countries', '' ); |
|
244
|
|
|
|
|
245
|
|
|
if ( 'disabled' === $shipping_enabled ) { |
|
246
|
|
|
return false; |
|
247
|
|
|
} |
|
248
|
|
|
|
|
249
|
|
|
return true; |
|
250
|
|
|
} |
|
251
|
|
|
|
|
252
|
|
|
/** |
|
253
|
|
|
* Enqueue JS scripts and styles for single product page. |
|
254
|
|
|
* |
|
255
|
|
|
* @since 3.1.0 |
|
256
|
|
|
* @version 3.1.4 |
|
257
|
|
|
*/ |
|
258
|
|
|
public function single_scripts() { |
|
259
|
|
|
if ( ! is_single() ) { |
|
260
|
|
|
return; |
|
261
|
|
|
} |
|
262
|
|
|
|
|
263
|
|
|
global $post; |
|
264
|
|
|
|
|
265
|
|
|
$product = wc_get_product( $post->ID ); |
|
266
|
|
|
|
|
267
|
|
View Code Duplication |
if ( ! is_object( $product ) || ! in_array( ( version_compare( WC_VERSION, '3.0.0', '<' ) ? $product->product_type : $product->get_type() ), $this->supported_product_types() ) ) { |
|
|
|
|
|
|
268
|
|
|
return; |
|
269
|
|
|
} |
|
270
|
|
|
|
|
271
|
|
|
$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; |
|
272
|
|
|
|
|
273
|
|
|
wp_enqueue_style( 'stripe_apple_pay', plugins_url( 'assets/css/stripe-apple-pay.css', WC_STRIPE_MAIN_FILE ), array(), WC_STRIPE_VERSION ); |
|
274
|
|
|
|
|
275
|
|
|
wp_enqueue_script( 'stripe', 'https://js.stripe.com/v2/', '', '1.0', true ); |
|
276
|
|
|
wp_enqueue_script( 'woocommerce_stripe_apple_pay_single', plugins_url( 'assets/js/stripe-apple-pay-single' . $suffix . '.js', WC_STRIPE_MAIN_FILE ), array( 'stripe' ), WC_STRIPE_VERSION, true ); |
|
277
|
|
|
|
|
278
|
|
|
$stripe_params = array( |
|
279
|
|
|
'key' => $this->publishable_key, |
|
280
|
|
|
'currency_code' => get_woocommerce_currency(), |
|
281
|
|
|
'country_code' => substr( get_option( 'woocommerce_default_country' ), 0, 2 ), |
|
282
|
|
|
'label' => $this->statement_descriptor, |
|
283
|
|
|
'ajaxurl' => WC_AJAX::get_endpoint( '%%endpoint%%' ), |
|
284
|
|
|
'stripe_apple_pay_nonce' => wp_create_nonce( '_wc_stripe_apple_pay_nonce' ), |
|
285
|
|
|
'stripe_apple_pay_cart_nonce' => wp_create_nonce( '_wc_stripe_apple_pay_cart_nonce' ), |
|
286
|
|
|
'stripe_apple_pay_get_shipping_methods_nonce' => wp_create_nonce( '_wc_stripe_apple_pay_get_shipping_methods_nonce' ), |
|
287
|
|
|
'stripe_apple_pay_update_shipping_method_nonce' => wp_create_nonce( '_wc_stripe_apple_pay_update_shipping_method_nonce' ), |
|
288
|
|
|
'needs_shipping' => ( $product->needs_shipping() && $this->is_shipping_enabled ) ? 'yes' : 'no', |
|
289
|
|
|
'i18n' => array( |
|
290
|
|
|
'sub_total' => __( 'Sub-Total', 'woocommerce-gateway-stripe' ), |
|
291
|
|
|
), |
|
292
|
|
|
); |
|
293
|
|
|
|
|
294
|
|
|
wp_localize_script( 'woocommerce_stripe_apple_pay_single', 'wc_stripe_apple_pay_single_params', apply_filters( 'wc_stripe_apple_pay_single_params', $stripe_params ) ); |
|
295
|
|
|
} |
|
296
|
|
|
|
|
297
|
|
|
/** |
|
298
|
|
|
* Enqueue JS scripts and styles for the cart/checkout. |
|
299
|
|
|
* |
|
300
|
|
|
* @since 3.1.0 |
|
301
|
|
|
* @version 3.1.0 |
|
302
|
|
|
*/ |
|
303
|
|
|
public function cart_scripts() { |
|
304
|
|
|
if ( ! is_cart() && ! is_checkout() && ! isset( $_GET['pay_for_order'] ) ) { |
|
305
|
|
|
return; |
|
306
|
|
|
} |
|
307
|
|
|
|
|
308
|
|
|
$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; |
|
309
|
|
|
|
|
310
|
|
|
wp_enqueue_style( 'stripe_apple_pay', plugins_url( 'assets/css/stripe-apple-pay.css', WC_STRIPE_MAIN_FILE ), array(), WC_STRIPE_VERSION ); |
|
311
|
|
|
|
|
312
|
|
|
wp_enqueue_script( 'stripe', 'https://js.stripe.com/v2/', '', '1.0', true ); |
|
313
|
|
|
wp_enqueue_script( 'woocommerce_stripe_apple_pay', plugins_url( 'assets/js/stripe-apple-pay' . $suffix . '.js', WC_STRIPE_MAIN_FILE ), array( 'stripe' ), WC_STRIPE_VERSION, true ); |
|
314
|
|
|
|
|
315
|
|
|
$stripe_params = array( |
|
316
|
|
|
'key' => $this->publishable_key, |
|
317
|
|
|
'currency_code' => get_woocommerce_currency(), |
|
318
|
|
|
'country_code' => substr( get_option( 'woocommerce_default_country' ), 0, 2 ), |
|
319
|
|
|
'label' => $this->statement_descriptor, |
|
320
|
|
|
'ajaxurl' => WC_AJAX::get_endpoint( '%%endpoint%%' ), |
|
321
|
|
|
'stripe_apple_pay_nonce' => wp_create_nonce( '_wc_stripe_apple_pay_nonce' ), |
|
322
|
|
|
'stripe_apple_pay_cart_nonce' => wp_create_nonce( '_wc_stripe_apple_pay_cart_nonce' ), |
|
323
|
|
|
'stripe_apple_pay_get_shipping_methods_nonce' => wp_create_nonce( '_wc_stripe_apple_pay_get_shipping_methods_nonce' ), |
|
324
|
|
|
'stripe_apple_pay_update_shipping_method_nonce' => wp_create_nonce( '_wc_stripe_apple_pay_update_shipping_method_nonce' ), |
|
325
|
|
|
'needs_shipping' => ( WC()->cart->needs_shipping() && $this->is_shipping_enabled ) ? 'yes' : 'no', |
|
326
|
|
|
'is_cart_page' => is_cart() ? 'yes' : 'no', |
|
327
|
|
|
); |
|
328
|
|
|
|
|
329
|
|
|
wp_localize_script( 'woocommerce_stripe_apple_pay', 'wc_stripe_apple_pay_params', apply_filters( 'wc_stripe_apple_pay_params', $stripe_params ) ); |
|
330
|
|
|
} |
|
331
|
|
|
|
|
332
|
|
|
/** |
|
333
|
|
|
* Checks to make sure product type is supported by Apple Pay. |
|
334
|
|
|
* |
|
335
|
|
|
* @since 3.1.0 |
|
336
|
|
|
* @version 3.1.0 |
|
337
|
|
|
* @return array |
|
338
|
|
|
*/ |
|
339
|
|
|
public function supported_product_types() { |
|
340
|
|
|
return array( |
|
341
|
|
|
'simple', |
|
342
|
|
|
'variable', |
|
343
|
|
|
'variation', |
|
344
|
|
|
); |
|
345
|
|
|
} |
|
346
|
|
|
|
|
347
|
|
|
/** |
|
348
|
|
|
* Checks the cart to see if all items are allowed to use |
|
349
|
|
|
* Apple Pay. |
|
350
|
|
|
* |
|
351
|
|
|
* @since 3.1.4 |
|
352
|
|
|
* @version 3.1.4 |
|
353
|
|
|
* @return bool |
|
354
|
|
|
*/ |
|
355
|
|
|
public function allowed_items_in_cart() { |
|
356
|
|
|
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) { |
|
357
|
|
|
$_product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key ); |
|
358
|
|
|
|
|
359
|
|
View Code Duplication |
if ( ! in_array( ( version_compare( WC_VERSION, '3.0.0', '<' ) ? $_product->product_type : $_product->get_type() ), $this->supported_product_types() ) ) { |
|
|
|
|
|
|
360
|
|
|
return false; |
|
361
|
|
|
} |
|
362
|
|
|
} |
|
363
|
|
|
|
|
364
|
|
|
return true; |
|
365
|
|
|
} |
|
366
|
|
|
|
|
367
|
|
|
/** |
|
368
|
|
|
* Display Apple Pay button on the cart page |
|
369
|
|
|
* |
|
370
|
|
|
* @since 3.1.0 |
|
371
|
|
|
* @version 3.1.0 |
|
372
|
|
|
*/ |
|
373
|
|
|
public function display_apple_pay_button() { |
|
374
|
|
|
$gateways = WC()->payment_gateways->get_available_payment_gateways(); |
|
375
|
|
|
|
|
376
|
|
|
/** |
|
377
|
|
|
* In order for the Apple Pay button to show on product detail page, |
|
378
|
|
|
* Apple Pay must be enabled and Stripe gateway must be enabled. |
|
379
|
|
|
*/ |
|
380
|
|
|
if ( ! $this->apple_pay || ! isset( $gateways['stripe'] ) ) { |
|
381
|
|
|
$this->log( 'Apple Pay not enabled or Stripe is not an available gateway ( Apple Pay button disabled )' ); |
|
382
|
|
|
return; |
|
383
|
|
|
} |
|
384
|
|
|
|
|
385
|
|
|
if ( is_single() ) { |
|
386
|
|
|
global $post; |
|
387
|
|
|
|
|
388
|
|
|
$product = wc_get_product( $post->ID ); |
|
389
|
|
|
|
|
390
|
|
View Code Duplication |
if ( ! is_object( $product ) || ! in_array( ( version_compare( WC_VERSION, '3.0.0', '<' ) ? $product->product_type : $product->get_type() ), $this->supported_product_types() ) ) { |
|
|
|
|
|
|
391
|
|
|
return; |
|
392
|
|
|
} |
|
393
|
|
|
} else { |
|
394
|
|
|
if ( ! $this->allowed_items_in_cart() ) { |
|
395
|
|
|
$this->log( 'Items in the cart has unsupported product type ( Apple Pay button disabled )' ); |
|
396
|
|
|
return; |
|
397
|
|
|
} |
|
398
|
|
|
} |
|
399
|
|
|
|
|
400
|
|
|
?> |
|
401
|
|
|
<div class="apple-pay-button-wrapper"> |
|
402
|
|
|
<button class="apple-pay-button" lang="<?php echo esc_attr( $this->apple_pay_button_lang ); ?>" style="-webkit-appearance: -apple-pay-button; -apple-pay-button-type: buy; -apple-pay-button-style: <?php echo esc_attr( $this->apple_pay_button ); ?>;"></button> |
|
403
|
|
|
</div> |
|
404
|
|
|
<?php |
|
405
|
|
|
} |
|
406
|
|
|
|
|
407
|
|
|
/** |
|
408
|
|
|
* Display Apple Pay button on the cart page |
|
409
|
|
|
* |
|
410
|
|
|
* @since 3.1.0 |
|
411
|
|
|
* @version 3.1.0 |
|
412
|
|
|
*/ |
|
413
|
|
|
public function display_apple_pay_separator_html() { |
|
414
|
|
|
$gateways = WC()->payment_gateways->get_available_payment_gateways(); |
|
415
|
|
|
|
|
416
|
|
|
/** |
|
417
|
|
|
* In order for the Apple Pay button to show on cart page, |
|
418
|
|
|
* Apple Pay must be enabled and Stripe gateway must be enabled. |
|
419
|
|
|
*/ |
|
420
|
|
|
if ( ! $this->apple_pay || ! isset( $gateways['stripe'] ) ) { |
|
421
|
|
|
$this->log( 'Apple Pay not enabled or Stripe is not an available gateway ( Apple Pay button disabled )' ); |
|
422
|
|
|
return; |
|
423
|
|
|
} |
|
424
|
|
|
|
|
425
|
|
|
if ( ! $this->allowed_items_in_cart() ) { |
|
426
|
|
|
$this->log( 'Items in the cart has unsupported product type ( Apple Pay button disabled )' ); |
|
427
|
|
|
return; |
|
428
|
|
|
} |
|
429
|
|
|
?> |
|
430
|
|
|
<p class="apple-pay-button-checkout-separator">- <?php esc_html_e( 'Or', 'woocommerce-gateway-stripe' ); ?> -</p> |
|
431
|
|
|
<?php |
|
432
|
|
|
} |
|
433
|
|
|
|
|
434
|
|
|
/** |
|
435
|
|
|
* Generates the Apple Pay single cart. |
|
436
|
|
|
* |
|
437
|
|
|
* @since 3.1.0 |
|
438
|
|
|
* @version 3.1.0 |
|
439
|
|
|
*/ |
|
440
|
|
|
public function generate_apple_pay_single() { |
|
441
|
|
|
if ( ! wp_verify_nonce( $_POST['nonce'], '_wc_stripe_apple_pay_cart_nonce' ) ) { |
|
442
|
|
|
wp_die( __( 'Cheatin’ huh?', 'woocommerce-gateway-stripe' ) ); |
|
443
|
|
|
} |
|
444
|
|
|
|
|
445
|
|
|
if ( ! defined( 'WOOCOMMERCE_CART' ) ) { |
|
446
|
|
|
define( 'WOOCOMMERCE_CART', true ); |
|
447
|
|
|
} |
|
448
|
|
|
|
|
449
|
|
|
WC()->shipping->reset_shipping(); |
|
450
|
|
|
|
|
451
|
|
|
global $post; |
|
452
|
|
|
|
|
453
|
|
|
$product = wc_get_product( $post->ID ); |
|
454
|
|
|
$qty = ! isset( $_POST['qty'] ) ? 1 : absint( $_POST['qty'] ); |
|
455
|
|
|
|
|
456
|
|
|
/** |
|
457
|
|
|
* If this page is single product page, we need to simulate |
|
458
|
|
|
* adding the product to the cart taken account if it is a |
|
459
|
|
|
* simple or variable product. |
|
460
|
|
|
*/ |
|
461
|
|
|
if ( is_single() ) { |
|
462
|
|
|
// First empty the cart to prevent wrong calculation. |
|
463
|
|
|
WC()->cart->empty_cart(); |
|
464
|
|
|
|
|
465
|
|
|
if ( 'variable' === ( version_compare( WC_VERSION, '3.0.0', '<' ) ? $product->product_type : $product->get_type() ) && isset( $_POST['attributes'] ) ) { |
|
466
|
|
|
$attributes = array_map( 'wc_clean', $_POST['attributes'] ); |
|
467
|
|
|
|
|
468
|
|
|
if ( version_compare( WC_VERSION, '3.0.0', '<' ) ) { |
|
469
|
|
|
$variation_id = $product->get_matching_variation( $attributes ); |
|
470
|
|
|
} else { |
|
471
|
|
|
$data_store = WC_Data_Store::load( 'product' ); |
|
472
|
|
|
$variation_id = $data_store->find_matching_product_variation( $product, $attributes ); |
|
473
|
|
|
} |
|
474
|
|
|
|
|
475
|
|
|
WC()->cart->add_to_cart( $product->get_id(), $qty, $variation_id, $attributes ); |
|
476
|
|
|
} |
|
477
|
|
|
|
|
478
|
|
|
if ( 'simple' === ( version_compare( WC_VERSION, '3.0.0', '<' ) ? $product->product_type : $product->get_type() ) ) { |
|
479
|
|
|
WC()->cart->add_to_cart( $product->get_id(), $qty ); |
|
480
|
|
|
} |
|
481
|
|
|
} |
|
482
|
|
|
|
|
483
|
|
|
WC()->cart->calculate_totals(); |
|
484
|
|
|
|
|
485
|
|
|
wp_send_json( array( 'line_items' => $this->build_line_items(), 'total' => WC()->cart->total ) ); |
|
486
|
|
|
} |
|
487
|
|
|
|
|
488
|
|
|
/** |
|
489
|
|
|
* Generates the Apple Pay cart. |
|
490
|
|
|
* |
|
491
|
|
|
* @since 3.1.0 |
|
492
|
|
|
* @version 3.1.0 |
|
493
|
|
|
*/ |
|
494
|
|
|
public function generate_apple_pay_cart() { |
|
495
|
|
|
if ( ! wp_verify_nonce( $_POST['nonce'], '_wc_stripe_apple_pay_cart_nonce' ) ) { |
|
496
|
|
|
wp_die( __( 'Cheatin’ huh?', 'woocommerce-gateway-stripe' ) ); |
|
497
|
|
|
} |
|
498
|
|
|
|
|
499
|
|
|
wp_send_json( array( 'line_items' => $this->build_line_items(), 'total' => WC()->cart->total ) ); |
|
500
|
|
|
} |
|
501
|
|
|
|
|
502
|
|
|
/** |
|
503
|
|
|
* Clears Apple Pay cart. |
|
504
|
|
|
* |
|
505
|
|
|
* @since 3.1.4 |
|
506
|
|
|
* @version 3.1.4 |
|
507
|
|
|
*/ |
|
508
|
|
|
public function clear_cart() { |
|
509
|
|
|
WC()->cart->empty_cart(); |
|
510
|
|
|
exit; |
|
511
|
|
|
} |
|
512
|
|
|
|
|
513
|
|
|
/** |
|
514
|
|
|
* Calculate and set shipping method. |
|
515
|
|
|
* |
|
516
|
|
|
* @since 3.1.0 |
|
517
|
|
|
* @version 3.1.0 |
|
518
|
|
|
* @param array $address |
|
519
|
|
|
*/ |
|
520
|
|
|
public function calculate_shipping( $address = array() ) { |
|
521
|
|
|
$country = strtoupper( $address['countryCode'] ); |
|
522
|
|
|
$state = strtoupper( $address['administrativeArea'] ); |
|
523
|
|
|
$postcode = $address['postalCode']; |
|
524
|
|
|
$city = $address['locality']; |
|
525
|
|
|
|
|
526
|
|
|
WC()->shipping->reset_shipping(); |
|
527
|
|
|
|
|
528
|
|
|
if ( $postcode && ! WC_Validation::is_postcode( $postcode, $country ) ) { |
|
529
|
|
|
throw new Exception( __( 'Please enter a valid postcode/ZIP.', 'woocommerce-gateway-stripe' ) ); |
|
530
|
|
|
} elseif ( $postcode ) { |
|
531
|
|
|
$postcode = wc_format_postcode( $postcode, $country ); |
|
532
|
|
|
} |
|
533
|
|
|
|
|
534
|
|
View Code Duplication |
if ( $country ) { |
|
|
|
|
|
|
535
|
|
|
WC()->customer->set_location( $country, $state, $postcode, $city ); |
|
536
|
|
|
WC()->customer->set_shipping_location( $country, $state, $postcode, $city ); |
|
537
|
|
|
} else { |
|
538
|
|
|
WC()->customer->set_to_base(); |
|
539
|
|
|
WC()->customer->set_shipping_to_base(); |
|
540
|
|
|
} |
|
541
|
|
|
|
|
542
|
|
|
WC()->customer->calculated_shipping( true ); |
|
543
|
|
|
|
|
544
|
|
|
/** |
|
545
|
|
|
* Set the shipping package. |
|
546
|
|
|
* |
|
547
|
|
|
* Note that address lines are not provided at this point |
|
548
|
|
|
* because Apple Pay does not supply that until after |
|
549
|
|
|
* authentication via passcode or Touch ID. We will need to |
|
550
|
|
|
* capture this information when we process the payment. |
|
551
|
|
|
*/ |
|
552
|
|
|
|
|
553
|
|
|
$packages = array(); |
|
554
|
|
|
|
|
555
|
|
|
$packages[0]['contents'] = WC()->cart->get_cart(); |
|
556
|
|
|
$packages[0]['contents_cost'] = 0; |
|
557
|
|
|
$packages[0]['applied_coupons'] = WC()->cart->applied_coupons; |
|
558
|
|
|
$packages[0]['user']['ID'] = get_current_user_id(); |
|
559
|
|
|
$packages[0]['destination']['country'] = $country; |
|
560
|
|
|
$packages[0]['destination']['state'] = $state; |
|
561
|
|
|
$packages[0]['destination']['postcode'] = $postcode; |
|
562
|
|
|
$packages[0]['destination']['city'] = $city; |
|
563
|
|
|
|
|
564
|
|
View Code Duplication |
foreach ( WC()->cart->get_cart() as $item ) { |
|
|
|
|
|
|
565
|
|
|
if ( $item['data']->needs_shipping() ) { |
|
566
|
|
|
if ( isset( $item['line_total'] ) ) { |
|
567
|
|
|
$packages[0]['contents_cost'] += $item['line_total']; |
|
568
|
|
|
} |
|
569
|
|
|
} |
|
570
|
|
|
} |
|
571
|
|
|
|
|
572
|
|
|
$packages = apply_filters( 'woocommerce_cart_shipping_packages', $packages ); |
|
573
|
|
|
|
|
574
|
|
|
WC()->shipping->calculate_shipping( $packages ); |
|
575
|
|
|
} |
|
576
|
|
|
|
|
577
|
|
|
/** |
|
578
|
|
|
* Gets shipping for Apple Pay Payment sheet. |
|
579
|
|
|
* |
|
580
|
|
|
* @since 3.1.0 |
|
581
|
|
|
* @version 3.1.0 |
|
582
|
|
|
*/ |
|
583
|
|
|
public function get_shipping_methods() { |
|
584
|
|
|
if ( ! wp_verify_nonce( $_POST['nonce'], '_wc_stripe_apple_pay_get_shipping_methods_nonce' ) ) { |
|
585
|
|
|
wp_die( __( 'Cheatin’ huh?', 'woocommerce-gateway-stripe' ) ); |
|
586
|
|
|
} |
|
587
|
|
|
|
|
588
|
|
|
if ( ! defined( 'WOOCOMMERCE_CART' ) ) { |
|
589
|
|
|
define( 'WOOCOMMERCE_CART', true ); |
|
590
|
|
|
} |
|
591
|
|
|
|
|
592
|
|
|
try { |
|
593
|
|
|
$address = array_map( 'wc_clean', $_POST['address'] ); |
|
594
|
|
|
|
|
595
|
|
|
$this->calculate_shipping( $address ); |
|
596
|
|
|
|
|
597
|
|
|
// Set the shipping options. |
|
598
|
|
|
$currency = get_woocommerce_currency(); |
|
599
|
|
|
$data = array(); |
|
600
|
|
|
|
|
601
|
|
|
$packages = WC()->shipping->get_packages(); |
|
602
|
|
|
|
|
603
|
|
|
if ( ! empty( $packages ) && WC()->customer->has_calculated_shipping() ) { |
|
604
|
|
|
foreach ( $packages as $package_key => $package ) { |
|
605
|
|
|
if ( empty( $package['rates'] ) ) { |
|
606
|
|
|
throw new Exception( __( 'Unable to find shipping method for address.', 'woocommerce-gateway-stripe' ) ); |
|
607
|
|
|
} |
|
608
|
|
|
|
|
609
|
|
View Code Duplication |
foreach ( $package['rates'] as $key => $rate ) { |
|
|
|
|
|
|
610
|
|
|
$data[] = array( |
|
611
|
|
|
'id' => $rate->id, |
|
612
|
|
|
'label' => $rate->label, |
|
613
|
|
|
'amount' => array( |
|
614
|
|
|
'currency' => $currency, |
|
615
|
|
|
'value' => $rate->cost, |
|
616
|
|
|
), |
|
617
|
|
|
'selected' => false, |
|
618
|
|
|
); |
|
619
|
|
|
} |
|
620
|
|
|
} |
|
621
|
|
|
|
|
622
|
|
|
// Auto select the first shipping method. |
|
623
|
|
|
WC()->session->set( 'chosen_shipping_methods', array( $data[0]['id'] ) ); |
|
624
|
|
|
|
|
625
|
|
|
WC()->cart->calculate_totals(); |
|
626
|
|
|
|
|
627
|
|
|
wp_send_json( array( 'success' => 'true', 'shipping_methods' => $this->build_shipping_methods( $data ), 'line_items' => $this->build_line_items(), 'total' => WC()->cart->total ) ); |
|
628
|
|
|
} else { |
|
629
|
|
|
throw new Exception( __( 'Unable to find shipping method for address.', 'woocommerce-gateway-stripe' ) ); |
|
630
|
|
|
} |
|
631
|
|
|
} catch ( Exception $e ) { |
|
632
|
|
|
wp_send_json( array( 'success' => 'false', 'shipping_methods' => array(), 'line_items' => $this->build_line_items(), 'total' => WC()->cart->total ) ); |
|
633
|
|
|
} |
|
634
|
|
|
} |
|
635
|
|
|
|
|
636
|
|
|
/** |
|
637
|
|
|
* Updates shipping method on cart session. |
|
638
|
|
|
* |
|
639
|
|
|
* @since 3.1.0 |
|
640
|
|
|
* @version 3.1.0 |
|
641
|
|
|
*/ |
|
642
|
|
|
public function update_shipping_method() { |
|
643
|
|
|
if ( ! defined( 'WOOCOMMERCE_CART' ) ) { |
|
644
|
|
|
define( 'WOOCOMMERCE_CART', true ); |
|
645
|
|
|
} |
|
646
|
|
|
|
|
647
|
|
|
if ( ! wp_verify_nonce( $_POST['nonce'], '_wc_stripe_apple_pay_update_shipping_method_nonce' ) ) { |
|
648
|
|
|
wp_die( __( 'Cheatin’ huh?', 'woocommerce-gateway-stripe' ) ); |
|
649
|
|
|
} |
|
650
|
|
|
|
|
651
|
|
|
$selected_shipping_method = array_map( 'wc_clean', $_POST['selected_shipping_method'] ); |
|
652
|
|
|
|
|
653
|
|
|
WC()->session->set( 'chosen_shipping_methods', array( $selected_shipping_method['identifier'] ) ); |
|
654
|
|
|
|
|
655
|
|
|
WC()->cart->calculate_totals(); |
|
656
|
|
|
|
|
657
|
|
|
// Send back the new cart total. |
|
658
|
|
|
$currency = get_woocommerce_currency(); |
|
659
|
|
|
$tax_total = max( 0, round( WC()->cart->tax_total + WC()->cart->shipping_tax_total, WC()->cart->dp ) ); |
|
660
|
|
|
$data = array( |
|
661
|
|
|
'total' => WC()->cart->total, |
|
662
|
|
|
); |
|
663
|
|
|
|
|
664
|
|
|
// Include fees and taxes as displayItems. |
|
665
|
|
View Code Duplication |
foreach ( WC()->cart->fees as $key => $fee ) { |
|
|
|
|
|
|
666
|
|
|
$data['items'][] = array( |
|
667
|
|
|
'label' => $fee->name, |
|
668
|
|
|
'amount' => array( |
|
669
|
|
|
'currency' => $currency, |
|
670
|
|
|
'value' => $fee->amount, |
|
671
|
|
|
), |
|
672
|
|
|
); |
|
673
|
|
|
} |
|
674
|
|
View Code Duplication |
if ( 0 < $tax_total ) { |
|
|
|
|
|
|
675
|
|
|
$data['items'][] = array( |
|
676
|
|
|
'label' => __( 'Tax', 'woocommerce-gateway-stripe' ), |
|
677
|
|
|
'amount' => array( |
|
678
|
|
|
'currency' => $currency, |
|
679
|
|
|
'value' => $tax_total, |
|
680
|
|
|
), |
|
681
|
|
|
); |
|
682
|
|
|
} |
|
683
|
|
|
|
|
684
|
|
|
wp_send_json( array( 'success' => 'true', 'line_items' => $this->build_line_items(), 'total' => WC()->cart->total ) ); |
|
685
|
|
|
} |
|
686
|
|
|
|
|
687
|
|
|
/** |
|
688
|
|
|
* Handles the Apple Pay processing via AJAX |
|
689
|
|
|
* |
|
690
|
|
|
* @access public |
|
691
|
|
|
* @since 3.1.0 |
|
692
|
|
|
* @version 3.1.0 |
|
693
|
|
|
*/ |
|
694
|
|
|
public function process_apple_pay() { |
|
695
|
|
|
if ( ! wp_verify_nonce( $_POST['nonce'], '_wc_stripe_apple_pay_nonce' ) ) { |
|
696
|
|
|
wp_die( __( 'Cheatin’ huh?', 'woocommerce-gateway-stripe' ) ); |
|
697
|
|
|
} |
|
698
|
|
|
|
|
699
|
|
|
try { |
|
700
|
|
|
$result = array_map( 'wc_clean', $_POST['result'] ); |
|
701
|
|
|
|
|
702
|
|
|
$order = $this->create_order( $result ); |
|
703
|
|
|
|
|
704
|
|
|
$order_id = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->id : $order->get_id(); |
|
705
|
|
|
|
|
706
|
|
|
// Handle payment. |
|
707
|
|
|
if ( $order->get_total() > 0 ) { |
|
708
|
|
|
|
|
709
|
|
View Code Duplication |
if ( $order->get_total() * 100 < WC_Stripe::get_minimum_amount() ) { |
|
|
|
|
|
|
710
|
|
|
return new WP_Error( 'stripe_error', 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 ) ) ); |
|
711
|
|
|
} |
|
712
|
|
|
|
|
713
|
|
|
$this->log( "Info: Begin processing payment for order {$order_id} for the amount of {$order->get_total()}" ); |
|
714
|
|
|
|
|
715
|
|
|
// Make the request. |
|
716
|
|
|
$response = WC_Stripe_API::request( $this->generate_payment_request( $order, $result['token']['id'] ) ); |
|
717
|
|
|
|
|
718
|
|
|
if ( is_wp_error( $response ) ) { |
|
719
|
|
|
$localized_messages = $this->get_localized_messages(); |
|
720
|
|
|
|
|
721
|
|
|
throw new Exception( ( isset( $localized_messages[ $response->get_error_code() ] ) ? $localized_messages[ $response->get_error_code() ] : $response->get_error_message() ) ); |
|
722
|
|
|
} |
|
723
|
|
|
|
|
724
|
|
|
// Process valid response. |
|
725
|
|
|
$this->process_response( $response, $order ); |
|
726
|
|
|
} else { |
|
727
|
|
|
$order->payment_complete(); |
|
728
|
|
|
} |
|
729
|
|
|
|
|
730
|
|
|
// Remove cart. |
|
731
|
|
|
WC()->cart->empty_cart(); |
|
732
|
|
|
|
|
733
|
|
|
update_post_meta( $order_id, '_customer_user', get_current_user_id() ); |
|
734
|
|
|
update_post_meta( $order_id, '_payment_method_title', 'Apple Pay (Stripe)' ); |
|
735
|
|
|
|
|
736
|
|
|
// Return thank you page redirect. |
|
737
|
|
|
wp_send_json( array( |
|
738
|
|
|
'success' => 'true', |
|
739
|
|
|
'redirect' => $this->get_return_url( $order ), |
|
740
|
|
|
) ); |
|
741
|
|
|
|
|
742
|
|
|
} catch ( Exception $e ) { |
|
743
|
|
|
WC()->session->set( 'refresh_totals', true ); |
|
744
|
|
|
$this->log( sprintf( __( 'Error: %s', 'woocommerce-gateway-stripe' ), $e->getMessage() ) ); |
|
745
|
|
|
|
|
746
|
|
|
if ( is_object( $order ) && isset( $order_id ) && $order->has_status( array( 'pending', 'failed' ) ) ) { |
|
|
|
|
|
|
747
|
|
|
$this->send_failed_order_email( $order_id ); |
|
748
|
|
|
} |
|
749
|
|
|
|
|
750
|
|
|
wp_send_json( array( 'success' => 'false', 'msg' => $e->getMessage() ) ); |
|
751
|
|
|
} |
|
752
|
|
|
} |
|
753
|
|
|
|
|
754
|
|
|
/** |
|
755
|
|
|
* Generate the request for the payment. |
|
756
|
|
|
* @param WC_Order $order |
|
757
|
|
|
* @param string $source token |
|
758
|
|
|
* @return array() |
|
|
|
|
|
|
759
|
|
|
*/ |
|
760
|
|
|
protected function generate_payment_request( $order, $source ) { |
|
761
|
|
|
$post_data = array(); |
|
762
|
|
|
$post_data['currency'] = strtolower( version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->get_order_currency() : $order->get_currency() ); |
|
763
|
|
|
$post_data['amount'] = $this->get_stripe_amount( $order->get_total(), $post_data['currency'] ); |
|
764
|
|
|
$post_data['description'] = sprintf( __( '%1$s - Order %2$s', 'woocommerce-gateway-stripe' ), $this->statement_descriptor, $order->get_order_number() ); |
|
765
|
|
|
$post_data['capture'] = $this->capture ? 'true' : 'false'; |
|
766
|
|
|
|
|
767
|
|
|
$billing_email = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->billing_email : $order->get_billing_email(); |
|
768
|
|
|
|
|
769
|
|
|
if ( ! empty( $billing_email ) && apply_filters( 'wc_stripe_send_stripe_receipt', false ) ) { |
|
770
|
|
|
$post_data['receipt_email'] = $billing_email; |
|
771
|
|
|
} |
|
772
|
|
|
|
|
773
|
|
|
$post_data['expand[]'] = 'balance_transaction'; |
|
774
|
|
|
$post_data['source'] = $source; |
|
775
|
|
|
|
|
776
|
|
|
/** |
|
777
|
|
|
* Filter the return value of the WC_Payment_Gateway_CC::generate_payment_request. |
|
778
|
|
|
* |
|
779
|
|
|
* @since 3.1.0 |
|
780
|
|
|
* @param array $post_data |
|
781
|
|
|
* @param WC_Order $order |
|
782
|
|
|
* @param object $source |
|
783
|
|
|
*/ |
|
784
|
|
|
return apply_filters( 'wc_stripe_generate_payment_request', $post_data, $order ); |
|
785
|
|
|
} |
|
786
|
|
|
|
|
787
|
|
|
/** |
|
788
|
|
|
* Builds the shippings methods to pass to Apple Pay. |
|
789
|
|
|
* |
|
790
|
|
|
* @since 3.1.0 |
|
791
|
|
|
* @version 3.1.0 |
|
792
|
|
|
*/ |
|
793
|
|
|
public function build_shipping_methods( $shipping_methods ) { |
|
794
|
|
|
if ( empty( $shipping_methods ) ) { |
|
795
|
|
|
return array(); |
|
796
|
|
|
} |
|
797
|
|
|
|
|
798
|
|
|
$shipping = array(); |
|
799
|
|
|
|
|
800
|
|
|
foreach ( $shipping_methods as $method ) { |
|
801
|
|
|
$shipping[] = array( |
|
802
|
|
|
'label' => $method['label'], |
|
803
|
|
|
'detail' => '', |
|
804
|
|
|
'amount' => $method['amount']['value'], |
|
805
|
|
|
'identifier' => $method['id'], |
|
806
|
|
|
); |
|
807
|
|
|
} |
|
808
|
|
|
|
|
809
|
|
|
return $shipping; |
|
810
|
|
|
} |
|
811
|
|
|
|
|
812
|
|
|
/** |
|
813
|
|
|
* Builds the line items to pass to Apple Pay. |
|
814
|
|
|
* |
|
815
|
|
|
* @since 3.1.0 |
|
816
|
|
|
* @version 3.1.0 |
|
817
|
|
|
*/ |
|
818
|
|
|
public function build_line_items() { |
|
819
|
|
|
if ( ! defined( 'WOOCOMMERCE_CART' ) ) { |
|
820
|
|
|
define( 'WOOCOMMERCE_CART', true ); |
|
821
|
|
|
} |
|
822
|
|
|
|
|
823
|
|
|
$decimals = apply_filters( 'wc_stripe_apple_pay_decimals', 2 ); |
|
824
|
|
|
|
|
825
|
|
|
$items = array(); |
|
826
|
|
|
$subtotal = 0; |
|
827
|
|
|
|
|
828
|
|
|
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) { |
|
829
|
|
|
$amount = wc_format_decimal( $cart_item['line_subtotal'], $decimals ); |
|
830
|
|
|
$subtotal += $cart_item['line_subtotal']; |
|
831
|
|
|
$quantity_label = 1 < $cart_item['quantity'] ? ' (x' . $cart_item['quantity'] . ')' : ''; |
|
832
|
|
|
|
|
833
|
|
|
$item = array( |
|
834
|
|
|
'type' => 'final', |
|
835
|
|
|
'label' => $cart_item['data']->post->post_title . $quantity_label, |
|
836
|
|
|
'amount' => wc_format_decimal( $amount, $decimals ), |
|
837
|
|
|
); |
|
838
|
|
|
|
|
839
|
|
|
$items[] = $item; |
|
840
|
|
|
} |
|
841
|
|
|
|
|
842
|
|
|
// Default show only subtotal instead of itemization. |
|
843
|
|
|
if ( apply_filters( 'wc_stripe_apple_pay_disable_itemization', true ) ) { |
|
844
|
|
|
$items = array(); |
|
845
|
|
|
$items[] = array( |
|
846
|
|
|
'type' => 'final', |
|
847
|
|
|
'label' => esc_html( __( 'Sub-Total', 'woocommerce-gateway-stripe' ) ), |
|
848
|
|
|
'amount' => wc_format_decimal( $subtotal, $decimals ), |
|
849
|
|
|
); |
|
850
|
|
|
} |
|
851
|
|
|
|
|
852
|
|
|
$discounts = wc_format_decimal( WC()->cart->get_cart_discount_total(), $decimals ); |
|
853
|
|
|
$tax = wc_format_decimal( WC()->cart->tax_total + WC()->cart->shipping_tax_total, $decimals ); |
|
854
|
|
|
$shipping = wc_format_decimal( WC()->cart->shipping_total, $decimals ); |
|
855
|
|
|
$item_total = wc_format_decimal( WC()->cart->cart_contents_total, $decimals ) + $discounts; |
|
856
|
|
|
$order_total = wc_format_decimal( $item_total + $tax + $shipping, $decimals ); |
|
|
|
|
|
|
857
|
|
|
|
|
858
|
|
View Code Duplication |
if ( wc_tax_enabled() ) { |
|
|
|
|
|
|
859
|
|
|
$items[] = array( |
|
860
|
|
|
'type' => 'final', |
|
861
|
|
|
'label' => esc_html( __( 'Tax', 'woocommerce-gateway-stripe' ) ), |
|
862
|
|
|
'amount' => $tax, |
|
863
|
|
|
); |
|
864
|
|
|
} |
|
865
|
|
|
|
|
866
|
|
|
if ( WC()->cart->needs_shipping() && $this->is_shipping_enabled ) { |
|
867
|
|
|
$items[] = array( |
|
868
|
|
|
'type' => 'final', |
|
869
|
|
|
'label' => esc_html( __( 'Shipping', 'woocommerce-gateway-stripe' ) ), |
|
870
|
|
|
'amount' => $shipping, |
|
871
|
|
|
); |
|
872
|
|
|
} |
|
873
|
|
|
|
|
874
|
|
View Code Duplication |
if ( WC()->cart->has_discount() ) { |
|
|
|
|
|
|
875
|
|
|
$items[] = array( |
|
876
|
|
|
'type' => 'final', |
|
877
|
|
|
'label' => esc_html( __( 'Discount', 'woocommerce-gateway-stripe' ) ), |
|
878
|
|
|
'amount' => '-' . $discounts, |
|
879
|
|
|
); |
|
880
|
|
|
} |
|
881
|
|
|
|
|
882
|
|
|
return $items; |
|
883
|
|
|
} |
|
884
|
|
|
|
|
885
|
|
|
/** |
|
886
|
|
|
* Create order programatically. |
|
887
|
|
|
* |
|
888
|
|
|
* @since 3.1.0 |
|
889
|
|
|
* @version 3.1.0 |
|
890
|
|
|
* @param array $data |
|
891
|
|
|
* @return object $order |
|
892
|
|
|
*/ |
|
893
|
|
|
public function create_order( $data = array() ) { |
|
894
|
|
|
if ( empty( $data ) ) { |
|
895
|
|
|
throw new Exception( sprintf( __( 'Error %d: Unable to create order. Please try again.', 'woocommerce-gateway-stripe' ), 520 ) ); |
|
896
|
|
|
} |
|
897
|
|
|
|
|
898
|
|
|
$order = wc_create_order(); |
|
899
|
|
|
$order_id = version_compare( WC_VERSION, '3.0.0', '<' ) ? $order->id : $order->get_id(); |
|
900
|
|
|
|
|
901
|
|
|
if ( is_wp_error( $order ) ) { |
|
902
|
|
|
throw new Exception( sprintf( __( 'Error %d: Unable to create order. Please try again.', 'woocommerce-gateway-stripe' ), 520 ) ); |
|
903
|
|
|
} elseif ( false === $order ) { |
|
904
|
|
|
throw new Exception( sprintf( __( 'Error %d: Unable to create order. Please try again.', 'woocommerce-gateway-stripe' ), 521 ) ); |
|
905
|
|
|
} else { |
|
906
|
|
|
do_action( 'woocommerce_new_order', $order_id ); |
|
907
|
|
|
} |
|
908
|
|
|
|
|
909
|
|
|
// Store the line items to the new/resumed order |
|
910
|
|
|
foreach ( WC()->cart->get_cart() as $cart_item_key => $values ) { |
|
911
|
|
|
$item_id = $order->add_product( |
|
912
|
|
|
$values['data'], |
|
913
|
|
|
$values['quantity'], |
|
914
|
|
|
array( |
|
915
|
|
|
'variation' => $values['variation'], |
|
916
|
|
|
'totals' => array( |
|
917
|
|
|
'subtotal' => $values['line_subtotal'], |
|
918
|
|
|
'subtotal_tax' => $values['line_subtotal_tax'], |
|
919
|
|
|
'total' => $values['line_total'], |
|
920
|
|
|
'tax' => $values['line_tax'], |
|
921
|
|
|
'tax_data' => $values['line_tax_data'], // Since 2.2 |
|
922
|
|
|
), |
|
923
|
|
|
) |
|
924
|
|
|
); |
|
925
|
|
|
|
|
926
|
|
|
if ( ! $item_id ) { |
|
927
|
|
|
throw new Exception( sprintf( __( 'Error %d: Unable to create order. Please try again.', 'woocommerce-gateway-stripe' ), 525 ) ); |
|
928
|
|
|
} |
|
929
|
|
|
|
|
930
|
|
|
// Allow plugins to add order item meta |
|
931
|
|
View Code Duplication |
if ( version_compare( WC_VERSION, '3.0', '<' ) ) { |
|
|
|
|
|
|
932
|
|
|
do_action( 'woocommerce_add_order_item_meta', $item_id, $values, $cart_item_key ); |
|
933
|
|
|
} else { |
|
934
|
|
|
do_action( 'woocommerce_new_order_item', $item_id, wc_get_product( $item_id ), $order->get_id() ); |
|
935
|
|
|
} |
|
936
|
|
|
} |
|
937
|
|
|
|
|
938
|
|
|
// Store fees |
|
939
|
|
|
foreach ( WC()->cart->get_fees() as $fee_key => $fee ) { |
|
940
|
|
|
if ( version_compare( WC_VERSION, '3.0', '<' ) ) { |
|
941
|
|
|
$item_id = $order->add_fee( $fee ); |
|
942
|
|
|
} else { |
|
943
|
|
|
$item = new WC_Order_Item_Fee(); |
|
944
|
|
|
$item->set_props( array( |
|
945
|
|
|
'name' => $fee->name, |
|
946
|
|
|
'tax_class' => $fee->taxable ? $fee->tax_class : 0, |
|
947
|
|
|
'total' => $fee->amount, |
|
948
|
|
|
'total_tax' => $fee->tax, |
|
949
|
|
|
'taxes' => array( |
|
950
|
|
|
'total' => $fee->tax_data, |
|
951
|
|
|
), |
|
952
|
|
|
'order_id' => $order->get_id(), |
|
953
|
|
|
) ); |
|
954
|
|
|
$item_id = $item->save(); |
|
955
|
|
|
$order->add_item( $item ); |
|
956
|
|
|
} |
|
957
|
|
|
|
|
958
|
|
|
if ( ! $item_id ) { |
|
959
|
|
|
throw new Exception( sprintf( __( 'Error %d: Unable to create order. Please try again.', 'woocommerce-gateway-stripe' ), 526 ) ); |
|
960
|
|
|
} |
|
961
|
|
|
|
|
962
|
|
|
// Allow plugins to add order item meta to fees |
|
963
|
|
View Code Duplication |
if ( version_compare( WC_VERSION, '3.0', '<' ) ) { |
|
|
|
|
|
|
964
|
|
|
do_action( 'woocommerce_add_order_fee_meta', $order_id, $item_id, $fee, $fee_key ); |
|
965
|
|
|
} else { |
|
966
|
|
|
do_action( 'woocommerce_new_order_item', $item_id, $fee, $order->get_id() ); |
|
967
|
|
|
} |
|
968
|
|
|
} |
|
969
|
|
|
|
|
970
|
|
|
// Store tax rows |
|
971
|
|
|
foreach ( array_keys( WC()->cart->taxes + WC()->cart->shipping_taxes ) as $tax_rate_id ) { |
|
972
|
|
|
$tax_amount = WC()->cart->get_tax_amount( $tax_rate_id ); |
|
973
|
|
|
$shipping_tax_amount = WC()->cart->get_shipping_tax_amount( $tax_rate_id ); |
|
974
|
|
|
|
|
975
|
|
|
if ( version_compare( WC_VERSION, '3.0', '<' ) ) { |
|
976
|
|
|
$item_id = $order->add_tax( $tax_rate_id, $tax_amount, $shipping_tax_amount ); |
|
977
|
|
|
} else { |
|
978
|
|
|
$item = new WC_Order_Item_Tax(); |
|
979
|
|
|
$item->set_props( array( |
|
980
|
|
|
'rate_id' => $tax_rate_id, |
|
981
|
|
|
'tax_total' => $tax_amount, |
|
982
|
|
|
'shipping_tax_total' => $shipping_tax_amount, |
|
983
|
|
|
) ); |
|
984
|
|
|
$item->set_rate( $tax_rate_id ); |
|
985
|
|
|
$item->set_order_id( $order->get_id() ); |
|
986
|
|
|
$item_id = $item->save(); |
|
987
|
|
|
$order->add_item( $item ); |
|
988
|
|
|
} |
|
989
|
|
|
|
|
990
|
|
|
if ( $tax_rate_id && ! $item_id && apply_filters( 'woocommerce_cart_remove_taxes_zero_rate_id', 'zero-rated' ) !== $tax_rate_id ) { |
|
991
|
|
|
throw new Exception( sprintf( __( 'Error %d: Unable to create order. Please try again.', 'woocommerce-gateway-stripe' ), 528 ) ); |
|
992
|
|
|
} |
|
993
|
|
|
} |
|
994
|
|
|
|
|
995
|
|
|
// Store coupons |
|
996
|
|
|
$discount = WC()->cart->get_coupon_discount_amount( $code ); |
|
|
|
|
|
|
997
|
|
|
$discount_tax = WC()->cart->get_coupon_discount_tax_amount( $code ); |
|
|
|
|
|
|
998
|
|
|
|
|
999
|
|
|
foreach ( WC()->cart->get_coupons() as $code => $coupon ) { |
|
1000
|
|
|
if ( version_compare( WC_VERSION, '3.0', '<' ) ) { |
|
1001
|
|
|
$coupon_id = $order->add_coupon( $code, $discount, $discount_tax ); |
|
1002
|
|
|
} else { |
|
1003
|
|
|
$item = new WC_Order_Item_Coupon(); |
|
1004
|
|
|
$item->set_props( array( |
|
1005
|
|
|
'code' => $code, |
|
1006
|
|
|
'discount' => $discount, |
|
1007
|
|
|
'discount_tax' => $discount_tax, |
|
1008
|
|
|
'order_id' => $order->get_id(), |
|
1009
|
|
|
) ); |
|
1010
|
|
|
$coupon_id = $item->save(); |
|
1011
|
|
|
$order->add_item( $item ); |
|
1012
|
|
|
} |
|
1013
|
|
|
|
|
1014
|
|
|
if ( ! $coupon_id ) { |
|
1015
|
|
|
throw new Exception( sprintf( __( 'Error %d: Unable to create order. Please try again.', 'woocommerce-gateway-stripe' ), 529 ) ); |
|
1016
|
|
|
} |
|
1017
|
|
|
} |
|
1018
|
|
|
|
|
1019
|
|
|
// Billing address |
|
1020
|
|
|
$billing_address = array(); |
|
1021
|
|
|
if ( ! empty( $data['token']['card'] ) ) { |
|
1022
|
|
|
// Name from Stripe is a full name string. |
|
1023
|
|
|
$name = explode( ' ', $data['token']['card']['name'] ); |
|
1024
|
|
|
$lastname = array_pop( $name ); |
|
1025
|
|
|
$firstname = implode( ' ', $name ); |
|
1026
|
|
|
$billing_address['first_name'] = $firstname; |
|
1027
|
|
|
$billing_address['last_name'] = $lastname; |
|
1028
|
|
|
$billing_address['email'] = $data['shippingContact']['emailAddress']; |
|
1029
|
|
|
$billing_address['phone'] = $data['shippingContact']['phoneNumber']; |
|
1030
|
|
|
$billing_address['country'] = $data['token']['card']['country']; |
|
1031
|
|
|
$billing_address['address_1'] = $data['token']['card']['address_line1']; |
|
1032
|
|
|
$billing_address['address_2'] = $data['token']['card']['address_line2']; |
|
1033
|
|
|
$billing_address['city'] = $data['token']['card']['address_city']; |
|
1034
|
|
|
$billing_address['state'] = $data['token']['card']['address_state']; |
|
1035
|
|
|
$billing_address['postcode'] = $data['token']['card']['address_zip']; |
|
1036
|
|
|
} |
|
1037
|
|
|
|
|
1038
|
|
|
// Shipping address. |
|
1039
|
|
|
$shipping_address = array(); |
|
1040
|
|
|
if ( WC()->cart->needs_shipping() && $this->is_shipping_enabled && ! empty( $data['shippingContact'] ) ) { |
|
1041
|
|
|
$shipping_address['first_name'] = $data['shippingContact']['givenName']; |
|
1042
|
|
|
$shipping_address['last_name'] = $data['shippingContact']['familyName']; |
|
1043
|
|
|
$shipping_address['email'] = $data['shippingContact']['emailAddress']; |
|
1044
|
|
|
$shipping_address['phone'] = $data['shippingContact']['phoneNumber']; |
|
1045
|
|
|
$shipping_address['country'] = $data['shippingContact']['countryCode']; |
|
1046
|
|
|
$shipping_address['address_1'] = $data['shippingContact']['addressLines'][0]; |
|
1047
|
|
|
$shipping_address['address_2'] = $data['shippingContact']['addressLines'][1]; |
|
1048
|
|
|
$shipping_address['city'] = $data['shippingContact']['locality']; |
|
1049
|
|
|
$shipping_address['state'] = $data['shippingContact']['administrativeArea']; |
|
1050
|
|
|
$shipping_address['postcode'] = $data['shippingContact']['postalCode']; |
|
1051
|
|
|
} elseif ( ! empty( $data['shippingContact'] ) ) { |
|
1052
|
|
|
$shipping_address['first_name'] = $firstname; |
|
|
|
|
|
|
1053
|
|
|
$shipping_address['last_name'] = $lastname; |
|
|
|
|
|
|
1054
|
|
|
$shipping_address['email'] = $data['shippingContact']['emailAddress']; |
|
1055
|
|
|
$shipping_address['phone'] = $data['shippingContact']['phoneNumber']; |
|
1056
|
|
|
$shipping_address['country'] = $data['token']['card']['country']; |
|
1057
|
|
|
$shipping_address['address_1'] = $data['token']['card']['address_line1']; |
|
1058
|
|
|
$shipping_address['address_2'] = $data['token']['card']['address_line2']; |
|
1059
|
|
|
$shipping_address['city'] = $data['token']['card']['address_city']; |
|
1060
|
|
|
$shipping_address['state'] = $data['token']['card']['address_state']; |
|
1061
|
|
|
$shipping_address['postcode'] = $data['token']['card']['address_zip']; |
|
1062
|
|
|
} |
|
1063
|
|
|
|
|
1064
|
|
|
$order->set_address( $billing_address, 'billing' ); |
|
1065
|
|
|
$order->set_address( $shipping_address, 'shipping' ); |
|
1066
|
|
|
|
|
1067
|
|
|
WC()->shipping->calculate_shipping( WC()->cart->get_shipping_packages() ); |
|
1068
|
|
|
|
|
1069
|
|
|
// Get the rate object selected by user. |
|
1070
|
|
|
foreach ( WC()->shipping->get_packages() as $package_key => $package ) { |
|
1071
|
|
|
foreach ( $package['rates'] as $key => $rate ) { |
|
1072
|
|
|
// Loop through user chosen shipping methods. |
|
1073
|
|
|
foreach ( WC()->session->get( 'chosen_shipping_methods' ) as $method ) { |
|
1074
|
|
|
if ( $method === $key ) { |
|
1075
|
|
|
if ( version_compare( WC_VERSION, '3.0', '<' ) ) { |
|
1076
|
|
|
$order->add_shipping( $rate ); |
|
1077
|
|
|
} else { |
|
1078
|
|
|
$item = new WC_Order_Item_Shipping(); |
|
1079
|
|
|
$item->set_props( array( |
|
1080
|
|
|
'method_title' => $rate->label, |
|
1081
|
|
|
'method_id' => $rate->id, |
|
1082
|
|
|
'total' => wc_format_decimal( $rate->cost ), |
|
1083
|
|
|
'taxes' => $rate->taxes, |
|
1084
|
|
|
'order_id' => $order->get_id(), |
|
1085
|
|
|
) ); |
|
1086
|
|
|
foreach ( $rate->get_meta_data() as $key => $value ) { |
|
1087
|
|
|
$item->add_meta_data( $key, $value, true ); |
|
1088
|
|
|
} |
|
1089
|
|
|
$item->save(); |
|
1090
|
|
|
$order->add_item( $item ); |
|
1091
|
|
|
} |
|
1092
|
|
|
} |
|
1093
|
|
|
} |
|
1094
|
|
|
} |
|
1095
|
|
|
} |
|
1096
|
|
|
|
|
1097
|
|
|
$available_gateways = WC()->payment_gateways->get_available_payment_gateways(); |
|
1098
|
|
|
$order->set_payment_method( $available_gateways['stripe'] ); |
|
1099
|
|
|
$order->set_total( WC()->cart->shipping_total, 'shipping' ); |
|
1100
|
|
|
$order->set_total( WC()->cart->get_cart_discount_total(), 'cart_discount' ); |
|
1101
|
|
|
$order->set_total( WC()->cart->get_cart_discount_tax_total(), 'cart_discount_tax' ); |
|
1102
|
|
|
$order->set_total( WC()->cart->tax_total, 'tax' ); |
|
1103
|
|
|
$order->set_total( WC()->cart->shipping_tax_total, 'shipping_tax' ); |
|
1104
|
|
|
$order->set_total( WC()->cart->total ); |
|
1105
|
|
|
|
|
1106
|
|
|
// If we got here, the order was created without problems! |
|
1107
|
|
|
wc_transaction_query( 'commit' ); |
|
1108
|
|
|
|
|
1109
|
|
|
return $order; |
|
1110
|
|
|
} |
|
1111
|
|
|
|
|
1112
|
|
|
/** |
|
1113
|
|
|
* Logs |
|
1114
|
|
|
* |
|
1115
|
|
|
* @since 3.1.0 |
|
1116
|
|
|
* @version 3.1.0 |
|
1117
|
|
|
* |
|
1118
|
|
|
* @param string $message |
|
1119
|
|
|
*/ |
|
1120
|
|
|
public function log( $message ) { |
|
1121
|
|
|
if ( $this->logging ) { |
|
1122
|
|
|
WC_Stripe::log( 'Apple Pay: ' . $message ); |
|
1123
|
|
|
} |
|
1124
|
|
|
} |
|
1125
|
|
|
} |
|
1126
|
|
|
|
|
1127
|
|
|
new WC_Stripe_Apple_Pay(); |
|
1128
|
|
|
|
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.