diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..723ef36 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea \ No newline at end of file diff --git a/readme.txt b/readme.txt index 0280284..9594bf7 100644 --- a/readme.txt +++ b/readme.txt @@ -4,7 +4,7 @@ Tags: payment, paymentgateway, woocommerce, ecommerce Requires at least: 4.0 & WooCommerce 2.6+ Tested up to: Wordpress 5.7.2 & Woocommerce 5.3 PHP Version: 5.6 or higher -Stable tag: 1.7.3 +Stable tag: 1.8.0 License: The MIT License (MIT) Official Paymentwall module for WordPress WooCommerce. @@ -37,6 +37,9 @@ View our full installation guide: - ")); - Brick_Payment.showNotification(errors, 'error'); - } else { - jQuery('#brick-token').val(response.token); - jQuery('#brick-fingerprint').val(Brick.getFingerprint()); - jQuery('#brick-get-token-success').val(1); - - Brick_Payment.sendPaymentRequest(); - window.addEventListener("message", Brick_Payment.threeDSecureMessageHandle, false); - } - }); - }, openConfirm3ds: function () { - var win = window.open("", "Brick: Verify 3D secure", "toolbar=no, directories=no, status=no, menubar=no, scrollbars=yes, resizable=no, width=1024, height=720"); - win.document.body.innerHTML += Brick_Payment.form3Ds; - win.document.forms[0].submit(); - return false; - }, threeDSecureMessageHandle: function (event) { - var origin = event.origin || event.originalEvent.origin; - if (origin !== "https://api.paymentwall.com") { - return; - } - Brick_Payment.showLoading(); - var brickData = JSON.parse(event.data); - if (brickData && brickData.event == '3dSecureComplete') { - jQuery('#hidden-brick-secure-token').val(brickData.data.secure_token); - jQuery('#hidden-brick-charge-id').val(brickData.data.charge_id); - Brick_Payment.sendPaymentRequest(); } - }, - sendPaymentRequest: function () { - jQuery.ajax({ - type: 'POST', - url: '?wc-ajax=checkout', - data: jQuery('form.checkout').serialize(), - dataType: 'json', - encode: true, - beforeSend: function () { - Brick_Payment.showLoading(); - }, - success: function (response) { - if (response.result == 'success') { - Brick_Payment.showNotification(response.message); - window.location.href = response.redirect; - } else if (response.result == 'secure') { - Brick_Payment.form3Ds = response.secure; - var requireConfirm = "Please verify 3D-secure to continue checkout. Click here !"; - Brick_Payment.showNotification(requireConfirm); - } else if (response.result == 'failure') { - jQuery('#brick-loading').hide(); - jQuery('#brick-errors').html(response.messages); - jQuery('#brick-errors').show(); - } else { - Brick_Payment.showNotification(response.message, 'error'); - } - } - }); - }, showNotification: function (message, type) { - type = (type != undefined) ? type : 'message'; - jQuery('#brick-loading').hide(); - jQuery('#brick-errors').html(''); - jQuery('#brick-errors').show(); - }, showLoading: function () { - jQuery('#brick-errors').hide(); - jQuery('#brick-loading').show(); } -}; - -(function ($) { - $( document ).ready(function() { - $('.paymentwall-method .pw_payment_system').on('change', function () { - var paymentSystem = $(this).data('payment-system'); - var inputPaymentSystem = $('#pw_gateway'); - inputPaymentSystem.val(JSON.stringify(paymentSystem)); - }) - }) -})(jQuery); \ No newline at end of file +})() \ No newline at end of file diff --git a/src/includes/admin/settings/brick.php b/src/includes/admin/settings/brick.php index 056c275..b227bea 100644 --- a/src/includes/admin/settings/brick.php +++ b/src/includes/admin/settings/brick.php @@ -44,16 +44,6 @@ 'description' => __('Your Brick Private Key', PW_TEXT_DOMAIN), 'default' => '' ), - 'test_mode' => array( - 'title' => __('Test Mode', PW_TEXT_DOMAIN), - 'type' => 'select', - 'description' => __('Enable test mode', PW_TEXT_DOMAIN), - 'options' => array( - '0' => 'No', - '1' => 'Yes' - ), - 'default' => '0' - ), 'enable_delivery' => array( 'title' => __('Enable Delivery Confirmation API', PW_TEXT_DOMAIN), 'type' => 'select', @@ -64,12 +54,12 @@ ), 'default' => '1' ), - 'saved_cards' => array( - 'title' => __('Saved Cards', PW_TEXT_DOMAIN), - 'lable' => __('Enable Payment via Saved Cards', PW_TEXT_DOMAIN), - 'type' => 'checkbox', - 'description' => __('If enabled, users will be able to pay with a saved card during checkout. Card details are saved on Paymentwall servers, not on your store', PW_TEXT_DOMAIN), - 'default' => 'no', - 'desc_tip' => true, - ) +// 'saved_cards' => array( +// 'title' => __('Saved Cards', PW_TEXT_DOMAIN), +// 'lable' => __('Enable Payment via Saved Cards', PW_TEXT_DOMAIN), +// 'type' => 'checkbox', +// 'description' => __('If enabled, users will be able to pay with a saved card during checkout. Card details are saved on Paymentwall servers, not on your store', PW_TEXT_DOMAIN), +// 'default' => 'no', +// 'desc_tip' => true, +// ) ); diff --git a/src/includes/class-paymentwall-abstract.php b/src/includes/class-paymentwall-abstract.php index c33e007..095c52e 100644 --- a/src/includes/class-paymentwall-abstract.php +++ b/src/includes/class-paymentwall-abstract.php @@ -136,20 +136,21 @@ function get_customer_orders($status, $billing_email) { return $customer_orders; } - function cumulative_payments_customer($status, $billing_email) { - + function cumulative_payments_customer($status, $billing_email) + { + $customer_orders = $this->get_customer_orders($status, $billing_email); $sum_total = 0; - + if (!empty($customer_orders)) { - foreach ( $customer_orders as $customer_order ) { + foreach ($customer_orders as $customer_order) { $order = new WC_Order($customer_order->ID); $amount = $order->get_total(); $sum_total += $amount; } + + return $sum_total; } - - return $sum_total; } function s_datediff( $str_interval, $dt_menor, $dt_maior, $relative=false){ @@ -256,4 +257,4 @@ function get_subscription_data(WC_Subscription $subscription) { return $subsData; } -} \ No newline at end of file +} diff --git a/src/includes/class-paymentwall-api.php b/src/includes/class-paymentwall-api.php index 639bac7..a120fa1 100644 --- a/src/includes/class-paymentwall-api.php +++ b/src/includes/class-paymentwall-api.php @@ -80,4 +80,4 @@ function prepare_delivery_confirmation_data($orderId, $deliveryStatus = '', $tra } return $data; } -} \ No newline at end of file +} diff --git a/src/includes/class-paymentwall-brick-subscription.php b/src/includes/class-paymentwall-brick-subscription.php index 11292f4..e052a7b 100644 --- a/src/includes/class-paymentwall-brick-subscription.php +++ b/src/includes/class-paymentwall-brick-subscription.php @@ -17,8 +17,7 @@ public function __construct() { $this->supports = array( 'products', 'subscriptions', - 'subscription_suspension', - 'subscription_reactivation' + 'subscription_cancellation', ); $this->reference_transaction_supported_features = array( @@ -42,21 +41,12 @@ public function __construct() { * @return array */ public function process_payment($order_id) { - $this->init_configs(); $order = wc_get_order($order_id); - - try { - if (wcs_order_contains_subscription($order)) { - $subscription = wcs_get_subscriptions_for_order($order); - $subscription = reset($subscription); // The current version does not support multi subscription - $return = $this->process_subscription_payment($order, $subscription); - } else { - $return = $this->process_standard_payment($order); - } - - } catch (Exception $e) { - wc_add_notice($e->getMessage(), 'error'); + if ($this->cart_subscription_exists()) { + $return = $this->process_subscription_payment($order); + } else { + $return = $this->process_standard_payment($order); } // Return redirect @@ -69,7 +59,13 @@ public function process_payment($order_id) { * @return array * @throws Exception */ - public function process_subscription_payment(WC_Order $order, WC_Subscription $subscription) { + public function process_subscription_payment(WC_Order $order) + { + if (!$this->is_valid_order()) { + $this->checkout_error_response("Order is invalid"); + } + + session_start(); $this->init_configs(); $return = array( 'result' => 'fail', @@ -77,96 +73,225 @@ public function process_subscription_payment(WC_Order $order, WC_Subscription $s ); $orderData = $this->get_order_data($order); - - $userId = $orderData['user_id']; - $billingEmail = $orderData['billing_email']; - - $paymentwall_subscription = new Paymentwall_Subscription(); - $paymentwall_subscription->create(array_merge( - $this->prepare_subscription_data($order, $subscription), - $this->prepare_user_profile_data($order), - array( - 'custom[integration_module]' => 'woocommerce', - 'uid' => empty($userId) ? (empty($billingEmail) ? $this->getRealClientIP() : $orderData['billing_email']) : $orderData['user_id'] - ) - )); - $response = json_decode($paymentwall_subscription->GetRawResponseData()); - - if ($paymentwall_subscription->isSuccessful() && $response->object == 'subscription') { - + if (isset($_POST['wc-brick-payment-token']) && $_POST['wc-brick-payment-token'] != 'new') { + $parameters = $_POST; + $orderId = $order->get_id(); + $subscriptionInfo = $this->prepare_subscription_info($parameters, $orderId); + $paymentwall_subscription = $this->create_subscription($subscriptionInfo); + } else { + $paymentwall_subscription = WC()->session->get('brick_subscription'); + } + $response = json_decode($paymentwall_subscription->getRawResponseData()); + if ($paymentwall_subscription->isSuccessful()) { if ($paymentwall_subscription->isActive()) { // Add order note $order->add_order_note(sprintf(__('Brick subscription payment approved (ID: %s)', PW_TEXT_DOMAIN), $response->id)); update_post_meta( $orderData['order_id'], '_subscription_id', $response->id); } - $return['result'] = 'success'; $return['redirect'] = $this->get_return_url($order); $return['message'] = 'Your order has been received !'; - // Clear shopping cart WC()->cart->empty_cart(); WC()->session->set('orderId', null); - } elseif (!empty($response->secure)) { - WC()->session->set('orderId', $orderData['order_id']); - $return['result'] = 'secure'; - $return['secure'] = $response->secure->formHTML; - die(json_encode($return)); + WC()->session->set('amount_charge_brick', null); + WC()->session->set('cart_charge_brick', null); } else { - $return['result'] ='error'; - $return['message'] = $response->error; - wc_add_notice(__($response->error), 'error'); - die(json_encode($return)); - } + $this->checkout_error_response($response->error); + } + $_SESSION['message_thank_you_page'] = $return['message']; + return $return; } /** - * @param $order + * @param $is_supported + * @param $feature * @param $subscription - * @return array - * @throws Exception + * @return bool + */ + public function add_feature_support_for_subscription($is_supported, $feature, $subscription) { + if ($this->id === $subscription->get_payment_method()) { + + if ('gateway_scheduled_payments' === $feature) { + $is_supported = false; + } elseif (in_array($feature, $this->supports)) { + $is_supported = true; + } + } + return $is_supported; + } + + /** + * Cancel subscription from merchant site + * + * @param $subscription + */ + public function cancel_subscription_action($subscription) { + $this->init_configs(); + $order_id = !method_exists($subscription, 'get_id') ? $subscription->order->id : $subscription->order->get_id(); + + if ($subscription_key = $this->get_subscription_key($order_id)) { + $subscription_api = new Paymentwall_Subscription($subscription_key); + $result = $subscription_api->cancel(); + } + } + + /** + * @param $post_id + * @return mixed */ - protected function prepare_subscription_data(WC_Order $order, WC_Subscription $subscription) { - if (!isset($_POST['brick'])) { - throw new Exception("Payment Invalid!"); + protected function get_subscription_key($post_id) { + $subscription_key = get_post_meta($post_id, '_subscription_id'); + return isset($subscription_key[0]) ? $subscription_key[0] : false; + } + + public function handle_brick_subscription() + { + if (!$this->is_processable_subscription_payment()) { + return json_encode($this->prepare_unprocessable_subscriptions_error_response()); } - $brick = $_POST['brick']; - $trial_data = $this->prepare_trial_data($order, $subscription); + $orderId = $this->create_temporary_order(); + $this->set_subscription($orderId); - $orderData = $this->get_order_data($order); + $this->init_configs(); + $parameters = $_POST; + $dataPrepare = $this->prepare_subscription_info($parameters, $orderId); + $subscription = $this->create_subscription($dataPrepare); + WC()->session->set('brick_subscription', $subscription); + $response = $subscription->getPublicData(); + $responseData = json_decode($subscription->getRawResponseData()); + + WC()->session->set('brick_response_subscription', $responseData); + WC()->session->set('amount_charge_brick', (float) WC()->cart->get_total('edit')); + WC()->session->set('cart_charge_brick', WC()->cart->get_cart()); + $result = [ + 'is_successful' => $subscription->isSuccessful(), + 'payment' => $responseData + ]; + WC()->session->set('email_brick_subscription', $parameters['email']); + + $result = array_merge($result, json_decode($response, true)); + + return json_encode($result); + } + + /** + * @return int + */ + private function is_processable_subscription_payment() + { + $count = 0; + if ( ! empty( WC()->cart->cart_contents ) && ! wcs_cart_contains_renewal() ) { + foreach ( WC()->cart->cart_contents as $cart_item ) { + if ( WC_Subscriptions_Product::is_subscription( $cart_item['data'] ) ) { + $count++; + } else { + return false; + } + } + } + if ($count > 1) { + return false; + } + + return true; + } + + /** + * @return array[] + */ + private function prepare_unprocessable_subscriptions_error_response() + { + return [ + "error" => [ + 'message' => 'Brick currently does not support payment for multiple subscriptions or mixed cart' + ] + ]; + } + + public function create_subscription($dataPrepare) + { + $subscription = new Paymentwall_Subscription(); + $subscription->create($dataPrepare); + + return $subscription; + } + + /** + * @param $parameters + * @param $orderId + * @return array + */ + public function prepare_subscription_info($parameters, $orderId) + { + $subscription = $this->get_subscription($orderId); $subscriptionData = $this->get_subscription_data($subscription); - $data = array( - 'amount' => WC_Subscriptions_Order::get_recurring_total($order), - 'currency' => $orderData['currencyCode'], - 'email' => $orderData['billing_email'], - 'description' => sprintf(__('%s - Order #%s', PW_TEXT_DOMAIN), esc_html(get_bloginfo('name', 'display')), $order->get_order_number()), - 'plan' => $orderData['order_id'], + $subscriptionInfo = array( + 'token' => $parameters['brick_token'], + 'email' => $parameters['email'], + 'currency' => get_woocommerce_currency(), + 'amount' => WC_Subscriptions_Order::get_recurring_total(wc_get_order($orderId)), + 'fingerprint' => $_POST['brick_fingerprint'], + 'plan' => $orderId, + 'description' => PW_TEXT_DOMAIN, 'period' => $subscriptionData['billing_period'], 'period_duration' => $subscriptionData['billing_interval'], - 'secure_token' => (!empty($brick['cc_brick_secure_token'])) ? $brick['cc_brick_secure_token'] : null, - 'charge_id' => (!empty($brick['cc_brick_charge_id'])) ? $brick['cc_brick_charge_id'] : null, ); + if (!empty($_POST['wc-brick-payment-token'])) { + $token = WC_Payment_Tokens::get($_POST['wc-brick-payment-token']); + $subscriptionInfo['token'] = $token->get_token(); + $subscriptionInfo['email'] = $token->get_meta('email'); + } + $trialData = $this->prepare_trial_data(wc_get_order($orderId), $subscription); + $subscriptionInfo = array_merge($subscriptionInfo, $trialData); + + $userProfile = $this->prepare_user_profile(); + + return array_merge($subscriptionInfo, $userProfile); + } - if ($brick['token'] && $brick['fingerprint']) { - $data = array_merge($data, array( - 'token' => $brick['token'], - 'fingerprint' => $brick['fingerprint'] - )); - } elseif (!empty($_POST['wc-brick-payment-token'])) { - $token = WC_Payment_Tokens::get($_POST['wc-brick-payment-token'])->get_token(); - $data = array_merge($data, array( - 'token' => $token - )); + /** + * @param $orderId + */ + private function set_subscription($orderId) + { + WC_Subscriptions_Cart::calculate_subscription_totals(0, WC()->cart); + foreach (WC()->cart->recurring_carts as $cart) { + WC_Subscriptions_Checkout::create_subscription(wc_get_order( $orderId ), $cart, []); } + } - return array_merge( - $data, - $trial_data - ); + /** + * @param $orderId + * @return mixed + */ + private function get_subscription($orderId) + { + $subscription = wcs_get_subscriptions_for_order(wc_get_order($orderId)); + $subscription = reset($subscription); + + return $subscription; + } + + /** + * @return mixed + */ + protected function create_temporary_order() + { + $order = new WC_Order(); + $order->set_total( WC()->cart->get_total( 'edit' ) ); + $cartHash = WC()->cart->get_cart_hash(); + $order->set_cart_hash( $cartHash ); + $order->set_customer_id(get_current_user_id()); + $orderId = $order->save(); + $order = wc_get_order( $orderId ); + WC()->session->set( 'order_awaiting_payment', $orderId); + + return $orderId; } /** @@ -207,46 +332,10 @@ protected function prepare_trial_data(WC_Order $order, WC_Subscription $subscrip 'trial[period_duration]' => $trial_period_duration, ); } - - /** - * @param $is_supported - * @param $feature - * @param $subscription - * @return bool - */ - public function add_feature_support_for_subscription($is_supported, $feature, $subscription) { - if ($this->id === $subscription->get_payment_method()) { - - if ('gateway_scheduled_payments' === $feature) { - $is_supported = false; - } elseif (in_array($feature, $this->supports)) { - $is_supported = true; - } - } - return $is_supported; - } - - /** - * Cancel subscription from merchant site - * - * @param $subscription - */ - public function cancel_subscription_action($subscription) { - $this->init_configs(); - $order_id = !method_exists($subscription, 'get_id') ? $subscription->order->id : $subscription->order->get_id(); - - if ($subscription_key = $this->get_subscription_key($order_id)) { - $subscription_api = new Paymentwall_Subscription($subscription_key); - $result = $subscription_api->cancel(); - } - } - - /** - * @param $post_id - * @return mixed - */ - protected function get_subscription_key($post_id) { - $subscription_key = get_post_meta($post_id, '_subscription_id'); - return isset($subscription_key[0]) ? $subscription_key[0] : false; + + public function prepare_user_profile() + { + return parent::prepare_user_profile(); } + } \ No newline at end of file diff --git a/src/includes/class-paymentwall-brick.php b/src/includes/class-paymentwall-brick.php index 2707716..2685d6f 100644 --- a/src/includes/class-paymentwall-brick.php +++ b/src/includes/class-paymentwall-brick.php @@ -26,21 +26,16 @@ public function __construct() { $this->notify_url = str_replace('https:', 'http:', add_query_arg('wc-api', 'Paymentwall_Brick', home_url('/'))); $this->method_title = __('Brick', 'paymentwall-for-woocommerce'); $this->method_description = __('Brick provides in-app and fully customizable credit card processing for merchants around the world. With Brick connected to banks in different countries, Paymentwall has created the best global credit card processing solution in the world to help you process in local currency.', PW_TEXT_DOMAIN); - $this->saved_cards = 'yes' === $this->get_option( 'saved_cards' ); +// $this->saved_cards = 'yes' === $this->get_option( 'saved_cards' ); + $this->saved_cards = false; $this->supports = array( 'tokenization', ); // Our Actions - add_filter('woocommerce_after_checkout_validation', array($this, 'brick_fields_validation')); + add_filter('woocommerce_after_checkout_validation', __CLASS__ . '::brick_preprocessing_validation'); add_action('woocommerce_update_options_payment_gateways_' . $this->id, array($this, 'process_admin_options')); - add_filter( 'woocommerce_available_payment_gateways', __CLASS__ . '::get_available_payment_gateways'); - - $wcSession = WC()->session; - if(!empty($wcSession) && isset($_POST['brick']) && $orderId = WC()->session->get('orderId')) { - $result = $this->process_payment($orderId); - die(json_encode($result)); - } + add_filter('woocommerce_available_payment_gateways', __CLASS__ . '::get_available_payment_gateways'); } /** @@ -50,7 +45,7 @@ public function init_configs($isPingback = false) { if ($isPingback) { Paymentwall_Config::getInstance()->set(array( 'api_type' => Paymentwall_Config::API_GOODS, - 'private_key' => $this->settings['test_mode'] ? $this->settings['privatekey'] : $this->settings['secretkey'] + 'private_key' => $this->settings['secretkey'] )); } else { Paymentwall_Config::getInstance()->set(array( @@ -64,27 +59,34 @@ public function init_configs($isPingback = false) { /** * Displays credit card form */ - public function payment_fields() { + public function payment_fields() + { $display_tokenization = is_checkout() && $this->saved_cards; - - if ( $display_tokenization ) { + if ($display_tokenization) { $this->supports = array_merge($this->supports, array('tokenization')); $this->tokenization_script(); $this->saved_payment_methods(); } + if (count($this->get_tokens()) > 0) { + $haveToken = true; + } else { + $haveToken = false; + } + $haveToken = false; + $brickFormUrl = get_site_url() . '/?wc-api=paymentwall_gateway&action=brick_form'; echo $this->get_template('brick/form.html', array( 'payment_id' => $this->id, 'public_key' => $this->settings['publickey'], 'entry_card_number' => __("Card number", PW_TEXT_DOMAIN), 'entry_card_expiration' => __("Card expiration", PW_TEXT_DOMAIN), 'entry_card_cvv' => __("Card CVV", PW_TEXT_DOMAIN), - 'plugin_url' => PW_PLUGIN_URL + 'plugin_url' => PW_PLUGIN_URL, + 'brick_form_url' => $brickFormUrl, + 'have_token' => $haveToken )); - $hasSubscription = class_exists( 'WC_Subscriptions_Cart' ) && WC_Subscriptions_Cart::cart_contains_subscription(); - - if ( !$hasSubscription && apply_filters( 'wc_brick_display_save_payment_method_checkbox', $display_tokenization ) ) { + if (!$this->cart_subscription_exists() && apply_filters('wc_brick_display_save_payment_method_checkbox', $display_tokenization)) { $this->save_payment_method_checkbox(); } } @@ -95,7 +97,8 @@ public function payment_fields() { * @param int $order_id * @return array */ - public function process_payment($order_id) { + public function process_payment($order_id) + { $this->init_configs(); $order = wc_get_order($order_id); try { @@ -113,12 +116,8 @@ public function process_payment($order_id) { * @return array * @throws Exception */ - function prepare_card_info($order) { - if (!isset($_POST['brick'])) { - throw new Exception("Payment Invalid!"); - } - - $brick = $_POST['brick']; + function prepare_card_info($order) + { $data = array( 'amount' => $order->get_total(), 'currency' => $order->get_currency(), @@ -126,37 +125,16 @@ function prepare_card_info($order) { 'plan' => !method_exists($order, 'get_id') ? $order->id : $order->get_id(), 'description' => sprintf(__('%s - Order #%s', PW_TEXT_DOMAIN), esc_html(get_bloginfo('name', 'display')), $order->get_order_number()), ); - if ($brick['token'] && $brick['fingerprint']) { - $data = array_merge($data, array( - 'token' => $brick['token'], - 'fingerprint' => $brick['fingerprint'] - )); - } elseif (!empty($_POST['wc-brick-payment-token'])) { - $token = WC_Payment_Tokens::get($_POST['wc-brick-payment-token'])->get_token(); - $data = array_merge($data, array( - 'token' => $token - )); - } - if (!empty($brick['cc_brick_secure_token'])) { - $data['secure_token'] = $brick['cc_brick_secure_token']; - } - if (!empty($brick['cc_brick_charge_id'])) { - $data['charge_id'] = $brick['cc_brick_charge_id']; - } return $data; } /** - * Add custom fields validation + * @return bool */ - public function brick_fields_validation() { - if ($_POST['payment_method'] == $this->id) { - $brick = $_POST['brick']; - - if ((trim($brick['token']) == '' || trim($brick['fingerprint']) == '') && empty($_POST['wc-brick-payment-token'])) - wc_add_notice(sprintf(__('The %s payment has some errors. Please try again.', PW_TEXT_DOMAIN), $this->title), 'error'); - } + protected function cart_subscription_exists() + { + return class_exists('WC_Subscriptions_Cart') && WC_Subscriptions_Cart::cart_contains_subscription(); } /** @@ -164,51 +142,44 @@ public function brick_fields_validation() { * @return array * @throws Exception */ - public function process_standard_payment($order) { + public function process_standard_payment($order) + { + if (!$this->is_valid_order()) { + $this->checkout_error_response("Order is invalid"); + } + if (isset($_POST['wc-brick-payment-token']) && $_POST['wc-brick-payment-token'] != 'new') { + $parameters = $_POST; + $chargeInfo = $this->prepare_charge_info($parameters, $order); + $charge = $this->create_charge($chargeInfo); + } else { + $charge = WC()->session->get('brick_charge'); + } $return = array(); - $cardInfo = $this->prepare_card_info($order); - $charge = new Paymentwall_Charge(); - $charge->create(array_merge( - $this->prepare_user_profile_data($order), // for User Profile API - $cardInfo, - $this->get_extra_data($order) - )); - - $response = $charge->getPublicData(); - $responseData = json_decode($charge->getRawResponseData(), true); - - if ($charge->isSuccessful() && empty($responseData['secure'])) { + if ($charge->isSuccessful()) { $return['result'] = 'success'; $return['redirect'] = $this->process_success($order, $charge, $message); $return['message'] = $message; - - if (is_checkout() && !empty($_POST['wc-brick-new-payment-method']) && $_POST['wc-brick-payment-token'] == 'new') { - $token = new WC_Payment_Token_CC(); - $token->set_token($responseData['card']['token']); - $token->set_gateway_id($this->id); - $token->set_card_type($responseData['card']['type']); - $token->set_last4($responseData['card']['last4']); - $token->set_expiry_month($responseData['card']['exp_month']); - $token->set_expiry_year('20' . $responseData['card']['exp_year']); - $token->set_user_id(get_current_user_id()); - $token->save(); - } - } elseif (!empty($responseData['secure'])) { - WC()->session->set('orderId', !method_exists($order, 'get_id') ? $order->id : $order->get_id()); - $return['result'] = 'secure'; - $return['secure'] = $responseData['secure']['formHTML']; - die(json_encode($return)); + $this->handle_storing_card($charge, WC()->session->get('email_brick_charge')); } else { - $return['result'] ='error'; - $return['message'] = $responseData['error']; - wc_add_notice(__($responseData['error']), 'error'); - die(json_encode($return)); + $this->checkout_error_response("Payment error"); } return $return; } - public function get_extra_data($order) { + /** + * @param $message + */ + protected function checkout_error_response($message) + { + $return['result'] = 'error'; + $return['message'] = $message; + wc_add_notice(__($message), 'error'); + die(json_encode($return)); + } + + public function get_extra_data($order) + { $userId = $order->get_user_id(); return array( 'custom[integration_module]' => 'woocomerce', @@ -216,33 +187,215 @@ public function get_extra_data($order) { ); } - public function process_success($order, $charge, &$message) { - if ($charge->isCaptured()) { - // Add order note - $order->add_order_note(sprintf( - __('Brick payment approved (ID: %s)', PW_TEXT_DOMAIN), - $charge->getId())); - // Payment complete - $message = "Your order has been received !"; - } elseif ($charge->isUnderReview()) { - $order->update_status('on-hold'); - $message = 'Your order is under review !'; + public function process_success($order, $charge, &$message) + { + $order->add_order_note(sprintf( + __('Brick payment approved (ID: %s)', PW_TEXT_DOMAIN), + $charge->getId())); + + if ($charge->isUnderReview()) { + $message = "Thank you. Your order has been received, the payment is under review!"; + } else { + $message = "Thank you. Your order has been received!"; } + $_SESSION['message_thank_you_page'] = $message; $thanksPage = $this->get_return_url($order); WC()->session->set('orderId', null); + WC()->session->set('amount_charge_brick', null); + WC()->session->set('cart_charge_brick', null); WC()->cart->empty_cart(); - unset($_POST['brick']); return $thanksPage; } - public static function get_available_payment_gateways( $available_gateways ) { + public static function get_available_payment_gateways($available_gateways) + { foreach ($available_gateways as $gateway_id => $gateway) { if (self::BRICK_METHOD == $gateway_id && is_add_payment_method_page()) { - unset($available_gateways[ $gateway_id ]); + unset($available_gateways[ $gateway_id] ); } } return $available_gateways; } -} + + public function handle_brick_charge() + { + $this->init_configs(); + $parameters = $_POST; + $orderId = $this->create_temporary_order(); + $order = wc_get_order($orderId); + $amount = (float)WC()->cart->get_total('edit'); + $currency = WC()->session->get('currency'); + $order->set_total($amount); + $order->set_currency($currency); + $chargeInfo = $this->prepare_charge_info($parameters, $order); + $charge = $this->create_charge($chargeInfo); + $response = $charge->getPublicData(); + $responseData = json_decode($charge->getRawResponseData(), true); + WC()->session->set('brick_charge', $charge); + WC()->session->set('amount_charge_brick', (float)WC()->cart->get_total('edit')); + WC()->session->set('cart_charge_brick', WC()->cart->get_cart()); + $result = [ + 'is_successful' => $charge->isSuccessful(), + 'is_captured' => $charge->isCaptured(), + 'is_under_review' => $charge->isUnderReview(), + 'payment' => $responseData + ]; + WC()->session->set('email_brick_charge', $parameters['email']); + $result = array_merge($result, json_decode($response, true)); + + echo json_encode($result); + die(); + } + + /** + * @return mixed + */ + protected function create_temporary_order() + { + $order = new WC_Order(); + $order->set_total(WC()->cart->get_total('edit')); + $cartHash = WC()->cart->get_cart_hash(); + $order->set_cart_hash($cartHash); + $orderId = $order->save(); + $order = wc_get_order($orderId); + WC()->session->set('order_awaiting_payment', $orderId); + + return $orderId; + } + + + /** + * @param $charge + * @param $responseData + */ + protected function handle_storing_card($charge, $email) + { + return; + if (!$charge->isSuccessful()) { + return; + } + $isNewCard = true; + if (count($this->get_tokens()) > 0) { + $isNewCard = $_POST['wc-brick-payment-token'] == 'new'; + } + if (is_checkout() && !empty($_POST['wc-brick-new-payment-method']) && $isNewCard) { + $responseData = json_decode($charge->getRawResponseData(), true); + $token = new WC_Payment_Token_CC(); + $token->set_token($responseData['card']['token']); + $token->set_gateway_id($this->id); + $token->set_card_type($responseData['card']['type']); + $token->set_last4($responseData['card']['last4']); + $token->set_expiry_month($responseData['card']['exp_month']); + $token->set_expiry_year($responseData['card']['exp_year']); + $token->set_user_id(get_current_user_id()); + $token->add_meta_data('email', $email); + $token->save(); + } + } + + /** + * @param $params + * @param $orderId + * @return array + */ + public function prepare_charge_info($params, $order) + { + $chargeInfo = [ + 'email' => $params['email'], + 'history[registration_date]' => '1489655092', + 'amount' => $order->get_total(), + 'currency' => $order->get_currency(), + 'description' => 'Brick Paymentwall', + 'plan' => $order->get_id(), + ]; + if (isset($params['brick_token'])) { + $chargeInfo['token'] = $params['brick_token']; + $chargeInfo['fingerprint'] = $params['brick_fingerprint']; + } elseif (!empty($_POST['wc-brick-payment-token'])) { + $token = WC_Payment_Tokens::get($_POST['wc-brick-payment-token']); + $chargeInfo['token'] = $token->get_token(); + $chargeInfo['email'] = $token->get_meta('email'); + } + if (isset($params['brick_charge_id']) && isset($params['brick_secure_token'])) { + $chargeInfo['charge_id'] = $params['brick_charge_id']; + $chargeInfo['secure_token'] = $params['brick_secure_token']; + } + if (!empty($params['brick_reference_id'])) { + $chargeInfo['reference_id'] = $params['brick_reference_id']; + } + $userProfileData = $this->prepare_user_profile(); + + return array_merge($chargeInfo, $userProfileData); + } + + /** + * @return bool + */ + protected function is_valid_order() + { + return (WC()->session->get('amount_charge_brick') == (float)WC()->cart->get_total('edit')) + && (WC()->session->get('cart_charge_brick') == WC()->cart->get_cart()); + } + + public function prepare_user_profile() + { + $customer = WC()->customer; + + return array( + 'customer[city]' => $customer->get_city(), + 'customer[state]' => $customer->get_state() ? $customer->get_state() : 'NA', + 'customer[address]' => $customer->get_address(), + 'customer[country]' => $customer->get_country(), + 'customer[zip]' => $customer->get_postcode(), + 'customer[username]' => $customer->get_email(), + 'customer[firstname]' => $customer->get_first_name(), + 'customer[lastname]' => $customer->get_last_name(), + ); + } + + public function create_charge($chargeInfo) + { + $charge = new Paymentwall_Charge(); + $charge->create($chargeInfo); + + return $charge; + } + + public function prepare_brick_form() + { + WC()->session->set('currency', get_woocommerce_currency()); + echo $this->get_template('pages/brick_form.html', array( + 'cart_total' => (float)WC()->cart->get_total('edit'), + 'currency' => get_woocommerce_currency(), + 'private_key' => $this->settings['privatekey'], + 'public_key' => $this->settings['publickey'], + 'brick_form_action' => $this->prepare_brick_action_endpoint(), + 'save_card' => $this->saved_cards && !$this->cart_subscription_exists() && is_user_logged_in(), + 'payment_js_url' => PW_PLUGIN_URL . '/assets/js/payment.js' + ) + ); + die(); + } + + private function prepare_brick_action_endpoint() + { + $endpoint = get_site_url() . '/?wc-api=paymentwall_gateway&action='; + + if ($this->cart_subscription_exists()) { + return $endpoint . 'brick_subscription'; + } + + return $endpoint . 'brick_charge'; + } + + public static function brick_preprocessing_validation($posted) { + if ($posted['payment_method'] != self::BRICK_METHOD) { + return; + } + if ($_POST['brick-pre-validation-flag'] == "1") { + wc_add_notice( __( "brick_custom_notice", 'fake_error' ), 'error'); + } + } +} \ No newline at end of file diff --git a/src/includes/class-paymentwall-gateway.php b/src/includes/class-paymentwall-gateway.php index 21bab19..31c5e6e 100644 --- a/src/includes/class-paymentwall-gateway.php +++ b/src/includes/class-paymentwall-gateway.php @@ -1,4 +1,5 @@ init_configs(true); - $pingback_params = $_GET; - $pingback = new Paymentwall_Pingback($pingback_params, $this->getRealClientIP()); if ($pingback->validate(true)) { @@ -268,10 +266,10 @@ function ipn_response() { $subscription_key = get_post_meta($original_order_id, '_subscription_id'); } - if ($pingback->getParameter('initial_ref') && (isset($subscription_key[0]) && $subscription_key[0] == $pingback->getParameter('initial_ref'))) { + if ($this->is_valid_renewal_pingback($pingback_params, $original_order_id)) { $subscription->update_status('on-hold'); $subscription->add_order_note(__('Subscription renewal payment due: Status changed from Active to On hold.', PW_TEXT_DOMAIN)); - $new_order = wcs_create_renewal_order( $subscription ); + $new_order = wcs_create_renewal_order($subscription); $new_order->add_order_note(__('Payment approved by Paymentwall - Transaction Id: ' . $pingback->getReferenceId(), PW_TEXT_DOMAIN)); update_post_meta(!method_exists($new_order, 'get_id') ? $new_order->id : $new_order->get_id(), '_subscription_id', $pingback->getReferenceId()); $new_order->set_payment_method($subscription->payment_gateway); @@ -304,6 +302,25 @@ function ipn_response() { } } + /** + * @param $pingback_params + * @param $orderId + * @return bool + */ + private function is_valid_renewal_pingback($pingback_params, $orderId) + { + $subscription_key = get_post_meta($orderId, '_subscription_id'); + + if (empty($pingback_params['initial_ref']) + || empty($pingback_params['subscription_id']) + || !isset($subscription_key[0]) + ) { + return false; + } + + return $subscription_key[0] == $pingback_params['subscription_id']; + } + /** * Process Ajax Request */ @@ -337,6 +354,15 @@ function handle_action() { case 'ipn': $this->ipn_response(); break; + case 'brick_charge': + $this->handle_brick_charge(); + break; + case 'brick_subscription': + $this->handle_brick_subscription(); + break; + case 'brick_form': + $this->prepare_brick_form(); + break; default: break; } @@ -546,4 +572,25 @@ public function save_data_to_session($name, $data) { } } + public function handle_brick_charge() + { + $paymentwallBrick = new Paymentwall_Brick(); + + return $paymentwallBrick->handle_brick_charge(); + } + + public function handle_brick_subscription() + { + $paymentwallBrickSubcription = new Paymentwall_Brick_Subscription(); + + echo $paymentwallBrickSubcription->handle_brick_subscription(); + die(); + } + + public function prepare_brick_form() + { + $paymentwallBrick = new Paymentwall_Brick(); + + return $paymentwallBrick->prepare_brick_form(); + } } diff --git a/src/paymentwall-for-woocommerce.php b/src/paymentwall-for-woocommerce.php index 9c0b4de..1276040 100644 --- a/src/paymentwall-for-woocommerce.php +++ b/src/paymentwall-for-woocommerce.php @@ -5,7 +5,7 @@ * Plugin Name: Paymentwall for WooCommerce * Plugin URI: https://docs.paymentwall.com/modules/woocommerce * Description: Official Paymentwall module for WordPress WooCommerce. - * Version: 1.7.4 + * Version: 1.8.0 * Author: The Paymentwall Team * Author URI: http://www.paymentwall.com/ * Text Domain: paymentwall-for-woocommerce @@ -237,3 +237,13 @@ function paymentwall_load_textdomain() { load_plugin_textdomain( PW_TEXT_DOMAIN, false, dirname( plugin_basename( __FILE__ ) ) . '/languages' ); } +add_filter('woocommerce_thankyou_order_received_text', 'custom_message_thank_you_page', 20, 2); +function custom_message_thank_you_page() +{ + $str = null; + if (isset($_SESSION['message_thank_you_page'])) { + $str = '

' . $_SESSION['message_thank_you_page'] . '

'; + } + + return $str; +} \ No newline at end of file diff --git a/src/templates/brick/form.html b/src/templates/brick/form.html index 01b1cd7..59fa21b 100644 --- a/src/templates/brick/form.html +++ b/src/templates/brick/form.html @@ -1,98 +1,96 @@ - -
- - - - - - - + + + + - diff --git a/src/templates/pages/brick_form.html b/src/templates/pages/brick_form.html new file mode 100644 index 0000000..e16ffc4 --- /dev/null +++ b/src/templates/pages/brick_form.html @@ -0,0 +1,53 @@ + + +
+ + + + \ No newline at end of file