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