/** * Gets the plugin configuration URL * * @since 1.0.0 * @see SV_WC_Plugin::get_settings_url() * @param string $gateway_id the gateway identifier * @return string gateway settings URL */ public function get_settings_url($gateway_id = null) { // default to first gateway if (is_null($gateway_id) || $gateway_id === $this->get_id()) { reset($this->gateways); $gateway_id = key($this->gateways); } return SV_WC_Payment_Gateway_Helper::get_payment_gateway_configuration_url($this->get_gateway_class_name($gateway_id)); }
/** * Performs a credit card transaction for the given order and returns the * result * * @since 1.0.0 * @param WC_Order $order the order object * @param SV_WC_Payment_Gateway_API_Response $response optional credit card transaction response * @return SV_WC_Payment_Gateway_API_Response the response * @throws SV_WC_Payment_Gateway_Exception network timeouts, etc */ protected function do_credit_card_transaction($order, $response = null) { if (is_null($response)) { if ($this->perform_credit_card_charge()) { $response = $this->get_api()->credit_card_charge($order); } else { $response = $this->get_api()->credit_card_authorization($order); } } // success! update order record if ($response->transaction_approved()) { $last_four = substr($order->payment->account_number, -4); // use direct card type if set, or try to guess it from card number if (!empty($order->payment->card_type)) { $card_type = $order->payment->card_type; } elseif ($first_four = substr($order->payment->account_number, 0, 4)) { $card_type = SV_WC_Payment_Gateway_Helper::card_type_from_account_number($first_four); } else { $card_type = 'card'; } // credit card order note $message = sprintf(esc_html__('%1$s %2$s %3$s Approved: %4$s ending in %5$s (expires %6$s)', 'woocommerce-plugin-framework'), $this->get_method_title(), $this->is_test_environment() ? esc_html_x('Test', 'noun, software environment', 'woocommerce-plugin-framework') : '', $this->perform_credit_card_authorization() ? esc_html_x('Authorization', 'credit card transaction type', 'woocommerce-plugin-framework') : esc_html_x('Charge', 'noun, credit card transaction type', 'woocommerce-plugin-framework'), SV_WC_Payment_Gateway_Helper::payment_type_to_name($card_type), $last_four, $order->payment->exp_month . '/' . substr($order->payment->exp_year, -2)); // adds the transaction id (if any) to the order note if ($response->get_transaction_id()) { /* translators: Placeholders: %s - transaction ID */ $message .= ' ' . sprintf(esc_html__('(Transaction ID %s)', 'woocommerce-plugin-framework'), $response->get_transaction_id()); } /** * Direct Gateway Credit Card Transaction Approved Order Note Filter. * * Allow actors to modify the order note added when a Credit Card transaction * is approved. * * @since 4.1.0 * @param string $message order note * @param \WC_Order $order order object * @param \SV_WC_Payment_Gateway_API_Response $response transaction response * @param \SV_WC_Payment_Gateway_Direct $this instance */ $message = apply_filters('wc_payment_gateway_' . $this->get_id() . '_credit_card_transaction_approved_order_note', $message, $order, $response, $this); $order->add_order_note($message); } return $response; }
/** * Performs a credit card transaction for the given order and returns the * result * * @since 1.0.0 * @param WC_Order $order the order object * @param SV_WC_Payment_Gateway_API_Response $response optional credit card transaction response * @return SV_WC_Payment_Gateway_API_Response the response * @throws SV_WC_Payment_Gateway_Exception network timeouts, etc */ protected function do_credit_card_transaction($order, $response = null) { if (is_null($response)) { if ($this->perform_credit_card_charge()) { $response = $this->get_api()->credit_card_charge($order); } else { $response = $this->get_api()->credit_card_authorization($order); } } // success! update order record if ($response->transaction_approved()) { $last_four = substr($order->payment->account_number, -4); // use direct card type if set, or try to guess it from card number if (!empty($order->payment->card_type)) { $card_type = $order->payment->card_type; } elseif ($first_four = substr($order->payment->account_number, 0, 4)) { $card_type = SV_WC_Payment_Gateway_Helper::card_type_from_account_number($first_four); } else { $card_type = 'card'; } // credit card order note $message = sprintf(_x('%s %s %s Approved: %s ending in %s (expires %s)', 'Supports direct credit card', $this->text_domain), $this->get_method_title(), $this->is_test_environment() ? _x('Test', 'Supports direct credit card', $this->text_domain) : '', $this->perform_credit_card_authorization() ? 'Authorization' : 'Charge', SV_WC_Payment_Gateway_Helper::payment_type_to_name($card_type), $last_four, $order->payment->exp_month . '/' . substr($order->payment->exp_year, -2)); // adds the transaction id (if any) to the order note if ($response->get_transaction_id()) { $message .= ' ' . sprintf(_x('(Transaction ID %s)', 'Supports direct credit card', $this->text_domain), $response->get_transaction_id()); } $message = apply_filters('wc_payment_gateway_' . $this->get_id() . '_credit_card_transaction_approved_order_note', $message, $order, $response, $this); $order->add_order_note($message); } return $response; }
/** * Adds an order note, along with anything else required after an approved * echeck transaction * * @since 2.2.0 * @param WC_Order $order the order * @param SV_WC_Payment_Gateway_API_Payment_Notification_Response transaction response */ protected function do_check_transaction_approved($order, $response) { $last_four = substr($response->get_account_number(), -4); // credit card order note $message = sprintf(__('%s %s Transaction Approved: %s ending in %s', $this->text_domain), $this->get_method_title(), $this->is_test_environment() ? 'Test' : '', SV_WC_Payment_Gateway_Helper::payment_type_to_name($response->get_account_type() ? $response->get_account_type() : 'bank'), $last_four); // adds the check number (if any) to the order note if ($response->get_check_number()) { $message .= ' ' . sprintf(__('(expires %s)', $this->text_domain), $response->get_check_number()); } // adds the transaction id (if any) to the order note if ($response->get_transaction_id()) { $message .= ' ' . sprintf(__('(Transaction ID %s)', $this->text_domain), $response->get_transaction_id()); } $order->add_order_note($message); }
/** * Add payment-specific info to the data array used to build the token given * an order. This is used when creating a customer profile or payment profile, * as the response from Authorize.Net does not contain some useful information * (like the card/account type) that improves the token display * * @since 2.0.0 * @param \WC_Order $order * @return array */ protected function parse_data_from_order(WC_Order $order) { // defaults for both credit cards/eChecks $data = array('default' => true, 'type' => $order->payment->type, 'last_four' => $order->payment->last_four, 'customer_profile_id' => $order->customer_id); if ('credit_card' === $data['type']) { $data['card_type'] = isset($order->payment->card_type) ? $order->payment->card_type : SV_WC_Payment_Gateway_Helper::card_type_from_account_number($order->payment->account_number); $data['exp_month'] = $order->payment->exp_month; $data['exp_year'] = $order->payment->exp_year; } elseif ('echeck' === $data['type']) { $data['account_type'] = $order->payment->account_type; } return $data; }
/** * Conditionally adds the payment token fields to the Admin User Edit * screen, if tokenization is enabled on the gateway, and the gateway * API does not support payment token retrieval (meaning the tokens * are stored only locally) * * @see SV_WC_Payment_Gateway_Admin_User_Edit_Handler::save_user_profile_tokenization_fields() * @param SV_WC_Payment_Gateway $gateway the gateway instance * @param WP_User $user user object for the current edit page */ protected function maybe_add_user_profile_tokenization_fields($gateway, $user) { // ensure that it supports tokenization, but doesn't have a "get tokens" request, meaning that the tokens are stored and accessed locally if ($gateway->tokenization_enabled() && !$gateway->get_api()->supports_get_tokenized_payment_methods()) { $environments = $gateway->get_environments(); foreach ($environments as $environment_id => $environment_name) { // get any payment tokens $payment_tokens = $gateway->get_payment_tokens($user->ID, array('environment_id' => $environment_id)); ?> <table class="form-table"> <tr> <th style="padding-bottom: 0;"><?php echo count($environments) > 1 ? sprintf(esc_html__('%s Payment Tokens', 'woocommerce-plugin-framework'), $environment_name) : esc_html__('Payment Tokens', 'woocommerce-plugin-framework'); ?> </th> <td style="padding-bottom: 0;"> <?php if (empty($payment_tokens)) { /* translators: Payment Token as in a specific entity used to make payments, such as a specific credit card, e-check account, bank account, etc. */ echo "<p>" . esc_html__('This customer has no saved payment tokens', 'woocommerce-plugin-framework') . "</p>"; } else { ?> <ul style="margin:0;"> <?php foreach ($payment_tokens as $token) { ?> <li> <?php echo esc_html($token->get_id()); ?> (<?php /* translators: %1$s - credit card type (mastercard, visa, ...), %2$s - last 4 numbers of the card, %3$s - card expiry date */ printf('%1$s ending in %2$s expiring %3$s', $token->get_type_full(), $token->get_last_four(), $token->get_exp_month() . '/' . $token->get_exp_year()); echo $token->is_default() ? ' <strong>' . esc_html__('Default card', 'woocommerce-plugin-framework') . '</strong>' : ''; ?> ) <a href="#" class="js-sv-wc-payment-token-delete" data-payment_token="<?php echo esc_attr($token->get_id()); ?> "><?php esc_html_e('Delete', 'woocommerce-plugin-framework'); ?> </a> </li> <?php } ?> </ul> <input type="hidden" class="js-sv-wc-payment-tokens-deleted" name="wc_<?php echo $gateway->get_id(); ?> _payment_tokens_deleted_<?php echo $environment_id; ?> " value="" /> <?php } ?> </td> </tr> <tr> <?php /* translators: Payment Token as in a specific entity used to make payments, such as a specific credit card, e-check account, bank account, etc. */ ?> <th style="padding-top: 0;"><?php esc_html_e('Add a Payment Token', 'woocommerce-plugin-framework'); ?> </th> <td style="padding-top: 0;"> <input type="text" name="wc_<?php echo $gateway->get_id(); ?> _payment_token_<?php echo $environment_id; ?> " placeholder="<?php esc_attr_e('Token', 'woocommerce-plugin-framework'); ?> " style="width:145px;" /> <?php if ($gateway->supports(SV_WC_Payment_Gateway::FEATURE_CARD_TYPES)) { ?> <select name="wc_<?php echo $gateway->get_id(); ?> _payment_token_type_<?php echo $environment_id; ?> "> <option value=""><?php esc_html_e('Card Type', 'woocommerce-plugin-framework'); ?> </option> <?php foreach ($gateway->get_card_types() as $card_type) { $card_type = strtolower($card_type); ?> <option value="<?php echo esc_attr($card_type); ?> "><?php echo esc_html(SV_WC_Payment_Gateway_Helper::payment_type_to_name($card_type)); ?> </option> <?php } ?> </select> <?php } ?> <input type="text" name="wc_<?php echo $gateway->get_id(); ?> _payment_token_last_four_<?php echo $environment_id; ?> " placeholder="<?php printf(esc_attr__('Last Four', 'woocommerce-plugin-framework'), substr(date('Y') + 1, -2)); ?> " style="width:75px;" /> <input type="text" name="wc_<?php echo $gateway->get_id(); ?> _payment_token_exp_date_<?php echo $environment_id; ?> " placeholder="<?php printf(esc_attr__('Expiry Date (01/%s)', 'woocommerce-plugin-framework'), date('Y') + 1); ?> " style="width:155px;" /> <br/> <span class="description"><?php echo apply_filters('wc_payment_gateway_' . $gateway->get_id() . '_user_profile_add_token_description', '', $gateway, $user); ?> </span> </td> </tr> </table> <?php } $this->maybe_add_user_profile_tokenization_fields_js(); } }
/** * Adds an order note, along with anything else required after an approved * echeck transaction * * @since 2.2.0 * @param WC_Order $order the order * @param SV_WC_Payment_Gateway_API_Payment_Notification_Response transaction response */ protected function do_check_transaction_approved($order, $response) { $note = ''; // Add the check type and last four digits, if available if ($response->get_account_number()) { $note .= ': ' . sprintf(__('%1$s ending in %2$s', 'woocommerce-plugin-framework'), SV_WC_Payment_Gateway_Helper::payment_type_to_name($response->get_account_type() ? $response->get_account_type() : 'bank'), substr($response->get_account_number(), -4)); } // Add the check number, if available if ($response->get_check_number()) { $note .= ' ' . sprintf(__('(check number %s)', 'woocommerce-plugin-framework'), $response->get_check_number()); } $this->do_transaction_approved($order, $response, array('method_type' => self::PAYMENT_TYPE_ECHECK, 'additional_note' => $note, 'transaction_id' => $response->get_transaction_id())); }
/** * Returns the full payment type, ie Visa, MasterCard, American Express, * Discover, Diners, JCB, eCheck, etc * * @since 1.0.0 * @return string the payment type */ public function get_type_full() { if ($this->is_credit_card()) { $type = $this->get_card_type() ? $this->get_card_type() : 'card'; } else { $type = $this->get_account_type() ? $this->get_account_type() : 'bank'; } return SV_WC_Payment_Gateway_Helper::payment_type_to_name($type); }
/** * Adds an order note, along with anything else required after an approved * echeck transaction * * @since 2.2.0 * @param WC_Order $order the order * @param SV_WC_Payment_Gateway_API_Payment_Notification_Response transaction response */ protected function do_check_transaction_approved($order, $response) { $last_four = substr($response->get_account_number(), -4); // credit card order note $message = sprintf(esc_html__('%1$s %2$s Transaction Approved: %3$s ending in %4$s', 'woocommerce-plugin-framework'), $this->get_method_title(), $this->is_test_environment() ? esc_html_x('Test', 'noun, software environment', 'woocommerce-plugin-framework') : '', SV_WC_Payment_Gateway_Helper::payment_type_to_name($response->get_account_type() ? $response->get_account_type() : 'bank'), $last_four); // adds the check number (if any) to the order note if ($response->get_check_number()) { /* translators: Placeholders: %s - check number */ $message .= ' ' . sprintf(esc_html__('(check number %s)', 'woocommerce-plugin-framework'), $response->get_check_number()); } // adds the transaction id (if any) to the order note if ($response->get_transaction_id()) { $message .= ' ' . sprintf(esc_html__('(Transaction ID %s)', 'woocommerce-plugin-framework'), $response->get_transaction_id()); } $order->add_order_note($message); }
/** * Process a pre-order payment when the pre-order is released * * @since 4.1.0 * @param \WC_Order $order original order containing the pre-order */ public function process_release_payment($order) { try { // set order defaults $order = $this->get_gateway()->get_order($order->id); // order description $order->description = sprintf(__('%s - Pre-Order Release Payment for Order %s', 'woocommerce-plugin-framework'), esc_html(get_bloginfo('name')), $order->get_order_number()); // token is required if (!$order->payment->token) { throw new SV_WC_Payment_Gateway_Exception(__('Payment token missing/invalid.', 'woocommerce-plugin-framework')); } // perform the transaction if ($this->get_gateway()->is_credit_card_gateway()) { if ($this->get_gateway()->perform_credit_card_charge()) { $response = $this->get_gateway()->get_api()->credit_card_charge($order); } else { $response = $this->get_gateway()->get_api()->credit_card_authorization($order); } } elseif ($this->get_gateway()->is_echeck_gateway()) { $response = $this->get_gateway()->get_api()->check_debit($order); } // success! update order record if ($response->transaction_approved()) { $last_four = substr($order->payment->account_number, -4); // order note based on gateway type if ($this->get_gateway()->is_credit_card_gateway()) { $message = sprintf(__('%s %s Pre-Order Release Payment Approved: %s ending in %s (expires %s)', 'woocommerce-plugin-framework'), $this->get_gateway()->get_method_title(), $this->get_gateway()->perform_credit_card_authorization() ? 'Authorization' : 'Charge', SV_WC_Payment_Gateway_Helper::payment_type_to_name(!empty($order->payment->card_type) ? $order->payment->card_type : 'card'), $last_four, $order->payment->exp_month . '/' . substr($order->payment->exp_year, -2)); } elseif ($this->get_gateway()->is_echeck_gateway()) { // account type (checking/savings) may or may not be available, which is fine $message = sprintf(__('%s eCheck Pre-Order Release Payment Approved: %s ending in %s', 'woocommerce-plugin-framework'), $this->get_gateway()->get_method_title(), SV_WC_Payment_Gateway_Helper::payment_type_to_name(!empty($order->payment->account_type) ? $order->payment->account_type : 'bank'), $last_four); } // adds the transaction id (if any) to the order note if ($response->get_transaction_id()) { $message .= ' ' . sprintf(__('(Transaction ID %s)', 'woocommerce-plugin-framework'), $response->get_transaction_id()); } $order->add_order_note($message); } if ($response->transaction_approved() || $response->transaction_held()) { // add the standard transaction data $this->get_gateway()->add_transaction_data($order, $response); // allow the concrete class to add any gateway-specific transaction data to the order $this->get_gateway()->add_payment_gateway_transaction_data($order, $response); // if the transaction was held (ie fraud validation failure) mark it as such if ($response->transaction_held() || $this->get_gateway()->supports(SV_WC_Payment_Gateway::FEATURE_CREDIT_CARD_AUTHORIZATION) && $this->get_gateway()->perform_credit_card_authorization()) { $this->get_gateway()->mark_order_as_held($order, $this->get_gateway()->supports(SV_WC_Payment_Gateway::FEATURE_CREDIT_CARD_AUTHORIZATION) && $this->get_gateway()->perform_credit_card_authorization() ? __('Authorization only transaction', 'woocommerce-plugin-framework') : $response->get_status_message(), $response); $order->reduce_order_stock(); // reduce stock for held orders, but don't complete payment } else { // otherwise complete the order $order->payment_complete(); } } else { // failure throw new SV_WC_Payment_Gateway_Exception(sprintf('%s: %s', $response->get_status_code(), $response->get_status_message())); } } catch (SV_WC_Plugin_Exception $e) { // Mark order as failed $this->get_gateway()->mark_order_as_failed($order, sprintf(__('Pre-Order Release Payment Failed: %s', 'woocommerce-plugin-framework')), $e->getMessage()); } }
/** * Validates the provided credit card account number * * @since 2.1.0 * @param string $account_number the credit card account number * @return boolean true if the card account number is valid, false otherwise */ protected function validate_credit_card_account_number($account_number) { $is_valid = true; // validate card number $account_number = str_replace(array(' ', '-'), '', $account_number); if (empty($account_number)) { SV_WC_Helper::wc_add_notice(_x('Card number is missing', 'Supports direct credit card', $this->text_domain), 'error'); $is_valid = false; } else { if (strlen($account_number) < 12 || strlen($account_number) > 19) { SV_WC_Helper::wc_add_notice(_x('Card number is invalid (wrong length)', 'Supports direct credit card', $this->text_domain), 'error'); $is_valid = false; } if (!ctype_digit($account_number)) { SV_WC_Helper::wc_add_notice(_x('Card number is invalid (only digits allowed)', 'Supports direct credit card', $this->text_domain), 'error'); $is_valid = false; } if (!SV_WC_Payment_Gateway_Helper::luhn_check($account_number)) { SV_WC_Helper::wc_add_notice(_x('Card number is invalid', 'Supports direct credit card', $this->text_domain), 'error'); $is_valid = false; } } return $is_valid; }
/** * Get the credit card type field options. * * @since 4.3.0 * @return array */ protected function get_card_type_options() { $card_types = $this->get_gateway()->get_card_types(); $options = array(); foreach ($card_types as $card_type) { // TODO: the gateway card types setting for Discover (`DISC`) doesn't match what most gateway // implementations will use as the token card type (`discover`), so manually add // it for now, until we improve our consistency here @MR 2016-03-31 if ('DISC' === $card_type) { $card_type = 'discover'; } $options[strtolower($card_type)] = SV_WC_Payment_Gateway_Helper::payment_type_to_name($card_type); } return $options; }