PluginProbe
HyperPay Payments / 5.3.0
HyperPay Payments v5.3.0
6.6.0 trunk 1.7 1.8 1.8.1 1.8.2 1.8.3 1.8.4 1.8.5 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.1.0 2.2.0 2.3.0 2.3.1 2.3.2 2.3.3 3.0.0 3.0.5 4.0.0 4.0.2 All 34 releases
hyperpay-gateways / src / App / HyperpayExpressBlock.php

HyperpayExpressBlock.php in HyperPay Payments 5.3.0, at src/App/HyperpayExpressBlock.php

450 lines 13.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Hyperpay\Gateways\App;
4 if ( ! defined( 'ABSPATH' ) ) exit;
5
6 use WC_Validation;
7 use Exception;
8
9 /**
10 * Express Payments Blocks integration
11 *
12 * @since 1.0.3
13 */
14 trait HyperpayExpressBlock
15 {
16
17 public function initialize()
18 {
19 add_action('wc_ajax_hyperpay_prepare_checkout', [$this, "initCheckout"]);
20 add_action('wc_ajax_hyperpay_update_method', [$this, 'ajax_update_shipping_method']);
21 add_action('wc_ajax_hyperpay_update_checkout', [$this, "init_shipping_options"]);
22 add_action('wc_ajax_hyperpay_process_checkout', [$this, 'process_checkout']);
23 }
24
25
26 public function initCheckout()
27 {
28 $data = [
29 'headers' => [
30 "Authorization" => "Bearer {$this->accessToken}"
31 ],
32 'body' => [
33 "entityId" => $this->entityId,
34 "paymentType" => $this->trans_type,
35 ]
36 ];
37
38
39 if ($this->testMode) {
40 $data['body']["testMode"] = $this->trans_mode;
41 }
42
43 if ($this->server_to_server) {
44 $data['body']['paymentBrand'] = $this->brands[0];
45 }
46
47
48 $response = wp_remote_post($this->token_url, $data);
49 $result = json_decode(wp_remote_retrieve_body($response), true);
50
51
52 if (is_wp_error($response)) {
53 $error = $response->get_error_message();
54 } elseif (wp_remote_retrieve_response_code($response) != 200) {
55 $error = $result['result']['description'] ?? "something wrong";
56 }
57
58 if (isset($error) || !\preg_match("/^(000\.200)/", $result['result']['code'] ?? '')) {
59 return wp_send_json_error($result['result']['description'] ?? $error);
60 }
61
62
63 return wp_send_json($result['id']);
64 }
65
66
67 public function init_shipping_options()
68 {
69
70 $shipping_inputs = filter_input_array(
71 INPUT_POST,
72 [
73 'countryCode' => FILTER_SANITIZE_STRING,
74 'administrativeArea' => FILTER_SANITIZE_STRING,
75 'postalCode' => FILTER_SANITIZE_STRING,
76 'locality' => FILTER_SANITIZE_STRING,
77 'address' => FILTER_SANITIZE_STRING,
78 'address_2' => FILTER_SANITIZE_STRING,
79 ]
80 );
81
82 $shipping_address = [
83 'country' => $shipping_inputs['countryCode'],
84 'state' => $shipping_inputs['administrativeArea'],
85 'postcode' => $shipping_inputs['postalCode'],
86 'city' => $shipping_inputs['locality'],
87 'address' => $shipping_inputs['address'],
88 'address_2' => $shipping_inputs['address_2'],
89 ];
90
91
92
93 $product_view_options = filter_input_array(INPUT_POST, ['is_product_page' => FILTER_SANITIZE_STRING]);
94 $should_show_itemized_view = !isset($product_view_options['is_product_page']) ? true : filter_var($product_view_options['is_product_page'], FILTER_VALIDATE_BOOLEAN);
95
96 $shipping_options = $this->get_shipping_options($shipping_address, $should_show_itemized_view);
97 return wp_send_json($shipping_options);
98 }
99
100 /**
101 * Update shipping method.
102 */
103 public function ajax_update_shipping_method()
104 {
105
106 if (!defined('WOOCOMMERCE_CART')) {
107 define('WOOCOMMERCE_CART', true);
108 }
109
110 $shipping_methods = filter_input(INPUT_POST, 'shipping_method', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
111 $this->update_shipping_method($shipping_methods);
112
113 WC()->cart->calculate_totals();
114
115 $product_view_options = filter_input_array(INPUT_POST, ['is_product_page' => FILTER_SANITIZE_STRING]);
116 $should_show_itemized_view = !isset($product_view_options['is_product_page']) ? true : filter_var($product_view_options['is_product_page'], FILTER_VALIDATE_BOOLEAN);
117
118 $data = [];
119 $data += $this->build_display_items($should_show_itemized_view);
120 $data['result'] = 'success';
121
122 wp_send_json($data);
123 }
124
125 /**
126 * Gets shipping options available for specified shipping address
127 *
128 * @param array $shipping_address Shipping address.
129 * @param boolean $itemized_display_items Indicates whether to show subtotals or itemized views.
130 *
131 * @return array Shipping options data.
132 * phpcs:ignore Squiz.Commenting.FunctionCommentThrowTag
133 */
134 public function get_shipping_options($shipping_address, $itemized_display_items = false)
135 {
136 try {
137 // Set the shipping options.
138 $data = [];
139
140 // Remember current shipping method before resetting.
141 $chosen_shipping_methods = WC()->session->get('chosen_shipping_methods');
142 $this->calculate_shipping($shipping_address);
143
144 $packages = WC()->shipping->get_packages();
145 $shipping_rate_ids = [];
146
147 if (!empty($packages) && WC()->customer->has_calculated_shipping()) {
148 foreach ($packages as $package) {
149 if (empty($package['rates'])) {
150 throw new Exception(__('Unable to find shipping method for address.', 'hyperpay-gateways'));
151 }
152
153 foreach ($package['rates'] as $rate) {
154 if (in_array($rate->id, $shipping_rate_ids, true)) {
155 // The Payment Requests will try to load indefinitely if there are duplicate shipping
156 // option IDs.
157 throw new Exception(__('Unable to provide shipping options for Payment Requests.', 'hyperpay-gateways'));
158 }
159 $shipping_rate_ids[] = $rate->id;
160 $data['shipping_options'][] = [
161 'identifier' => $rate->id,
162 'label' => $rate->label,
163 'detail' => '',
164 'amount' => (float)($rate->cost),
165 ];
166 }
167 }
168 } else {
169 throw new Exception(__('Unable to find shipping method for address.', 'hyperpay-gateways'));
170 }
171
172 // The first shipping option is automatically applied on the client.
173 // Keep chosen shipping method by sorting shipping options if the method still available for new address.
174 // Fallback to the first available shipping method.
175 if (isset($data['shipping_options'][0])) {
176 if (isset($chosen_shipping_methods[0])) {
177 $chosen_method_id = $chosen_shipping_methods[0];
178 $compare_shipping_options = function ($a, $b) use ($chosen_method_id) {
179 if ($a['id'] === $chosen_method_id) {
180 return -1;
181 }
182
183 if ($b['id'] === $chosen_method_id) {
184 return 1;
185 }
186
187 return 0;
188 };
189 usort($data['shipping_options'], $compare_shipping_options);
190 }
191
192 $first_shipping_method_id = $data['shipping_options'][0]['id'];
193 $this->update_shipping_method([$first_shipping_method_id]);
194 }
195
196 WC()->cart->calculate_totals();
197
198 $data += $this->build_display_items($itemized_display_items);
199 $data['result'] = 'success';
200 } catch (Exception $e) {
201 $data += $this->build_display_items($itemized_display_items);
202 $data['result'] = $e->getMessage();
203 }
204
205 return $data;
206 }
207
208
209 /**
210 * Updates shipping method in WC session
211 *
212 * @param array $shipping_methods Array of selected shipping methods ids.
213 */
214 public function update_shipping_method($shipping_methods)
215 {
216 $chosen_shipping_methods = WC()->session->get('chosen_shipping_methods');
217
218 if (is_array($shipping_methods)) {
219 foreach ($shipping_methods as $i => $value) {
220 $chosen_shipping_methods[$i] = wc_clean($value);
221 }
222 }
223
224 WC()->session->set('chosen_shipping_methods', $chosen_shipping_methods);
225 }
226
227 /**
228 * Builds the line items to pass to Payment Request
229 *
230 * @since 3.1.0
231 * @version 4.0.0
232 */
233 protected function build_display_items($itemized_display_items = false)
234 {
235 if (!defined('WOOCOMMERCE_CART')) {
236 define('WOOCOMMERCE_CART', true);
237 }
238
239 $items = [];
240 $lines = [];
241 $subtotal = 0;
242 $discounts = 0;
243 $display_items = !apply_filters('wc_stripe_payment_request_hide_itemization', true) || $itemized_display_items;
244
245 foreach (WC()->cart->get_cart() as $cart_item) {
246 $subtotal += $cart_item['line_subtotal'];
247 $amount = $cart_item['line_subtotal'];
248 $quantity_label = 1 < $cart_item['quantity'] ? ' (x' . $cart_item['quantity'] . ')' : '';
249 $product_name = $cart_item['data']->get_name();
250
251 $lines[] = [
252 'label' => $product_name . $quantity_label,
253 'amount' => (float)($amount),
254 ];
255 }
256
257 if ($display_items) {
258 $items = array_merge($items, $lines);
259 } else {
260 // Default show only subtotal instead of itemization.
261
262 $items[] = [
263 'label' => 'Subtotal',
264 'amount' => (float)($subtotal),
265 ];
266 }
267
268 if (version_compare(WC_VERSION, '3.2', '<')) {
269 $discounts = wc_format_decimal(WC()->cart->get_cart_discount_total(), WC()->cart->dp);
270 } else {
271 $applied_coupons = array_values(WC()->cart->get_coupon_discount_totals());
272
273 foreach ($applied_coupons as $amount) {
274 $discounts += (float) $amount;
275 }
276 }
277
278 $discounts = wc_format_decimal($discounts, WC()->cart->dp);
279 $tax = wc_format_decimal(WC()->cart->tax_total + WC()->cart->shipping_tax_total, WC()->cart->dp);
280 $shipping = wc_format_decimal(WC()->cart->shipping_total, WC()->cart->dp);
281 $items_total = wc_format_decimal(WC()->cart->cart_contents_total, WC()->cart->dp) + $discounts;
282 $order_total = version_compare(WC_VERSION, '3.2', '<') ? wc_format_decimal($items_total + $tax + $shipping - $discounts, WC()->cart->dp) : WC()->cart->get_total(false);
283
284 if (wc_tax_enabled()) {
285 $items[] = [
286 'label' => esc_html(__('Tax', 'hyperpay-gateways')),
287 'amount' => (float)($tax),
288 ];
289 }
290
291 if (WC()->cart->needs_shipping()) {
292 $items[] = [
293 'label' => esc_html(__('Shipping', 'hyperpay-gateways')),
294 'amount' => (float)($shipping),
295 ];
296 }
297
298 if (WC()->cart->has_discount()) {
299 $items[] = [
300 'label' => esc_html(__('Discount', 'hyperpay-gateways')),
301 'amount' => (float)($discounts),
302 ];
303 }
304
305 if (version_compare(WC_VERSION, '3.2', '<')) {
306 $cart_fees = WC()->cart->fees;
307 } else {
308 $cart_fees = WC()->cart->get_fees();
309 }
310
311 // Include fees and taxes as display items.
312 foreach ($cart_fees as $key => $fee) {
313 $items[] = [
314 'label' => $fee->name,
315 'amount' => (float)($fee->amount),
316 ];
317 }
318
319 return [
320 'displayItems' => $items,
321 'total' => [
322 'label' => "By HyperPay",
323 'amount' => max(0, apply_filters('woocommerce_stripe_calculated_total', (float)($order_total), $order_total, WC()->cart)),
324 'pending' => false,
325 ],
326 ];
327 }
328
329
330
331 /**
332 * Calculate and set shipping method.
333 *
334 * @param array $address Shipping address.
335 *
336 * @since 3.1.0
337 * @version 5.0.0
338 */
339 protected function calculate_shipping($address = [])
340 {
341 $country = $address['country'];
342 $state = $address['state'];
343 $postcode = $address['postcode'];
344 $city = $address['city'];
345 $address_1 = $address['address'];
346 $address_2 = $address['address_2'];
347
348 // Normalizes state to calculate shipping zones.
349
350 // Normalizes postal code in case of redacted data from Apple Pay.
351
352 WC()->shipping->reset_shipping();
353
354 if ($postcode && WC_Validation::is_postcode($postcode, $country)) {
355 $postcode = wc_format_postcode($postcode, $country);
356 }
357
358 if ($country) {
359 WC()->customer->set_location($country, $state, $postcode, $city);
360 WC()->customer->set_shipping_location($country, $state, $postcode, $city);
361 } else {
362 WC()->customer->set_billing_address_to_base();
363 WC()->customer->set_shipping_address_to_base();
364 }
365
366 WC()->customer->set_calculated_shipping(true);
367 WC()->customer->save();
368
369 $packages = [];
370
371 $packages[0]['contents'] = WC()->cart->get_cart();
372 $packages[0]['contents_cost'] = 0;
373 $packages[0]['applied_coupons'] = WC()->cart->applied_coupons;
374 $packages[0]['user']['ID'] = get_current_user_id();
375 $packages[0]['destination']['country'] = $country;
376 $packages[0]['destination']['state'] = $state;
377 $packages[0]['destination']['postcode'] = $postcode;
378 $packages[0]['destination']['city'] = $city;
379 $packages[0]['destination']['address'] = $address_1;
380 $packages[0]['destination']['address_2'] = $address_2;
381
382 foreach (WC()->cart->get_cart() as $item) {
383 if ($item['data']->needs_shipping()) {
384 if (isset($item['line_total'])) {
385 $packages[0]['contents_cost'] += $item['line_total'];
386 }
387 }
388 }
389
390 $packages = apply_filters('woocommerce_cart_shipping_packages', $packages);
391
392 WC()->shipping->calculate_shipping($packages);
393 }
394
395 /**
396 * Create order. Security is handled by WC.
397 *
398 * @since 3.1.0
399 * @version 5.1.0
400 */
401 public function process_checkout()
402 {
403 if (WC()->cart->is_empty()) {
404 wp_send_json_error(__('Empty cart', 'hyperpay-gateways'));
405 }
406
407 if (!isset($_POST['checkoutId'])) {
408 wp_send_json_error(__('invalid checkoutId', 'hyperpay-gateways'));
409 }
410
411 if (!defined('WOOCOMMERCE_CHECKOUT')) {
412 define('WOOCOMMERCE_CHECKOUT', true);
413 }
414
415
416 $this->legacy = false;
417
418 WC()->checkout()->process_checkout();
419
420 die(0);
421 }
422
423
424 public function process_payment($order_id)
425 {
426 // that mean the request comes from checkout blocks
427 if (isset($_POST['checkoutId'])) {
428
429 $checkoutId = sanitize_text_field($_POST['checkoutId']);
430 $url = $this->token_url . "/$checkoutId";
431
432
433 $checkout = $this->getCheckoutData($order_id);
434 $checkout['data']['body']['shopperResultUrl'] = $checkout['postBackURL'];
435
436 // HTTP Request to oppwa to get checkout
437 $response = Http::post($url, $checkout['data']);
438
439 if (!\preg_match("/^(000\.200)/", $response['result']['code'] ?? '')) {
440 return wp_send_json_error($response['result']['description'] ?? 'unable to update checkout');
441 }
442
443 return wp_send_json(["result" => "SUCCESS"]);
444 }
445
446 // legacy checkout
447 return parent::process_payment($order_id);
448 }
449 }
450