/**
  * 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, etc)
  * $order->payment->type           - one of 'credit_card' or 'check'
  * $order->description             - an order description based on the order
  * $order->unique_transaction_ref  - a combination of order number + retry count, should provide a unique value for each transaction attempt
  *
  * 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.
  *
  * The returned order is expected to be used in a transaction request.
  *
  * @since 1.0.0
  * @param int|WC_Order $order the order or order ID being processed
  * @return WC_Order object with payment and transaction information attached
  */
 protected function get_order($order)
 {
     if (is_numeric($order)) {
         $order = SV_WC_Plugin_Compatibility::wc_get_order($order);
     }
     // set payment total here so it can be modified for later by add-ons like subscriptions which may need to charge an amount different than the get_total()
     $order->payment_total = number_format($order->get_total(), 2, '.', '');
     // logged in customer?
     if (0 != SV_WC_Plugin_Compatibility::get_order_user_id($order) && false !== ($customer_id = $this->get_customer_id(SV_WC_Plugin_Compatibility::get_order_user_id($order), array('order' => $order)))) {
         $order->customer_id = $customer_id;
     }
     // add payment info
     $order->payment = new stdClass();
     // payment type (credit_card/check/etc)
     $order->payment->type = str_replace('-', '_', $this->get_payment_type());
     $order->description = sprintf(_x('%s - Order %s', 'Order description', $this->text_domain), esc_html(get_bloginfo('name')), $order->get_order_number());
     $order = $this->get_order_with_unique_transaction_ref($order);
     return $order;
 }
 /**
  * Tokenizes the current payment method and adds the standard transaction
  * data to the order post record.
  *
  * @since 1.0.0
  * @param WC_Order $order the order object
  * @param SV_WC_Payment_Gateway_API_Create_Payment_Token_Response $response optional create payment token response, or null if the tokenize payment method request should be made
  * @param string $environment_id optional environment id, defaults to plugin current environment
  * @return WC_Order the order object
  * @throws SV_WC_Payment_Gateway_Exception on network error or request error
  */
 protected function create_payment_token($order, $response = null, $environment_id = null)
 {
     assert($this->supports_tokenization());
     // default to current environment
     if (is_null($environment_id)) {
         $environment_id = $this->get_environment();
     }
     // perform the API request to tokenize the payment method if needed
     if (!$response || $this->tokenize_after_sale()) {
         $response = $this->get_api()->tokenize_payment_method($order);
     }
     if ($response->transaction_approved()) {
         // add the token to the order object for processing
         $token = $response->get_payment_token();
         $order->payment->token = $token->get_token();
         // for credit card transactions add the card type, if known (some gateways return the credit card type as part of the response, others may require it as part of the request, and still others it may never be known)
         if ($this->is_credit_card_gateway() && $token->get_card_type()) {
             $order->payment->card_type = $token->get_card_type();
         }
         // checking/savings, if known
         if ($this->is_echeck_gateway() && $token->get_account_type()) {
             $order->payment->account_type = $token->get_account_type();
         }
         // set the token to the user account
         if (SV_WC_Plugin_Compatibility::get_order_user_id($order)) {
             $this->add_payment_token(SV_WC_Plugin_Compatibility::get_order_user_id($order), $token, $environment_id);
         }
         // order note based on gateway type
         if ($this->is_credit_card_gateway()) {
             $message = sprintf(_x('%s Payment Method Saved: %s ending in %s (expires %s)', 'Supports direct credit card tokenization', $this->text_domain), $this->get_method_title(), $token->get_type_full(), $token->get_last_four(), $token->get_exp_date());
         } elseif ($this->is_echeck_gateway()) {
             // account type (checking/savings) may or may not be available, which is fine
             $message = sprintf(_x('%s eCheck Payment Method Saved: %s account ending in %s', 'Supports direct cheque tokenization', $this->text_domain), $this->get_method_title(), $token->get_account_type(), $token->get_last_four());
         }
         $order->add_order_note($message);
         // add the standard transaction data
         $this->add_transaction_data($order, $response);
     } else {
         if ($response->get_status_code() && $response->get_status_message()) {
             $message = sprintf('%s: %s', $response->get_status_code(), $response->get_status_message());
         } elseif ($response->get_status_code()) {
             $message = sprintf('Code: %s', $response->get_status_code());
         } elseif ($response->get_status_message()) {
             $message = sprintf('%s', $response->get_status_message());
         } else {
             $message = 'Unknown Error';
         }
         throw new SV_WC_Payment_Gateway_Exception($message);
     }
     return $order;
 }