From 8dc675c20baded25071ce88bf980899f0b3a1bdf Mon Sep 17 00:00:00 2001 From: Onur Polattimur Date: Wed, 20 Apr 2022 10:38:58 +0300 Subject: [PATCH] Add webhook endpoint (#12) --- craftgate-payment-gateway.php | 145 +++++++++++++++---- languages/craftgate-payment-gateway-tr_TR.mo | Bin 2958 -> 3673 bytes languages/craftgate-payment-gateway-tr_TR.po | 89 +++++++----- readme.txt | 8 +- 4 files changed, 179 insertions(+), 63 deletions(-) diff --git a/craftgate-payment-gateway.php b/craftgate-payment-gateway.php index c4383b0..bc2b593 100644 --- a/craftgate-payment-gateway.php +++ b/craftgate-payment-gateway.php @@ -5,7 +5,7 @@ * Description: Accept debit/credit card payments easily and directly on your WordPress site using Craftgate. * Author: Craftgate * Author URI: https://craftgate.io/ - * Version: 1.0.4 + * Version: 1.0.5 * Requires at least: 4.4 * Tested up to: 5.8.3 * WC requires at least: 3.0.0 @@ -137,6 +137,7 @@ private function define_woocommerce_actions() add_action('woocommerce_update_options_payment_gateways_' . $this->id, array($this, 'process_admin_options')); add_action('woocommerce_receipt_craftgate_gateway', array($this, 'init_craftgate_checkout_form')); add_action('woocommerce_api_craftgate_gateway_callback', array($this, 'handle_craftgate_checkout_form_result')); + add_action('woocommerce_api_craftgate_gateway_webhook', array($this, 'handle_craftgate_webhook_result')); } /** @@ -175,39 +176,121 @@ public function init_craftgate_checkout_form($order_id = null) } } + /** + * Check payment is processed before + */ + private function is_payment_processed_before($checkout_token) + { + $orders = wc_get_orders(array( + 'limit' => -1, + 'meta_key' => 'craftgate_checkout_token', + 'meta_value' => $checkout_token, + 'meta_compare' => '=', + 'return' => 'objects' + )); + + foreach ($orders as $order) { + if (!in_array($order->get_status(), ['failed', 'pending'])) { + return true; + } + } + return false; + } + + /** + * Decide whether process webhook request and return checkout token + */ + private function should_process_webhook_request($webhook_data) + { + if ($_SERVER['REQUEST_METHOD'] !== 'POST') { + return false; + } + + $event_type = wc_clean($webhook_data['eventType']); + $status = wc_clean($webhook_data['status']); + $checkout_token = wc_clean($webhook_data['payloadId']); + + if ($event_type !== 'CHECKOUTFORM_AUTH' || $status !== "SUCCESS" || !isset($checkout_token) || $this->is_payment_processed_before($checkout_token)) { + return false; + } + return true; + } + + /** + * Handles Craftgate webhook result. + */ + public function handle_craftgate_webhook_result() + { + $webhook_data = json_decode(file_get_contents('php://input'), true); + if (!isset($webhook_data) || !$this->should_process_webhook_request($webhook_data)) { + exit(); + } + + $checkout_token = wc_clean($webhook_data['payloadId']);; + $checkout_form_result = $this->retrieve_checkout_form_result($checkout_token); + if ($checkout_form_result->paymentStatus !== 'SUCCESS') { + exit(); + } + + $conversationId = $checkout_form_result->conversationId; + if (!isset($conversationId)) { + exit(); + } + $order = $this->retrieve_order($conversationId); + $this->update_order_checkout_form_result_metadata($order, $checkout_form_result, $checkout_token); + $this->complete_order_for_success_payment($checkout_form_result, $order); + exit(); + } + + /** + * Completes order for success payment. + */ + private function complete_order_for_success_payment($checkout_form_result, $order) + { + global $woocommerce; + if ($order->get_status() !== 'pending' && $order->get_status() !== 'failed') { + return; + } + + if ($checkout_form_result->installment > 1) { + $this->update_order_for_installment($order, $checkout_form_result); + } + + $customer_id = $order->get_user()->ID; + if (isset($checkout_form_result->cardUserKey) && $this->retrieve_card_user_key($customer_id, $this->api_key) != $checkout_form_result->cardUserKey) { + $this->save_card_user_key($customer_id, $checkout_form_result->cardUserKey, $this->api_key); + } + + $order->payment_complete(); + $orderMessage = 'Payment ID: ' . $checkout_form_result->id; + $order->add_order_note($orderMessage, 0, true); + WC()->cart->empty_cart(); + $woocommerce->cart->empty_cart(); + wc_empty_cart(); + } + /** * Handles Craftgate checkout result. */ public function handle_craftgate_checkout_form_result() { try { - global $woocommerce; $this->validate_handle_checkout_form_result_params(); $order_id = wc_clean($_GET["order_id"]); $order = $this->retrieve_order($order_id); - $GLOBALS["cg-lang-header"] = $this->get_option("language"); - $checkout_form_result = $this->craftgate_api->retrieve_checkout_form_result(wc_clean($_POST["token"])); + if ($order->get_status() == 'processing') { + echo ""; + exit; + } + $checkout_token = wc_clean($_POST["token"]); + $checkout_form_result = $this->retrieve_checkout_form_result($checkout_token); $this->validate_order_id_equals_conversation_id($checkout_form_result, $order_id); - $this->update_order_checkout_form_result_metadata($order, $checkout_form_result); + $this->update_order_checkout_form_result_metadata($order, $checkout_form_result, $checkout_token); // Checks payment error. if (!isset($checkout_form_result->paymentError) && $checkout_form_result->paymentStatus === 'SUCCESS') { - if ($checkout_form_result->installment > 1) { - $this->update_order_for_installment($order, $checkout_form_result); - } - - $customer_id = $order->get_user()->ID; - if (isset($checkout_form_result->cardUserKey) && $this->retrieve_card_user_key($customer_id, $this->api_key) != $checkout_form_result->cardUserKey) { - $this->save_card_user_key($customer_id, $checkout_form_result->cardUserKey, $this->api_key); - } - - $order->payment_complete(); - $orderMessage = 'Payment ID: ' . $checkout_form_result->id; - $order->add_order_note($orderMessage, 0, true); - WC()->cart->empty_cart(); - $woocommerce->cart->empty_cart(); - wc_empty_cart(); + $this->complete_order_for_success_payment($checkout_form_result, $order); echo ""; } else { $error = $checkout_form_result->paymentError->errorCode . ' - ' . $checkout_form_result->paymentError->errorDescription . ' - ' . $checkout_form_result->paymentError->errorGroup; @@ -215,20 +298,24 @@ public function handle_craftgate_checkout_form_result() $order->update_status('failed', $error); $order->save(); wc_add_notice(__($checkout_form_result->paymentError->errorDescription, $this->text_domain), 'error'); - $redirectUrl = wc_get_checkout_url(); - echo ""; + echo ""; } exit; } catch (Exception $e) { error_log($e->getMessage()); wc_add_notice(__($e->getMessage(), $this->text_domain), 'error'); - $redirectUrl = wc_get_checkout_url(); - echo ""; + echo ""; $this->render_error_message(__('An error occurred. Error Code: ', $this->text_domain) . '-2'); } } + private function retrieve_checkout_form_result($checkout_token) + { + $GLOBALS["cg-lang-header"] = $this->get_option("language"); + return $this->craftgate_api->retrieve_checkout_form_result($checkout_token); + } + /** * Checks if API request is valid. * @@ -446,11 +533,12 @@ private function validate_order_id_equals_conversation_id($checkout_form_result, * @param $order object WooCommerce order * @param $checkout_form_result object Checkout Form result */ - private function update_order_checkout_form_result_metadata($order, $checkout_form_result) + private function update_order_checkout_form_result_metadata($order, $checkout_form_result, $checkout_token) { if (isset($checkout_form_result->id)) { $order->update_meta_data('environment', $this->is_sandbox_active ? 'sandbox' : 'live'); $order->update_meta_data('craftgate_payment_id', $checkout_form_result->id); + $order->update_meta_data('craftgate_checkout_token', $checkout_token); } $order->save(); } @@ -561,6 +649,13 @@ public function init_admin_settings_form_fields() 'description' => __('Example: hideFooter=true&animatedCard=true', $this->text_domain), 'default' => '', ), + 'webhook_url' => array( + 'title' => __('Webhook URL', $this->text_domain), + 'type' => 'text', + 'disabled' => true, + 'description' => __('The URL that payment results will be sent to on the server-side. You should enter this webhook address to Craftgate Merchant Panel to get webhook request. You can see details here.', $this->text_domain), + 'default' => rtrim(get_bloginfo('url'), '/') . '/' . "?wc-api=craftgate_gateway_webhook", + ), ); } diff --git a/languages/craftgate-payment-gateway-tr_TR.mo b/languages/craftgate-payment-gateway-tr_TR.mo index c077c58c5f8befe8cc02a1f0569b881672ad250b..e936c3ff274a5a3c0d3361fc0ff4d06347d39342 100644 GIT binary patch delta 1500 zcmb8uO=uoP9LMoVn#4A#T4QT{i8{toiU57%PvV=sTqyguDD@Uj;Dh)n%CqNj0qo3|e|%eao^_n({wI6{#|AkB&Le;7T`qTFfy1n?KBiH@HJromQ5M|EMIzTY ziqE3P8p?)G;Q>5{68SHsH;}iY{z5rv4>8?=J5Z7yMM-i7TU2$7i$wGWau}7O3|PkB z@I#c7#J4JS5I@7G@H>=9Wfj&^+wd{mg>u5fNI;z;2av*4ogy3N4YxY)THc#1+)I^{ zNs$Tf@3gvcm(5Nhd^nvbrB74kG;-q2A|IYaE=6A9L!DOla!=W2@1*f~cc;=PCzcfC zYi8qWH&qIsL+3w3+PqS=b^UVh^`6PO6Q>cl^{kF;FfPe8yPP&U_IBaWXdFT#pBf*J?6OU=hV_-&<{A~3 zjhA~Eor$ft)8l5QqF!P5S(-F;UNjn+Cm3BT+OPMo4!v4#m@L}A_pb~-F*b2PPaK@u zKe_G)KHoCCaoVSLX-fb9q@QaVpBR7XLVNq*nbyYX$P#~^rA4hsi&VSB25QY-T63D! zD|&M)E)RAovEHRlo5WOIQnyRmZG7$0e-Crx;);xjY^tjT@sqyOi_X_=;&PY1<5nvA zd9rM>C37>%YbU?>Z(&|Ld1j_scoUga64gawF0aYfoM(0>Z=V}H`;Rb>49)!w`NTD2 delta 764 zcmZ9~%_~Gv7{~Ev%y=8FcjKK2p%|G_L(Ilo%EHc4%8F95(v+H&jY7G}!b@3D%5K=m z!bY(YD=aLOq?G&t%J+B8%4zQXoOABn`#k44=c#_9D)mwp*fv_2t6rDStW#!jqut;% z-eMEB`^{Q$9HY2^m3V*!c!ni-h2?mUjrfKg7zmgZVFatqQkI}o$HY{|CDaS+Sd6Eb zhnHB0*O~bTtY!R~8UJLSJK1Js%-5pci=YC=u?5F)80RrTd^@GX&px=d;TN`ID90>G zH3o5(@pqJ%%m4VRMAVdE@%O;u5ayq1pm-+k_6_P+a=bL_6=CWEm^PhU71ABgp&oxEMY P`&qE(&N+u}Wzpy_XSqN8 diff --git a/languages/craftgate-payment-gateway-tr_TR.po b/languages/craftgate-payment-gateway-tr_TR.po index a835b5e..0491661 100644 --- a/languages/craftgate-payment-gateway-tr_TR.po +++ b/languages/craftgate-payment-gateway-tr_TR.po @@ -1,8 +1,8 @@ msgid "" msgstr "" "Project-Id-Version: \n" -"POT-Creation-Date: 2022-02-07 16:20+0300\n" -"PO-Revision-Date: 2022-02-07 16:20+0300\n" +"POT-Creation-Date: 2022-04-12 17:03+0300\n" +"PO-Revision-Date: 2022-04-12 18:09+0300\n" "Last-Translator: \n" "Language-Team: \n" "Language: tr\n" @@ -24,28 +24,28 @@ msgstr "" "Craftgate ile WordPress siteniz üzerinden kolay ve doğrudan banka/kredi " "kartı ile ödeme alın." -#: craftgate-payment-gateway.php:96 craftgate-payment-gateway.php:487 +#: craftgate-payment-gateway.php:96 craftgate-payment-gateway.php:603 msgid "Pay with Debit/Credit Card" msgstr "Banka/Kredi Kartı ile Öde" -#: craftgate-payment-gateway.php:160 craftgate-payment-gateway.php:164 -#: craftgate-payment-gateway.php:217 +#: craftgate-payment-gateway.php:171 craftgate-payment-gateway.php:175 +#: craftgate-payment-gateway.php:315 msgid "An error occurred. Error Code: " msgstr "Bir hata meydana geldi. Hata Kodu: " -#: craftgate-payment-gateway.php:257 +#: craftgate-payment-gateway.php:361 msgid "Installment Fee" msgstr "Taksit Komisyonu" -#: craftgate-payment-gateway.php:346 +#: craftgate-payment-gateway.php:450 msgid "Shipping Total" msgstr "Gönderim Ücreti" -#: craftgate-payment-gateway.php:404 craftgate-payment-gateway.php:417 +#: craftgate-payment-gateway.php:519 craftgate-payment-gateway.php:532 msgid "Your payment could not be processed." msgstr "Ödemeniz alınamadı." -#: craftgate-payment-gateway.php:459 +#: craftgate-payment-gateway.php:575 #, fuzzy #| msgid "" #| "You can create your Craftgate Payment Gateway account buradan oluşturabilirsiniz." -#: craftgate-payment-gateway.php:463 +#: craftgate-payment-gateway.php:579 msgid "Craftgate Payment Gateway is not available to use" msgstr "Craftgate Payment Gateway kullanılamaz" -#: craftgate-payment-gateway.php:463 +#: craftgate-payment-gateway.php:579 msgid "The only supported currency is TRY." msgstr "Sadece Türk lirası desteklenmektedir." -#: craftgate-payment-gateway.php:476 +#: craftgate-payment-gateway.php:592 msgid "Enable/Disable" msgstr "Aktif/Pasif" -#: craftgate-payment-gateway.php:478 +#: craftgate-payment-gateway.php:594 msgid "Enable Craftgate" msgstr "Craftgate’i Aktif Et" -#: craftgate-payment-gateway.php:479 +#: craftgate-payment-gateway.php:595 msgid "Enable or disable the gateway." msgstr "Craftgate’i aktif veya pasif yapabilirsiniz." -#: craftgate-payment-gateway.php:483 +#: craftgate-payment-gateway.php:599 msgid "Title" msgstr "Başlık" -#: craftgate-payment-gateway.php:485 +#: craftgate-payment-gateway.php:601 msgid "This controls the title which the user sees during checkout." msgstr "Kullanıcının ödeme esnasında göreceği başlık." -#: craftgate-payment-gateway.php:490 +#: craftgate-payment-gateway.php:606 msgid "Description" msgstr "Açıklama" -#: craftgate-payment-gateway.php:492 +#: craftgate-payment-gateway.php:608 msgid "This controls the description which the user sees during checkout." msgstr "Kullanıcının ödeme esnasında göreceği açıklama." -#: craftgate-payment-gateway.php:493 +#: craftgate-payment-gateway.php:609 msgid "You can pay with Debit and Credit Card" msgstr "Banka veya Kredi Kartı ile ödeyebilirsiniz" -#: craftgate-payment-gateway.php:496 +#: craftgate-payment-gateway.php:612 msgid "Live API Key" msgstr "Canlı API Key" -#: craftgate-payment-gateway.php:498 +#: craftgate-payment-gateway.php:614 msgid "Enter your Live API Key." msgstr "Canlı API Key’inizi giriniz." -#: craftgate-payment-gateway.php:502 +#: craftgate-payment-gateway.php:618 msgid "Live Secret Key" msgstr "Canlı Secret Key" -#: craftgate-payment-gateway.php:504 +#: craftgate-payment-gateway.php:620 msgid "Enter your Live Secret Key." msgstr "Canlı Secret Key’inizi giriniz." -#: craftgate-payment-gateway.php:508 +#: craftgate-payment-gateway.php:624 msgid "Sandbox API Key" msgstr "Sandbox API Key" -#: craftgate-payment-gateway.php:510 +#: craftgate-payment-gateway.php:626 msgid "Enter your Sandbox API Key." msgstr "Sandbox API Key’inizi giriniz." -#: craftgate-payment-gateway.php:514 +#: craftgate-payment-gateway.php:630 msgid "Sandbox Secret Key" msgstr "Sandbox Secret Key" -#: craftgate-payment-gateway.php:516 +#: craftgate-payment-gateway.php:632 msgid "Enter your Sandbox Secret Key." msgstr "Sandbox Secret Key’inizi giriniz." -#: craftgate-payment-gateway.php:520 +#: craftgate-payment-gateway.php:636 msgid "Sandbox Mode" msgstr "Sandbox Modu" -#: craftgate-payment-gateway.php:522 +#: craftgate-payment-gateway.php:638 msgid "Enable Sandbox Mode" msgstr "Sandbox Modu Aktif" -#: craftgate-payment-gateway.php:524 +#: craftgate-payment-gateway.php:640 msgid "Enable test mode using sandbox API keys." msgstr "Sandbox API bilgilerinizi kullanarak test modunu aktif edebilirsiniz." -#: craftgate-payment-gateway.php:527 +#: craftgate-payment-gateway.php:643 msgid "Language" msgstr "Dil" -#: craftgate-payment-gateway.php:533 +#: craftgate-payment-gateway.php:649 msgid "Change the language of payment form." msgstr "" "Kullanıcının ödeme esnasında yer alan metinlerin gösterileceği dil seçeneği." -#: craftgate-payment-gateway.php:537 +#: craftgate-payment-gateway.php:653 msgid "Iframe Options" -msgstr "" +msgstr "Iframe Ayarları" -#: craftgate-payment-gateway.php:539 +#: craftgate-payment-gateway.php:655 msgid "Example: hideFooter=true&animatedCard=true" +msgstr "Örnek: Example: hideFooter=true&animatedCard=true" + +#: craftgate-payment-gateway.php:659 +msgid "Webhook URL" +msgstr "Webhook URL" + +#: craftgate-payment-gateway.php:662 +msgid "" +"The URL that payment results will be sent to on the server-side. You should " +"enter this webhook address to Craftgate Merchant Panel to get webhook " +"request. You can see details at here." msgstr "" +"Ödeme sonucunun iletileceği URL. Webhook isteklerini alabilmek için " +"Craftgate Merchant Panel üzerinden bu adresi girmelisiniz. Detaylara buradan ulaşabilirsiniz." -#: craftgate-payment-gateway.php:610 +#: craftgate-payment-gateway.php:733 msgid "Craftgate Payment URL" msgstr "Craftgate Ödeme URL" -#: craftgate-payment-gateway.php:643 +#: craftgate-payment-gateway.php:766 msgid "Settings" msgstr "Ayarlar" diff --git a/readme.txt b/readme.txt index dec5a19..d17ca35 100644 --- a/readme.txt +++ b/readme.txt @@ -4,7 +4,7 @@ Tags: craftgate, payment gateway, kredi kartı, banka kartı, ödeme, sanal pos, Requires at least: 4.4 Tested up to: 5.8.3 Requires PHP: 5.6 -Stable tag: 1.0.4 +Stable tag: 1.0.5 License: GPLv3 License URI: https://www.gnu.org/licenses/gpl-3.0.html @@ -50,6 +50,9 @@ Craftgate kullanarak ödeme geçirebilmek için üyeliğinizin olması gerekmekt 6. Sipariş Yönetim Sayfası == Changelog == += 1.0.5 - 2022-04-20 = +* adds webhook feature to determine unhandled payments on client side + = 1.0.4 - 2022-02-28 = * adds card storage functionality * adds shipping total to payment items @@ -72,6 +75,9 @@ Craftgate kullanarak ödeme geçirebilmek için üyeliğinizin olması gerekmekt * First Release == Upgrade Notice == += 1.0.5 - 2022-04-20 = +* adds webhook feature to determine unhandled payments on client side + = 1.0.4 - 2022-02-28 = * adds card storage functionality * adds shipping total to payment items