From 0e039c3393a6c9b548abfc03cb85d135018786fe Mon Sep 17 00:00:00 2001 From: Vrishab Srivatsa Date: Tue, 12 Mar 2024 19:03:47 +0530 Subject: [PATCH 1/6] Checkout blocks compatibility --- hyperswitch-checkout.php | 39 +++++++++++++------ includes/hyperswitch-wc-blocks-support.php | 45 ++++++++++++++++++++++ js/hyperswitch-checkout-blocks.js | 39 +++++++++++++++++++ 3 files changed, 111 insertions(+), 12 deletions(-) create mode 100644 includes/hyperswitch-wc-blocks-support.php create mode 100644 js/hyperswitch-checkout-blocks.js diff --git a/hyperswitch-checkout.php b/hyperswitch-checkout.php index ebdd1ab..103d580 100644 --- a/hyperswitch-checkout.php +++ b/hyperswitch-checkout.php @@ -5,7 +5,7 @@ * Description: Hyperswitch checkout plugin for WooCommerce * Author: Hyperswitch * Author URI: https://hyperswitch.io/ - * Version: 1.5.0 + * Version: 1.6.0 * License: GPLv2 or later * * WC requires at least: 4.0.0 @@ -32,7 +32,7 @@ exit; // Exit if accessed directly } -define('HYPERSWITCH_CHECKOUT_PLUGIN_VERSION', '1.5.0'); +define('HYPERSWITCH_CHECKOUT_PLUGIN_VERSION', '1.6.0'); define('HYPERSWITCH_PLUGIN_URL', untrailingslashit(plugins_url(basename(plugin_dir_path(__FILE__)), basename(__FILE__)))); require_once __DIR__ . '/includes/hyperswitch-webhook.php'; @@ -42,6 +42,7 @@ add_action('wp_ajax_nopriv_hyperswitch_create_or_update_payment_intent', 'hyperswitch_create_or_update_payment_intent', 5); add_action('wp_ajax_hyperswitch_create_or_update_payment_intent', 'hyperswitch_create_or_update_payment_intent', 5); add_action('before_woocommerce_init', 'hyperswitch_declare_compatibility', 5); +add_action('woocommerce_blocks_loaded', 'woocommerce_gateway_hyperswitch_woocommerce_block_support'); function hyperswitch_init_payment_class() { @@ -114,7 +115,7 @@ public function __construct() wp_register_script( 'hyperswitch-hyperservice', - plugins_url('/js/hyperswitch-hyperservice.js', __FILE__), + HYPERSWITCH_PLUGIN_URL . '/js/hyperswitch-hyperservice.js', array('hyperswitch-hyperloader'), 'HYPERSWITCH_CHECKOUT_PLUGIN_VERSION' ); @@ -391,9 +392,9 @@ public function init_form_fields() ); } - function receipt_page($payment_id) + function receipt_page($order_id) { - $payment_intent = $this->create_payment_intent($payment_id); + $payment_intent = $this->create_payment_intent($order_id); if (isset($payment_intent['clientSecret']) && isset($payment_intent['paymentId'])) { $client_secret = $payment_intent['clientSecret']; $payment_id = $payment_intent['paymentId']; @@ -411,8 +412,8 @@ function receipt_page($payment_id) ; } else { global $woocommerce; - $order = new WC_Order($payment_id); - $error = $payment_intent['body']; + $order = new WC_Order($order_id); + $error = $payment_intent['error']; $order->add_order_note(__('Unable to Create Hyperswitch Payment Intent.', 'hyperswitch-checkout')); $order->add_order_note('Error: ' . $error); $this->post_log("WC_FAILED_TO_CREATE_PAYMENT_INTENT", $error); @@ -453,7 +454,7 @@ function render_payment_sheet($order_id, $client_secret = null) } else { global $woocommerce; $order = new WC_Order($order_id); - $error = $payment_intent['body']; + $error = $payment_intent['error']; $order->add_order_note(__('Unable to Create Hyperswitch Payment Intent.', 'hyperswitch-checkout')); $order->add_order_note('Error: ' . $error); $this->post_log("WC_FAILED_TO_CREATE_PAYMENT_INTENT", $error); @@ -819,10 +820,10 @@ public function create_refund($payment_id, $amount, $reason, $refund_num, $order **/ function process_payment($payment_id) { - $nonce = $_POST['woocommerce-process-checkout-nonce']; - if (!wp_verify_nonce($nonce, 'woocommerce-process_checkout')) { - return array('result' => 'failure', 'nonce' => 'failed'); - } + // $nonce = $_POST['woocommerce-process-checkout-nonce']; + // if (!wp_verify_nonce($nonce, 'woocommerce-process_checkout')) { + // return array('result' => 'failure', 'nonce' => 'failed'); + // } $order = new WC_Order($payment_id); return array('result' => 'success', 'redirect' => $order->get_checkout_payment_url(true)); } @@ -959,5 +960,19 @@ function hyperswitch_declare_compatibility() { if (class_exists('\Automattic\WooCommerce\Utilities\FeaturesUtil')) { \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility('custom_order_tables', __FILE__, true); + \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility('cart_checkout_blocks', __FILE__, true); + } +} +function woocommerce_gateway_hyperswitch_woocommerce_block_support() +{ + if (class_exists('Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType')) { + require_once __DIR__ . '/includes/hyperswitch-wc-blocks-support.php'; + add_action( + 'woocommerce_blocks_payment_method_type_registration', + function (Automattic\WooCommerce\Blocks\Payments\PaymentMethodRegistry $payment_method_registry) { + $payment_method_registry->register(new Hyperswitch_Checkout_Blocks); + }, + 5 + ); } } \ No newline at end of file diff --git a/includes/hyperswitch-wc-blocks-support.php b/includes/hyperswitch-wc-blocks-support.php new file mode 100644 index 0000000..93946f7 --- /dev/null +++ b/includes/hyperswitch-wc-blocks-support.php @@ -0,0 +1,45 @@ +settings = get_option('woocommerce_hyperswitch_checkout_settings', []); + $this->gateway = new Hyperswitch_Checkout(); + } + + public function is_active() + { + return !empty($this->settings['enabled']) && 'yes' === $this->settings['enabled']; + } + + public function get_payment_method_script_handles() + { + wp_register_script( + 'hyperswitch_checkout-blocks-integration', + HYPERSWITCH_PLUGIN_URL . '/js/hyperswitch-checkout-blocks.js', + ['wc-blocks-registry', 'wc-settings', 'wp-element', 'wp-html-entities', 'wp-i18n'], + 'HYPERSWITCH_CHECKOUT_PLUGIN_VERSION', + true + ); + + if (function_exists('wp_set_script_translations')) { + wp_set_script_translations('hyperswitch_checkout-blocks-integration'); + } + + return ['hyperswitch_checkout-blocks-integration']; + } + + public function get_payment_method_data() + { + return ['title' => $this->gateway->title]; + } +} \ No newline at end of file diff --git a/js/hyperswitch-checkout-blocks.js b/js/hyperswitch-checkout-blocks.js new file mode 100644 index 0000000..36f05cc --- /dev/null +++ b/js/hyperswitch-checkout-blocks.js @@ -0,0 +1,39 @@ +const settings = window.wc.wcSettings.getSetting( + "hyperswitch_checkout_data", + {} +); +const label = + window.wp.htmlEntities.decodeEntities(settings.title) || + window.wp.i18n.__("Hyperswitch", "hyperswitch-checkout"); + +const Block_Gateway = { + name: "hyperswitch_checkout", + label: label, + content: Object(window.wp.element.createElement)( + "div", + { id: "hyperswitch-checkout" }, + "Sample content inside the div" + ), + edit: Object(window.wp.element.createElement)( + "div", + null, + "Sample content inside the div" + ), + canMakePayment: () => { + console.log("settings"); + console.log(settings); + return true; + }, + ariaLabel: label, + supports: { + features: settings.supports, + }, + placeOrderButtonLabel: "Proceed to Pay", + onSubmit: (ev) => { + console.log("settings"); + console.log(settings); + console.log("onsubmit"); + console.log(ev); + }, +}; +window.wc.wcBlocksRegistry.registerPaymentMethod(Block_Gateway); From e038aa7f2d1cf8fd326e6fcc04d7698f82307f6b Mon Sep 17 00:00:00 2001 From: Vrishab Srivatsa Date: Thu, 14 Mar 2024 17:59:28 +0530 Subject: [PATCH 2/6] Support for redirection flow - WC checkout blocks --- .gitignore | 3 ++- hyperswitch-checkout.php | 4 ++-- js/hyperswitch-checkout-blocks.js | 23 +++++------------------ js/hyperswitch-hyperservice.js | 15 +++++++++++++-- readme.txt | 8 ++++---- 5 files changed, 26 insertions(+), 27 deletions(-) diff --git a/.gitignore b/.gitignore index d128159..e59ca1b 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -hyperswitch-woocommerce-plugin.zip \ No newline at end of file +*.zip +*.sh \ No newline at end of file diff --git a/hyperswitch-checkout.php b/hyperswitch-checkout.php index 103d580..651a4e8 100644 --- a/hyperswitch-checkout.php +++ b/hyperswitch-checkout.php @@ -818,13 +818,13 @@ public function create_refund($payment_id, $amount, $reason, $refund_num, $order /** * Process the payment and return the result **/ - function process_payment($payment_id) + function process_payment($order_id) { // $nonce = $_POST['woocommerce-process-checkout-nonce']; // if (!wp_verify_nonce($nonce, 'woocommerce-process_checkout')) { // return array('result' => 'failure', 'nonce' => 'failed'); // } - $order = new WC_Order($payment_id); + $order = new WC_Order($order_id); return array('result' => 'success', 'redirect' => $order->get_checkout_payment_url(true)); } diff --git a/js/hyperswitch-checkout-blocks.js b/js/hyperswitch-checkout-blocks.js index 36f05cc..a7f1035 100644 --- a/js/hyperswitch-checkout-blocks.js +++ b/js/hyperswitch-checkout-blocks.js @@ -2,6 +2,9 @@ const settings = window.wc.wcSettings.getSetting( "hyperswitch_checkout_data", {} ); +const Content = () => { + return window.wp.htmlEntities.decodeEntities(settings.description || ""); +}; const label = window.wp.htmlEntities.decodeEntities(settings.title) || window.wp.i18n.__("Hyperswitch", "hyperswitch-checkout"); @@ -9,19 +12,9 @@ const label = const Block_Gateway = { name: "hyperswitch_checkout", label: label, - content: Object(window.wp.element.createElement)( - "div", - { id: "hyperswitch-checkout" }, - "Sample content inside the div" - ), - edit: Object(window.wp.element.createElement)( - "div", - null, - "Sample content inside the div" - ), + content: Object(window.wp.element.createElement)(Content, null), + edit: Object(window.wp.element.createElement)(Content, null), canMakePayment: () => { - console.log("settings"); - console.log(settings); return true; }, ariaLabel: label, @@ -29,11 +22,5 @@ const Block_Gateway = { features: settings.supports, }, placeOrderButtonLabel: "Proceed to Pay", - onSubmit: (ev) => { - console.log("settings"); - console.log(settings); - console.log("onsubmit"); - console.log(ev); - }, }; window.wc.wcBlocksRegistry.registerPaymentMethod(Block_Gateway); diff --git a/js/hyperswitch-hyperservice.js b/js/hyperswitch-hyperservice.js index cb2638b..e59bbc6 100644 --- a/js/hyperswitch-hyperservice.js +++ b/js/hyperswitch-hyperservice.js @@ -191,17 +191,28 @@ function renderHyperswitchSDK(client_secret, return_url) { var disableSaveCards = !enable_saved_payment_methods; var showCardFormByDefault = !!show_card_from_by_default; + var currentUrl = window.location.href; + var regex = /\/checkout\/order-pay/; + var containsCheckoutOrderPay = regex.test(currentUrl); + var sdkHandlePayments = containsCheckoutOrderPay; + hyperswitchUnifiedCheckoutOptions = { layout: layout1, wallets: { walletReturnUrl: hyperswitchReturnUrl, style, }, - sdkHandleConfirmPayment: false, + sdkHandleConfirmPayment: { + handleConfirm: sdkHandlePayments, + buttonText: "Pay Now", + confirmParams: { + return_url: hyperswitchReturnUrl, + }, + }, disableSaveCards, branding: "never", showCardFormByDefault, - sdkHandleOneClickConfirmPayment: false, + sdkHandleOneClickConfirmPayment: sdkHandlePayments, }; hyperswitchUnifiedCheckout = hyperswitchWidgets.create( "payment", diff --git a/readme.txt b/readme.txt index 8d743b7..a0bd6ee 100644 --- a/readme.txt +++ b/readme.txt @@ -1,11 +1,11 @@ === Hyperswitch Checkout for WooCommerce === Contributors: hyperswitch, vrishabjuspay Tags: woocommerce, hyperswitch, payment, ecommerce, e-commerce, checkout -Requires at least: 4.0 +Requires at least: 5.8 Tested up to: 6.4.3 -Stable tag: 1.5.0 -Requires PHP: 7.0 -WC requires at least: 4.0.0 +Stable tag: 1.5.1 +Requires PHP: 7.2 +WC requires at least: 7.0.0 WC tested up to: 8.6.1 License: GPLv2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html From dcb232b574e0c822a0d7e5f9f12ed18df3445bbd Mon Sep 17 00:00:00 2001 From: Vrishab Srivatsa Date: Sat, 16 Mar 2024 22:35:12 +0530 Subject: [PATCH 3/6] Code formatting, webhook bugfix, logger payload fix --- hyperswitch-checkout.php | 1809 +++++++++++++++--------------- includes/hyperswitch-webhook.php | 383 ++++--- 2 files changed, 1077 insertions(+), 1115 deletions(-) diff --git a/hyperswitch-checkout.php b/hyperswitch-checkout.php index 651a4e8..32e7b46 100644 --- a/hyperswitch-checkout.php +++ b/hyperswitch-checkout.php @@ -28,951 +28,920 @@ */ -if (!defined('ABSPATH')) { - exit; // Exit if accessed directly +if ( ! defined( 'ABSPATH' ) ) { + exit; // Exit if accessed directly } -define('HYPERSWITCH_CHECKOUT_PLUGIN_VERSION', '1.6.0'); -define('HYPERSWITCH_PLUGIN_URL', untrailingslashit(plugins_url(basename(plugin_dir_path(__FILE__)), basename(__FILE__)))); +define( 'HYPERSWITCH_CHECKOUT_PLUGIN_VERSION', '1.6.0' ); +define( 'HYPERSWITCH_PLUGIN_URL', untrailingslashit( plugins_url( basename( plugin_dir_path( __FILE__ ) ), basename( __FILE__ ) ) ) ); require_once __DIR__ . '/includes/hyperswitch-webhook.php'; -add_action('plugins_loaded', 'hyperswitch_init_payment_class', 0); -add_action('admin_post_nopriv_hyperswitch_wc_webhook', 'hyperswitch_webhook_init', 10); -add_action('wp_ajax_nopriv_hyperswitch_create_or_update_payment_intent', 'hyperswitch_create_or_update_payment_intent', 5); -add_action('wp_ajax_hyperswitch_create_or_update_payment_intent', 'hyperswitch_create_or_update_payment_intent', 5); -add_action('before_woocommerce_init', 'hyperswitch_declare_compatibility', 5); -add_action('woocommerce_blocks_loaded', 'woocommerce_gateway_hyperswitch_woocommerce_block_support'); - -function hyperswitch_init_payment_class() -{ - - if (!class_exists('WC_Payment_Gateway')) { - return; - } - - class Hyperswitch_Checkout extends WC_Payment_Gateway - { - - public function __construct() - { - $this->enabled = $this->get_option('enabled'); - $this->id = 'hyperswitch_checkout'; - $this->method_title = __('Hyperswitch'); - $this->method_description = __('Allow customers to securely pay via Hyperswitch', 'hyperswitch-checkout'); - - $this->has_fields = true; - - $this->init_form_fields(); - $this->init_settings(); - - $this->title = $this->get_option('method_title'); - $this->icon = HYPERSWITCH_PLUGIN_URL . '/assets/images/default.svg'; - $this->plugin_url = HYPERSWITCH_PLUGIN_URL . '/assets/images/'; - $this->environment = $this->get_option('environment'); - $this->enable_saved_payment_methods = $this->get_option('enable_saved_payment_methods') === 'yes'; - $this->show_card_from_by_default = $this->get_option('show_card_from_by_default') === 'yes'; - $this->supports = [ - 'products', - 'refunds' - ]; - $this->processing_payment_order_status = $this->get_option('hold_order') === 'yes' ? 'on-hold' : 'pending'; - switch ($this->environment) { - case "sandbox": - $this->hyperswitch_url = 'https://sandbox.hyperswitch.io'; - $script_url = 'https://beta.hyperswitch.io/v1/HyperLoader.js'; - break; - case "production": - $this->hyperswitch_url = 'https://api.hyperswitch.io'; - $script_url = 'https://checkout.hyperswitch.io/v0/HyperLoader.js'; - break; - default: - $this->hyperswitch_url = 'https://sandbox.hyperswitch.io'; - $script_url = 'https://beta.hyperswitch.io/v1/HyperLoader.js'; - break; - } - - $this->notify_url = home_url('/wc-api/wc_hyperswitch'); - - add_action('woocommerce_update_options_payment_gateways_' . $this->id, array($this, 'process_admin_options')); - add_filter('plugin_action_links_' . plugin_basename(__FILE__), [$this, 'plugin_action_links']); - - if ($this->enabled == 'yes') { - add_action('woocommerce_api_wc_hyperswitch', array($this, 'check_hyperswitch_response')); - wp_enqueue_style('hyperswitchcss', plugins_url('/css/hyperswitch.css', __FILE__), array(), HYPERSWITCH_CHECKOUT_PLUGIN_VERSION); - $client_data = [ - 'publishable_key' => $this->get_option('publishable_key'), - 'appearance_obj' => $this->get_option('appearance'), - 'layout' => $this->get_option('layout'), - 'enable_saved_payment_methods' => $this->get_option('enable_saved_payment_methods') === 'yes', - 'show_card_from_by_default' => $this->get_option('show_card_from_by_default') === 'yes', - 'endpoint' => $this->hyperswitch_url, - 'plugin_url' => $this->plugin_url, - 'plugin_version' => HYPERSWITCH_CHECKOUT_PLUGIN_VERSION, - ]; - - wp_enqueue_script('hyperswitch-hyperloader', $script_url); - - wp_register_script( - 'hyperswitch-hyperservice', - HYPERSWITCH_PLUGIN_URL . '/js/hyperswitch-hyperservice.js', - array('hyperswitch-hyperloader'), - 'HYPERSWITCH_CHECKOUT_PLUGIN_VERSION' - ); - wp_localize_script('hyperswitch-hyperservice', 'clientdata', $client_data); - wp_enqueue_script('hyperswitch-hyperservice'); - add_action("woocommerce_receipt_" . $this->id, array($this, 'receipt_page')); - add_action('woocommerce_order_actions', array($this, 'hyperswitch_add_manual_actions')); - add_action('woocommerce_order_action_wc_manual_capture_action', array($this, 'hyperswitch_process_manual_capture_action')); - add_action('woocommerce_order_action_wc_manual_sync_action', array($this, 'hyperswitch_process_manual_sync_action')); - add_filter('woocommerce_order_button_html', array($this, 'place_order_custom_button')); - add_filter('woocommerce_thankyou_order_received_text', array($this, 'hyperswitch_thankyou')); - } - } - - function plugin_action_links($links) - { - $plugin_links = [ - '' . esc_html__('Settings', 'hyperswitch-checkout') . '', - ]; - return array_merge($plugin_links, $links); - } - - function hyperswitch_thankyou($esc_html__) - { - $order_id = wc_get_order_id_by_order_key($_GET['key']); - $order = wc_get_order($order_id); - $payment_method = $order->get_payment_method(); - if ($payment_method == 'hyperswitch_checkout') { - $payment_id = $order->get_transaction_id(); - $paymentResponse = $this->retrieve_payment_intent($payment_id); - $status = $paymentResponse['status']; - $pm = $paymentResponse['payment_method']; - $pmt = $paymentResponse['payment_method_type']; - $intermediate_status = array("processing", "requires_merchant_action", "requires_customer_action", "requires_confirmation", "requires_capture"); - $msg = $esc_html__; - - global $woocommerce; - if ($status == 'succeeded') { - $woocommerce->cart->empty_cart(); - } else if (in_array($status, $intermediate_status)) { - if ($status == 'requires_capture') { - $msg = "Thank you for shopping with us. Please note that your payment has been authorized and can now be captured by the merchant. Kindly check the status of your order after some time."; - } else { - $msg = "Thank you for shopping with us. Please note that your payment is currently being processed. Kindly check the status of your order after some time."; - } - $woocommerce->cart->empty_cart(); - } else { - $msg = "Thank you for shopping with us. However, the payment has failed. Please retry the payment."; - } - $this->post_log( - "WC_THANK_YOU_MESSAGE", - array( - "payment_method" => $pm, - "payment_method_type" => $pmt, - "order_id" => $order_id, - "payment_id" => $payment_id, - "message" => $msg - ) - ); - return esc_html__($msg, 'hyperswitch-checkout'); - } else { - return $esc_html__; - } - } - - function place_order_custom_button($button_html) - { - // not escaping here as the only variable is $button_html which is returned by default even otherwise - echo - '
' . $button_html . '
' - ; - } - - - function process_refund($order_id, $amount = NULL, $reason = '') - { - $refund = new WC_Order_Refund; - $order = wc_get_order($order_id); - $payment_id = $order->get_transaction_id(); - $refund_num = $refund->id; - $responseObj = $this->create_refund($payment_id, $amount, $reason, $refund_num, $order_id); - $status = $responseObj['status']; - $refund_id = $responseObj['refund_id']; - $intermediate_status = array("pending"); - if ($status == 'succeeded') { - $refund->set_refunded_payment(true); - $order->add_order_note('Refund Successful (Hyperswitch Refund ID: ' . $refund_id . ')'); - } else if (in_array($status, $intermediate_status)) { - $order->add_order_note('Refund processing (Hyperswitch Refund ID: ' . $refund_id . ')'); - $refund->set_refunded_payment(true); - $refund->set_status("processing"); - } else { - $refund->set_refunded_payment(false); - $order->add_order_note('Refund failed with error message: ' . $responseObj['error']['message']); - return false; - } - $this->post_log("WC_MANUAL_REFUND", $status, $payment_id); - return true; - } - - function hyperswitch_add_manual_actions($actions) - { - global $theorder; - $this->method_title = __('Hyperswitch'); - $payment_id = $theorder->get_transaction_id(); - $terminal_status = array("processing", "refunded"); - // bail if the order has been paid for or this action has been run - if (!($theorder->is_paid() || $theorder->get_meta('payment_captured') == 'yes' || strlen($payment_id) < 3 || in_array($theorder->status, $terminal_status))) { - $actions['wc_manual_capture_action'] = __('Capture Payment with Hyperswitch', 'hyperswitch-checkout'); - } - - if (!(in_array($theorder->status, $terminal_status) || strlen($payment_id) < 3)) { - $actions['wc_manual_sync_action'] = __('Sync Payment with Hyperswitch', 'hyperswitch-checkout'); - } - return $actions; - } - - function hyperswitch_process_manual_capture_action($order) - { - $payment_id = $order->get_transaction_id(); - $responseObj = $this->manual_capture($payment_id); - $status = $responseObj['status']; - $payment_method = $responseObj['payment_method']; - $intermediate_status = array("processing", "requires_merchant_action", "requires_customer_action", "requires_confirmation", "requires_capture"); - if ($status == 'succeeded') { - if ($order->status !== 'processing' && $order->status !== 'refunded') { - $order->payment_complete($payment_id); - $order->add_order_note('Manual Capture successful (Hyperswitch Payment ID: ' . $payment_id . ')'); - $order->add_order_note('Payment successful via ' . $payment_method . ' (Hyperswitch Payment ID: ' . $payment_id . ')'); - $order->update_meta_data('payment_captured', 'yes'); - $this->post_log("WC_ORDER_PLACED", null, $payment_id); - } - } else if (in_array($status, $intermediate_status)) { - $order->update_status($this->processing_payment_order_status); - $order->add_order_note('Manual Capture processing (Hyperswitch Payment ID: ' . $payment_id . ')'); - } else { - $order->update_status($this->processing_payment_order_status); - $errorMessage = $responseObj['error']['message'] ?? $responseObj['error_code'] ?? "NA"; - $order->add_order_note('Manual Capture failed (Hyperswitch Payment ID: ' . $payment_id . ') with error message: ' . $errorMessage); - } - $this->post_log("WC_MANUAL_CAPTURE", $status, $payment_id); - } - - function hyperswitch_process_manual_sync_action($order) - { - $payment_id = $order->get_transaction_id(); - $responseObj = $this->retrieve_payment_intent($payment_id); - $status = $responseObj['status']; - $payment_method = $responseObj['payment_method']; - $intermediate_status = array("processing", "requires_merchant_action", "requires_customer_action", "requires_confirmation", "requires_capture"); - $order->add_order_note('Synced Payment Status (Hyperswitch Payment ID: ' . $payment_id . ')'); - if ($status == 'succeeded') { - if ($order->status !== 'processing' && $order->status !== 'refunded') { - $this->post_log("WC_ORDER_PLACED", null, $payment_id); - } - if ($order->status !== 'refunded') { - $order->add_order_note('Payment successful via ' . $payment_method . ' (Hyperswitch Payment ID: ' . $payment_id . ')'); - $order->payment_complete($payment_id); - } - } else if (in_array($status, $intermediate_status)) { - $order->add_order_note('Payment processing via ' . $payment_method . ' (Hyperswitch Payment ID: ' . $payment_id . ')'); - } else { - $order->add_order_note('Payment failed via ' . $payment_method . ' (Hyperswitch Payment ID: ' . $payment_id . ')'); - } - $this->post_log("WC_MANUAL_SYNC", $status, $payment_id); - } - - public function init_form_fields() - { - - $webhookUrl = esc_url(admin_url('admin-post.php')) . '?action=hyperswitch_wc_webhook'; - - $this->form_fields = array( - 'enabled' => array( - 'title' => __('Enable/Disable', 'hyperswitch-checkout'), - 'label' => __('Enable Hyperswitch', 'hyperswitch-checkout'), - 'type' => 'checkbox', - 'description' => '', - 'default' => 'yes' - ), - 'method_title' => array( - 'title' => __('Title', 'hyperswitch-checkout'), - 'type' => 'textarea', - 'description' => __('The title to be displayed for Hyperswitch Payment Method (in case of multiple WooCommerce Payment Gateways/ Methods)', 'hyperswitch-checkout'), - 'default' => __('Credit, Debit Card and Wallet Payments (powered by Hyperswitch)', 'hyperswitch-checkout') - ), - 'environment' => array( - 'title' => __('Environment'), - 'label' => __('Select Environment'), - 'type' => 'select', - 'options' => array( - 'production' => __('Production', 'hyperswitch-checkout'), - 'sandbox' => __('Sandbox', 'hyperswitch-checkout'), - ), - 'default' => 'sandbox', - ), - 'api_key' => array( - 'title' => 'Api Key', - 'type' => 'password', - 'description' => __('Find this on Developers > API Keys section of Hyperswitch Dashboard', 'hyperswitch-checkout') - ), - 'publishable_key' => array( - 'title' => 'Publishable key', - 'type' => 'text', - 'description' => __('Find this on Developers > API Keys section of Hyperswitch Dashboard', 'hyperswitch-checkout') - ), - 'webhook_secret_key' => array( - 'title' => 'Payment Response Hash Key', - 'type' => 'password', - 'description' => __('Find this on Developers > API Keys section of Hyperswitch Dashboard', 'hyperswitch-checkout') - ), - 'enable_webhook' => array( - 'title' => __('Enable Webhook', 'hyperswitch-checkout'), - 'type' => 'checkbox', - 'description' => __("Allow webhooks from Hyperswitch to receive real time updates of payments to update orders.

$webhookUrl

Use this URL to be entered as Webhook URL on Hyperswitch dashboard", 'hyperswitch-checkout'), - 'label' => __('Enable Hyperswitch Webhook', 'hyperswitch-checkout'), - 'default' => 'yes' - ), - 'capture_method' => array( - 'title' => __('Capture Method', 'hyperswitch-checkout'), - 'label' => __('Select Capture Method', 'hyperswitch-checkout'), - 'type' => 'select', - 'description' => __("Specify whether you want to capture payments manually or automatically", 'hyperswitch-checkout'), - 'options' => array( - 'automatic' => __('Automatic', 'hyperswitch-checkout'), - 'manual' => __('Manual', 'hyperswitch-checkout'), - ), - 'default' => 'automatic', - ), - 'enable_saved_payment_methods' => array( - 'title' => __('Enable Saved Payment Methods', 'hyperswitch-checkout'), - 'type' => 'checkbox', - 'description' => __('Allow registered customers to pay via saved payment methods', 'hyperswitch-checkout'), - 'label' => __('Enable Saved Payment Methods', 'hyperswitch-checkout'), - 'default' => 'yes' - ), - 'show_card_from_by_default' => array( - 'title' => __('Show Card Form Always', 'hyperswitch-checkout'), - 'type' => 'checkbox', - 'label' => __('Show Card Form before Payment Methods List has loaded', 'hyperswitch-checkout'), - 'default' => 'yes' - ), - 'appearance' => array( - 'title' => 'Appearance', - 'type' => 'textarea', - 'default' => '{}', - 'description' => __('Use the above parameter to pass appearance config (in json format) to the checkout.', 'hyperswitch-checkout'), - ), - 'layout' => array( - 'title' => 'Layout', - 'label' => 'Select Layout', - 'type' => 'select', - 'description' => __("Choose a layout that fits well with your UI pattern.", 'hyperswitch-checkout'), - 'options' => array( - 'tabs' => __('Tabs', 'hyperswitch-checkout'), - 'accordion' => __('Accordion', 'hyperswitch-checkout'), - 'spaced' => __('Spaced Accordion', 'hyperswitch-checkout'), - ), - 'default' => 'tabs', - ), - 'hold_order' => array( - 'title' => __('Hold Order on Processing Payments', 'hyperswitch-checkout'), - 'type' => 'checkbox', - 'description' => __("Disable this only if you do not want to reduce stock levels until the payment is successful.", 'hyperswitch-checkout'), - 'label' => __('Whether to hold order, reduce stock if a payment goes into processing status.', 'hyperswitch-checkout'), - 'default' => 'yes' - ), - ); - } - - function receipt_page($order_id) - { - $payment_intent = $this->create_payment_intent($order_id); - if (isset($payment_intent['clientSecret']) && isset($payment_intent['paymentId'])) { - $client_secret = $payment_intent['clientSecret']; - $payment_id = $payment_intent['paymentId']; - $this->post_log("WC_PAYMENT_INTENT_CREATED", null, $payment_id); - $return_url = $this->notify_url . '/?payment_id=' . $payment_id; - echo ' -
+add_action( 'plugins_loaded', 'hyperswitch_init_payment_class', 0 ); +add_action( 'admin_post_nopriv_hyperswitch_wc_webhook', 'hyperswitch_webhook_init', 10 ); +add_action( 'wp_ajax_nopriv_hyperswitch_create_or_update_payment_intent', 'hyperswitch_create_or_update_payment_intent', 5 ); +add_action( 'wp_ajax_hyperswitch_create_or_update_payment_intent', 'hyperswitch_create_or_update_payment_intent', 5 ); +add_action( 'before_woocommerce_init', 'hyperswitch_declare_compatibility', 5 ); +add_action( 'woocommerce_blocks_loaded', 'woocommerce_gateway_hyperswitch_woocommerce_block_support' ); + +function hyperswitch_init_payment_class() { + + if ( ! class_exists( 'WC_Payment_Gateway' ) ) { + return; + } + + class Hyperswitch_Checkout extends WC_Payment_Gateway { + + public function __construct() { + $this->enabled = $this->get_option( 'enabled' ); + $this->id = 'hyperswitch_checkout'; + $this->method_title = __( 'Hyperswitch' ); + $this->method_description = __( 'Allow customers to securely pay via Hyperswitch', 'hyperswitch-checkout' ); + + $this->has_fields = true; + + $this->init_form_fields(); + $this->init_settings(); + + $this->title = $this->get_option( 'method_title' ); + $this->icon = HYPERSWITCH_PLUGIN_URL . '/assets/images/default.svg'; + $this->plugin_url = HYPERSWITCH_PLUGIN_URL . '/assets/images/'; + $this->environment = $this->get_option( 'environment' ); + $this->enable_saved_payment_methods = $this->get_option( 'enable_saved_payment_methods' ) === 'yes'; + $this->show_card_from_by_default = $this->get_option( 'show_card_from_by_default' ) === 'yes'; + $this->supports = [ + 'products', + 'refunds' + ]; + $this->processing_payment_order_status = $this->get_option( 'hold_order' ) === 'yes' ? 'on-hold' : 'pending'; + switch ( $this->environment ) { + case "sandbox": + $this->hyperswitch_url = 'https://sandbox.hyperswitch.io'; + $script_url = 'https://beta.hyperswitch.io/v1/HyperLoader.js'; + break; + case "production": + $this->hyperswitch_url = 'https://api.hyperswitch.io'; + $script_url = 'https://checkout.hyperswitch.io/v0/HyperLoader.js'; + break; + default: + $this->hyperswitch_url = 'https://sandbox.hyperswitch.io'; + $script_url = 'https://beta.hyperswitch.io/v1/HyperLoader.js'; + break; + } + + $this->notify_url = home_url( '/wc-api/wc_hyperswitch' ); + + add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) ); + add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), [ $this, 'plugin_action_links' ] ); + + if ( $this->enabled == 'yes' ) { + add_action( 'woocommerce_api_wc_hyperswitch', array( $this, 'check_hyperswitch_response' ) ); + wp_enqueue_style( 'hyperswitchcss', plugins_url( '/css/hyperswitch.css', __FILE__ ), array(), HYPERSWITCH_CHECKOUT_PLUGIN_VERSION ); + $client_data = [ + 'publishable_key' => $this->get_option( 'publishable_key' ), + 'appearance_obj' => $this->get_option( 'appearance' ), + 'layout' => $this->get_option( 'layout' ), + 'enable_saved_payment_methods' => $this->get_option( 'enable_saved_payment_methods' ) === 'yes', + 'show_card_from_by_default' => $this->get_option( 'show_card_from_by_default' ) === 'yes', + 'endpoint' => $this->hyperswitch_url, + 'plugin_url' => $this->plugin_url, + 'plugin_version' => HYPERSWITCH_CHECKOUT_PLUGIN_VERSION, + ]; + + wp_enqueue_script( 'hyperswitch-hyperloader', $script_url ); + + wp_register_script( + 'hyperswitch-hyperservice', + HYPERSWITCH_PLUGIN_URL . '/js/hyperswitch-hyperservice.js', + array( 'hyperswitch-hyperloader' ), + 'HYPERSWITCH_CHECKOUT_PLUGIN_VERSION' + ); + wp_localize_script( 'hyperswitch-hyperservice', 'clientdata', $client_data ); + wp_enqueue_script( 'hyperswitch-hyperservice' ); + add_action( "woocommerce_receipt_" . $this->id, array( $this, 'receipt_page' ) ); + add_action( 'woocommerce_order_actions', array( $this, 'hyperswitch_add_manual_actions' ) ); + add_action( 'woocommerce_order_action_wc_manual_capture_action', array( $this, 'hyperswitch_process_manual_capture_action' ) ); + add_action( 'woocommerce_order_action_wc_manual_sync_action', array( $this, 'hyperswitch_process_manual_sync_action' ) ); + add_filter( 'woocommerce_order_button_html', array( $this, 'place_order_custom_button' ) ); + add_filter( 'woocommerce_thankyou_order_received_text', array( $this, 'hyperswitch_thankyou' ) ); + } + } + + function plugin_action_links( $links ) { + $plugin_links = [ + '' . esc_html__( 'Settings', 'hyperswitch-checkout' ) . '', + ]; + return array_merge( $plugin_links, $links ); + } + + function hyperswitch_thankyou( $esc_html__ ) { + $order_id = wc_get_order_id_by_order_key( $_GET['key'] ); + $order = wc_get_order( $order_id ); + $payment_method = $order->get_payment_method(); + if ( $payment_method == 'hyperswitch_checkout' ) { + $payment_id = $order->get_transaction_id(); + $paymentResponse = $this->retrieve_payment_intent( $payment_id ); + $status = $paymentResponse['status']; + $pm = $paymentResponse['payment_method']; + $pmt = $paymentResponse['payment_method_type']; + $intermediate_status = array( "processing", "requires_merchant_action", "requires_customer_action", "requires_confirmation", "requires_capture" ); + $msg = $esc_html__; + + global $woocommerce; + if ( $status == 'succeeded' ) { + $woocommerce->cart->empty_cart(); + } else if ( in_array( $status, $intermediate_status ) ) { + if ( $status == 'requires_capture' ) { + $msg = "Thank you for shopping with us. Please note that your payment has been authorized and can now be captured by the merchant. Kindly check the status of your order after some time."; + } else { + $msg = "Thank you for shopping with us. Please note that your payment is currently being processed. Kindly check the status of your order after some time."; + } + $woocommerce->cart->empty_cart(); + } else { + $msg = "Thank you for shopping with us. However, the payment has failed. Please retry the payment."; + } + $this->post_log( + "WC_THANK_YOU_MESSAGE", + array( + "payment_method" => $pm, + "payment_method_type" => $pmt, + "order_id" => $order_id, + "payment_id" => $payment_id, + "message" => $msg + ) + ); + return esc_html__( $msg, 'hyperswitch-checkout' ); + } else { + return $esc_html__; + } + } + + function place_order_custom_button( $button_html ) { + // not escaping here as the only variable is $button_html which is returned by default even otherwise + echo + '
' . $button_html . '
' + ; + } + + + function process_refund( $order_id, $amount = NULL, $reason = '' ) { + $refund = new WC_Order_Refund; + $order = wc_get_order( $order_id ); + $payment_id = $order->get_transaction_id(); + $refund_num = $refund->id; + $responseObj = $this->create_refund( $payment_id, $amount, $reason, $refund_num, $order_id ); + $status = $responseObj['status']; + $refund_id = $responseObj['refund_id']; + $intermediate_status = array( "pending" ); + if ( $status == 'succeeded' ) { + $refund->set_refunded_payment( true ); + $order->add_order_note( 'Refund Successful (Hyperswitch Refund ID: ' . $refund_id . ')' ); + } else if ( in_array( $status, $intermediate_status ) ) { + $order->add_order_note( 'Refund processing (Hyperswitch Refund ID: ' . $refund_id . ')' ); + $refund->set_refunded_payment( true ); + $refund->set_status( "processing" ); + } else { + $refund->set_refunded_payment( false ); + $order->add_order_note( 'Refund failed with error message: ' . $responseObj['error']['message'] ); + return false; + } + $this->post_log( "WC_MANUAL_REFUND", $status, $payment_id ); + return true; + } + + function hyperswitch_add_manual_actions( $actions ) { + global $theorder; + $this->method_title = __( 'Hyperswitch' ); + $payment_id = $theorder->get_transaction_id(); + $terminal_status = array( "processing", "refunded" ); + // bail if the order has been paid for or this action has been run + if ( ! ( $theorder->is_paid() || $theorder->get_meta( 'payment_captured' ) == 'yes' || strlen( $payment_id ) < 3 || in_array( $theorder->status, $terminal_status ) ) ) { + $actions['wc_manual_capture_action'] = __( 'Capture Payment with Hyperswitch', 'hyperswitch-checkout' ); + } + + if ( ! ( in_array( $theorder->status, $terminal_status ) || strlen( $payment_id ) < 3 ) ) { + $actions['wc_manual_sync_action'] = __( 'Sync Payment with Hyperswitch', 'hyperswitch-checkout' ); + } + return $actions; + } + + function hyperswitch_process_manual_capture_action( $order ) { + $payment_id = $order->get_transaction_id(); + $responseObj = $this->manual_capture( $payment_id ); + $status = $responseObj['status']; + $payment_method = $responseObj['payment_method']; + $intermediate_status = array( "processing", "requires_merchant_action", "requires_customer_action", "requires_confirmation", "requires_capture" ); + if ( $status == 'succeeded' ) { + if ( $order->status !== 'processing' && $order->status !== 'refunded' ) { + $order->payment_complete( $payment_id ); + $order->add_order_note( 'Manual Capture successful (Hyperswitch Payment ID: ' . $payment_id . ')' ); + $order->add_order_note( 'Payment successful via ' . $payment_method . ' (Hyperswitch Payment ID: ' . $payment_id . ')' ); + $order->update_meta_data( 'payment_captured', 'yes' ); + $this->post_log( "WC_ORDER_PLACED", null, $payment_id ); + } + } else if ( in_array( $status, $intermediate_status ) ) { + $order->update_status( $this->processing_payment_order_status ); + $order->add_order_note( 'Manual Capture processing (Hyperswitch Payment ID: ' . $payment_id . ')' ); + } else { + $order->update_status( $this->processing_payment_order_status ); + $errorMessage = $responseObj['error']['message'] ?? $responseObj['error_code'] ?? "NA"; + $order->add_order_note( 'Manual Capture failed (Hyperswitch Payment ID: ' . $payment_id . ') with error message: ' . $errorMessage ); + } + $this->post_log( "WC_MANUAL_CAPTURE", $status, $payment_id ); + } + + function hyperswitch_process_manual_sync_action( $order ) { + $payment_id = $order->get_transaction_id(); + $responseObj = $this->retrieve_payment_intent( $payment_id ); + $status = $responseObj['status']; + $payment_method = $responseObj['payment_method']; + $intermediate_status = array( "processing", "requires_merchant_action", "requires_customer_action", "requires_confirmation", "requires_capture" ); + $order->add_order_note( 'Synced Payment Status (Hyperswitch Payment ID: ' . $payment_id . ')' ); + if ( $status == 'succeeded' ) { + if ( $order->status !== 'processing' && $order->status !== 'refunded' ) { + $this->post_log( "WC_ORDER_PLACED", null, $payment_id ); + } + if ( $order->status !== 'refunded' ) { + $order->add_order_note( 'Payment successful via ' . $payment_method . ' (Hyperswitch Payment ID: ' . $payment_id . ')' ); + $order->payment_complete( $payment_id ); + } + } else if ( in_array( $status, $intermediate_status ) ) { + $order->add_order_note( 'Payment processing via ' . $payment_method . ' (Hyperswitch Payment ID: ' . $payment_id . ')' ); + } else { + $order->add_order_note( 'Payment failed via ' . $payment_method . ' (Hyperswitch Payment ID: ' . $payment_id . ')' ); + } + $this->post_log( "WC_MANUAL_SYNC", $status, $payment_id ); + } + + public function init_form_fields() { + + $webhookUrl = esc_url( admin_url( 'admin-post.php' ) ) . '?action=hyperswitch_wc_webhook'; + + $this->form_fields = array( + 'enabled' => array( + 'title' => __( 'Enable/Disable', 'hyperswitch-checkout' ), + 'label' => __( 'Enable Hyperswitch', 'hyperswitch-checkout' ), + 'type' => 'checkbox', + 'description' => '', + 'default' => 'yes' + ), + 'method_title' => array( + 'title' => __( 'Title', 'hyperswitch-checkout' ), + 'type' => 'textarea', + 'description' => __( 'The title to be displayed for Hyperswitch Payment Method (in case of multiple WooCommerce Payment Gateways/ Methods)', 'hyperswitch-checkout' ), + 'default' => __( 'Credit, Debit Card and Wallet Payments (powered by Hyperswitch)', 'hyperswitch-checkout' ) + ), + 'environment' => array( + 'title' => __( 'Environment' ), + 'label' => __( 'Select Environment' ), + 'type' => 'select', + 'options' => array( + 'production' => __( 'Production', 'hyperswitch-checkout' ), + 'sandbox' => __( 'Sandbox', 'hyperswitch-checkout' ), + ), + 'default' => 'sandbox', + ), + 'api_key' => array( + 'title' => 'Api Key', + 'type' => 'password', + 'description' => __( 'Find this on Developers > API Keys section of Hyperswitch Dashboard', 'hyperswitch-checkout' ) + ), + 'publishable_key' => array( + 'title' => 'Publishable key', + 'type' => 'text', + 'description' => __( 'Find this on Developers > API Keys section of Hyperswitch Dashboard', 'hyperswitch-checkout' ) + ), + 'webhook_secret_key' => array( + 'title' => 'Payment Response Hash Key', + 'type' => 'password', + 'description' => __( 'Find this on Developers > API Keys section of Hyperswitch Dashboard', 'hyperswitch-checkout' ) + ), + 'enable_webhook' => array( + 'title' => __( 'Enable Webhook', 'hyperswitch-checkout' ), + 'type' => 'checkbox', + 'description' => __( "Allow webhooks from Hyperswitch to receive real time updates of payments to update orders.

$webhookUrl

Use this URL to be entered as Webhook URL on Hyperswitch dashboard", 'hyperswitch-checkout' ), + 'label' => __( 'Enable Hyperswitch Webhook', 'hyperswitch-checkout' ), + 'default' => 'yes' + ), + 'capture_method' => array( + 'title' => __( 'Capture Method', 'hyperswitch-checkout' ), + 'label' => __( 'Select Capture Method', 'hyperswitch-checkout' ), + 'type' => 'select', + 'description' => __( "Specify whether you want to capture payments manually or automatically", 'hyperswitch-checkout' ), + 'options' => array( + 'automatic' => __( 'Automatic', 'hyperswitch-checkout' ), + 'manual' => __( 'Manual', 'hyperswitch-checkout' ), + ), + 'default' => 'automatic', + ), + 'enable_saved_payment_methods' => array( + 'title' => __( 'Enable Saved Payment Methods', 'hyperswitch-checkout' ), + 'type' => 'checkbox', + 'description' => __( 'Allow registered customers to pay via saved payment methods', 'hyperswitch-checkout' ), + 'label' => __( 'Enable Saved Payment Methods', 'hyperswitch-checkout' ), + 'default' => 'yes' + ), + 'show_card_from_by_default' => array( + 'title' => __( 'Show Card Form Always', 'hyperswitch-checkout' ), + 'type' => 'checkbox', + 'label' => __( 'Show Card Form before Payment Methods List has loaded', 'hyperswitch-checkout' ), + 'default' => 'yes' + ), + 'appearance' => array( + 'title' => 'Appearance', + 'type' => 'textarea', + 'default' => '{}', + 'description' => __( 'Use the above parameter to pass appearance config (in json format) to the checkout.', 'hyperswitch-checkout' ), + ), + 'layout' => array( + 'title' => 'Layout', + 'label' => 'Select Layout', + 'type' => 'select', + 'description' => __( "Choose a layout that fits well with your UI pattern.", 'hyperswitch-checkout' ), + 'options' => array( + 'tabs' => __( 'Tabs', 'hyperswitch-checkout' ), + 'accordion' => __( 'Accordion', 'hyperswitch-checkout' ), + 'spaced' => __( 'Spaced Accordion', 'hyperswitch-checkout' ), + ), + 'default' => 'tabs', + ), + 'hold_order' => array( + 'title' => __( 'Hold Order on Processing Payments', 'hyperswitch-checkout' ), + 'type' => 'checkbox', + 'description' => __( "Disable this only if you do not want to reduce stock levels until the payment is successful.", 'hyperswitch-checkout' ), + 'label' => __( 'Whether to hold order, reduce stock if a payment goes into processing status.', 'hyperswitch-checkout' ), + 'default' => 'yes' + ), + ); + } + + function receipt_page( $order_id ) { + $payment_intent = $this->create_payment_intent( $order_id ); + if ( isset ( $payment_intent['clientSecret'] ) && isset ( $payment_intent['paymentId'] ) ) { + $client_secret = $payment_intent['clientSecret']; + $payment_id = $payment_intent['paymentId']; + $this->post_log( "WC_PAYMENT_INTENT_CREATED", null, $payment_id ); + $return_url = $this->notify_url . '/?payment_id=' . $payment_id; + echo ' +
' - ; - } else { - global $woocommerce; - $order = new WC_Order($order_id); - $error = $payment_intent['error']; - $order->add_order_note(__('Unable to Create Hyperswitch Payment Intent.', 'hyperswitch-checkout')); - $order->add_order_note('Error: ' . $error); - $this->post_log("WC_FAILED_TO_CREATE_PAYMENT_INTENT", $error); - if (function_exists('wc_add_notice')) { - wc_add_notice(__("Something went wrong. Please contact support for assistance.", 'hyperswitch-checkout'), 'error'); - - } else { - $woocommerce->add_error(__("Something went wrong. Please contact support for assistance.", 'hyperswitch-checkout')); - $woocommerce->set_messages(); - } - $redirect_url = get_permalink(woocommerce_get_page_id('cart')); - wp_redirect($redirect_url); - exit; - } - } - - function render_payment_sheet($order_id, $client_secret = null) - { - $payment_intent = $this->create_payment_intent($order_id, $client_secret); - if (isset($payment_intent['clientSecret']) && isset($payment_intent['paymentId'])) { - $client_secret = $payment_intent['clientSecret']; - $payment_id = $payment_intent['paymentId']; - $this->post_log("WC_PAYMENT_INTENT_CREATED", null, $payment_id); - $return_url = $this->notify_url . '/?payment_id=' . $payment_id; - $return_html = ' -
+ ; + } else { + global $woocommerce; + $order = new WC_Order( $order_id ); + $error = $payment_intent['error']; + $order->add_order_note( __( 'Unable to Create Hyperswitch Payment Intent.', 'hyperswitch-checkout' ) ); + $order->add_order_note( 'Error: ' . $error ); + $this->post_log( "WC_FAILED_TO_CREATE_PAYMENT_INTENT", $error ); + if ( function_exists( 'wc_add_notice' ) ) { + wc_add_notice( __( "Something went wrong. Please contact support for assistance.", 'hyperswitch-checkout' ), 'error' ); + + } else { + $woocommerce->add_error( __( "Something went wrong. Please contact support for assistance.", 'hyperswitch-checkout' ) ); + $woocommerce->set_messages(); + } + $redirect_url = get_permalink( woocommerce_get_page_id( 'cart' ) ); + wp_redirect( $redirect_url ); + exit; + } + } + + function render_payment_sheet( $order_id, $client_secret = null ) { + $payment_intent = $this->create_payment_intent( $order_id, $client_secret ); + if ( isset ( $payment_intent['clientSecret'] ) && isset ( $payment_intent['paymentId'] ) ) { + $client_secret = $payment_intent['clientSecret']; + $payment_id = $payment_intent['paymentId']; + $this->post_log( "WC_PAYMENT_INTENT_CREATED", null, $payment_id ); + $return_url = $this->notify_url . '/?payment_id=' . $payment_id; + $return_html = ' +
'; - return array( - "payment_sheet" => $return_html - ); - } else { - global $woocommerce; - $order = new WC_Order($order_id); - $error = $payment_intent['error']; - $order->add_order_note(__('Unable to Create Hyperswitch Payment Intent.', 'hyperswitch-checkout')); - $order->add_order_note('Error: ' . $error); - $this->post_log("WC_FAILED_TO_CREATE_PAYMENT_INTENT", $error); - if (function_exists('wc_add_notice')) { - wc_add_notice(__("Something went wrong. Please contact support for assistance.", 'hyperswitch-checkout'), 'error'); - - } else { - $woocommerce->add_error(__("Something went wrong. Please contact support for assistance.", 'hyperswitch-checkout')); - $woocommerce->set_messages(); - } - $redirect_url = get_permalink(woocommerce_get_page_id('cart')); - return array( - "redirect_url" => $redirect_url - ); - } - } - - function create_payment_intent($order_id, $client_secret = null) - { - global $woocommerce; - $order = wc_get_order($order_id); - $apiKey = $this->get_option('api_key'); - $publishable_key = $this->get_option('publishable_key'); - if (isset($client_secret)) { - $payment_id = ""; - $parts = explode("_secret", $client_secret); - if (count($parts) === 2) { - $payment_id = $parts[0]; - } - $url = $this->hyperswitch_url . "/payments/" . $payment_id; - } else { - $url = $this->hyperswitch_url . "/payments"; - } - - $payload = array(); - $currency = get_woocommerce_currency(); - $amount = (int) ($woocommerce->cart->total * 100); - $billing = array("phone" => null, "address" => null); - $shipping = array("phone" => null, "address" => null); - $return_url = $this->notify_url; - $capture_method = $this->get_option('capture_method'); - if ($order) { - $amount = (int) ($order->get_total() * 100); - //billing details - $billing_city = $order->get_billing_city(); - $billing_state = $order->get_billing_state(); - $billing_country = $order->get_billing_country(); - $billing_zip = $order->get_billing_postcode(); - $billing_first_name = $order->get_billing_first_name(); - $billing_last_name = $order->get_billing_last_name(); - $billing_line1 = $order->get_billing_address_1(); - $billing_line2 = $order->get_billing_address_2(); - $billing_phone = $order->get_billing_phone(); - //shipping details - $shipping_city = $order->get_shipping_city(); - $shipping_state = $order->get_shipping_state(); - $shipping_country = $order->get_shipping_country(); - $shipping_zip = $order->get_shipping_postcode(); - $shipping_first_name = $order->get_shipping_first_name(); - $shipping_last_name = $order->get_shipping_last_name(); - $shipping_line1 = $order->get_shipping_address_1(); - $shipping_line2 = $order->get_shipping_address_2(); - $shipping_phone = $order->get_shipping_phone(); - - $currency = $order->get_currency(); - $phone = $order->get_billing_phone(); - $email = $order->get_billing_email(); - - $order_details = array(); - foreach ($order->get_items() as $item) { - $product = wc_get_product($item->get_product_id()); - $order_details[] = array( - "product_name" => $item->get_name(), - "quantity" => (int) ($item->get_quantity()), - "amount" => (int) ($product->get_price() * 100) - ); - } - $order_note = $order->get_customer_note(); - $billing_address = array( - "city" => $billing_city, - "state" => $billing_state, - "country" => $billing_country, - "zip" => $billing_zip, - "first_name" => $billing_first_name, - "last_name" => $billing_last_name, - "line1" => $billing_line1, - "line2" => $billing_line2 - ); - - $billing_phone = array( - "number" => $billing_phone - ); - - $shipping_address = array( - "city" => strlen(str_replace($shipping_city, '"', '')) > 0 ? $shipping_city : $billing_city, - "state" => strlen(str_replace($shipping_state, '"', '')) > 0 ? $shipping_state : $billing_state, - "country" => strlen(str_replace($shipping_country, '"', '')) > 0 ? $shipping_country : $billing_country, - "zip" => strlen(str_replace($shipping_zip, '"', '')) > 0 ? $shipping_zip : $billing_zip, - "first_name" => strlen(str_replace($shipping_first_name, '"', '')) > 0 ? $shipping_first_name : $billing_first_name, - "last_name" => strlen(str_replace($shipping_last_name, '"', '')) > 0 ? $shipping_last_name : $billing_last_name, - "line1" => strlen(str_replace($shipping_line1, '"', '')) > 0 ? $shipping_line1 : $billing_line1, - "line2" => strlen(str_replace($shipping_line2, '"', '')) > 0 ? $shipping_line2 : $billing_line2 - ); - - if (strlen(str_replace($shipping_phone, '"', '')) > 0) { - $shipping_phone = array( - "phone" => $shipping_phone - ); - } else { - $shipping_phone = $billing_phone; - } - - $billing = array( - "address" => $billing_address, - "phone" => $billing_phone - ); - - $shipping = array( - "address" => $shipping_address, - "phone" => $shipping_phone - ); - } - - $customer = wp_get_current_user(); - if ($customer->ID === 0) { - $customer_id = "guest"; - $customer_id_hash = substr(hash_hmac('sha512', $customer_id, time() . "" . $publishable_key), 0, 16); - $customer_id = "guest_" . $customer_id_hash; - } else { - $customer_id = $customer->ID . ""; - $customer_registered = $customer->user_registered; - $customer_id_hash = substr(hash_hmac('sha512', $customer_id, $customer_registered . "" . $publishable_key), 0, 16); - $customer_id = "cust_" . $customer_id_hash; - } - - $customer_created = true; - $customer_logged_in = str_starts_with($customer_id, "cust"); - - $metadata = array( - "customer_created" => $customer_created, - "customer_logged_in" => $customer_logged_in, - ); - - if ($order) { - $metadata["order_num"] = $order_id; - $metadata["customer_note"] = $order_note; - $payload["email"] = $email; - $payload["name"] = $billing_first_name . " " . $billing_last_name; - $payload["phone"] = $phone; - $payload["order_details"] = $order_details; - } - $payload["customer_id"] = $customer_id; - $payload["metadata"] = $metadata; - $payload["return_url"] = $return_url; - $payload["shipping"] = $shipping; - $payload["billing"] = $billing; - $payload["capture_method"] = $capture_method; - $payload["amount"] = $amount; - $payload["currency"] = $currency; - - $args = array( - 'body' => wp_json_encode($payload), - 'timeout' => 45, - 'redirection' => 5, - 'httpversion' => 1.0, - 'blocking' => true, - 'data_format' => 'body', - 'headers' => array( - 'Content-Type' => 'application/json', - 'api-key' => $apiKey - ) - ); - - $response = wp_remote_retrieve_body(wp_remote_post($url, $args)); - - // Parse the 'client_secret' key from the response - $responseData = json_decode($response, true); - $clientSecret = isset($responseData['client_secret']) ? $responseData['client_secret'] : null; - $paymentId = isset($responseData['payment_id']) ? $responseData['payment_id'] : null; - $error = isset($responseData['error']) ? $responseData['error'] : null; - return array( - "clientSecret" => $clientSecret, - "paymentId" => $paymentId, - "error" => json_encode($error), - "body" => wp_json_encode($payload), - ); - } - - function retrieve_payment_intent($payment_id) - { - $apiKey = $this->get_option('api_key'); - - $url = $this->hyperswitch_url . "/payments/" . $payment_id; - - $args = array( - 'timeout' => 45, - 'redirection' => 5, - 'httpversion' => 1.0, - 'blocking' => true, - 'headers' => array( - 'Content-Type' => 'application/json', - 'api-key' => $apiKey - ) - ); - - // Execute the request - $response = wp_remote_retrieve_body(wp_remote_get($url, $args)); - - return json_decode($response, true); - } - - public function create_customer($customer_id, $name, $email) - { - $apiKey = $this->get_option('api_key'); - - $url = $this->hyperswitch_url . "/customers"; - $payload = array( - "customer_id" => $customer_id, - "email" => $email, - "name" => $name, - "description" => __("Customer created via Woocommerce Application", 'hyperswitch-checkout') - ); - $args = array( - 'body' => wp_json_encode($payload), - 'timeout' => 45, - 'redirection' => 5, - 'httpversion' => 1.0, - 'blocking' => true, - 'data_format' => 'body', - 'headers' => array( - 'Content-Type' => 'application/json', - 'api-key' => $apiKey - ) - ); - - $response = wp_remote_retrieve_body(wp_remote_post($url, $args)); - return json_decode($response, true); - } - - public function post_log($event_name, $value = null, $payment_id = null) - { - $publishable_key = $this->get_option('publishable_key'); - - switch ($this->environment) { - case "sandbox": - $url = "https://sandbox.hyperswitch.io/logs/sdk"; - break; - case "production": - $url = "https://api.hyperswitch.io/logs/sdk"; - break; - default: - $url = "https://sandbox.hyperswitch.io/logs/sdk"; - break; - } - - if (str_contains($event_name, "ERROR")) { - $log_type = "ERROR"; - } else { - $log_type = "INFO"; - } - - $payload = array( - "merchant_id" => $publishable_key, - "event_name" => $event_name, - "component" => "PLUGIN", - "version" => HYPERSWITCH_CHECKOUT_PLUGIN_VERSION, - "source" => "WORDPRESS", - "log_type" => $log_type, - "log_category" => "MERCHANT_EVENT", - "timestamp" => floor(microtime(true) * 1000) . "" - ); - - if (isset($payment_id)) { - $payload["payment_id"] = $payment_id; - } - - if (isset($value)) { - $payload["value"] = $value; - } - - $data = array( - "data" => [$payload] - ); - - $args = array( - 'body' => wp_json_encode($data), - 'timeout' => 45, - 'redirection' => 5, - 'httpversion' => 1.0, - 'blocking' => false, - 'data_format' => 'body', - 'headers' => array( - 'Content-Type' => 'application/json' - ) - ); - - $response = wp_remote_retrieve_body(wp_remote_post($url, $args)); - return json_decode($response, true); - } - - public function manual_capture($payment_id) - { - $apiKey = $this->get_option('api_key'); - - $url = $this->hyperswitch_url . "/payments/" . $payment_id . "/capture"; - - // Execute the request - $args = array( - 'timeout' => 45, - 'redirection' => 5, - 'httpversion' => 1.0, - 'blocking' => false, - 'headers' => array( - 'Content-Type' => 'application/json', - 'api-key' => $apiKey - ) - ); - - $response = wp_remote_retrieve_body(wp_remote_post($url, $args)); - return json_decode($response, true); - } - - public function create_refund($payment_id, $amount, $reason, $refund_num, $order_id) - { - $apiKey = $this->get_option('api_key'); - - $url = $this->hyperswitch_url . "/refunds"; - - $metadata = array( - "refund_num" => $refund_num, - "order_num" => $order_id - ); - - $payload = array( - "payment_id" => $payment_id, - "amount" => ((int) $amount * 100), - "reason" => $reason, - "refund_type" => "instant", - "metadata" => $metadata - ); - - // Execute the request - $args = array( - 'body' => wp_json_encode($payload), - 'timeout' => 45, - 'redirection' => 5, - 'httpversion' => 1.0, - 'blocking' => false, - 'data_format' => 'body', - 'headers' => array( - 'Content-Type' => 'application/json', - 'api-key' => $apiKey - ) - ); - - $response = wp_remote_retrieve_body(wp_remote_post($url, $args)); - - return json_decode($response, true); - } - - /** - * Process the payment and return the result - **/ - function process_payment($order_id) - { - // $nonce = $_POST['woocommerce-process-checkout-nonce']; - // if (!wp_verify_nonce($nonce, 'woocommerce-process_checkout')) { - // return array('result' => 'failure', 'nonce' => 'failed'); - // } - $order = new WC_Order($order_id); - return array('result' => 'success', 'redirect' => $order->get_checkout_payment_url(true)); - } - - public function check_hyperswitch_response() - { - - global $woocommerce; - $payment_id = $_GET['payment_id']; - - $msg['class'] = 'error'; - $msg['message'] = "Thank you for shopping with us. However, the transaction has been declined."; - - $paymentResponse = $this->retrieve_payment_intent($payment_id); - $status = $paymentResponse['status']; - $payment_method = $paymentResponse['payment_method']; - $intermediate_status = array("processing", "requires_merchant_action", "requires_customer_action", "requires_confirmation", "requires_capture"); - $order_num = ($paymentResponse['metadata'])['order_num']; - $order = new WC_Order($order_num); - if ($status == 'succeeded') { - $msg['class'] = 'success'; - $order->payment_complete($payment_id); - $order->add_order_note('Payment successful via ' . $payment_method . ' (Hyperswitch Payment ID: ' . $payment_id . ')'); - $woocommerce->cart->empty_cart(); - $this->post_log("WC_ORDER_PLACED", null, $payment_id); - } else if (in_array($status, $intermediate_status)) { - $original_status = $order->status; - if ($status == 'requires_capture') { - $order->add_order_note('Payment authorized via ' . $payment_method . ' (Hyperswitch Payment ID: ' . $payment_id . '). Note: Requires Capture'); - } else { - $order->add_order_note('Payment processing via ' . $payment_method . ' (Hyperswitch Payment ID: ' . $payment_id . ')'); - } - $order->set_transaction_id($payment_id); - $order->update_status($this->processing_payment_order_status); - $woocommerce->cart->empty_cart(); - $msg['class'] = 'success'; - $this->post_log("WC_ORDER_ON_HOLD", $status, $payment_id); - } else { - $errorMessage = $paymentResponse['error']['message'] ?? $paymentResponse['error_code'] ?? "NA"; - $order->add_order_note('Payment failed via ' . $payment_method . ' (Hyperswitch Payment ID: ' . $payment_id . ') with error message: ' . $errorMessage); - $order->update_status('pending'); - $msg['class'] = 'error'; - $msg['message'] = "Thank you for shopping with us. However, the payment has failed. Please retry the payment."; - $this->post_log("WC_ERROR_IN_PLACING_ORDER", $errorMessage, $payment_id); - } - - if ($paymentResponse['capture_method'] === "automatic") { - $order->update_meta_data('payment_captured', 'yes'); - } - - if ($msg['class'] != 'success') { - if (function_exists('wc_add_notice')) { - wc_add_notice(__($msg['message'], 'hyperswitch-checkout'), $msg['class']); - - } else { - $woocommerce->add_error(__($msg['message'], 'hyperswitch-checkout')); - $woocommerce->set_messages(); - } - } - - if ($msg['class'] == 'success') { - $redirect_url = $this->get_return_url($order); - } else { - $redirect_url = get_permalink(woocommerce_get_page_id('cart')); - } - $order->save(); - wp_redirect($redirect_url); - exit; - } - } - - function hyperswitch_add_payment_class($gateways) - { - $gateways[] = 'Hyperswitch_Checkout'; - return $gateways; - } - - add_filter('woocommerce_payment_gateways', 'hyperswitch_add_payment_class'); + return array( + "payment_sheet" => $return_html + ); + } else { + global $woocommerce; + $order = new WC_Order( $order_id ); + $error = $payment_intent['error']; + $order->add_order_note( __( 'Unable to Create Hyperswitch Payment Intent.', 'hyperswitch-checkout' ) ); + $order->add_order_note( 'Error: ' . $error ); + $this->post_log( "WC_FAILED_TO_CREATE_PAYMENT_INTENT", $error ); + if ( function_exists( 'wc_add_notice' ) ) { + wc_add_notice( __( "Something went wrong. Please contact support for assistance.", 'hyperswitch-checkout' ), 'error' ); + + } else { + $woocommerce->add_error( __( "Something went wrong. Please contact support for assistance.", 'hyperswitch-checkout' ) ); + $woocommerce->set_messages(); + } + $redirect_url = get_permalink( woocommerce_get_page_id( 'cart' ) ); + return array( + "redirect_url" => $redirect_url + ); + } + } + + function create_payment_intent( $order_id, $client_secret = null ) { + global $woocommerce; + $order = wc_get_order( $order_id ); + $apiKey = $this->get_option( 'api_key' ); + $publishable_key = $this->get_option( 'publishable_key' ); + if ( isset ( $client_secret ) ) { + $payment_id = ""; + $parts = explode( "_secret", $client_secret ); + if ( count( $parts ) === 2 ) { + $payment_id = $parts[0]; + } + $url = $this->hyperswitch_url . "/payments/" . $payment_id; + } else { + $url = $this->hyperswitch_url . "/payments"; + } + + $payload = array(); + $currency = get_woocommerce_currency(); + $amount = (int) ( $woocommerce->cart->total * 100 ); + $billing = array( "phone" => null, "address" => null ); + $shipping = array( "phone" => null, "address" => null ); + $return_url = $this->notify_url; + $capture_method = $this->get_option( 'capture_method' ); + if ( $order ) { + $amount = (int) ( $order->get_total() * 100 ); + //billing details + $billing_city = $order->get_billing_city(); + $billing_state = $order->get_billing_state(); + $billing_country = $order->get_billing_country(); + $billing_zip = $order->get_billing_postcode(); + $billing_first_name = $order->get_billing_first_name(); + $billing_last_name = $order->get_billing_last_name(); + $billing_line1 = $order->get_billing_address_1(); + $billing_line2 = $order->get_billing_address_2(); + $billing_phone = $order->get_billing_phone(); + //shipping details + $shipping_city = $order->get_shipping_city(); + $shipping_state = $order->get_shipping_state(); + $shipping_country = $order->get_shipping_country(); + $shipping_zip = $order->get_shipping_postcode(); + $shipping_first_name = $order->get_shipping_first_name(); + $shipping_last_name = $order->get_shipping_last_name(); + $shipping_line1 = $order->get_shipping_address_1(); + $shipping_line2 = $order->get_shipping_address_2(); + $shipping_phone = $order->get_shipping_phone(); + + $currency = $order->get_currency(); + $phone = $order->get_billing_phone(); + $email = $order->get_billing_email(); + + $order_details = array(); + foreach ( $order->get_items() as $item ) { + $product = wc_get_product( $item->get_product_id() ); + $order_details[] = array( + "product_name" => $item->get_name(), + "quantity" => (int) ( $item->get_quantity() ), + "amount" => (int) ( $product->get_price() * 100 ) + ); + } + $order_note = $order->get_customer_note(); + $billing_address = array( + "city" => $billing_city, + "state" => $billing_state, + "country" => $billing_country, + "zip" => $billing_zip, + "first_name" => $billing_first_name, + "last_name" => $billing_last_name, + "line1" => $billing_line1, + "line2" => $billing_line2 + ); + + $billing_phone = array( + "number" => $billing_phone + ); + + $shipping_address = array( + "city" => strlen( str_replace( $shipping_city, '"', '' ) ) > 0 ? $shipping_city : $billing_city, + "state" => strlen( str_replace( $shipping_state, '"', '' ) ) > 0 ? $shipping_state : $billing_state, + "country" => strlen( str_replace( $shipping_country, '"', '' ) ) > 0 ? $shipping_country : $billing_country, + "zip" => strlen( str_replace( $shipping_zip, '"', '' ) ) > 0 ? $shipping_zip : $billing_zip, + "first_name" => strlen( str_replace( $shipping_first_name, '"', '' ) ) > 0 ? $shipping_first_name : $billing_first_name, + "last_name" => strlen( str_replace( $shipping_last_name, '"', '' ) ) > 0 ? $shipping_last_name : $billing_last_name, + "line1" => strlen( str_replace( $shipping_line1, '"', '' ) ) > 0 ? $shipping_line1 : $billing_line1, + "line2" => strlen( str_replace( $shipping_line2, '"', '' ) ) > 0 ? $shipping_line2 : $billing_line2 + ); + + if ( strlen( str_replace( $shipping_phone, '"', '' ) ) > 0 ) { + $shipping_phone = array( + "phone" => $shipping_phone + ); + } else { + $shipping_phone = $billing_phone; + } + + $billing = array( + "address" => $billing_address, + "phone" => $billing_phone + ); + + $shipping = array( + "address" => $shipping_address, + "phone" => $shipping_phone + ); + } + + $customer = wp_get_current_user(); + if ( $customer->ID === 0 ) { + $customer_id = "guest"; + $customer_id_hash = substr( hash_hmac( 'sha512', $customer_id, time() . "" . $publishable_key ), 0, 16 ); + $customer_id = "guest_" . $customer_id_hash; + $customer_logged_in = false; + } else { + $customer_id = $customer->ID . ""; + $customer_registered = $customer->user_registered; + $customer_id_hash = substr( hash_hmac( 'sha512', $customer_id, $customer_registered . "" . $publishable_key ), 0, 16 ); + $customer_id = "cust_" . $customer_id_hash; + $payload["customer_id"] = $customer_id; + $customer_logged_in = true; + } + + + $metadata = array( + "customer_logged_in" => $customer_logged_in, + ); + + if ( $order ) { + $metadata["order_num"] = $order_id; + $metadata["customer_note"] = $order_note; + $payload["email"] = $email; + $payload["name"] = $billing_first_name . " " . $billing_last_name; + $payload["phone"] = $phone; + $payload["order_details"] = $order_details; + } + $payload["metadata"] = $metadata; + $payload["return_url"] = $return_url; + $payload["shipping"] = $shipping; + $payload["billing"] = $billing; + $payload["capture_method"] = $capture_method; + $payload["amount"] = $amount; + $payload["currency"] = $currency; + + $args = array( + 'body' => wp_json_encode( $payload ), + 'timeout' => 45, + 'redirection' => 5, + 'httpversion' => 1.0, + 'blocking' => true, + 'data_format' => 'body', + 'headers' => array( + 'Content-Type' => 'application/json', + 'api-key' => $apiKey + ) + ); + + $response = wp_remote_retrieve_body( wp_remote_post( $url, $args ) ); + + // Parse the 'client_secret' key from the response + $responseData = json_decode( $response, true ); + $clientSecret = isset ( $responseData['client_secret'] ) ? $responseData['client_secret'] : null; + $paymentId = isset ( $responseData['payment_id'] ) ? $responseData['payment_id'] : null; + $error = isset ( $responseData['error'] ) ? $responseData['error'] : null; + return array( + "clientSecret" => $clientSecret, + "paymentId" => $paymentId, + "error" => json_encode( $error ), + "body" => wp_json_encode( $payload ), + ); + } + + function retrieve_payment_intent( $payment_id ) { + $apiKey = $this->get_option( 'api_key' ); + + $url = $this->hyperswitch_url . "/payments/" . $payment_id; + + $args = array( + 'timeout' => 45, + 'redirection' => 5, + 'httpversion' => 1.0, + 'blocking' => true, + 'headers' => array( + 'Content-Type' => 'application/json', + 'api-key' => $apiKey + ) + ); + + // Execute the request + $response = wp_remote_retrieve_body( wp_remote_get( $url, $args ) ); + + return json_decode( $response, true ); + } + + public function create_customer( $customer_id, $name, $email ) { + $apiKey = $this->get_option( 'api_key' ); + + $url = $this->hyperswitch_url . "/customers"; + $payload = array( + "customer_id" => $customer_id, + "email" => $email, + "name" => $name, + "description" => __( "Customer created via Woocommerce Application", 'hyperswitch-checkout' ) + ); + $args = array( + 'body' => wp_json_encode( $payload ), + 'timeout' => 45, + 'redirection' => 5, + 'httpversion' => 1.0, + 'blocking' => true, + 'data_format' => 'body', + 'headers' => array( + 'Content-Type' => 'application/json', + 'api-key' => $apiKey + ) + ); + + $response = wp_remote_retrieve_body( wp_remote_post( $url, $args ) ); + return json_decode( $response, true ); + } + + public function post_log( $event_name, $value = null, $payment_id = null ) { + $publishable_key = $this->get_option( 'publishable_key' ); + + switch ( $this->environment ) { + case "sandbox": + $url = "https://sandbox.hyperswitch.io/logs/sdk"; + break; + case "production": + $url = "https://api.hyperswitch.io/logs/sdk"; + break; + default: + $url = "https://sandbox.hyperswitch.io/logs/sdk"; + break; + } + + if ( str_contains( $event_name, "ERROR" ) ) { + $log_type = "ERROR"; + } else { + $log_type = "INFO"; + } + + $payload = array( + "merchant_id" => $publishable_key, + "event_name" => $event_name, + "component" => "PLUGIN", + "version" => HYPERSWITCH_CHECKOUT_PLUGIN_VERSION, + "source" => "WORDPRESS", + "log_type" => $log_type, + "log_category" => "MERCHANT_EVENT", + "timestamp" => floor( microtime( true ) * 1000 ) . "" + ); + + if ( isset ( $payment_id ) ) { + $payload["payment_id"] = $payment_id; + } + + if ( isset ( $value ) ) { + $payload["value"] = $value; + } + + $args = array( + 'body' => wp_json_encode( $payload ), + 'timeout' => 45, + 'redirection' => 5, + 'httpversion' => 1.0, + 'blocking' => false, + 'data_format' => 'body', + 'headers' => array( + 'Content-Type' => 'application/json' + ) + ); + + $response = wp_remote_retrieve_body( wp_remote_post( $url, $args ) ); + return json_decode( $response, true ); + } + + public function manual_capture( $payment_id ) { + $apiKey = $this->get_option( 'api_key' ); + + $url = $this->hyperswitch_url . "/payments/" . $payment_id . "/capture"; + + // Execute the request + $args = array( + 'timeout' => 45, + 'redirection' => 5, + 'httpversion' => 1.0, + 'blocking' => false, + 'headers' => array( + 'Content-Type' => 'application/json', + 'api-key' => $apiKey + ) + ); + + $response = wp_remote_retrieve_body( wp_remote_post( $url, $args ) ); + return json_decode( $response, true ); + } + + public function create_refund( $payment_id, $amount, $reason, $refund_num, $order_id ) { + $apiKey = $this->get_option( 'api_key' ); + + $url = $this->hyperswitch_url . "/refunds"; + + $metadata = array( + "refund_num" => $refund_num, + "order_num" => $order_id + ); + + $payload = array( + "payment_id" => $payment_id, + "amount" => ( (int) $amount * 100 ), + "reason" => $reason, + "refund_type" => "instant", + "metadata" => $metadata + ); + + // Execute the request + $args = array( + 'body' => wp_json_encode( $payload ), + 'timeout' => 45, + 'redirection' => 5, + 'httpversion' => 1.0, + 'blocking' => false, + 'data_format' => 'body', + 'headers' => array( + 'Content-Type' => 'application/json', + 'api-key' => $apiKey + ) + ); + + $response = wp_remote_retrieve_body( wp_remote_post( $url, $args ) ); + + return json_decode( $response, true ); + } + + /** + * Process the payment and return the result + **/ + function process_payment( $order_id ) { + // $nonce = $_POST['woocommerce-process-checkout-nonce']; + // if (!wp_verify_nonce($nonce, 'woocommerce-process_checkout')) { + // return array('result' => 'failure', 'nonce' => 'failed'); + // } + $order = new WC_Order( $order_id ); + return array( 'result' => 'success', 'redirect' => $order->get_checkout_payment_url( true ) ); + } + + public function check_hyperswitch_response() { + + global $woocommerce; + $payment_id = $_GET['payment_id']; + + $msg['class'] = 'error'; + $msg['message'] = "Thank you for shopping with us. However, the transaction has been declined."; + + $paymentResponse = $this->retrieve_payment_intent( $payment_id ); + $status = $paymentResponse['status']; + $payment_method = $paymentResponse['payment_method']; + $intermediate_status = array( "processing", "requires_merchant_action", "requires_customer_action", "requires_confirmation", "requires_capture" ); + $order_num = ( $paymentResponse['metadata'] )['order_num']; + $order = new WC_Order( $order_num ); + if ( $status == 'succeeded' ) { + $msg['class'] = 'success'; + $order->payment_complete( $payment_id ); + $order->add_order_note( 'Payment successful via ' . $payment_method . ' (Hyperswitch Payment ID: ' . $payment_id . ')' ); + $woocommerce->cart->empty_cart(); + $this->post_log( "WC_ORDER_PLACED", null, $payment_id ); + } else if ( in_array( $status, $intermediate_status ) ) { + $original_status = $order->status; + if ( $status == 'requires_capture' ) { + $order->add_order_note( 'Payment authorized via ' . $payment_method . ' (Hyperswitch Payment ID: ' . $payment_id . '). Note: Requires Capture' ); + } else { + $order->add_order_note( 'Payment processing via ' . $payment_method . ' (Hyperswitch Payment ID: ' . $payment_id . ')' ); + } + $order->set_transaction_id( $payment_id ); + $order->update_status( $this->processing_payment_order_status ); + $woocommerce->cart->empty_cart(); + $msg['class'] = 'success'; + $this->post_log( "WC_ORDER_ON_HOLD", $status, $payment_id ); + } else { + $errorMessage = $paymentResponse['error']['message'] ?? $paymentResponse['error_code'] ?? "NA"; + $order->add_order_note( 'Payment failed via ' . $payment_method . ' (Hyperswitch Payment ID: ' . $payment_id . ') with error message: ' . $errorMessage ); + $order->update_status( 'pending' ); + $msg['class'] = 'error'; + $msg['message'] = "Thank you for shopping with us. However, the payment has failed. Please retry the payment."; + $this->post_log( "WC_ERROR_IN_PLACING_ORDER", $errorMessage, $payment_id ); + } + + if ( $paymentResponse['capture_method'] === "automatic" ) { + $order->update_meta_data( 'payment_captured', 'yes' ); + } + + if ( $msg['class'] != 'success' ) { + if ( function_exists( 'wc_add_notice' ) ) { + wc_add_notice( __( $msg['message'], 'hyperswitch-checkout' ), $msg['class'] ); + + } else { + $woocommerce->add_error( __( $msg['message'], 'hyperswitch-checkout' ) ); + $woocommerce->set_messages(); + } + } + + if ( $msg['class'] == 'success' ) { + $redirect_url = $this->get_return_url( $order ); + } else { + $redirect_url = get_permalink( woocommerce_get_page_id( 'cart' ) ); + } + $order->save(); + wp_redirect( $redirect_url ); + exit; + } + } + + function hyperswitch_add_payment_class( $gateways ) { + $gateways[] = 'Hyperswitch_Checkout'; + return $gateways; + } + + add_filter( 'woocommerce_payment_gateways', 'hyperswitch_add_payment_class' ); } // This is set to a priority of 10 -function hyperswitch_webhook_init() -{ - $hyperswitchWebhook = new Hyperswitch_Webhook(); - $hyperswitchWebhook->process(); +function hyperswitch_webhook_init() { + $hyperswitchWebhook = new Hyperswitch_Webhook(); + $hyperswitchWebhook->process(); } -function hyperswitch_create_or_update_payment_intent() -{ - $nonce = $_POST['wc_nonce']; - if (!wp_verify_nonce($nonce, 'woocommerce-process_checkout')) { - wp_send_json( - array( - "messages" => __("Something went wrong. Please try again or reload the page.", 'hyperswitch-checkout') - ) - ); - } else { - $hyperswitch = new Hyperswitch_Checkout(); - $order_id = $_POST['order_id']; - $client_secret = $_POST['client_secret']; - if (!isset($client_secret)) { - $hyperswitch->post_log("WC_ORDER_CREATE", null, $order_id); - } else { - $payment_id = ""; - $parts = explode("_secret", $client_secret); - if (count($parts) === 2) { - $payment_id = $parts[0]; - } - $hyperswitch->post_log("WC_ORDER_UPDATE", $payment_id, $order_id); - } - $payment_sheet = $hyperswitch->render_payment_sheet($order_id, $client_secret); - if (isset($payment_sheet['payment_sheet'])) { - $hyperswitch->post_log("WC_CHECKOUT_INITIATED", $order_id, $order_id); - wp_send_json( - array( - "order_id" => $order_id, - "payment_sheet" => $payment_sheet['payment_sheet'] - ) - ); - } else { - $hyperswitch->post_log("WC_INTEGRATION_ERROR", $order_id, $order_id); - wp_send_json( - array( - "order_id" => $order_id, - "redirect" => $payment_sheet['redirect_url'] - ) - ); - } - } +function hyperswitch_create_or_update_payment_intent() { + $nonce = $_POST['wc_nonce']; + if ( ! wp_verify_nonce( $nonce, 'woocommerce-process_checkout' ) ) { + wp_send_json( + array( + "messages" => __( "Something went wrong. Please try again or reload the page.", 'hyperswitch-checkout' ) + ) + ); + } else { + $hyperswitch = new Hyperswitch_Checkout(); + $order_id = $_POST['order_id']; + $client_secret = $_POST['client_secret']; + if ( ! isset ( $client_secret ) ) { + $hyperswitch->post_log( "WC_ORDER_CREATE", null, $order_id ); + } else { + $payment_id = ""; + $parts = explode( "_secret", $client_secret ); + if ( count( $parts ) === 2 ) { + $payment_id = $parts[0]; + } + $hyperswitch->post_log( "WC_ORDER_UPDATE", $payment_id, $order_id ); + } + $payment_sheet = $hyperswitch->render_payment_sheet( $order_id, $client_secret ); + if ( isset ( $payment_sheet['payment_sheet'] ) ) { + $hyperswitch->post_log( "WC_CHECKOUT_INITIATED", $order_id, $order_id ); + wp_send_json( + array( + "order_id" => $order_id, + "payment_sheet" => $payment_sheet['payment_sheet'] + ) + ); + } else { + $hyperswitch->post_log( "WC_INTEGRATION_ERROR", $order_id, $order_id ); + wp_send_json( + array( + "order_id" => $order_id, + "redirect" => $payment_sheet['redirect_url'] + ) + ); + } + } } -function hyperswitch_declare_compatibility() -{ - if (class_exists('\Automattic\WooCommerce\Utilities\FeaturesUtil')) { - \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility('custom_order_tables', __FILE__, true); - \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility('cart_checkout_blocks', __FILE__, true); - } +function hyperswitch_declare_compatibility() { + if ( class_exists( '\Automattic\WooCommerce\Utilities\FeaturesUtil' ) ) { + \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'custom_order_tables', __FILE__, true ); + \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'cart_checkout_blocks', __FILE__, true ); + } } -function woocommerce_gateway_hyperswitch_woocommerce_block_support() -{ - if (class_exists('Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType')) { - require_once __DIR__ . '/includes/hyperswitch-wc-blocks-support.php'; - add_action( - 'woocommerce_blocks_payment_method_type_registration', - function (Automattic\WooCommerce\Blocks\Payments\PaymentMethodRegistry $payment_method_registry) { - $payment_method_registry->register(new Hyperswitch_Checkout_Blocks); - }, - 5 - ); - } +function woocommerce_gateway_hyperswitch_woocommerce_block_support() { + if ( class_exists( 'Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType' ) ) { + require_once __DIR__ . '/includes/hyperswitch-wc-blocks-support.php'; + add_action( + 'woocommerce_blocks_payment_method_type_registration', + function (Automattic\WooCommerce\Blocks\Payments\PaymentMethodRegistry $payment_method_registry) { + $payment_method_registry->register( new Hyperswitch_Checkout_Blocks ); + }, + 5 + ); + } } \ No newline at end of file diff --git a/includes/hyperswitch-webhook.php b/includes/hyperswitch-webhook.php index 141aafe..05efad5 100644 --- a/includes/hyperswitch-webhook.php +++ b/includes/hyperswitch-webhook.php @@ -1,200 +1,193 @@ hyperswitch = new Hyperswitch_Checkout(); - - } - - public function process() - { - if ($_SERVER['REQUEST_METHOD'] === 'POST') { - $raw_post_data = file_get_contents('php://input'); - if (!empty($raw_post_data)) { - $data = json_decode($raw_post_data, true); - - $signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE_512']; - - - if (json_last_error() !== 0) { - return; - } - - $enabled = $this->hyperswitch->get_option('enable_webhook'); - - if (($enabled === 'yes') and (empty($data['event_type']) === false)) { - // Skip the webhook if webhooks are disabled, or the event type is unrecognised - $payment_id = $data['content']['object']['payment_id']; - $this->hyperswitch->post_log("WC_WEBHOOK_RECEIVED", $data['event_type'], $payment_id); - if ($this->shouldConsumeWebhook($data, $signature, $raw_post_data) === false) { - return; - } - switch ($data['event_type']) { - case self::PAYMENT_SUCCEEDED: - return $this->paymentAuthorized($data); - - case self::PAYMENT_FAILED: - return $this->paymentHandle($data, "failed"); - - case self::PAYMENT_PROCESSING: - return $this->paymentHandle($data, "processing"); - - case self::ACTION_REQURIED: - return $this->paymentHandle($data, "action required"); - - case self::REFUND_SUCCEEDED: - return $this->refundedCreated($data); - - default: - return; - } - } - } - } - } - - protected function paymentAuthorized(array $data) - { - - $order_id = $data['content']['object']['metadata']['order_num']; - - $order = wc_get_order($order_id); - - if ($order) { - $payment_id = $data['content']['object']['payment_id']; - $payment_method = $data['content']['object']['payment_method']; - if ($order->status !== 'processing') { - $this->hyperswitch->post_log("WC_ORDER_PLACED", null, $payment_id); - } - $order->payment_complete($payment_id); - $order->add_order_note('Payment successful via ' . $payment_method . ' (Hyperswitch Payment ID: ' . $payment_id . ') (via Hyperswitch Webhook)'); - if ($data['object']['capture_method'] === "automatic") { - $order->update_meta_data('payment_captured', 'yes'); - } - $this->hyperswitch->post_log("WC_PAYMENT_SUCCEEDED_WEBHOOK", null, $payment_id); - - } else { - exit; // Not a Woocommerce Order - } - - exit; - } - - protected function paymentHandle(array $data, $status) - { - - $order_id = $data['content']['object']['metadata']['order_num']; - - $order = wc_get_order($order_id); - - if ($order) { - $payment_id = $data['content']['object']['payment_id']; - $payment_method = $data['content']['object']['payment_method']; - $order->set_transaction_id($payment_id); - if ($status == 'processing') { - $order->update_status($this->hyperswitch->processing_payment_order_status); - } else { - $order->update_status('pending'); - } - $order->add_order_note('Payment ' . $status . ' via ' . $payment_method . ' (Hyperswitch Payment ID: ' . $payment_id . ') (via Hyperswitch Webhook)'); - $this->hyperswitch->post_log("WC_PAYMENT_" . str_replace(" ", "_", strtoupper($status)) . "_WEBHOOK", null, $payment_id); - } - - exit; - } - - protected function refundedCreated(array $data) - { - $payment_id = $data['content']['object']['payment_id']; - if (isset($data['content']['object']['metadata']['order_num'])) { - $order_id = $data['content']['object']['metadata']['order_num']; - } else { - $payment_intent = $this->hyperswitch->retrieve_payment_intent($payment_id); - $order_id = $payment_intent['metadata']['order_num']; - } - $refund_num = $data['content']['object']['metadata']['refund_num']; - $refund_id = $data['content']['object']['refund_id']; - - $order = wc_get_order($order_id); - if ($order) { - $refunds = $order->get_refunds(); - $targetRefund = null; - if (isset($refund_num)) { - foreach ($refunds as $refund) { - if ($refund->id == $refund_num) { - $targetRefund = $refund; - break; - } - } - } - if (!isset($targetRefund)) { // Refund initiated via Hyperswitch Dashboard - $refund = new WC_Order_Refund; - $amount = $data['content']['object']['amount']; - $reason = $data['content']['object']['reason']; - $refund->set_amount((float) $amount / 100); - $refund->set_reason($reason); - } - $order->add_order_note('Refund Successful (Hyperswitch Refund ID: ' . $refund_id . ') (via Hyperswitch Webhook)'); - $refund->set_refunded_payment(true); - } else { - exit; // Not a refund for a Woocommerce Order - } - // Graceful exit since payment is now refunded. - exit; - } - - - protected function shouldConsumeWebhook($data, $signature, $payload) - { - $webhook_key = $this->hyperswitch->get_option('webhook_secret_key'); - $generated_signature = hash_hmac('sha512', $payload, $webhook_key); - $signature_verification_result = $generated_signature === $signature; - - if ( - (isset($data['event_type'])) and - (in_array($data['event_type'], $this->eventsArray) && $signature_verification_result) - ) { - return true; - } - - return false; - } +class Hyperswitch_Webhook { + + protected $hyperswitch; + const PAYMENT_SUCCEEDED = 'payment_succeeded'; + const PAYMENT_FAILED = 'payment_failed'; + const PAYMENT_PROCESSING = 'payment_processing'; + const ACTION_REQURIED = 'action_required'; + const REFUND_SUCCEEDED = 'refund_succeeded'; + // const REFUND_FAILED = 'refund_failed'; + // const DISPUTE_OPENED = 'dispute_opened'; + // const DISPUTE_EXPIRED = 'dispute_expired'; + // const DISPUTE_ACCEPTED = 'dispute_accepted'; + // const DISPUTE_CANCELLED = 'dispute_cancelled'; + // const DISPUTE_CHALLENGED = 'dispute_challenged'; + // const DISPUTE_WON = 'dispute_won'; + // const DISPUTE_LOST = 'dispute_lost'; + + protected $eventsArray = [ + self::PAYMENT_SUCCEEDED, + self::PAYMENT_FAILED, + self::PAYMENT_PROCESSING, + self::ACTION_REQURIED, + self::REFUND_SUCCEEDED, + // self::REFUND_FAILED, + // self::DISPUTE_OPENED, + // self::DISPUTE_EXPIRED, + // self::DISPUTE_ACCEPTED, + // self::DISPUTE_CANCELLED, + // self::DISPUTE_CHALLENGED, + // self::DISPUTE_WON, + // self::DISPUTE_LOST + ]; + + public function __construct() { + $this->hyperswitch = new Hyperswitch_Checkout(); + + } + + public function process() { + if ( $_SERVER['REQUEST_METHOD'] === 'POST' ) { + $raw_post_data = file_get_contents( 'php://input' ); + if ( ! empty ( $raw_post_data ) ) { + $data = json_decode( $raw_post_data, true ); + + $signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE_512']; + + + if ( json_last_error() !== 0 ) { + return; + } + + $enabled = $this->hyperswitch->get_option( 'enable_webhook' ); + + if ( ( $enabled === 'yes' ) and ( empty ( $data['event_type'] ) === false ) ) { + // Skip the webhook if webhooks are disabled, or the event type is unrecognised + $payment_id = $data['content']['object']['payment_id']; + $this->hyperswitch->post_log( "WC_WEBHOOK_RECEIVED", $data['event_type'], $payment_id ); + if ( $this->shouldConsumeWebhook( $data, $signature, $raw_post_data ) === false ) { + return; + } + switch ( $data['event_type'] ) { + case self::PAYMENT_SUCCEEDED: + return $this->paymentAuthorized( $data ); + + case self::PAYMENT_FAILED: + return $this->paymentHandle( $data, "failed" ); + + case self::PAYMENT_PROCESSING: + return $this->paymentHandle( $data, "processing" ); + + case self::ACTION_REQURIED: + return $this->paymentHandle( $data, "action required" ); + + case self::REFUND_SUCCEEDED: + return $this->refundedCreated( $data ); + + default: + return; + } + } + } + } + } + + protected function paymentAuthorized( array $data ) { + + $order_id = $data['content']['object']['metadata']['order_num']; + + $order = wc_get_order( $order_id ); + + if ( $order ) { + $payment_id = $data['content']['object']['payment_id']; + $payment_method = $data['content']['object']['payment_method']; + if ( $order->status !== 'processing' ) { + $this->hyperswitch->post_log( "WC_ORDER_PLACED", null, $payment_id ); + } + $order->payment_complete( $payment_id ); + $order->add_order_note( 'Payment successful via ' . $payment_method . ' (Hyperswitch Payment ID: ' . $payment_id . ') (via Hyperswitch Webhook)' ); + if ( $data['object']['content']['capture_method'] === "automatic" ) { + $order->update_meta_data( 'payment_captured', 'yes' ); + } + $this->hyperswitch->post_log( "WC_PAYMENT_SUCCEEDED_WEBHOOK", null, $payment_id ); + + } else { + exit; // Not a Woocommerce Order + } + + exit; + } + + protected function paymentHandle( array $data, $status ) { + + $order_id = $data['content']['object']['metadata']['order_num']; + + $order = wc_get_order( $order_id ); + + if ( $order ) { + $payment_id = $data['content']['object']['payment_id']; + $payment_method = $data['content']['object']['payment_method']; + $order->set_transaction_id( $payment_id ); + if ( $status == 'processing' ) { + $order->update_status( $this->hyperswitch->processing_payment_order_status ); + } else { + $order->update_status( 'pending' ); + } + $order->add_order_note( 'Payment ' . $status . ' via ' . $payment_method . ' (Hyperswitch Payment ID: ' . $payment_id . ') (via Hyperswitch Webhook)' ); + $this->hyperswitch->post_log( "WC_PAYMENT_" . str_replace( " ", "_", strtoupper( $status ) ) . "_WEBHOOK", null, $payment_id ); + } + + exit; + } + + protected function refundedCreated( array $data ) { + $payment_id = $data['content']['object']['payment_id']; + if ( isset ( $data['content']['object']['metadata']['order_num'] ) ) { + $order_id = $data['content']['object']['metadata']['order_num']; + } else { + $payment_intent = $this->hyperswitch->retrieve_payment_intent( $payment_id ); + $order_id = $payment_intent['metadata']['order_num']; + } + $refund_num = $data['content']['object']['metadata']['refund_num']; + $refund_id = $data['content']['object']['refund_id']; + + $order = wc_get_order( $order_id ); + if ( $order ) { + $refunds = $order->get_refunds(); + $targetRefund = null; + if ( isset ( $refund_num ) ) { + foreach ( $refunds as $refund ) { + if ( $refund->id == $refund_num ) { + $targetRefund = $refund; + break; + } + } + } + if ( ! isset ( $targetRefund ) ) { // Refund initiated via Hyperswitch Dashboard + $refund = new WC_Order_Refund; + $amount = $data['content']['object']['amount']; + $reason = $data['content']['object']['reason']; + $refund->set_amount( (float) $amount / 100 ); + $refund->set_reason( $reason ); + } + $order->add_order_note( 'Refund Successful (Hyperswitch Refund ID: ' . $refund_id . ') (via Hyperswitch Webhook)' ); + $refund->set_refunded_payment( true ); + } else { + exit; // Not a refund for a Woocommerce Order + } + // Graceful exit since payment is now refunded. + exit; + } + + + protected function shouldConsumeWebhook( $data, $signature, $payload ) { + $webhook_key = $this->hyperswitch->get_option( 'webhook_secret_key' ); + $generated_signature = hash_hmac( 'sha512', $payload, $webhook_key ); + $signature_verification_result = $generated_signature === $signature; + + if ( + ( isset ( $data['event_type'] ) ) and + ( in_array( $data['event_type'], $this->eventsArray ) && $signature_verification_result ) + ) { + return true; + } + + return false; + } } \ No newline at end of file From 4859ac171cb2dcede152e1b6baa123f106f4895b Mon Sep 17 00:00:00 2001 From: Vrishab Srivatsa Date: Mon, 18 Mar 2024 18:43:49 +0530 Subject: [PATCH 4/6] Minor bugfixes - using constants, auto formatting --- hyperswitch-checkout.php | 2 +- includes/hyperswitch-wc-blocks-support.php | 73 ++++++++++------------ js/hyperswitch-hyperservice.js | 73 ++++++---------------- 3 files changed, 55 insertions(+), 93 deletions(-) diff --git a/hyperswitch-checkout.php b/hyperswitch-checkout.php index 32e7b46..dbcb21c 100644 --- a/hyperswitch-checkout.php +++ b/hyperswitch-checkout.php @@ -114,7 +114,7 @@ public function __construct() { 'hyperswitch-hyperservice', HYPERSWITCH_PLUGIN_URL . '/js/hyperswitch-hyperservice.js', array( 'hyperswitch-hyperloader' ), - 'HYPERSWITCH_CHECKOUT_PLUGIN_VERSION' + HYPERSWITCH_CHECKOUT_PLUGIN_VERSION ); wp_localize_script( 'hyperswitch-hyperservice', 'clientdata', $client_data ); wp_enqueue_script( 'hyperswitch-hyperservice' ); diff --git a/includes/hyperswitch-wc-blocks-support.php b/includes/hyperswitch-wc-blocks-support.php index 93946f7..c9f10c5 100644 --- a/includes/hyperswitch-wc-blocks-support.php +++ b/includes/hyperswitch-wc-blocks-support.php @@ -1,45 +1,40 @@ settings = get_option('woocommerce_hyperswitch_checkout_settings', []); - $this->gateway = new Hyperswitch_Checkout(); - } - - public function is_active() - { - return !empty($this->settings['enabled']) && 'yes' === $this->settings['enabled']; - } - - public function get_payment_method_script_handles() - { - wp_register_script( - 'hyperswitch_checkout-blocks-integration', - HYPERSWITCH_PLUGIN_URL . '/js/hyperswitch-checkout-blocks.js', - ['wc-blocks-registry', 'wc-settings', 'wp-element', 'wp-html-entities', 'wp-i18n'], - 'HYPERSWITCH_CHECKOUT_PLUGIN_VERSION', - true - ); - - if (function_exists('wp_set_script_translations')) { - wp_set_script_translations('hyperswitch_checkout-blocks-integration'); - } - - return ['hyperswitch_checkout-blocks-integration']; - } - - public function get_payment_method_data() - { - return ['title' => $this->gateway->title]; - } +final class Hyperswitch_Checkout_Blocks extends AbstractPaymentMethodType { + private $gateway; + protected $name = 'hyperswitch_checkout'; + + public function initialize() { + $this->settings = get_option( 'woocommerce_hyperswitch_checkout_settings', [] ); + $this->gateway = new Hyperswitch_Checkout(); + } + + public function is_active() { + return ! empty ( $this->settings['enabled'] ) && 'yes' === $this->settings['enabled']; + } + + public function get_payment_method_script_handles() { + wp_register_script( + 'hyperswitch_checkout-blocks-integration', + HYPERSWITCH_PLUGIN_URL . '/js/hyperswitch-checkout-blocks.js', + [ 'wc-blocks-registry', 'wc-settings', 'wp-element', 'wp-html-entities', 'wp-i18n' ], + HYPERSWITCH_CHECKOUT_PLUGIN_VERSION, + true + ); + + if ( function_exists( 'wp_set_script_translations' ) ) { + wp_set_script_translations( 'hyperswitch_checkout-blocks-integration' ); + } + + return [ 'hyperswitch_checkout-blocks-integration' ]; + } + + public function get_payment_method_data() { + return [ 'title' => $this->gateway->title ]; + } } \ No newline at end of file diff --git a/js/hyperswitch-hyperservice.js b/js/hyperswitch-hyperservice.js index e59bbc6..5e3e0c1 100644 --- a/js/hyperswitch-hyperservice.js +++ b/js/hyperswitch-hyperservice.js @@ -100,14 +100,9 @@ function renderHyperswitchSDK(client_secret, return_url) { pmt_set = Array.from(pmt_set); var i = 0; setInterval(function () { - jQuery( - ".wc_payment_method.payment_method_hyperswitch_checkout label img" - ) + jQuery(".wc_payment_method.payment_method_hyperswitch_checkout label img") .css("opacity", 0) - .attr( - "src", - plugin_url + pmt_set[i] + ".svg?version=" + plugin_version - ) + .attr("src", plugin_url + pmt_set[i] + ".svg?version=" + plugin_version) .attr("alt", pmt_set[i]) .animate({ opacity: 1 }, "slow"); i++; @@ -142,9 +137,7 @@ function renderHyperswitchSDK(client_secret, return_url) { variables.colorText = colorText; } if (!variables.colorTextSecondary) { - var colorTextSecondary = jQuery("#payment, #payment-form, body").css( - "color" - ); + var colorTextSecondary = jQuery("#payment, #payment-form, body").css("color"); variables.colorTextSecondary = colorStringToHex(colorTextSecondary) + "B3"; } if (!variables.colorPrimaryText) { @@ -152,11 +145,8 @@ function renderHyperswitchSDK(client_secret, return_url) { variables.colorPrimaryText = colorPrimaryText; } if (!variables.colorTextPlaceholder) { - var colorTextPlaceholder = jQuery("#payment, #payment-form, body").css( - "color" - ); - variables.colorTextPlaceholder = - colorStringToHex(colorTextPlaceholder) + "50"; + var colorTextPlaceholder = jQuery("#payment, #payment-form, body").css("color"); + variables.colorTextPlaceholder = colorStringToHex(colorTextPlaceholder) + "50"; } if (!variables.borderColor) { var borderColor = jQuery("#payment, #payment-form, body").css("color"); @@ -169,14 +159,14 @@ function renderHyperswitchSDK(client_secret, return_url) { appearance.variables = variables; - hyperswitchWidgets = hyper.widgets({ appearance, clientSecret }); - if (checkWcHexIsLight(colorStringToHex(variables.colorBackground))) { theme = "dark"; } else { theme = "light"; } + hyperswitchWidgets = hyper.widgets({ appearance, clientSecret }); + style = { theme: theme, }; @@ -226,9 +216,7 @@ function renderHyperswitchSDK(client_secret, return_url) { function handleHyperswitchAjax(isOneClickPaymentMethod = false) { jQuery(".woocommerce-error").remove(); - jQuery(".payment_method_hyperswitch_checkout").block( - hyperswitchLoaderCustomSettings - ); + jQuery(".payment_method_hyperswitch_checkout").block(hyperswitchLoaderCustomSettings); clientSecret = jQuery("#payment-form").data("client-secret"); request = jQuery.ajax({ type: "post", @@ -248,9 +236,9 @@ function handleHyperswitchAjax(isOneClickPaymentMethod = false) { } } } - var nonce = new URLSearchParams( - jQuery("form.checkout").serialize() - ).get("woocommerce-process-checkout-nonce"); + var nonce = new URLSearchParams(jQuery("form.checkout").serialize()).get( + "woocommerce-process-checkout-nonce" + ); var payment_intent_data = { action: "hyperswitch_create_or_update_payment_intent", order_id: order_id, @@ -286,9 +274,7 @@ function handleHyperswitchAjax(isOneClickPaymentMethod = false) { document.addEventListener("DOMContentLoaded", () => { jQuery("form.checkout, form.checkout_coupon").on("change", function (event) { - paymentMethod = new URLSearchParams( - jQuery("form.checkout").serialize() - ).get("payment_method"); + paymentMethod = new URLSearchParams(jQuery("form.checkout").serialize()).get("payment_method"); clientSecret = jQuery("#payment-form").data("client-secret"); // Ignore when other payment method selected, default behaviour is not affected if (paymentMethod === "hyperswitch_checkout" || clientSecret == null) { @@ -325,9 +311,7 @@ async function hyperswitchPaymentHandleSubmit(isOneClickPaymentMethod, result) { if (error.type == "validation_error") { jQuery([document.documentElement, document.body]).animate( { - scrollTop: jQuery( - ".payment_box.payment_method_hyperswitch_checkout" - ).offset().top, + scrollTop: jQuery(".payment_box.payment_method_hyperswitch_checkout").offset().top, }, 500 ); @@ -347,9 +331,7 @@ async function hyperswitchPaymentHandleSubmit(isOneClickPaymentMethod, result) { function updatePaymentIntent(inputChangeId) { if (!hyperswitchUpdatePaymentIntentLock) { hyperswitchUpdatePaymentIntentLock = true; - jQuery(".payment_method_hyperswitch_checkout").block( - hyperswitchLoaderCustomSettings - ); + jQuery(".payment_method_hyperswitch_checkout").block(hyperswitchLoaderCustomSettings); var formData = jQuery("form.checkout").serialize(); var forceIntentUpdate = inputChangeId.indexOf("country") !== -1; clientSecret = jQuery("#payment-form").data("client-secret"); @@ -369,33 +351,24 @@ function updatePaymentIntent(inputChangeId) { url: "/wp-admin/admin-ajax.php", data: payment_intent_data, success: function (msg2) { - if ( - clientSecret == null || - (msg2.payment_sheet && forceIntentUpdate) - ) { + if (clientSecret == null || (msg2.payment_sheet && forceIntentUpdate)) { jQuery(".payment_box.payment_method_hyperswitch_checkout") .html(msg2.payment_sheet) .addClass("payment_sheet"); } - jQuery(".payment_method_hyperswitch_checkout").unblock( - hyperswitchLoaderCustomSettings - ); + jQuery(".payment_method_hyperswitch_checkout").unblock(hyperswitchLoaderCustomSettings); hyperswitchUpdatePaymentIntentLock = false; jQuery(".woocommerce-error").remove(); hyperswitchLastUpdatedFormData = formData; }, error: function (_error) { - jQuery(".payment_method_hyperswitch_checkout").unblock( - hyperswitchLoaderCustomSettings - ); + jQuery(".payment_method_hyperswitch_checkout").unblock(hyperswitchLoaderCustomSettings); hyperswitchUpdatePaymentIntentLock = false; }, }); } else { jQuery(".woocommerce-error").remove(); - jQuery(".payment_method_hyperswitch_checkout").unblock( - hyperswitchLoaderCustomSettings - ); + jQuery(".payment_method_hyperswitch_checkout").unblock(hyperswitchLoaderCustomSettings); hyperswitchUpdatePaymentIntentLock = false; } } @@ -459,10 +432,7 @@ function colorStringToHex(colorString) { } function checkMultiplePaymentMethods() { - if ( - jQuery(".wc_payment_methods.payment_methods.methods .wc_payment_method") - .length > 1 - ) { + if (jQuery(".wc_payment_methods.payment_methods.methods .wc_payment_method").length > 1) { if (jQuery('label[for="payment_method_hyperswitch_checkout"]').length) { jQuery('label[for="payment_method_hyperswitch_checkout"]').css({ display: "inline", @@ -473,7 +443,4 @@ function checkMultiplePaymentMethods() { function stopCheckMultiplePaymentMethods() { clearInterval(checkMultiplePaymentMethodsInterval); } -const checkMultiplePaymentMethodsInterval = setInterval( - checkMultiplePaymentMethods, - 500 -); +const checkMultiplePaymentMethodsInterval = setInterval(checkMultiplePaymentMethods, 500); From 451f979f4e95295a8d9d835636e531ac1bb258cf Mon Sep 17 00:00:00 2001 From: Vrishab Srivatsa Date: Wed, 20 Mar 2024 14:04:28 +0530 Subject: [PATCH 5/6] Renaming vars --- hyperswitch-checkout.php | 2 +- js/hyperswitch-checkout-blocks.js | 23 ++++++++++------------- 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/hyperswitch-checkout.php b/hyperswitch-checkout.php index dbcb21c..d88e48e 100644 --- a/hyperswitch-checkout.php +++ b/hyperswitch-checkout.php @@ -180,7 +180,7 @@ function place_order_custom_button( $button_html ) { // not escaping here as the only variable is $button_html which is returned by default even otherwise echo '
{ - return window.wp.htmlEntities.decodeEntities(settings.description || ""); +const hyperswitch_settings = window.wc.wcSettings.getSetting("hyperswitch_checkout_data", {}); +const HyperswitchContent = () => { + return window.wp.htmlEntities.decodeEntities(hyperswitch_settings.description || ""); }; -const label = - window.wp.htmlEntities.decodeEntities(settings.title) || +const hyperswitch_label = + window.wp.htmlEntities.decodeEntities(hyperswitch_settings.title) || window.wp.i18n.__("Hyperswitch", "hyperswitch-checkout"); -const Block_Gateway = { +const Hyperswitch_Block_Gateway = { name: "hyperswitch_checkout", - label: label, - content: Object(window.wp.element.createElement)(Content, null), - edit: Object(window.wp.element.createElement)(Content, null), + label: hyperswitch_label, + content: Object(window.wp.element.createElement)(HyperswitchContent, null), + edit: Object(window.wp.element.createElement)(HyperswitchContent, null), canMakePayment: () => { return true; }, @@ -23,4 +20,4 @@ const Block_Gateway = { }, placeOrderButtonLabel: "Proceed to Pay", }; -window.wc.wcBlocksRegistry.registerPaymentMethod(Block_Gateway); +window.wc.wcBlocksRegistry.registerPaymentMethod(Hyperswitch_Block_Gateway); From 413cf153e6fabd9459c64e5439d80b198c185176 Mon Sep 17 00:00:00 2001 From: Vrishab Srivatsa Date: Wed, 20 Mar 2024 14:32:55 +0530 Subject: [PATCH 6/6] Renaming vars --- hyperswitch-checkout.php | 6 +++--- js/hyperswitch-hyperservice.js | 7 +++---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/hyperswitch-checkout.php b/hyperswitch-checkout.php index d88e48e..eebfe36 100644 --- a/hyperswitch-checkout.php +++ b/hyperswitch-checkout.php @@ -68,7 +68,7 @@ public function __construct() { $this->plugin_url = HYPERSWITCH_PLUGIN_URL . '/assets/images/'; $this->environment = $this->get_option( 'environment' ); $this->enable_saved_payment_methods = $this->get_option( 'enable_saved_payment_methods' ) === 'yes'; - $this->show_card_from_by_default = $this->get_option( 'show_card_from_by_default' ) === 'yes'; + $this->show_card_form_by_default = $this->get_option( 'show_card_form_by_default' ) === 'yes'; $this->supports = [ 'products', 'refunds' @@ -102,7 +102,7 @@ public function __construct() { 'appearance_obj' => $this->get_option( 'appearance' ), 'layout' => $this->get_option( 'layout' ), 'enable_saved_payment_methods' => $this->get_option( 'enable_saved_payment_methods' ) === 'yes', - 'show_card_from_by_default' => $this->get_option( 'show_card_from_by_default' ) === 'yes', + 'show_card_form_by_default' => $this->get_option( 'show_card_form_by_default' ) === 'yes', 'endpoint' => $this->hyperswitch_url, 'plugin_url' => $this->plugin_url, 'plugin_version' => HYPERSWITCH_CHECKOUT_PLUGIN_VERSION, @@ -347,7 +347,7 @@ public function init_form_fields() { 'label' => __( 'Enable Saved Payment Methods', 'hyperswitch-checkout' ), 'default' => 'yes' ), - 'show_card_from_by_default' => array( + 'show_card_form_by_default' => array( 'title' => __( 'Show Card Form Always', 'hyperswitch-checkout' ), 'type' => 'checkbox', 'label' => __( 'Show Card Form before Payment Methods List has loaded', 'hyperswitch-checkout' ), diff --git a/js/hyperswitch-hyperservice.js b/js/hyperswitch-hyperservice.js index 5e3e0c1..8cd8211 100644 --- a/js/hyperswitch-hyperservice.js +++ b/js/hyperswitch-hyperservice.js @@ -55,7 +55,7 @@ function renderHyperswitchSDK(client_secret, return_url) { appearance_obj, layout, enable_saved_payment_methods, - show_card_from_by_default, + show_card_form_by_default, endpoint, plugin_url, plugin_version, @@ -179,12 +179,11 @@ function renderHyperswitchSDK(client_secret, return_url) { }; var disableSaveCards = !enable_saved_payment_methods; - var showCardFormByDefault = !!show_card_from_by_default; + var showCardFormByDefault = !!show_card_form_by_default; var currentUrl = window.location.href; var regex = /\/checkout\/order-pay/; - var containsCheckoutOrderPay = regex.test(currentUrl); - var sdkHandlePayments = containsCheckoutOrderPay; + var sdkHandlePayments = regex.test(currentUrl); hyperswitchUnifiedCheckoutOptions = { layout: layout1,