'Card', 'plain' => 'Plain' ]; public function boot() {} public function __construct() { $this->init_settings(); // <== to get saved settings from database $this->init_form_fields(); // <== render form inside admin panel $this->is_arabic = substr(get_locale(), 0, 2) == 'ar'; // <== to get current locale $this->testMode = $this->get_option('testmode'); // <== check if payments on test mode $this->title = $this->get_option('title'); // <== get title from setting $this->trans_type = $this->get_option('trans_type'); // <== get transaction type [DB / Pre-Auth] from setting $this->accessToken = $this->get_option('accesstoken'); // <== get access toke from setting $this->entityId = $this->getEntity(); // <== get entityId from setting $this->brands = is_array($this->get_option('hyper_pay_brands')) ? $this->get_option('hyper_pay_brands') : [$this->get_option('hyper_pay_brands')]; // <== get brands from setting $this->payment_style = $this->get_option('payment_style'); // <== get style from setting $this->order_status = $this->get_option('order_status'); // <== get order status after success from setting $this->custom_style = $this->get_option('custom_style'); // <== get custom style from setting $this->description = __('All transactions are processed in a secure environment.', 'hyperpay-gateways'); $this->latin_validation = $this->get_option('latin_validation'); // <== get custom style from setting $this->currency = get_woocommerce_currency(); $this->NONCE = \md5(wp_rand(1111111111, 9999999999)); /** * if test mode is one * overwrite currents URLs ti test URLs */ if ($this->testMode) { $this->query_url = "https://eu-test.oppwa.com/v1/query"; $this->token_url = "https://eu-test.oppwa.com/v1/checkouts"; $this->script_url = "https://eu-test.oppwa.com/v1/paymentWidgets.js?checkoutId="; $this->transaction_status_url = "https://eu-test.oppwa.com/v1/checkouts/##TOKEN##/payment"; $this->server_to_server_url = "https://eu-test.oppwa.com/v1/payments"; $this->ACI_base_url = "https://eu-test.oppwa.com"; } $this->query_url .= "?entityId=" . $this->entityId; $this->transaction_status_url .= "?entityId=" . $this->entityId; /** * default failed message * @var string */ $this->failed_message = __('Your transaction not completed .', 'hyperpay-gateways'); $this->success_message = __('Your payment has been processed successfully.', 'hyperpay-gateways'); /** * overwrite default update function * * @param woocommerce_update_options_payment_gateways_ * @param array[class,function_name] */ if (!has_action("woocommerce_update_options_payment_gateways_{$this->id}")) { add_action('woocommerce_update_options_payment_gateways_' . $this->id, array($this, 'process_admin_options')); } /** * prepare checkout form * * @param string woocommerce_receipt_ * @param array[class,function_name] */ if (!has_action("woocommerce_receipt_{$this->id}")) { add_action("woocommerce_receipt_{$this->id}", [$this, 'receipt_page']); } /** * set payments icon from src/assets/images/BRAND-log.png * * make sure when add new image to rename image according this format BRAND_NAME-logo.svg * * @param string woocommerce_gateway_icon * @param array[class,function_name] * */ add_filter('woocommerce_gateway_icon', [$this, 'set_icons'], 10, 2); /** * to include src/assets/js/admin.js * * @param string admin_enqueue_scripts * @param array[class,function_name] * */ add_action('admin_enqueue_scripts', [$this, 'admin_script']); add_action("woocommerce_thankyou_order_received_text", [$this, "order_received_text"], 10, 2); add_action('before_woocommerce_pay', [$this, 'action_before_woocommerce_pay'], 10, 0); if (!has_action("woocommerce_order_action_capture_payment")) { add_action('woocommerce_order_action_capture_payment', [$this, 'capture_payment']); } $this->boot(); $this->bootTraits(); } /** * Automatically calls all protected bootTraitName() methods from used traits. */ protected function bootTraits(): void { $traits = class_uses($this, false); // false = don't autoload, if not needed foreach ($traits as $fullyQualifiedTraitName) { // Extract the short name of the trait $parts = explode('\\', $fullyQualifiedTraitName); $traitName = end($parts); // Construct the expected method name $bootMethod = 'boot' . $traitName; if (method_exists($this, $bootMethod)) { $this->$bootMethod(); } } } public function getEntity() { $available_currencies = $this->get_option('currencies_ids'); $current_currency = get_woocommerce_currency(); if (isset($available_currencies[$current_currency])) { return $available_currencies[$current_currency]; } return $this->get_option('entityId'); } public function process_admin_options() { $this->init_settings(); $post_data = $this->get_post_data(); foreach ($this->get_form_fields() as $key => $field) { if ('title' !== $this->get_field_type($field)) { try { $this->settings[$key] = $this->get_field_value($key, $field, $post_data); if ('select' === $field['type'] || 'checkbox' === $field['type']) { /** * Notify that a non-option setting has been updated. * * @since 7.8.0 */ do_action( 'woocommerce_update_non_option_setting', array( 'id' => $key, 'type' => $field['type'], 'value' => $this->settings[$key], ) ); } elseif ('currencies_ids_field' === $key && isset($post_data['currencies_ids'])) { $this->settings["currencies_ids"] = array_reduce($post_data['currencies_ids'], function ($result, $item) { if ($item['value'] && $item['name']) $result[$item['name']] = $item['value']; return $result; }, array()); } } catch (Exception $e) { $this->add_error($e->getMessage()); } } } $option_key = $this->get_option_key(); do_action('woocommerce_update_option', array('id' => $option_key)); // phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment return update_option($option_key, apply_filters('woocommerce_settings_api_sanitized_fields_' . $this->id, $this->settings), 'yes'); // phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment } public function capture_payment($order) { $orderAmount = number_format($order->get_total(), 2, '.', ''); $amount = number_format(round($orderAmount, 2), 2, '.', ''); $gateways = WC()->payment_gateways->payment_gateways(); $gateway = null; foreach ($gateways as $wc_gateway) { if ($wc_gateway->id == $order->get_payment_method()) { $gateway = $wc_gateway; break; } } if ($gateway) { $uniqueId = $order->get_meta('transaction_id'); $url = $gateway->server_to_server_url . "/$uniqueId"; $data = $gateway->getBasicData(); $data['body'] = \array_merge($data['body'], [ "amount" => $amount, "currency" => $gateway->currency, "paymentType" => 'CP' ]); $response = Http::post($url, $data); $resultCode = $response['result']['code'] ?? ''; if (preg_match($gateway->successCodePattern, $resultCode) || preg_match($gateway->successManualReviewCodePattern, $resultCode)) { $order->add_order_note("Captured Successfully"); $order->update_status($gateway->order_status); } else { $order->add_order_note("Captured Failed " . $response['result']['description'] ?? 'Unknown reason'); } } else { $order->add_order_note("Captured Failed No gateway found"); } // Safely check and unslash HTTP_REFERER $location = isset($_SERVER['HTTP_REFERER']) ? sanitize_url(wp_unslash($_SERVER['HTTP_REFERER'])) : home_url(); wp_safe_redirect($location); exit(); } public function auto_revisal($id) { $url = $this->server_to_server_url . "/$id"; $data = $this->getBasicData(); $data['body'] = \array_merge($data['body'], [ "amount" => TokenManager::TOKENIZATION_AMOUNT, "currency" => $this->currency, "paymentType" => 'RV' ]); $response = Http::post($url, $data); $resultCode = $response['result']['code'] ?? ''; if (preg_match($this->successCodePattern, $resultCode) || preg_match($this->successManualReviewCodePattern, $resultCode)) { return [ 'status' => 'success', 'message' => "Auto-Reversal Successfully" ]; } return [ 'status' => 'failed', 'message' => "Auto-Reversal Failed . " . ($response['result']['description'] ?? 'Unknown reason') ]; } public function action_before_woocommerce_pay() { global $wp; $order_id = absint($wp->query_vars['order-pay']); // The order ID $order = wc_get_order($order_id); if ($order->has_status('on-hold')) { $order->update_status('pending'); } elseif ($order->has_status($this->order_status)) { wp_safe_redirect($this->get_return_url($order)); exit(); } } public function order_received_text($thanks_text, $order) { $msg = $order->get_meta('gateway_note'); if ($order->get_payment_method() == $this->id && $order->get_status() == 'on-hold' && !empty($msg)) { wc_add_notice($msg, "notice"); wc_print_notices(); } else { return $thanks_text; } } /** * for validate settings form * @return void */ public function admin_script(): void { global $current_tab, $current_section; /** * to make sure load admin.js just when currents payments opened * */ if ($current_tab == 'checkout' && $current_section == $this->id) { $data = [ 'id' => $this->id, 'url' => $this->token_url, 'code_setting' => wp_enqueue_code_editor(['type' => 'text/css']) ]; wp_enqueue_script('hyperpay_admin', HYPERPAY_PLUGIN_DIR . '/src/assets/js/admin.js', ['jquery'], '1.0.0', true); wp_localize_script('hyperpay_admin', 'hyperpay_data', $data); } } public function iconSrc() { $icons = []; foreach ($this->brands as $brand) { $img = HYPERPAY_PLUGIN_DIR . '/src/assets/images/default.png'; if (file_exists(Main::ROOT_PATH . '/assets/images/' . esc_attr($brand) . "-logo.svg")) $img = HYPERPAY_PLUGIN_DIR . '/src/assets/images/' . esc_attr($brand) . "-logo.svg"; $icons[] = $img; } return $icons; } /** * to set payment icon based on supported brands * * @param string $icon * @param string $id current payment id * * @return string $icon new icon * */ public function set_icons($icon, $id) { if ($id == $this->id) { $icons = ""; foreach ($this->iconSrc() as $src) { $icons .= ""; } return $icons; } return $icon; } /** * Here you can define all fields thats will showing in setting page * @return void */ public function init_form_fields(): void { $this->form_fields = [ 'enabled' => [ 'title' => __('Enable/Disable', 'hyperpay-gateways'), 'type' => 'checkbox', 'label' => __('Enable Payment Module.', 'hyperpay-gateways'), 'default' => 'no' ], 'testmode' => [ 'title' => __('Test mode', 'hyperpay-gateways'), 'type' => 'select', 'options' => ['0' => __('Off', 'hyperpay-gateways'), '1' => __('On', 'hyperpay-gateways')] ], 'title' => [ 'title' => __('Title:', 'hyperpay-gateways'), 'type' => 'text', 'description' => __('This controls the title which the user sees during checkout.', 'hyperpay-gateways'), 'default' => $this->method_title ?? __('Credit Card', 'hyperpay-gateways') ], 'trans_type' => [ 'title' => __('Transaction type', 'hyperpay-gateways'), 'type' => 'select', 'options' => $this->get_hyperpay_trans_type(), ], 'accesstoken' => [ 'title' => __('Access Token', 'hyperpay-gateways'), 'type' => 'text', ], 'entityId' => [ 'title' => __('Entity ID', 'hyperpay-gateways'), 'type' => 'text', 'description' => __('This will used as default if multi-currency not configured', 'hyperpay-gateways'), ], 'currencies_ids_field' => [ 'custom_attributes' => [ 'data-currencies' => $this->get_option("currencies_ids") ? json_encode($this->get_option("currencies_ids")) : null, 'data-currencies_list' => json_encode(array_keys(get_woocommerce_currencies())) ], 'title' => __('Multi-currency', 'hyperpay-gateways'), 'type' => 'hidden', 'description' => __('In case you have a multi-currency store', 'hyperpay-gateways'), ], 'secret' => [ 'title' => __('Webhook Key', 'hyperpay-gateways'), 'type' => 'text', ], '_webhock' => [ 'title' => __('Webhook URL', 'hyperpay-gateways'), 'type' => 'text', 'class' => 'disabled', 'default' => get_site_url() . "/?rest_route=/hyperpay/v1/" . \str_replace("\\", "/", get_class($this)) ], 'hyper_pay_brands' => [ 'title' => __('Brands', 'hyperpay-gateways'), 'class' => count($this->supported_brands) !== 1 ?: 'disabled', 'type' => count($this->supported_brands) > 1 ? 'multiselect' : 'select', 'options' => $this->supported_brands, ], 'payment_style' => [ 'title' => __('Payment Style', 'hyperpay-gateways'), 'type' => 'select', 'class' => count($this->payment_style) !== 1 ?: 'disabled', 'options' => $this->payment_style, 'default' => 'plain' ], 'custom_style' => [ 'title' => __('Custom Style', 'hyperpay-gateways'), 'type' => 'textarea', 'description' => 'Input custom css for payment (Optional)', 'class' => 'hyperpay_custom_style' ], 'latin_validation' => [ 'title' => __('Enable Input validation (Accept English Characters only)', 'hyperpay-gateways'), 'type' => 'checkbox', 'label' => __('Yes', 'hyperpay-gateways'), 'default' => 'yes', 'description' => __('Disable this option may cause transaction declined by bank due to 3DSecure', 'hyperpay-gateways'), ], 'order_status' => [ 'title' => __('Status Of Order', 'hyperpay-gateways'), 'type' => 'select', 'options' => $this->get_order_status(), 'description' => __("select order status after success transaction.", 'hyperpay-gateways') ], ]; } /** * to fill order_status select fields * * @return array */ function get_order_status(): array { $order_status = [ 'processing' => __('Processing', 'hyperpay-gateways'), 'completed' => __('Completed', 'hyperpay-gateways') ]; return $order_status; } /** * to fill trans_type select fields * * @return array */ function get_hyperpay_trans_type(): array { $hyperpay_trans_type = [ 'DB' => 'Debit', 'PA' => 'Pre-Authorization' ]; return $hyperpay_trans_type; } /** * This function fire when click on Place order at checkout page * @param int $order_id * * @return void */ function receipt_page($order_id) { $order = new WC_Order($order_id); // if we have id param that mean the page result ACI redirection if (isset($_GET['resourcePath'])) { // Verify nonce for security (Recommended) if (!isset($_GET['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_GET['nonce'])), 'hyperpay_receipt_nonce')) { //TODO: } $resourcePath = sanitize_text_field(wp_unslash($_GET['resourcePath'])); $url = $this->ACI_base_url . $resourcePath; // set header request to contain access token $auth = $this->getAuthData(); $response = Http::get($url, $auth); //Dynamic fire function based on status $status = $this->check_status($response); return $this->$status($order, $response); } elseif ($result = $this->prepareCheckout($order_id)) { // process a new transaction return $this->renderPaymentForm($order, $result); } } private function isJson($string) { json_decode($string); return json_last_error() === JSON_ERROR_NONE; } /** * * render CopyAndPay form * @param WC_Order $order * @param string $token * @return void */ public function renderPaymentForm(WC_Order $order, $result) { if ($this->server_to_server) { $redirect = $result['response']['redirect']; $extra_params = []; $query_url = wp_parse_url($redirect['url'], PHP_URL_QUERY); if ($query_url) parse_str(wp_parse_url($redirect['url'], PHP_URL_QUERY), $extra_params); return View::render('server-to-server.html', \compact('redirect', 'extra_params')); } $token = $result['response']['id']; $postBackURL = $result['postBackURL']; $payment_brands = $this->brands; if (is_array($this->brands)) $payment_brands = implode(' ', $this->brands); $dataObj = [ 'is_arabic' => esc_js($this->is_arabic), 'style' => esc_html($this->payment_style), 'postBackURL' => ($postBackURL), 'payment_brands' => esc_html($payment_brands), 'custom_style' => esc_html($this->custom_style), 'scriptURL' => esc_html($this->script_url), 'checkoutId' => $token, 'integrity' => esc_html($result['integrity'] ?? ''), 'is_subscription' => SubscriptionsManager::orderContainsSubscription($order) ? 'yes' : 'no', 'orderId' => $order->id, 'hyperpay_update_nonce' => wp_create_nonce('hyperpay_update_checkout'), 'hyperpay_process_checkout_nonce' => wp_create_nonce('hyperpay_process_checkout'), 'nonce' => $this->NONCE, 'id' => $this->id ]; if ($this->supported_network) { $dataObj['supported_network'] = $this->supported_network; } add_action('wp_head', [$this, 'custom_add_to_head']); $scriptSrc = in_array('tokenization', $this->supports, true) ? "script.js" : "script_no_tokenization.js"; return View::render('copy-and-pay.html', compact('dataObj', 'scriptSrc')); } public function custom_add_to_head() { $data = [ 'url' => $this->ACI_base_url, 'home' => get_home_url(), 'nonce' => $this->NONCE ]; return View::render('header.html', \compact('data')); } /** * Process the payment and return the result * @param int $order_id * @return array[redirect,token,result] * */ public function process_payment($order_id) { $order = new WC_Order($order_id); /** * * validate data to prevent arabic character */ if ($this->latin_validation == 'yes') { $firstName = $order->get_billing_first_name(); $family = $order->get_billing_last_name(); $street = $order->get_billing_address_1(); $city = $order->get_billing_city(); $email = $order->get_billing_email(); $data_to_validate = [ 'first name' => $firstName, 'last name' => $family, 'street' => $street, 'city' => $city, 'email' => $email, ]; if ($order->get_billing_state()) { $data_to_validate['state'] = $order->get_billing_state(); } // raise a validation error if validation valid $this->validate_form($data_to_validate); } return [ 'result' => 'success', 'redirect' => $order->get_checkout_payment_url(true) ]; } protected function getAuthData() { return [ 'headers' => ["Authorization" => "Bearer {$this->accessToken}"], "body" => ["entityId" => $this->entityId] ]; } protected function getBasicData() { $data = $this->getAuthData(); if ($this->testMode) { $data['body']["testMode"] = $this->trans_mode; $data['body']["customParameters[3DS2_enrolled]"] = "true"; $data['body']["customParameters[3DS2_flow]"] = 'challenge'; } return $data; } protected function buildCheckoutParams(WC_Order $order) { $shipping_cost = number_format($order->get_shipping_total(), 2, '.', ''); $amount = number_format($order->get_total(), 2, '.', ''); $basicData = $this->getBasicData(); $data = [ "amount" => $amount, "currency" => $this->currency, "paymentType" => $this->trans_type, "customer.email" => $order->get_billing_email(), "notificationUrl" => $order->get_checkout_payment_url(true), "customParameters[bill_number]" => $order->get_id(), "customer.givenName" => $order->get_billing_first_name(), "customer.surname" => $order->get_billing_last_name(), "billing.street1" => $order->get_billing_address_1(), "billing.city" => $order->get_billing_city(), "billing.state" => $order->get_billing_state(), "billing.country" => $order->get_billing_country(), "billing.postcode" => $order->get_billing_postcode(), "shipping.postcode" => $order->get_billing_postcode(), "shipping.street1" => $order->get_billing_address_1(), "shipping.city" => $order->get_billing_city(), "shipping.state" => $order->get_billing_state(), "shipping.country" => $order->get_billing_country(), "shipping.cost" => $shipping_cost, "customParameters[branch_id]" => '1', "customParameters[teller_id]" => '1', "customParameters[device_id]" => '1', "customParameters[plugin]" => 'wordpress', "locale" => get_locale(), ]; $basicData['body'] = \array_merge($basicData['body'], $data); return $basicData; } public function getCheckoutData($order_id) { $order = new WC_Order($order_id); $data = $this->buildCheckoutParams($order); $transactionKey = wp_rand(11111111, 99999999); $postBackURL = $order->get_checkout_payment_url(true); $postBackURL .= wp_parse_url($postBackURL, PHP_URL_QUERY) ? '&' : '?'; $postBackURL .= 'callback=true'; $postBackURL .= "&transaction-key=$transactionKey"; $data['body']["merchantTransactionId"] = $order_id . "I" . $transactionKey; if ($this->server_to_server) { $data['body']['shopperResultUrl'] = $postBackURL; $data['body']['paymentBrand'] = $this->brands[0]; } else { $data['body']['integrity'] = true; } // charge 0.00 orders with 0.01 to prevent declined transactions if ($order->get_total() == '0.00') { $data['body']['amount'] = TokenManager::TOKENIZATION_AMOUNT; $data['body']['customParameters[auto_revisal]'] = 'true'; } // add extra parameters if exists return [ "data" => array_replace_recursive($data, $this->setExtraData($order)), "postBackURL" => $postBackURL ]; } public function prepareCheckout($order_id) { $url = $this->server_to_server ? $this->server_to_server_url : $this->token_url; $checkout = $this->getCheckoutData($order_id); $response = Http::post($url, $checkout['data']); $code = $response['result']['code'] ?? ''; $isValid = $this->server_to_server ? preg_match('/^(800\.400\.5|100\.400\.500)/', $code) : preg_match('/^(000\.200)/', $code); if (!$isValid) { $this->handleError($response); return false; } return [ 'response' => $response, 'postBackURL' => $checkout['postBackURL'], ]; } /** * check if all data valid to post {English Characters} * @param array * @return void */ function validate_form(array $data) { $errors = []; $translations = [ 'first name' => esc_html__('First Name', 'hyperpay-gateways'), 'last name' => esc_html__('Last Name', 'hyperpay-gateways'), 'street' => esc_html__('Street', 'hyperpay-gateways'), 'state' => esc_html__('State', 'hyperpay-gateways'), 'city' => esc_html__('City', 'hyperpay-gateways'), 'email' => esc_html__('Email', 'hyperpay-gateways'), ]; foreach ($data as $key => $field) { if (!preg_match("/^[a-zA-Z0-9-._!`'#%&,:;<>=@{}~\$\(\)\*\+\/\\\?\[\]\^\| +]+$/", $field) || strlen($field) < 2) $errors[$key] = ($translations[$key] ?? esc_html__('Unknown status', 'hyperpay-gateways')) . ' ' . __('format error', 'hyperpay-gateways'); } if (!preg_match('/^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,})$/i', $data['email'])) { $errors['email'] = __('Email format not valid', 'hyperpay-gateways'); } foreach ($errors as $msg) { if (self::has_checkout_block()) { throw new Exception(esc_html($msg)); } else { wc_add_notice('' . $msg . '', 'error'); } } // count equal to zero then no errors and it's valid return count($errors); } /** * * GET request to transaction report to check if transaction exists or not * @param int * @return array $response * */ public function queryTransactionReport(string $merchantTrxId): array { $url = $this->query_url . "&merchantTransactionId=$merchantTrxId"; return Http::get($url, ["headers" => ["Authorization" => "Bearer {$this->accessToken}"]]); } /** * * check the status * * @param array $resultJson * @return string */ public function check_status(array $resultJson): string { $status = 'failed'; $resultCode = $resultJson['result']['code'] ?? ''; if (preg_match($this->successCodePattern, $resultCode) || preg_match($this->successManualReviewCodePattern, $resultCode)) { $status = 'success'; } elseif (preg_match($this->pendingCodePattern, $resultCode)) { $status = "pending"; } elseif (isset($resultJson['card']['bin']) && $resultJson['result']['code'] == '800.300.401' && in_array($resultJson['card']['bin'], $this->blackBins)) { $this->failed_message = __('Sorry! Please select "mada" payment option in order to be able to complete your purchase successfully.', 'hyperpay-gateways'); } return $status; } /** * handel failed Payments * @param WC_Order $order * @param string $message * @return void */ public function failed(WC_Order $order, $resultJson) { if (isset($_GET["callback"]) && isset($_GET['transaction-key'])) { // Verify nonce for security (Recommended) if (!isset($_GET['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_GET['nonce'])), 'hyperpay_transaction_nonce')) { //TODO: } $hpOrderId = $order->get_id(); $transactionKey = sanitize_text_field(wp_unslash($_GET['transaction-key'])); $merchantTrxId = $hpOrderId . "I" . $transactionKey; $queryResponse = $this->queryTransactionReport($merchantTrxId); if (array_key_exists("payments", $queryResponse)) { return $this->processQueryResult($queryResponse, $order); } } return $this->handleError($resultJson); } public function handleError($resultJson) { $order = wc_get_order(wc_clean(get_query_var('order-pay'))); $error_code = $resultJson["result"]["code"]; $error_description = $resultJson["result"]["description"]; $aci_msg = $error_description; $error_list = []; if ($error_code == "600.200.500") { $aci_msg = "configuration error"; Log::write(["error" => $error_description, "response" => $resultJson]); } $order->add_order_note("{$this->failed_message} $error_code : $error_description"); $error_list = $this->getExtended($resultJson); if (empty($error_list)) { wc_add_notice($this->failed_message, "error"); wc_add_notice($aci_msg, "error"); } $flat_errors = []; array_walk_recursive($error_list, function ($item, $key) use (&$flat_errors) { if ($key === 'error') { $flat_errors[] = $item; } }); foreach ($flat_errors as $error_message) { wc_add_notice($error_message, "error"); $order->add_order_note("extended description : " . $error_message); } $order->update_status("failed"); wc_print_notices(); } public function getExtended($resultJson) { $error_list = []; if (isset($resultJson["resultDetails"]["ExtendedDescription"])) { $resultDetails = $resultJson["resultDetails"]["ExtendedDescription"]; if ($this->isJson($resultDetails)) { $resultDetails = json_decode($resultDetails, true); if (array_key_exists("details", $resultDetails)) { $error_list[] = $resultDetails["details"]; } elseif (array_key_exists("message", $resultDetails)) { $error_list[] = ["error" => $resultDetails['message']]; } } } return $error_list; } /** * check the result of transaction if success of failed * * @param array $resultJson * @param WC_Order $order * @return void */ public function processQueryResult(array $resultJson, WC_Order $order) { unset($_GET["callback"]); $payment = end($resultJson["payments"]); // get the last transaction if (isset($payment["result"]["code"])) { $status = $this->check_status($payment); return $this->$status($order, $payment); } } /** * set customParameters of requested data * @param WC_Order $order * @return array */ public function setExtraData(WC_Order $order): array { return []; } /** * update success order * @param WC_Order $order * @param array $resultJson * @return void */ public function success(WC_Order $order, $resultJson) { global $woocommerce; $woocommerce->cart->empty_cart(); $uniqueId = $resultJson["id"]; //to add action in order details to capture the pre authorization payments if (array_key_exists('paymentType', $resultJson) && $resultJson['paymentType'] == "PA") { $order->add_meta_data("is_pre_authorization", true); $order->add_meta_data("transaction_id", $uniqueId); $order->add_order_note("pre authorization transaction, need to capture"); $this->order_status = "on-hold"; } if (array_key_exists("invoice_id", $resultJson["resultDetails"] ?? [])) { $this->invoice_id = $resultJson["resultDetails"]["invoice_id"]; $order->add_meta_data("invoice_id", $this->invoice_id); $order->add_order_note("invoice id : " . $this->invoice_id); } $order->add_order_note($this->success_message . __("Transaction ID: ", "hyperpay-gateways") . esc_html($uniqueId)); $order->update_status($this->order_status); $order->payment_complete($uniqueId); $order->save(); // preform auto-revisal if (($resultJson['customParameters']['auto_revisal'] ?? null) == 'true') { $revisal_status = $this->auto_revisal($uniqueId); $order->add_order_note($revisal_status['message']); } do_action('hyperpay_payment_success_' . $this->id, $order, $resultJson); wp_safe_redirect($this->get_return_url($order)); exit(); } /** * update pending order * @param WC_Order $order * @param array $resultJson * @return void */ public function pending(WC_Order $order, $resultJson) { global $woocommerce; $order->update_status("on-hold"); $order->add_meta_data("gateway_note", __("Transaction is pending confirmation from ", "hyperpay-gateways") . str_replace("hyperpay_", "", $order->get_payment_method())); $order->save(); $woocommerce->cart->empty_cart(); $uniqueId = $resultJson["id"]; $order->add_order_note("the order waiting gateway confirmation" . __("Transaction ID: ", "hyperpay-gateways") . esc_html($uniqueId)); wp_safe_redirect($this->get_return_url($order)); exit(); } protected function is_successful_response($response) { $result_code = $response['result']['code'] ?? ''; return preg_match($this->successCodePattern, $result_code); } }