/**
  * Process an initial subscription payment if the order contains a
  * subscription, otherwise use the parent::process_payment() method
  *
  * @since  1.4
  * @param int $order_id the order identifier
  * @return array
  */
 public function process_payment($order_id)
 {
     require_once 'class-wc-realex-api.php';
     // processing subscription (which means we are ineligible for 3DSecure for now)
     if (SV_WC_Plugin_Compatibility::is_wc_subscriptions_version_gte_2_0() ? wcs_order_contains_subscription($order_id) : WC_Subscriptions_Order::order_contains_subscription($order_id)) {
         $order = wc_get_order($order_id);
         // redirect to payment page for payment if 3D secure is enabled
         if ($this->get_threedsecure()->is_3dsecure_available() && !SV_WC_Helper::get_post('woocommerce_pay_page')) {
             // empty cart before redirecting from Checkout page
             WC()->cart->empty_cart();
             // redirect to payment page to continue payment
             return array('result' => 'success', 'redirect' => $order->get_checkout_payment_url(true));
         }
         $order->payment_total = SV_WC_Helper::number_format(SV_WC_Plugin_Compatibility::is_wc_subscriptions_version_gte_2_0() ? $order->get_total() : WC_Subscriptions_Order::get_total_initial_payment($order));
         // create the realex api client
         $realex_client = new Realex_API($this->get_endpoint_url(), $this->get_realvault_endpoint_url(), $this->get_shared_secret());
         // create the customer/cc tokens, and authorize the initial payment amount, if any
         $result = $this->authorize($realex_client, $order);
         // subscription with initial payment, everything is now taken care of
         if (is_array($result)) {
             // for Subscriptions 2.0.x, save payment token to subscription object
             if (SV_WC_Plugin_Compatibility::is_wc_subscriptions_version_gte_2_0()) {
                 // a single order can contain multiple subscriptions
                 foreach (wcs_get_subscriptions_for_order($order->id) as $subscription) {
                     // payment token
                     update_post_meta($subscription->id, '_realex_cardref', get_post_meta($order->id, '_realex_cardref', true));
                 }
             }
             return $result;
         }
         // otherwise there was no initial payment, so we mark the order as complete, etc
         if ($order->payment_total == 0) {
             // mark order as having received payment
             $order->payment_complete();
             WC()->cart->empty_cart();
             return array('result' => 'success', 'redirect' => $this->get_return_url($order));
         }
     } else {
         // processing regular product
         return parent::process_payment($order_id);
     }
 }
 /**
  * Add payment and transaction information as class members of WC_Order
  * instance.  The standard information that can be added includes:
  *
  * $order->payment_total           - the payment total
  * $order->customer_id             - optional payment gateway customer id (useful for tokenized payments for certain gateways, etc)
  * $order->payment->account_number - the credit card or checking account number
  * $order->payment->last_four      - the last four digits of the account number
  * $order->payment->card_type      - the card type (e.g. visa) derived from the account number
  * $order->payment->routing_number - account routing number (check transactions only)
  * $order->payment->account_type   - optional type of account one of 'checking' or 'savings' if type is 'check'
  * $order->payment->card_type      - optional card type, ie one of 'visa', etc
  * $order->payment->exp_month      - the 2 digit credit card expiration month (for credit card gateways), e.g. 07
  * $order->payment->exp_year       - the 2 digit credit card expiration year (for credit card gateways), e.g. 17
  * $order->payment->csc            - the card security code (for credit card gateways)
  * $order->payment->check_number   - optional check number (check transactions only)
  * $order->payment->drivers_license_number - optional driver license number (check transactions only)
  * $order->payment->drivers_license_state  - optional driver license state code (check transactions only)
  * $order->payment->token          - payment token (for tokenized transactions)
  *
  * Note that not all gateways will necessarily pass or require all of the
  * above.  These represent the most common attributes used among a variety
  * of gateways, it's up to the specific gateway implementation to make use
  * of, or ignore them, or add custom ones by overridding this method.
  *
  * @since 1.0.0
  * @see SV_WC_Payment_Gateway::get_order()
  * @param int|\WC_Order $order_id order ID being processed
  * @return WC_Order object with payment and transaction information attached
  */
 public function get_order($order_id)
 {
     $order = parent::get_order($order_id);
     // payment info
     if (SV_WC_Helper::get_post('wc-' . $this->get_id_dasherized() . '-account-number') && !SV_WC_Helper::get_post('wc-' . $this->get_id_dasherized() . '-payment-token')) {
         // common attributes
         $order->payment->account_number = str_replace(array(' ', '-'), '', SV_WC_Helper::get_post('wc-' . $this->get_id_dasherized() . '-account-number'));
         $order->payment->last_four = substr($order->payment->account_number, -4);
         if ($this->is_credit_card_gateway()) {
             // credit card specific attributes
             $order->payment->card_type = SV_WC_Helper::get_post('wc-' . $this->get_id_dasherized() . '-card-type');
             $order->payment->exp_month = SV_WC_Helper::get_post('wc-' . $this->get_id_dasherized() . '-exp-month');
             $order->payment->exp_year = SV_WC_Helper::get_post('wc-' . $this->get_id_dasherized() . '-exp-year');
             // add card type for gateways that don't require it displayed at checkout
             if (empty($order->payment->card_type)) {
                 $order->payment->card_type = SV_WC_Payment_Gateway_Helper::card_type_from_account_number($order->payment->account_number);
             }
             // handle single expiry field formatted like "MM / YY" or "MM / YYYY"
             if (SV_WC_Helper::get_post('wc-' . $this->get_id_dasherized() . '-expiry')) {
                 list($order->payment->exp_month, $order->payment->exp_year) = array_map('trim', explode('/', SV_WC_Helper::get_post('wc-' . $this->get_id_dasherized() . '-expiry')));
             }
             // add CSC if enabled
             if ($this->csc_enabled()) {
                 $order->payment->csc = SV_WC_Helper::get_post('wc-' . $this->get_id_dasherized() . '-csc');
             }
         } elseif ($this->is_echeck_gateway()) {
             // echeck specific attributes
             $order->payment->routing_number = SV_WC_Helper::get_post('wc-' . $this->get_id_dasherized() . '-routing-number');
             $order->payment->account_type = SV_WC_Helper::get_post('wc-' . $this->get_id_dasherized() . '-account-type');
             $order->payment->check_number = SV_WC_Helper::get_post('wc-' . $this->get_id_dasherized() . '-check-number');
             $order->payment->drivers_license_number = SV_WC_Helper::get_post('wc-' . $this->get_id_dasherized() . '-drivers-license-number');
             $order->payment->drivers_license_state = SV_WC_Helper::get_post('wc-' . $this->get_id_dasherized() . '-drivers-license-state');
         }
     } elseif (SV_WC_Helper::get_post('wc-' . $this->get_id_dasherized() . '-payment-token')) {
         // paying with tokenized payment method (we've already verified that this token exists in the validate_fields method)
         $token = $this->get_payment_tokens_handler()->get_token($order->get_user_id(), SV_WC_Helper::get_post('wc-' . $this->get_id_dasherized() . '-payment-token'));
         $order->payment->token = $token->get_id();
         $order->payment->account_number = $token->get_last_four();
         $order->payment->last_four = $token->get_last_four();
         if ($this->is_credit_card_gateway()) {
             // credit card specific attributes
             $order->payment->card_type = $token->get_card_type();
             $order->payment->exp_month = $token->get_exp_month();
             $order->payment->exp_year = $token->get_exp_year();
             if ($this->csc_enabled()) {
                 $order->payment->csc = SV_WC_Helper::get_post('wc-' . $this->get_id_dasherized() . '-csc');
             }
         } elseif ($this->is_echeck_gateway()) {
             // echeck specific attributes
             $order->payment->account_type = $token->get_account_type();
         }
         // make this the new default payment token
         $this->get_payment_tokens_handler()->set_default_token($order->get_user_id(), $token);
     }
     // standardize expiration date year to 2 digits
     if (!empty($order->payment->exp_year) && 4 === strlen($order->payment->exp_year)) {
         $order->payment->exp_year = substr($order->payment->exp_year, 2);
     }
     /**
      * Direct Gateway Get Order Filter.
      *
      * Allow actors to modify the order object.
      *
      * @since 1.0.0
      * @param \WC_Order $order order object
      * @param \SV_WC_Payment_Gateway_Direct $this instance
      */
     return apply_filters('wc_payment_gateway_' . $this->get_id() . '_get_order', $order, $this);
 }
 /**
  * Returns true if the current payment method should be tokenized: whether
  * requested by customer or otherwise forced.  This parameter is passed from
  * the checkout page/payment form.
  *
  * @since 1.0.0
  * @return boolean true if the current payment method should be tokenized
  */
 protected function should_tokenize_payment_method()
 {
     assert($this->supports_tokenization());
     return SV_WC_Helper::get_post('wc-' . $this->get_id_dasherized() . '-tokenize-payment-method') && !SV_WC_Helper::get_post('wc-' . $this->get_id_dasherized() . '-payment-token');
 }
 /**
  * Save the Admin User Edit screen payment token fields, if any
  *
  * @see SV_WC_Payment_Gateway_Plugin::maybe_add_user_profile_tokenization_fields()
  * @param SV_WC_Payment_Gateway $gateway the gateway instance
  * @param int $user_id identifies the user to save the settings for
  */
 protected function save_user_profile_tokenization_fields($gateway, $user_id)
 {
     foreach (array_keys($gateway->get_environments()) as $environment_id) {
         // deleting any payment tokens?
         $payment_tokens_deleted_name = 'wc_' . $gateway->get_id() . '_payment_tokens_deleted_' . $environment_id;
         $delete_payment_tokens = SV_WC_Helper::get_post($payment_tokens_deleted_name) ? explode(',', trim(SV_WC_Helper::get_post($payment_tokens_deleted_name), ',')) : array();
         // see whether we're deleting any
         foreach ($delete_payment_tokens as $token) {
             $gateway->remove_payment_token($user_id, $token, $environment_id);
         }
         // adding a new payment token?
         $payment_token_name = 'wc_' . $gateway->get_id() . '_payment_token_' . $environment_id;
         if (SV_WC_Helper::get_post($payment_token_name)) {
             $exp_date = explode('/', SV_WC_Helper::get_post('wc_' . $gateway->get_id() . '_payment_token_exp_date_' . $environment_id));
             // add the new payment token, making it active if this is the first card
             $gateway->add_payment_token($user_id, $gateway->build_payment_token(SV_WC_Helper::get_post($payment_token_name), array('type' => $gateway->is_credit_card_gateway() ? 'credit_card' : 'check', 'card_type' => SV_WC_Helper::get_post('wc_' . $gateway->get_id() . '_payment_token_type_' . $environment_id), 'last_four' => SV_WC_Helper::get_post('wc_' . $gateway->get_id() . '_payment_token_last_four_' . $environment_id), 'exp_month' => count($exp_date) > 1 ? sprintf('%02s', $exp_date[0]) : null, 'exp_year' => count($exp_date) > 1 ? $exp_date[1] : null)));
         }
     }
 }
 /**
  * Add any Intuit QBMS specific payment and transaction information as
  * class members of WC_Order instance.  Added members can include:
  *
  * $order->trans_request_id           - an application-supplied value that identifies the transaction
  * $order->intuit_qbms_test_condition - a convenience for testing error conditions while in test mode
  *
  * @since 1.0
  * @see WC_Gateway_Intuit_QBMS::get_order()
  * @param int $order_id order ID being processed
  * @return WC_Order object with payment and transaction information attached
  */
 public function get_order($order_id)
 {
     // add common order members
     $order = parent::get_order($order_id);
     // add intuit credit card-specific order members
     // a convenience for testing error conditions while in test mode, this is passed as the NameOnCard
     if ($this->is_environment('test') && SV_WC_Helper::get_post('wc-intuit-qbms-test-condition')) {
         $order->intuit_qbms_test_condition = SV_WC_Helper::get_post('wc-intuit-qbms-test-condition');
     }
     return $order;
 }
 /**
  * Add payment data to the order.
  *
  * @since 2.4.0
  * @param int $order_id the order ID
  * @return \WC_Order
  */
 public function get_order($order_id)
 {
     $order = parent::get_order($order_id);
     if ($this->is_accept_js_enabled() && ($nonce = SV_WC_Helper::get_post('wc-' . $this->get_id_dasherized() . '-payment-nonce'))) {
         // expiry month/year
         list($order->payment->exp_month, $order->payment->exp_year) = array_map('trim', explode('/', SV_WC_Helper::get_post('wc-' . $this->get_id_dasherized() . '-expiry')));
         // card data
         $order->payment->card_type = SV_WC_Helper::get_post('wc-' . $this->get_id_dasherized() . '-card-type');
         $order->payment->account_number = $order->payment->last_four = SV_WC_Helper::get_post('wc-' . $this->get_id_dasherized() . '-last-four');
         // nonce data
         $order->payment->descriptor = SV_WC_Helper::get_post('wc-' . $this->get_id_dasherized() . '-payment-descriptor');
         $order->payment->nonce = $nonce;
     }
     return $order;
 }
 /**
  * Validate payment form fields
  */
 public function validate_fields()
 {
     if ($this->threedsecure->is_3dsecure_available() && !SV_WC_Helper::get_post('woocommerce_pay_page')) {
         return;
     }
     $vault_card_ref = $this->get_post('realex_card_ref');
     $card_type = $this->get_post('realex_cardType');
     $account_number = $this->get_post('realex_accountNumber');
     $cv_number = $this->get_post('realex_cvNumber');
     $expiration_month = $this->get_post('realex_expirationMonth');
     $expiration_year = $this->get_post('realex_expirationYear');
     $issue_number = $this->get_post('realex_issueNumber');
     // switch only
     // if we're using an existing vaulted credit card then there's nothing to validate
     if ($vault_card_ref) {
         return true;
     }
     if (empty($card_type)) {
         SV_WC_Helper::wc_add_notice(__('Please select a card type', 'woocommerce-gateway-realex'), 'error');
         return false;
     }
     if ($this->cvv == 'yes') {
         // check security code
         if (empty($cv_number)) {
             SV_WC_Helper::wc_add_notice(__('Card security code is missing', 'woocommerce-gateway-realex'), 'error');
             return false;
         }
         if (!ctype_digit($cv_number)) {
             SV_WC_Helper::wc_add_notice(__('Card security code is invalid (only digits are allowed)', 'woocommerce-gateway-realex'), 'error');
             return false;
         }
         if (strlen($cv_number) != 3 && in_array($card_type, array('VISA', 'MC')) || strlen($cv_number) != 4 && $card_type == 'AMEX') {
             SV_WC_Helper::wc_add_notice(__('Card security code is invalid (wrong length)', 'woocommerce-gateway-realex'), 'error');
             return false;
         }
     }
     // validate optional Switch issue number
     if ($card_type == 'SWITCH' && $issue_number) {
         if (!ctype_digit($issue_number)) {
             SV_WC_Helper::wc_add_notice(__('Switch issue number is invalid (only digits are allowed)', 'woocommerce-gateway-realex'), 'error');
             return false;
         }
         if (strlen($issue_number) > 3) {
             SV_WC_Helper::wc_add_notice(__('Switch issue number is invalid (wrong length)', 'woocommerce-gateway-realex'), 'error');
             return false;
         }
     }
     // check expiration data
     $current_year = date('Y');
     $current_month = date('n');
     if (!ctype_digit($expiration_month) || !ctype_digit($expiration_year) || $expiration_month > 12 || $expiration_month < 1 || $expiration_year < $current_year || $expiration_year == $current_year && $expiration_month < $current_month || $expiration_year > $current_year + 20) {
         SV_WC_Helper::wc_add_notice(__('Card expiration date is invalid', 'woocommerce-gateway-realex'), 'error');
         return false;
     }
     // check card number
     $account_number = str_replace(array(' ', '-'), '', $account_number);
     if (empty($account_number) || !ctype_digit($account_number) || strlen($account_number) < 12 || strlen($account_number) > 19 || !$this->luhn_check($account_number)) {
         SV_WC_Helper::wc_add_notice(__('Card number is invalid', 'woocommerce-gateway-realex'), 'error');
         return false;
     }
     return true;
 }
 /**
  * Returns true if the current payment method should be tokenized: whether
  * requested by customer or otherwise forced.  This parameter is passed from
  * the checkout page/payment form.
  *
  * @since 1.0.0
  * @return boolean true if the current payment method should be tokenized
  */
 public function should_tokenize()
 {
     return SV_WC_Helper::get_post('wc-' . $this->get_gateway()->get_id_dasherized() . '-tokenize-payment-method') && !SV_WC_Helper::get_post('wc-' . $this->get_gateway()->get_id_dasherized() . '-payment-token');
 }
 /**
  * Save the token editor.
  *
  * @since 4.3.0
  * @param int $user_id the user ID
  */
 public function save($user_id)
 {
     $tokens = isset($_POST[$this->get_input_name()]) ? $_POST[$this->get_input_name()] : array();
     $built_tokens = array();
     foreach ($tokens as $data) {
         $token_id = $data['id'];
         unset($data['id']);
         if (!$token_id) {
             continue;
         }
         if ('credit_card' === $data['type']) {
             $data = $this->prepare_expiry_date($data);
         }
         // Set the default method
         $data['default'] = $token_id === SV_WC_Helper::get_post($this->get_input_name() . '_default');
         if ($data = $this->validate_token_data($token_id, $data)) {
             $built_tokens[$token_id] = $this->build_token($user_id, $token_id, $data);
         }
     }
     $this->update_tokens($user_id, $built_tokens);
 }
 /**
  * Perform a 3DSecure payment authorization
  *
  * @param boolean $return
  * @param int $order_id the order identifier
  */
 function process_payment($return, $order_id)
 {
     // redirect to payment page for payment if 3D secure is enabled
     if ($this->is_3dsecure_available() && !SV_WC_Helper::get_post('woocommerce_pay_page')) {
         // unhook the standard payment processing filter
         remove_filter('wc_gateway_realex_process_payment', array($this->wc_gateway_realex, 'process_payment_authorize'), 10);
         // redirect from Checkout page
         $order = wc_get_order($order_id);
         WC()->cart->empty_cart();
         // redirect to payment page to continue payment
         return array('result' => 'success', 'redirect' => $order->get_checkout_payment_url(true));
     } else {
         require_once 'class-wc-realex-api.php';
         $order = wc_get_order($order_id);
         // set payment total here so it can be modified for subscriptions if needed
         $order->payment_total = number_format($order->get_total(), 2, '.', '');
         // create the realex api client
         $realex_client = new Realex_API($this->wc_gateway_realex->get_endpoint_url(), $this->wc_gateway_realex->get_realvault_endpoint_url(), $this->wc_gateway_realex->get_shared_secret());
         $realex_client->set_realmpi_endpoint_url($this->get_realmpi_endpoint_url());
         $vault_card_ref = $this->wc_gateway_realex->get_post('realex_card_ref');
         $card_type = $this->wc_gateway_realex->get_post('realex_cardType');
         // 3DSecure transaction with a supported card type?
         if ($this->is_3dsecure_available()) {
             if (!$vault_card_ref && in_array($card_type, array('VISA', 'MC', 'SWITCH'))) {
                 // unhook the standard payment processing filter
                 remove_filter('wc_gateway_realex_process_payment', array($this->wc_gateway_realex, 'process_payment_authorize'), 10, 2);
                 return $this->authorize_3dsecure($realex_client, $order);
             } elseif ($this->liability_shift() && !in_array($card_type, apply_filters('wc_gateway_realex_liability_shift_excluded_card_types', array()))) {
                 // liability shift required, order fail
                 // unhook the standard payment processing action
                 remove_filter('wc_gateway_realex_process_payment', array($this->wc_gateway_realex, 'process_payment_authorize'), 10, 2);
                 if ($vault_card_ref) {
                     $order_note = __('No Liability Shift: vaulted payments not compatible with 3D Secure.', 'woocommerce-gateway-realex');
                 } else {
                     $order_note = __('No Liability Shift: Card Type not compatible with 3D Secure.', 'woocommerce-gateway-realex');
                 }
                 $this->wc_gateway_realex->order_failed($order, $order_note);
                 SV_WC_Helper::wc_add_notice(__('The transaction has been declined, please wait and try again or try an alternative payment method.  Your order has been recorded, please contact us if you wish to provide payment over the phone.', 'woocommerce-gateway-realex'), 'error');
                 return;
             }
         }
     }
 }