<?php
/**
* Authorize Gateway.
*
* @package cartflows
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Class Cartflows_Pro_Gateway_Authorize_Net.
*/
class Cartflows_Pro_Gateway_Authorize_Net {
/**
* Member Variable
*
* @var instance
*/
private static $instance;
/**
* Key name variable
*
* @var key
*/
public $key = 'authorize_net_cim_credit_card';
/**
* Extra data required in other functions
*
* @var extra_data
*/
public $extra_data = array();
/**
* Opaque value variable
*
* @var unset_opaque_value
*/
public $unset_opaque_value = false;
/**
* Characterset encoding type
*
* @var mb_encoding
*/
public $mb_encoding = 'UTF-8';
/**
* Offer product
*
* @var offer_product
*/
public $offer_product = array();
/**
* Refund Supported
*
* @var is_api_refund
*/
public $is_api_refund = true;
/**
* Initiator
*/
public static function get_instance() {
if ( ! isset( self::$instance ) ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Constructor
*/
public function __construct() {
/**
* Force tokenization when needed for upsell/doownsell
*/
add_filter( 'wc_payment_gateway_' . $this->key . '_tokenization_forced', array( $this, 'maybe_force_tokenization' ) );
/**
* Create token for non logged-in user and authorize version greater than 3.0.0.
* Force guest tokenization when needed for upsell/doownsell
*/
add_filter( 'wc_payment_gateway_' . $this->key . '_process_payment', array( $this, 'create_token_process_payment' ), 10, 3 );
/**
*
* Send the data for the refund request.
*/
add_filter( 'wc_authorize_net_cim_api_request_data', array( $this, 'offer_refund_request_data' ), 10, 3 );
add_action( 'cartflows_offer_subscription_created', array( $this, 'add_subscription_payment_meta_for_authorize_net' ), 10, 3 );
}
/**
* Forces tokenization for upsell/downsells.
*
* @since 1.5.0
*
* @param bool $force_tokenization whether tokenization should be forced.
* @return bool
*/
public function maybe_force_tokenization( $force_tokenization ) {
wcf()->logger->log( 'Started: ' . __CLASS__ . '::' . __FUNCTION__ );
if ( isset( $_POST['post_data'] ) ) {
$post_data = array();
$post_raw_data = sanitize_text_field( wp_unslash( $_POST['post_data'] ) );
parse_str( $post_raw_data, $post_data );
$checkout_id = wcf_pro()->utils->get_checkout_id_from_data( $post_data );
$flow_id = wcf_pro()->utils->get_flow_id_from_data( $post_data );
if ( $checkout_id && $flow_id ) {
$wcf_step_obj = wcf_pro_get_step( $checkout_id );
$next_step_id = $wcf_step_obj->get_next_step_id();
$wcf_next_step_obj = wcf_pro_get_step( $next_step_id );
if ( $next_step_id && $wcf_next_step_obj->is_offer_page() ) {
$force_tokenization = true;
wcf()->logger->log( 'Force save source enabled' );
}
}
}
wcf()->logger->log( $force_tokenization );
return $force_tokenization;
}
/**
* Create token for non logged-in user and authorize version greater than 3.0.0
* Forces guest tokenization for upsell/downsells.
*
* @since 1.5.0
*
* @param array $result gateway data.
* @param int $order_id order id.
* @param object $anet_obj class instance.
* @return array
*/
public function create_token_process_payment( $result, $order_id, $anet_obj ) {
$create_token = false;
$checkout_id = wcf()->utils->get_checkout_id_from_post_data();
$flow_id = wcf()->utils->get_flow_id_from_post_data();
if ( $checkout_id && $flow_id ) {
$wcf_step_obj = wcf_pro_get_step( $checkout_id );
$next_step_id = $wcf_step_obj->get_next_step_id();
$wcf_next_step_obj = wcf_pro_get_step( $next_step_id );
if ( $next_step_id && $wcf_next_step_obj->is_offer_page() ) {
$create_token = true;
}
}
$order = $this->get_wc_gateway()->get_order( $order_id );
$get_user_id = $order->get_user_id();
if ( $create_token && empty( $get_user_id ) ) {
try {
// Check if token is already exist.
if ( isset( $order->payment->token ) && $order->payment->token ) {
$this->get_wc_gateway()->add_transaction_data( $order );
} else {
// else create new token.
$order_for_shipping = $order;
try {
$order = $this->get_wc_gateway()->get_payment_tokens_handler()->create_token( $order );
} catch ( Exception $e ) {
$re = '/[0-9]+/';
$str = $e->getMessage();
preg_match_all( $re, $str, $matches, PREG_SET_ORDER, 0 );
if ( $matches && is_array( $matches ) && isset( $matches[0][0] ) && '00039' === $matches[0][0] ) {
$get_order_by_meta = new WP_Query(
array(
'post_type' => 'shop_order',
'post_status' => 'any',
'meta_query' => array( //phpcs:ignore
array(
'key' => '_wc_authorize_net_cim_credit_card_customer_id',
'value' => $matches[1][0],
'compare' => '=',
),
),
'fields' => 'ids',
'order' => 'ASC',
)
);
if ( is_array( $get_order_by_meta->posts ) && count( $get_order_by_meta->posts ) > 0 ) {
$this->extra_data['authorize_net_cim_order_id'] = $get_order_by_meta->posts[0];
$order_for_shipping = $this->get_wc_gateway()->get_order( $get_order_by_meta->posts[0] );
$this->extra_data['authorize_net_cim_customer_id'] = $matches[1][0];
}
}
}
// otherwise tokenize the payment method.
$this->unset_opaque_value = true;
$order = $this->get_order( $order );
$this->get_wc_gateway()->add_transaction_data( $order );
/**
* We need to create shipping ID for the current user on Authorize.Net CIM API
* As ShippingAddressID is important for the cases when business owner has shipping-filters enabled in their merchant account.
*/
try {
/**
* When we are in a case when there is a returning user & not logged in then in this case there are chances that shipping API request might fail.
* In this case we need to try and get shipping ID from the order meta and set this up for further.
*/
$response = $this->get_wc_gateway()->get_api()->create_shipping_address( $order );
} catch ( Exception $e ) {
$response = intval( $order_for_shipping->get_meta( '_authorize_cim_shipping_address_id' ) );
}
$shipping_address_id = is_numeric( $response ) ? $response : $response->get_shipping_address_id();
$order->payment->shipping_address_id = $shipping_address_id;
$this->get_wc_gateway()->add_transaction_data( $order );
$this->do_main_transaction( $order );
}
$result = array(
'result' => 'success',
'redirect' => $this->get_wc_gateway()->get_return_url( $order ),
);
} catch ( Exception $e ) {
$result = array(
'result' => 'failure',
'message' => $e->getMessage(),
);
}
}
return $result;
}
/**
* Get current site name.
*
* @return string
*/
public function get_current_site_name() {
return ( is_multisite() ) ? get_blog_details()->blogname : get_bloginfo( 'name' );
}
/**
* Get order.
*
* @param object $order order object.
* @return object.
*/
public function get_order( $order ) {
if ( $order instanceof WC_Order && $this->key === $order->get_payment_method() ) {
if ( $this->has_token( $order ) && ! is_checkout_pay_page() ) {
$order_id = $order->get_id();
// retrieve the payment token.
$order->payment->token = $this->get_wc_gateway()->get_order_meta( $order_id, 'payment_token' );
$token_from_gateway = $this->get_token( $order );
if ( empty( $order->payment->token ) && ! empty( $token_from_gateway ) ) {
$order->payment->token = $token_from_gateway;
}
// retrieve the optional customer id.
$order->customer_id = $this->get_wc_gateway()->get_order_meta( $order_id, 'customer_id' );
/* May be we need customer id from session */
$customer_id_from_session = isset( $this->extra_data['authorize_net_cim_customer_id'] ) ? $this->extra_data['authorize_net_cim_customer_id'] : '';
if ( empty( $order->customer_id ) && ! empty( $customer_id_from_session ) ) {
$order->customer_id = $customer_id_from_session;
}
// set token data on order.
if ( $this->get_wc_gateway()->get_payment_tokens_handler()->user_has_token( $order->get_user_id(), $order->payment->token ) ) {
// an existing registered user with a saved payment token.
$token = $this->get_wc_gateway()->get_payment_tokens_handler()->get_token( $order->get_user_id(), $order->payment->token );
// account last four.
$order->payment->account_number = $token->get_last_four();
if ( $this->get_wc_gateway()->is_credit_card_gateway() ) {
// card type.
$order->payment->card_type = $token->get_card_type();
// exp month/year.
$order->payment->exp_month = $token->get_exp_month();
$order->payment->exp_year = $token->get_exp_year();
} elseif ( $this->get_wc_gateway()->is_echeck_gateway() ) {
// account type (checking/savings).
$order->payment->account_type = $token->get_account_type();
}
} else {
// a guest user means that token data must be set from the original order.
// account number.
$order->payment->account_number = $this->get_wc_gateway()->get_order_meta( $order_id, 'account_four' );
if ( $this->get_wc_gateway()->is_credit_card_gateway() ) {
// card type.
$order->payment->card_type = $this->get_wc_gateway()->get_order_meta( $order_id, 'card_type' );
// expiry date.
$expiry_date = $this->get_wc_gateway()->get_order_meta( $order_id, 'card_expiry_date' );
if ( ! empty( $expiry_date ) ) {
list( $exp_year, $exp_month ) = explode( '-', $expiry_date );
$order->payment->exp_month = $exp_month;
$order->payment->exp_year = $exp_year;
}
} elseif ( $this->get_wc_gateway()->is_echeck_gateway() ) {
// account type.
$order->payment->account_type = $this->get_wc_gateway()->get_order_meta( $order_id, 'account_type' );
}
}
}
$response = intval( $order->get_meta( '_authorize_cim_shipping_address_id' ) );
if ( ! empty( $response ) ) {
$order->payment->shipping_address_id = $response;
}
if ( true === $this->unset_opaque_value && isset( $order->payment->opaque_value ) ) {
unset( $order->payment->opaque_value );
}
}
return $order;
}
/**
* We cloned the function that we need to fire main transaction in the case when accept.js in is action and user is not logged in.
*
* @param object $order order object.
* @throws Exception Token exception.
*/
private function do_main_transaction( $order ) {
try {
// order description.
/* translators: %1s Release payment */
$order->description = sprintf( __( '%1$s - Release Payment for Order %2$s', 'cartflows-pro' ), esc_html( $this->get_current_site_name() ), $order->get_order_number() );
// token is required.
if ( ! $order->payment->token ) {
throw new Exception( __( 'Payment token missing/invalid.', 'cartflows-pro' ) );
}
// perform the transaction.
if ( $this->get_wc_gateway()->is_credit_card_gateway() ) {
if ( $this->get_wc_gateway()->perform_credit_card_charge( $order ) ) {
$response = $this->get_wc_gateway()->get_api()->credit_card_charge( $order );
} else {
$response = $this->get_wc_gateway()->get_api()->credit_card_authorization( $order );
}
} elseif ( $this->get_wc_gateway()->is_echeck_gateway() ) {
$response = $this->get_wc_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_wc_gateway()->is_credit_card_gateway() ) {
/* translators: %1s payment released */
$message = sprintf( __( '%1$s %2$s Release Payment Approved: %3$s ending in %4$s (expires %5$s)', 'cartflows-pro' ), $this->get_wc_gateway()->get_method_title(), $this->get_wc_gateway()->perform_credit_card_authorization( $order ) ? 'Authorization' : 'Charge', ! empty( $order->payment->card_type ) ? $order->payment->card_type : 'card', $last_four, ( ! empty( $order->payment->exp_month ) && ! empty( $order->payment->exp_year ) ? $order->payment->exp_month . '/' . substr( $order->payment->exp_year, - 2 ) : 'n/a' ) );
}
// adds the transaction id (if any) to the order note.
if ( $response->get_transaction_id() ) {
/* translators: %1s transaction id */
$message .= ' ' . sprintf( __( '(Transaction ID %s)', 'cartflows-pro' ), $response->get_transaction_id() );
}
$order->add_order_note( $message );
}
if ( $response->transaction_approved() || $response->transaction_held() ) {
// add the standard transaction data.
$this->get_wc_gateway()->add_transaction_data( $order, $response );
// allow the concrete class to add any gateway-specific transaction data to the order.
$this->get_wc_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_wc_gateway()->supports( 'authorization' ) && $this->get_wc_gateway()->perform_credit_card_authorization( $order ) ) ) {
$this->get_wc_gateway()->mark_order_as_held( $order, $this->get_wc_gateway()->supports( 'authorization' ) && $this->get_wc_gateway()->perform_credit_card_authorization( $order ) ? __( 'Authorization only transaction', 'cartflows-pro' ) : $response->get_status_message(), $response );
wc_reduce_stock_levels( $order->get_id() );
} else {
// otherwise complete the order.
$order->payment_complete();
}
} else {
// failure.
throw new Exception( sprintf( '%s: %s', $response->get_status_code(), $response->get_status_message() ) );
}
} catch ( Exception $e ) {
// Mark order as failed.
/* translators: %1s payment failed message */
$this->get_wc_gateway()->mark_order_as_failed( $order, sprintf( __( 'Pre-Order Release Payment Failed: %s', 'cartflows-pro' ), $e->getMessage() ) );
}
}
/**
* Get WooCommerce payment geteways.
*
* @return array
*/
public function get_wc_gateway() {
global $woocommerce;
$gateways = $woocommerce->payment_gateways->payment_gateways();
return $gateways[ $this->key ];
}
/********************************** Helper Function Start *********************************/
/**
* Truncates a given string. The total length of return string will not exceed the given length.
* The given length will include omission string
*
* @param string $string text to truncate.
* @param int $length total desired length of string, including omission.
* @param string $omission omission text, defaults to '...'.
*
* @return string
* @since 1.5.0
*/
public function string_truncate( $string, $length, $omission = '...' ) {
if ( extension_loaded( 'mbstring' ) ) {
if ( mb_strlen( $string, $this->mb_encoding ) <= $length ) {
return $string;
}
$length -= mb_strlen( $omission, $this->mb_encoding );
return mb_substr( $string, 0, $length, $this->mb_encoding ) . $omission;
} else {
$string = $this->str_to_ascii( $string );
if ( strlen( $string ) <= $length ) {
return $string;
}
$length -= strlen( $omission );
return substr( $string, 0, $length ) . $omission;
}
}
/********************************** Helper Function End *********************************/
/**
* Get the token from order if availble.
*
* @param object $order order object.
* @return bool
*/
public function has_token( $order ) {
$order_id = $order->get_id();
$token = get_post_meta( $order_id, '_wc_' . $this->key . '_payment_token', true );
if ( ! empty( $token ) ) {
return true;
}
/* Fallback */
if ( isset( $this->extra_data['authorize_net_cim_order_id'] ) ) {
$fallback_order_id = $this->extra_data['authorize_net_cim_order_id'];
$token = get_post_meta( $fallback_order_id, '_wc_' . $this->key . '_payment_token', true );
if ( ! empty( $token ) ) {
update_post_meta( $order_id, '_wc_' . $this->key . '_payment_token', $token );
return true;
}
}
return false;
}
/**
* Get the token from order if availble.
*
* @param object $order order object.
* @return string
*/
public function get_token( $order ) {
$order_id = $order->get_id();
$token = get_post_meta( $order_id, '_wc_' . $this->key . '_payment_token', true );
if ( ! empty( $token ) ) {
return $token;
}
return '';
}
/**
* Get customer id by order
*
* @param object $order order object.
*
* @return string customer id
*/
public function get_customer_id( $order ) {
$order_id = $order->get_id();
$customer_id = get_post_meta( $order_id, '_wc_' . $this->key . '_customer_id', true );
if ( ! empty( $customer_id ) ) {
return $customer_id;
}
return '';
}
/**
* Order items.
*
* @return array
* @since 1.5.0
*/
protected function get_line_items() {
$line_items = array();
$offer_product = $this->offer_product;
if ( isset( $offer_product['id'] ) && $offer_product['id'] > 0 ) {
$line_items[] = array(
'itemId' => $this->string_truncate( $offer_product['id'], 31 ),
'name' => $this->string_truncate( $offer_product['name'], 31 ),
'description' => $this->string_truncate( $offer_product['desc'], 255 ),
'quantity' => $offer_product['qty'],
'unitPrice' => number_format( (float) $offer_product['total'], 2, '.', '' ),
);
}
return $line_items;
}
/**
* Request attributes.
*
* @param array $request request data.
* @return array
* @since 1.5.0
*/
public function get_request_attributes( $request ) {
return array(
'method' => 'POST',
'timeout' => MINUTE_IN_SECONDS,
'redirection' => 0,
'httpversion' => '1.0',
'sslverify' => true,
'blocking' => true,
'headers' => array(
'content-type' => 'application/json',
'accept' => 'application/json',
),
'body' => wp_json_encode( $request ),
'cookies' => array(),
);
}
/**
* After payment process.
*
* @param array $order order data.
* @param array $product product data.
* @return array
*/
public function process_offer_payment( $order, $product ) {
$is_successful = false;
// Assign offer product.
$this->offer_product = $product;
if ( ! $this->has_token( $order ) ) {
wcf()->logger->log( 'Authorize payment : No token found' );
return $is_successful;
}
try {
$gateway = $this->get_wc_gateway();
$api = $gateway->get_api();
$environment = $gateway->get_environment();
$url = ( 'production' === $environment ) ? $api::PRODUCTION_ENDPOINT : $api::TEST_ENDPOINT;
/**
* Get order object and modify according to your need of token and other details.
*/
add_filter( 'wc_payment_gateway_' . $this->key . '_get_order', array( $this, 'get_update_order' ), 999 );
$new_order = $gateway->get_order( $order );
$request = $this->create_transaction_request( 'capture', $new_order );
$attributes = $this->get_request_attributes( $request );
$response = wp_safe_remote_request( $url, $attributes );
$body = wp_remote_retrieve_body( $response );
$body = preg_replace( '/[\x00-\x1F\x80-\xFF]/', '', $body );
$result = json_decode( $body, true );
if ( is_wp_error( $response ) ) {
wcf()->logger->log( 'Authorize Net WP Error : ' . print_r( $response, true ) ); //phpcs:ignore
} else {
if (
isset( $result['messages'] ) &&
isset( $result['messages']['message'][0]['code'] ) &&
'I00001' === $result['messages']['message'][0]['code']
) {
$is_successful = true;
/*
Get transaction id here
transaction_id
*/
$trasaction_id = $this->get_offer_transaction_id( $result['directResponse'] );
$response_data = array(
'id' => $trasaction_id,
);
$this->store_offer_transaction( $order, $response_data, $product );
} else {
wcf()->logger->log( 'Authorize Net Response Error : ' . print_r( $result, true ) ); //phpcs:ignore
/* translators: %1s error message */
$order_note = sprintf( __( 'Authorize.net CIM Transaction Failed (%s)', 'cartflows-pro' ), $result['messages']['message'][0]['text'] );
$order->add_order_note( $order_note );
}
}
} catch ( Exception $e ) {
// todo Show actual error if any.
wcf()->logger->log( 'Authorize Net exception catch : ' . print_r( $e, true ) ); //phpcs:ignore
/* translators: %1s site name */
$note = sprintf( __( 'Authorize.Net CIM Transaction Failed (%s)', 'cartflows-pro' ), $e->getMessage() );
$order->add_order_note( $note );
}
return $is_successful;
}
/**
* Set upsell/downsell offer order.
*
* @param object $order order data.
* @return object
*/
public function get_update_order( $order ) {
if ( $order instanceof WC_Order && $this->key === $order->get_payment_method() ) {
if ( $this->has_token( $order ) && ! is_checkout_pay_page() ) {
$order_id = $order->get_id();
// retrieve the payment token.
$order->payment->token = $this->get_wc_gateway()->get_order_meta( $order_id, 'payment_token' );
$token_from_gateway = $this->get_token( $order );
if ( empty( $order->payment->token ) && ! empty( $token_from_gateway ) ) {
$order->payment->token = $token_from_gateway;
}
// retrieve the optional customer id.
$order->customer_id = $this->get_wc_gateway()->get_order_meta( $order_id, 'customer_id' );
// set token data on order.
if ( $this->get_wc_gateway()->get_payment_tokens_handler()->user_has_token( $order->get_user_id(), $order->payment->token ) ) {
// an existing registered user with a saved payment token.
$token = $this->get_wc_gateway()->get_payment_tokens_handler()->get_token( $order->get_user_id(), $order->payment->token );
// account last four.
$order->payment->account_number = $token->get_last_four();
if ( $this->get_wc_gateway()->is_credit_card_gateway() ) {
// card type.
$order->payment->card_type = $token->get_card_type();
// exp month/year.
$order->payment->exp_month = $token->get_exp_month();
$order->payment->exp_year = $token->get_exp_year();
} elseif ( $this->get_wc_gateway()->is_echeck_gateway() ) {
// account type (checking/savings).
$order->payment->account_type = $token->get_account_type();
}
} else {
// a guest user means that token data must be set from the original order.
// account number.
$order->payment->account_number = $this->get_wc_gateway()->get_order_meta( $order_id, 'account_four' );
if ( $this->get_wc_gateway()->is_credit_card_gateway() ) {
// card type.
$order->payment->card_type = $this->get_wc_gateway()->get_order_meta( $order_id, 'card_type' );
// expiry date.
$expiry_date = $this->get_wc_gateway()->get_order_meta( $order_id, 'card_expiry_date' );
if ( ! empty( $expiry_date ) ) {
list( $exp_year, $exp_month ) = explode( '-', $expiry_date );
$order->payment->exp_month = $exp_month;
$order->payment->exp_year = $exp_year;
}
} elseif ( $this->get_wc_gateway()->is_echeck_gateway() ) {
// account type.
$order->payment->account_type = $this->get_wc_gateway()->get_order_meta( $order_id, 'account_type' );
}
}
}
$response = intval( $order->get_meta( '_authorize_cim_shipping_address_id' ) );
if ( ! empty( $response ) ) {
$order->payment->shipping_address_id = $response;
}
if ( true === $this->unset_opaque_value && isset( $order->payment->opaque_value ) ) {
unset( $order->payment->opaque_value );
}
}
return $order;
}
/**
* Set upsell/downsell offer order.
*
* @param string $type transactin type.
* @param object $new_order order data.
* @return object
*/
protected function create_transaction_request( $type, $new_order ) {
$order = $new_order;
$transaction_type = ( 'auth_only' === $type ) ? 'profileTransAuthOnly' : 'profileTransAuthCapture';
$offer_product = $this->offer_product;
/**
* We need to create shipping ID for the current user on Authorize.Net CIM API
* As ShippingAddressID is important for the cases when business owner has shipping-filters enabled in their merchant account.
*/
if ( isset( $order->payment ) && isset( $order->payment->shipping_address_id ) && ! empty( $order->payment->shipping_address_id ) ) {
$shipping_address_id = $order->payment->shipping_address_id;
} else {
$response = $this->get_wc_gateway()->get_api()->create_shipping_address( $order );
$shipping_address_id = is_numeric( $response ) ? $response : $response->get_shipping_address_id();
}
return array(
'createCustomerProfileTransactionRequest' => array(
'merchantAuthentication' => array(
'name' => wc_clean( $this->get_wc_gateway()->get_api_login_id() ),
'transactionKey' => wc_clean( $this->get_wc_gateway()->get_api_transaction_key() ),
),
'refId' => $order->get_id() . '_' . $offer_product['step_id'],
'transaction' => array(
$transaction_type => array(
'amount' => $offer_product['total'],
'tax' => array(),
'shipping' => array(),
'lineItems' => $this->get_line_items(),
'customerProfileId' => $this->get_customer_id( $order ),
'customerPaymentProfileId' => $this->get_token( $order ),
'customerShippingAddressId' => $shipping_address_id,
'order' => array(
'invoiceNumber' => $order->get_id() . '_' . $offer_product['step_id'],
'description' => $this->string_truncate( $offer_product['desc'], 255 ),
'purchaseOrderNumber' => $this->string_truncate( preg_replace( '/\W/', '', $order->payment->po_number ), 25 ),
),
),
),
/*
* Extra Option if any
* 'extraOptions' get_extra_options
*/
),
);
}
/**
* Creating refund request data.
*
* @param array $request_data request data.
* @param object $order order object.
* @param string $gateway gateway.
*
* @return array
*/
public function offer_refund_request_data( $request_data, $order, $gateway ) {
if ( isset( $_POST['cartflows_refund'] ) ) {
$order_id = $order->get_id();
$step_id = isset( $_POST['step_id'] ) ? intval( $_POST['step_id'] ) : 0;
$offer_id = isset( $_POST['offer_id'] ) ? intval( $_POST['offer_id'] ) : 0;
if ( isset( $request_data['createCustomerProfileTransactionRequest'] ) &&
isset( $request_data['createCustomerProfileTransactionRequest']['refId'] )
) {
$request_data['createCustomerProfileTransactionRequest']['refId'] = $order_id . '_' . $step_id;
}
if ( isset( $request_data['createCustomerProfileTransactionRequest'] ) &&
isset( $request_data['createCustomerProfileTransactionRequest']['transaction'] ) &&
isset( $request_data['createCustomerProfileTransactionRequest']['transaction']['profileTransRefund'] ) &&
isset( $request_data['createCustomerProfileTransactionRequest']['transaction']['profileTransRefund']['order'] )
&& isset( $request_data['createCustomerProfileTransactionRequest']['transaction']['profileTransRefund']['order']['invoiceNumber'] )
) {
$request_data['createCustomerProfileTransactionRequest']['transaction']['profileTransRefund']['order']['invoiceNumber'] = $order_id . '_' . $step_id;
}
}
return $request_data;
}
/**
* Process offer refund.
*
* @param object $order the order object.
* @param array $offer_data offer data.
*
* @return bool
*/
public function process_offer_refund( $order, $offer_data ) {
$order_id = $offer_data['order_id'];
$transaction_id = $offer_data['transaction_id'];
$refund_amount = $offer_data['refund_amount'];
$refund_reason = $offer_data['refund_reason'];
$gateway = $this->get_wc_gateway();
$api = $gateway->get_api();
$response_id = false;
$order->refund = new stdClass();
$order->refund->trans_id = $transaction_id;
$order->refund->amount = number_format( $refund_amount, 2, '.', '' );
$order->refund->reason = $refund_reason;
// profile refund/void.
$order->refund->customer_profile_id = $gateway->get_order_meta( $order, 'customer_id' );
$order->refund->customer_payment_profile_id = $gateway->get_order_meta( $order, 'payment_token' );
$response = $api->refund( $order );
$response_id = $response->get_transaction_id();
if ( ! $response_id ) {
$response = $api->void( $order );
$response_id = $response->get_transaction_id();
}
return $response_id;
}
/**
* Is gateway support offer refund?
*
* @return bool
*/
public function is_api_refund() {
return $this->is_api_refund;
}
/**
* Store Offer Trxn Charge.
*
* @param WC_Order $order The order that is being paid for.
* @param Object $response The response that is send from the payment gateway.
* @param array $product The product data.
*/
public function store_offer_transaction( $order, $response, $product ) {
$order_id = $order->get_id();
wcf()->logger->log( 'Authorize Net : Offer Transaction :: Transaction ID = ' . $response['id'] . ' Captured' );
$order->update_meta_data( 'cartflows_offer_txn_resp_' . $product['step_id'], $response['id'] );
$order->save();
}
/**
* Setup the Payment data for Authorize.net Automatic Subscription.
*
* @param WC_Subscription $subscription An instance of a subscription object.
* @param object $order Object of order.
* @param array $offer_product array of offer product.
*/
public function add_subscription_payment_meta_for_authorize_net( $subscription, $order, $offer_product ) {
if ( 'authorize_net_cim_credit_card' === $order->get_payment_method() ) {
$subscription_id = $subscription->get_id();
update_post_meta( $subscription_id, '_wc_authorize_net_cim_credit_card_customer_id', $order->get_meta( '_wc_authorize_net_cim_credit_card_customer_id', true ) );
update_post_meta( $subscription_id, '_wc_authorize_net_cim_credit_card_payment_token', $order->get_meta( '_wc_authorize_net_cim_credit_card_payment_token', true ) );
}
}
/**
* Get Offer Transaction ID.
*
* @param object $response The response that is send from the payment gateway.
* @return string
*/
private function get_offer_transaction_id( $response ) {
$response = explode( ',', $response );
if ( empty( $response ) ) {
return '';
}
// offset array by 1 to match Authorize.Net's order, mainly for readability.
array_unshift( $response, null );
$new_direct_response = array();
// direct response fields are URL encoded, but we currently do not use any fields.
// (e.g. billing/shipping details) that would be affected by that.
$response_fields = array(
'response_code' => 1,
'response_subcode' => 2,
'response_reason_code' => 3,
'response_reason_text' => 4,
'authorization_code' => 5,
'avs_response' => 6,
'transaction_id' => 7,
'amount' => 10,
'account_type' => 11, // CC or ECHECK.
'transaction_type' => 12, // AUTH_ONLY or AUTH_CAPTUREVOID probably.
'csc_response' => 39,
'cavv_response' => 40,
'account_last_four' => 51,
'card_type' => 52,
);
foreach ( $response_fields as $field => $order ) {
$new_direct_response[ $field ] = ( isset( $response[ $order ] ) ) ? $response[ $order ] : '';
}
return isset( $new_direct_response['transaction_id'] ) && '' !== $new_direct_response['transaction_id'] ? $new_direct_response['transaction_id'] : '';
}
}
/**
* Prepare if class 'Cartflows_Pro_Gateway_Authorize_Net' exist.
* Kicking this off by calling 'get_instance()' method
*/
Cartflows_Pro_Gateway_Authorize_Net::get_instance();