PluginProbe
PayPlug for WooCommerce (Official) / 2.18.0
PayPlug for WooCommerce (Official) v2.18.0
3.0.0 2.18.0 1.0.17 1.0.18 1.0.19 1.0.20 1.0.21 1.0.22 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.1.0 1.10.0 1.10.1 1.2.1 1.2.10 1.2.11 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 All 101 releases
payplug / src / PayplugWoocommerceRequest.php

PayplugWoocommerceRequest.php in PayPlug for WooCommerce (Official) 2.18.0, at src/PayplugWoocommerceRequest.php

543 lines 19.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Payplug\PayplugWoocommerce;
4
5 // Exit if accessed directly
6 use Automattic\WooCommerce\Utilities\OrderUtil;
7 use Payplug\PayplugWoocommerce\Gateway\PayplugAddressData;
8 use Payplug\PayplugWoocommerce\Gateway\PayplugGateway;
9 use Payplug\PayplugWoocommerce\Traits\ServiceGetter;
10
11 if (!defined('ABSPATH')) {
12 exit;
13 }
14
15 /**
16 * Class PayplugWoocommerceRequest
17 */
18 class PayplugWoocommerceRequest
19 {
20 use ServiceGetter;
21
22 /**
23 * Gateway settings.
24 *
25 * @var array
26 */
27 protected $settings;
28
29 /**
30 * @var PayplugGateway
31 */
32 protected $gateway;
33
34 /**
35 * PayplugWoocommerceRequest constructor.
36 */
37 public function __construct()
38 {
39 $this->settings = $this->get_configuration()->get_options();
40
41 if (empty($this->settings) || !isset($this->settings['enabled']) || !(bool) $this->settings['enabled']) {
42 return;
43 }
44
45 // Don't load for change payment method page.
46 if (isset($_GET['change_payment_method'])) {
47 return;
48 }
49
50 add_action('template_redirect', [$this, 'set_session']);
51 add_action('wc_ajax_payplug_create_order', [$this, 'ajax_create_order']);
52 add_action('wc_ajax_applepay_update_payment', [$this, 'applepay_update_payment']);
53 add_action('wc_ajax_applepay_get_order_totals', [$this, 'applepay_get_order_totals']);
54 add_action('wc_ajax_payplug_order_review_url', [$this, 'ajax_create_payment']);
55 add_action('wc_ajax_payplug_check_payment', [$this, 'check_payment']);
56 add_action('wc_ajax_payplug_create_intent', [$this, 'create_payment_intent']);
57 }
58
59 /**
60 * Sets the WC customer session if one is not set.
61 * This is needed so nonces can be verified by AJAX Request.
62 */
63 public function set_session()
64 {
65 if (!is_product() || (isset(WC()->session) && WC()->session->has_session())) {
66 return;
67 }
68
69 $session_class = apply_filters('woocommerce_session_handler', 'WC_Session_Handler');
70 $wc_session = new $session_class();
71
72 if (version_compare(WC_VERSION, '3.3', '>=')) {
73 $wc_session->init();
74 }
75
76 $wc_session->set_customer_session_cookie(true);
77 }
78
79 /**
80 * Create the woocommerce order in the BO
81 */
82 public function ajax_create_order()
83 {
84 if (WC()->cart->is_empty()) {
85 wp_send_json_error(__('Empty cart', 'payplug'));
86 }
87
88 if (!defined('WOOCOMMERCE_CHECKOUT')) {
89 define('WOOCOMMERCE_CHECKOUT', true);
90 }
91
92 WC()->checkout()->process_checkout();
93
94 die(0);
95 }
96
97 /**
98 * Create the woocommerce order in the BO
99 */
100 public function ajax_create_payment()
101 {
102 global $wp;
103
104 if (WC()->cart->is_empty()) {
105 wp_send_json_error(__('Empty cart', 'payplug'));
106 }
107
108 if (!defined('WOOCOMMERCE_CHECKOUT')) {
109 define('WOOCOMMERCE_CHECKOUT', true);
110 }
111
112 $payment_method = $_POST['payment_method'];
113
114 if ($payment_method === 'payplug' || $payment_method === 'american_express') {
115 $method = $this->get_configuration()->get_option('payment_methods.configuration.payplug.embedded_mode');
116 if ('integrated' != $method && 'popup' != $method) {
117 $this->ajax_create_order();
118 }
119 } else {
120 $this->ajax_create_order();
121 }
122
123 $https_referer = $_POST['_wp_http_referer'];
124 $path = parse_url($https_referer);
125 wp_parse_str($path['query'], $output);
126
127 if (isset($output['order-pay'])) {
128 $order_id = $output['order-pay'];
129 } else {
130 preg_match('/(?<=order-pay\/)\d*/', $path['path'], $matches);
131 $order_id = $matches[0];
132 }
133
134 $this->process_order_payment($order_id, $payment_method);
135 }
136
137 /**
138 * wordpress class-wc-checkout.php
139 * We don't need all the other verifications, at this point customer already had the checkout and it's all valid, the order already exists
140 * We can+t use WP method because it's protected
141 * Process an order that does require payment.
142 *
143 * @since 3.0.0
144 *
145 * @param int $order_id Order ID.
146 * @param string $payment_method Payment method.
147 */
148 protected function process_order_payment($order_id, $payment_method)
149 {
150 $available_gateways = WC()->payment_gateways->get_available_payment_gateways();
151
152 if (!isset($available_gateways[$payment_method])) {
153 return;
154 }
155
156 // Store Order ID in session so it can be re-used after payment failure.
157 WC()->session->set('order_awaiting_payment', $order_id);
158
159 // Process Payment.
160 $result = $available_gateways[$payment_method]->process_payment($order_id);
161
162 // Redirect to success/confirmation/payment page.
163 if (isset($result['result']) && 'success' === $result['result']) {
164 $result['order_id'] = $order_id;
165
166 $result = apply_filters('woocommerce_payment_successful_result', $result, $order_id);
167
168 if (!wp_doing_ajax()) {
169 // phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect
170 wp_redirect($result['redirect']);
171 exit;
172 }
173
174 wp_send_json($result);
175 }
176 }
177
178 /**
179 * Update Payplug API Payment for Apple Pay
180 */
181 public function applepay_update_payment()
182 {
183 $payment_id = $_POST['payment_id'];
184 $apiService = new \Payplug\PayplugWoocommerce\Service\Api();
185 $mode = PayplugWoocommerceHelper::check_mode() ? 'live' : 'test';
186 $bearer_token = $apiService->get_bearer_token($mode);
187 try {
188 \Payplug\Payplug::init([
189 'secretKey' => $bearer_token,
190 'apiVersion' => '2019-08-06',
191 ]);
192 } catch (\Exception $e) {
193 $is_401 = (method_exists($e, 'getCode') && $e->getCode() == 401)
194 || strpos($e->getMessage(), '401') !== false;
195 if ($is_401 && $this->try_refresh_jwt($apiService, $mode)) {
196 try {
197 \Payplug\Payplug::init([
198 'secretKey' => $apiService->get_bearer_token($mode),
199 'apiVersion' => '2019-08-06',
200 ]);
201 } catch (\Exception $e) {
202 PayplugWoocommerceHelper::payplug_logout();
203 wp_send_json_error(__('You have been disconnected from the Payplug module (error 401)', 'payplug'));
204
205 return;
206 }
207 } else {
208 if ($is_401) {
209 PayplugWoocommerceHelper::payplug_logout();
210 wp_send_json_error(__('You have been disconnected from the Payplug module (error 401)', 'payplug'));
211 } else {
212 wp_send_json_error($e->getMessage());
213 }
214
215 return;
216 }
217 }
218 $apple_pay = [];
219 $apple_pay['payment_token'] = $_POST['payment_token'];
220 $payment = \Payplug\Payment::retrieve($payment_id);
221 $data = ['apple_pay' => $apple_pay];
222 $update = $payment->update($data);
223 wp_send_json_success(['result' => $update->is_paid]);
224 }
225
226 public function applepay_get_order_totals()
227 {
228 try {
229 wp_send_json_success(WC()->cart->total);
230 } catch (\Exception $e) {
231 PayplugGateway::log($e->getMessage());
232 wp_send_json_error($e->getMessage());
233 }
234 }
235
236 /**
237 * Empty cart for Apple Pay on product page
238 */
239 public function applepay_empty_cart()
240 {
241 try {
242 WC()->cart->empty_cart();
243 wp_send_json_success();
244 } catch (\Exception $e) {
245 wp_send_json_error([
246 'message' => __('Your order was cancelled.', 'woocommerce'),
247 ]);
248 }
249 }
250
251 /**
252 * Add the product on the current page to the cart for Apple Pay on product page
253 */
254 public function applepay_add_to_cart()
255 {
256 try {
257 if (!empty($_POST['product_id'])) {
258 $product_id = $_POST['product_id'];
259 } else {
260 $product_id = $_POST['product_variation_id'];
261 }
262
263 $product_quantity = !empty($_POST['product_quantity']) ? $_POST['product_quantity'] : 1;
264
265 WC()->cart->add_to_cart($product_id, $product_quantity);
266 wp_send_json_success([
267 'total' => WC()->cart->total - WC()->cart->shipping_total,
268 ]);
269 } catch (\Exception $e) {
270 wp_send_json_error([
271 'message' => __('Your order was cancelled.', 'woocommerce'),
272 ]);
273 }
274 }
275
276 /**
277 * Limit string length.
278 *
279 * @param string $value
280 * @param int $maxlength
281 *
282 * @return string
283 */
284 public function limit_length($value, $maxlength = 100)
285 {
286 return (strlen($value) > $maxlength) ? substr($value, 0, $maxlength) : $value;
287 }
288
289 public function check_payment()
290 {
291 global $wpdb;
292 $payment_id = $_POST['payment_id'];
293 if (empty($payment_id)) {
294 wp_send_json_error(__('Invalid request.', 'payplug'));
295 }
296 $apiService = new \Payplug\PayplugWoocommerce\Service\Api();
297 $mode = PayplugWoocommerceHelper::check_mode() ? 'live' : 'test';
298 $bearer_token = $apiService->get_bearer_token($mode);
299 try {
300 \Payplug\Payplug::init([
301 'secretKey' => $bearer_token,
302 'apiVersion' => '2019-08-06',
303 ]);
304 $payment = \Payplug\Payment::retrieve($payment_id);
305 } catch (\Exception $e) {
306 $is_401 = (method_exists($e, 'getCode') && $e->getCode() == 401)
307 || strpos($e->getMessage(), '401') !== false;
308 if ($is_401) {
309 if ($this->try_refresh_jwt($apiService, $mode)) {
310 try {
311 \Payplug\Payplug::init([
312 'secretKey' => $apiService->get_bearer_token($mode),
313 'apiVersion' => '2019-08-06',
314 ]);
315 $payment = \Payplug\Payment::retrieve($payment_id);
316 } catch (\Exception $e) {
317 PayplugWoocommerceHelper::payplug_logout();
318 wp_send_json_error(__('You have been disconnected from the Payplug module (error 401)', 'payplug'));
319
320 return;
321 }
322 } else {
323 PayplugWoocommerceHelper::payplug_logout();
324 wp_send_json_error(__('You have been disconnected from the Payplug module (error 401)', 'payplug'));
325
326 return;
327 }
328 } else {
329 $order_id = $this->getOrderFromPaymentId($payment_id);
330 $order = wc_get_order($order_id);
331 PayplugGateway::log(
332 sprintf(
333 'Order #%s : An error occurred while retrieving the payment data with the message : %s',
334 $order_id,
335 $e->getMessage()
336 )
337 );
338 wp_send_json_error($e->getMessage());
339 }
340 }
341 $order_id = $this->getOrderFromPaymentId($payment_id);
342 $order = wc_get_order($order_id);
343 $return_url = esc_url_raw($order->get_checkout_order_received_url());
344 if ((isset($payment->failure)) && (!empty($payment->failure)) || ($payment->is_paid === false && is_null($payment->paid_at))) {
345 $order->update_status('failed', __('Order cancelled by customer.', 'woocommerce'));
346 wp_send_json_error(
347 [
348 'code' => isset($payment->failure->code) ? $payment->failure->code : 500,
349 'message' => !empty($payment->failure->message) ? $payment->failure->message : __('payplug_integrated_payment_error', 'payplug'),
350 'cancel_url' => esc_url_raw($order->get_cancel_order_url_raw()),
351 ]
352 );
353 }
354
355 wp_send_json_success([
356 'payment_id' => $payment->id,
357 'result' => 'success',
358 'redirect' => !empty($payment->hosted_payment->payment_url) ? $payment->hosted_payment->payment_url : $return_url,
359 'cancel' => !empty($payment->hosted_payment->cancel_url) ? $payment->hosted_payment->cancel_url : null,
360 ]);
361 }
362
363 /**
364 * Attempt to regenerate the JWT for the given mode and persist the new token.
365 *
366 * @param \Payplug\PayplugWoocommerce\Service\Api $apiService
367 * @param string $mode
368 *
369 * @return bool True if a new JWT was successfully obtained and stored.
370 */
371 private function try_refresh_jwt($apiService, $mode)
372 {
373 $configuration = $this->get_configuration();
374 $options = $configuration->get_options();
375 $oauth_client_data = isset($options['oauth_client_data']) ? json_decode($options['oauth_client_data'], true) : [];
376 $client_data = isset($oauth_client_data[$mode]) ? $oauth_client_data[$mode] : [];
377 if (empty($client_data)) {
378 return false;
379 }
380 $new_jwt = $apiService->generate_jwt(
381 isset($client_data['client_id']) ? $client_data['client_id'] : '',
382 isset($client_data['client_secret']) ? $client_data['client_secret'] : ''
383 );
384 if (empty($new_jwt) || !isset($new_jwt['access_token'])) {
385 return false;
386 }
387 $jwt = isset($options['jwt']) ? json_decode($options['jwt'], true) : [];
388 $jwt[$mode] = $new_jwt;
389 $api_keys = isset($options['api_key']) ? json_decode($options['api_key'], true) : [];
390 $api_keys[$mode] = $new_jwt['access_token'];
391 $configuration->update_option('jwt', json_encode($jwt));
392 $configuration->update_option('api_key', json_encode($api_keys));
393
394 return true;
395 }
396
397 /**
398 * @param $payment_id
399 *
400 * @return int|string|null
401 */
402 private function getOrderFromPaymentId($payment_id)
403 {
404 global $wpdb;
405
406 if (OrderUtil::custom_orders_table_usage_is_enabled()) {
407 $orders = wc_get_orders(
408 [
409 'field_query' => [
410 [
411 'key' => 'transaction_id',
412 'comparison' => $payment_id,
413 ],
414 ],
415 ]
416 );
417 $order = $orders[0];
418 $order_id = $order->get_id();
419 } else {
420 $sql = 'SELECT post_id
421 FROM $wpdb->postmeta
422 WHERE meta_key = "_transaction_id" AND meta_value = %s';
423 $order_id = $wpdb->get_var(
424 $wpdb->prepare(
425 $sql,
426 $payment_id
427 )
428 );
429 }
430
431 return $order_id;
432 }
433
434 public function create_payment_intent()
435 {
436 $order_id = $_POST['order_id'];
437 $this->gateway = $this->get_payplug_gateway($_POST['gateway']);
438 $order = wc_get_order($order_id);
439 $customer_id = PayplugWoocommerceHelper::is_pre_30() ? $order->customer_user : $order->get_customer_id();
440 $return_url = esc_url_raw($order->get_checkout_order_received_url());
441 $address_data = PayplugAddressData::from_order($order);
442 $amount = (int) PayplugWoocommerceHelper::get_payplug_amount($order->get_total());
443 $amount = $this->gateway->validate_order_amount($amount);
444
445 $payment_data = [
446 'amount' => $amount,
447 'currency' => get_woocommerce_currency(),
448 'allow_save_card' => $this->gateway->save_card_available() && (int) $customer_id > 0,
449 'billing' => $address_data->get_billing(),
450 'shipping' => $address_data->get_shipping(),
451 'hosted_payment' => [
452 'return_url' => $return_url,
453 ],
454 'notification_url' => esc_url_raw(WC()->api_request_url('PayplugGateway')),
455 'metadata' => [
456 'order_id' => $order_id,
457 'customer_id' => ((int) $customer_id > 0) ? $customer_id : 'guest',
458 'domain' => $this->limit_length(esc_url_raw(home_url()), 500),
459 ],
460 ];
461
462 if (PayplugWoocommerceHelper::is_checkout_block() && is_checkout()) {
463 $payment_data['metadata']['woocommerce_block'] = 'CHECKOUT';
464 } elseif (PayplugWoocommerceHelper::is_cart_block() && is_cart()) {
465 $payment_data['metadata']['woocommerce_block'] = 'CART';
466 }
467
468 if ($this->gateway->id === 'apple_pay') {
469 unset($payment_data['allow_save_card']);
470
471 $payment_data['payment_method'] = $this->gateway->id;
472 $payment_data['payment_context'] = [
473 'apple_pay' => [
474 'domain_name' => $this->gateway->domain_name,
475 'application_data' => base64_encode(json_encode([
476 'apple_pay_domain' => $this->gateway->domain_name,
477 ])),
478 ],
479 ];
480 $payment_data['hosted_payment']['cancel_url'] = esc_url_raw($order->get_cancel_order_url_raw());
481 $payment_data['metadata']['applepay_workflow'] = 'checkout';
482 }
483
484 $method = $this->get_configuration()->get_option('payment_methods.configuration.payplug.embedded_mode');
485
486 if ('integrated' == $method && $this->gateway->id === 'payplug') {
487 $payment_data['initiator'] = 'PAYER';
488 $payment_data['integration'] = 'INTEGRATED_PAYMENT';
489 unset($payment_data['hosted_payment']['cancel_url']);
490 }
491
492 if ('popup' == $method && $this->gateway->id === 'american_express') {
493 $payment_data['payment_method'] = $this->gateway->id;
494 }
495
496 /**
497 * Filter the payment data before it's used
498 *
499 * @param array $payment_data
500 * @param int $order_id
501 * @param array $customer_details
502 * @param PayplugAddressData $address_data
503 */
504 $payment_data = apply_filters('payplug_gateway_payment_data', $payment_data, $order_id, [], $address_data);
505
506 $payment = $this->gateway->payplug_api->payment_create($payment_data);
507
508 // Save transaction id on the order
509 PayplugWoocommerceHelper::is_pre_30() ? update_post_meta($order_id, '_transaction_id', $payment->id) : $order->set_transaction_id($payment->id);
510
511 if (is_callable([$order, 'save'])) {
512 $order->save();
513 }
514
515 $metadata = PayplugWoocommerceHelper::extract_transaction_metadata($payment);
516 PayplugWoocommerceHelper::save_transaction_metadata($order, $metadata);
517
518 wp_send_json_success([
519 'payment_id' => $payment->id,
520 'merchant_session' => isset($payment->payment_method['merchant_session']) ? $payment->payment_method['merchant_session'] : null,
521 'redirect' => !empty($payment->hosted_payment->payment_url) ? $payment->hosted_payment->payment_url : $return_url,
522 'cancel' => esc_url_raw($order->get_cancel_order_url_raw()),
523 ]);
524 }
525
526 /**
527 * Returns an instantiated gateway.
528 *
529 * @return PayplugGateway
530 */
531 protected function get_payplug_gateway($id)
532 {
533 if (!isset($this->gateway)) {
534 $gateways = WC()->payment_gateways()->payment_gateways();
535 foreach ($gateways as $gateway) {
536 if ($gateway->id === $id) {
537 return $gateway;
538 }
539 }
540 }
541 }
542 }
543