From 4ceb790c07912a1e1b34ef268b2d6558c70c94a8 Mon Sep 17 00:00:00 2001 From: mason Date: Thu, 18 Nov 2021 18:53:45 +0700 Subject: [PATCH 1/5] [PLAT-45] Change brick js --- .gitignore | 1 + readme.txt | 8 +- src/assets/js/payment.js | 129 +------ src/includes/class-paymentwall-abstract.php | 15 +- src/includes/class-paymentwall-api.php | 2 +- .../class-paymentwall-brick-subscription.php | 318 +++++++++++------ src/includes/class-paymentwall-brick.php | 333 +++++++++++++----- src/includes/class-paymentwall-gateway.php | 59 +++- src/paymentwall-for-woocommerce.php | 10 + src/templates/brick/form.html | 155 ++++---- src/templates/pages/brick_form.html | 44 +++ 11 files changed, 648 insertions(+), 426 deletions(-) create mode 100644 .gitignore create mode 100644 src/templates/pages/brick_form.html 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..38f6501 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. @@ -40,6 +40,12 @@ 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/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..fe13ce0 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,220 @@ 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('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->count_subscription_products() > 1) { + return json_encode($this->prepare_multiple_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('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 count_subscription_products() + { + $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++; + } + } + } + + return $count; + } + + /** + * @return array[] + */ + private function prepare_multiple_subscriptions_error_response() + { + return [ + "error" => [ + 'message' => 'Brick currently does not support payment for multiple subscriptions' + ] + ]; + } + + 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 +327,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..49f2622 100644 --- a/src/includes/class-paymentwall-brick.php +++ b/src/includes/class-paymentwall-brick.php @@ -34,13 +34,7 @@ public function __construct() { add_filter('woocommerce_after_checkout_validation', array($this, 'brick_fields_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'); } /** @@ -64,27 +58,33 @@ 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; + } + $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 +95,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 +114,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 +123,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 +140,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('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 +185,205 @@ 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('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) + { + 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'; + } +} \ 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..0ff1067 100644 --- a/src/paymentwall-for-woocommerce.php +++ b/src/paymentwall-for-woocommerce.php @@ -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..9a36585 100644 --- a/src/templates/brick/form.html +++ b/src/templates/brick/form.html @@ -1,98 +1,77 @@ - -
- - - - - - - - -

- - -

- -

- - - - / - -

- -

- - - - -

-
-
- + + + - diff --git a/src/templates/pages/brick_form.html b/src/templates/pages/brick_form.html new file mode 100644 index 0000000..25fd1ae --- /dev/null +++ b/src/templates/pages/brick_form.html @@ -0,0 +1,44 @@ + + +
+ + + + \ No newline at end of file From f64c9ed048f1780c6cfcdb89f199df33d46d36b8 Mon Sep 17 00:00:00 2001 From: harry Date: Fri, 3 Dec 2021 12:42:38 +0700 Subject: [PATCH 2/5] [PLAT-45] Update place-order logic and validation for subscription cart --- src/includes/admin/settings/brick.php | 10 -- .../class-paymentwall-brick-subscription.php | 17 ++-- src/includes/class-paymentwall-brick.php | 13 ++- src/templates/brick/form.html | 93 +++++++++++-------- src/templates/pages/brick_form.html | 15 ++- 5 files changed, 90 insertions(+), 58 deletions(-) diff --git a/src/includes/admin/settings/brick.php b/src/includes/admin/settings/brick.php index 056c275..cc55e27 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', diff --git a/src/includes/class-paymentwall-brick-subscription.php b/src/includes/class-paymentwall-brick-subscription.php index fe13ce0..1d4d6a4 100644 --- a/src/includes/class-paymentwall-brick-subscription.php +++ b/src/includes/class-paymentwall-brick-subscription.php @@ -149,8 +149,8 @@ protected function get_subscription_key($post_id) { public function handle_brick_subscription() { - if ($this->count_subscription_products() > 1) { - return json_encode($this->prepare_multiple_subscriptions_error_response()); + if (!$this->is_processable_subscription_payment()) { + return json_encode($this->prepare_unprocessable_subscriptions_error_response()); } $orderId = $this->create_temporary_order(); @@ -181,28 +181,33 @@ public function handle_brick_subscription() /** * @return int */ - private function count_subscription_products() + 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 $count; + return true; } /** * @return array[] */ - private function prepare_multiple_subscriptions_error_response() + private function prepare_unprocessable_subscriptions_error_response() { return [ "error" => [ - 'message' => 'Brick currently does not support payment for multiple subscriptions' + 'message' => 'Brick currently does not support payment for multiple subscriptions or mixed cart' ] ]; } diff --git a/src/includes/class-paymentwall-brick.php b/src/includes/class-paymentwall-brick.php index 49f2622..5bb526b 100644 --- a/src/includes/class-paymentwall-brick.php +++ b/src/includes/class-paymentwall-brick.php @@ -31,7 +31,7 @@ public function __construct() { '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'); @@ -44,7 +44,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( @@ -386,4 +386,13 @@ private function prepare_brick_action_endpoint() 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/templates/brick/form.html b/src/templates/brick/form.html index 9a36585..59fa21b 100644 --- a/src/templates/brick/form.html +++ b/src/templates/brick/form.html @@ -1,57 +1,72 @@ diff --git a/src/templates/pages/brick_form.html b/src/templates/pages/brick_form.html index 25fd1ae..e16ffc4 100644 --- a/src/templates/pages/brick_form.html +++ b/src/templates/pages/brick_form.html @@ -3,7 +3,7 @@