Capture and refund support
This commit is contained in:
parent
a816e8a92d
commit
d45be39758
|
@ -267,6 +267,7 @@ class WC_Gateway_Paypal extends WC_Payment_Gateway {
|
||||||
WC_Gateway_Paypal_API_Handler::$api_username = $this->get_option( 'api_username' );
|
WC_Gateway_Paypal_API_Handler::$api_username = $this->get_option( 'api_username' );
|
||||||
WC_Gateway_Paypal_API_Handler::$api_password = $this->get_option( 'api_password' );
|
WC_Gateway_Paypal_API_Handler::$api_password = $this->get_option( 'api_password' );
|
||||||
WC_Gateway_Paypal_API_Handler::$api_signature = $this->get_option( 'api_signature' );
|
WC_Gateway_Paypal_API_Handler::$api_signature = $this->get_option( 'api_signature' );
|
||||||
|
WC_Gateway_Paypal_API_Handler::$sandbox = $this->testmode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -286,7 +287,7 @@ class WC_Gateway_Paypal extends WC_Payment_Gateway {
|
||||||
|
|
||||||
$this->init_api();
|
$this->init_api();
|
||||||
|
|
||||||
$result = WC_Gateway_Paypal_API_Handler::refund_order( $order, $amount, $reason, $this->testmode );
|
$result = WC_Gateway_Paypal_API_Handler::refund_transaction( $order, $amount, $reason );
|
||||||
|
|
||||||
if ( is_wp_error( $result ) ) {
|
if ( is_wp_error( $result ) ) {
|
||||||
$this->log( 'Refund Failed: ' . $result->get_error_message() );
|
$this->log( 'Refund Failed: ' . $result->get_error_message() );
|
||||||
|
@ -295,15 +296,15 @@ class WC_Gateway_Paypal extends WC_Payment_Gateway {
|
||||||
|
|
||||||
$this->log( 'Refund Result: ' . print_r( $result, true ) );
|
$this->log( 'Refund Result: ' . print_r( $result, true ) );
|
||||||
|
|
||||||
switch ( strtolower( $result['ACK'] ) ) {
|
switch ( strtolower( $result->ACK ) ) {
|
||||||
case 'success':
|
case 'success':
|
||||||
case 'successwithwarning':
|
case 'successwithwarning':
|
||||||
$order->add_order_note( sprintf( __( 'Refunded %s - Refund ID: %s', 'woocommerce' ), $result['GROSSREFUNDAMT'], $result['REFUNDTRANSACTIONID'] ) );
|
$order->add_order_note( sprintf( __( 'Refunded %s - Refund ID: %s', 'woocommerce' ), $result->GROSSREFUNDAMT, $result->REFUNDTRANSACTIONID ) );
|
||||||
return true;
|
return true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return isset( $result['L_LONGMESSAGE0'] ) ? new WP_Error( 'error', $result['L_LONGMESSAGE0'] ) : false;
|
return isset( $result->L_LONGMESSAGE0 ) ? new WP_Error( 'error', $result->L_LONGMESSAGE0 ) : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -314,9 +315,30 @@ class WC_Gateway_Paypal extends WC_Payment_Gateway {
|
||||||
public function capture_payment( $order_id ) {
|
public function capture_payment( $order_id ) {
|
||||||
$order = wc_get_order( $order_id );
|
$order = wc_get_order( $order_id );
|
||||||
|
|
||||||
if ( 'paypal' === $order->payment_method ) {
|
if ( 'paypal' === $order->payment_method && 'pending' === get_post_meta( $order->id, '_paypal_status', true ) && $order->get_transaction_id() ) {
|
||||||
$this->init_api();
|
$this->init_api();
|
||||||
WC_Gateway_Paypal_API_Handler::do_capture( $order, $amount );
|
$result = WC_Gateway_Paypal_API_Handler::do_capture( $order );
|
||||||
|
|
||||||
|
if ( is_wp_error( $result ) ) {
|
||||||
|
$this->log( 'Capture Failed: ' . $result->get_error_message() );
|
||||||
|
$order->add_order_note( sprintf( __( 'Payment could not captured: %s', 'woocommerce' ), $result->get_error_message() ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->log( 'Capture Result: ' . print_r( $result, true ) );
|
||||||
|
|
||||||
|
if ( ! empty( $result->PAYMENTSTATUS ) ) {
|
||||||
|
switch ( $result->PAYMENTSTATUS ) {
|
||||||
|
case 'Completed' :
|
||||||
|
$order->add_order_note( sprintf( __( 'Payment of %s was captured - Auth ID: %s, Transaction ID: %s', 'woocommerce' ), $result->AMT, $result->AUTHORIZATIONID, $result->TRANSACTIONID ) );
|
||||||
|
update_post_meta( $order->id, '_paypal_status', $result->PAYMENTSTATUS );
|
||||||
|
update_post_meta( $order->id, '_transaction_id', $result->TRANSACTIONID );
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
$order->add_order_note( sprintf( __( 'Payment could not captured - Auth ID: %s, Status: %s', 'woocommerce' ), $result->AUTHORIZATIONID, $result->PAYMENTSTATUS ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,9 @@ class WC_Gateway_Paypal_API_Handler {
|
||||||
/** @var string API Signature */
|
/** @var string API Signature */
|
||||||
public static $api_signature;
|
public static $api_signature;
|
||||||
|
|
||||||
|
/** @var string API Signature */
|
||||||
|
public static $sandbox = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get capture request args.
|
* Get capture request args.
|
||||||
* See https://developer.paypal.com/docs/classic/api/merchant/DoCapture_API_Operation_NVP/.
|
* See https://developer.paypal.com/docs/classic/api/merchant/DoCapture_API_Operation_NVP/.
|
||||||
|
@ -35,86 +38,13 @@ class WC_Gateway_Paypal_API_Handler {
|
||||||
'PWD' => self::$api_password,
|
'PWD' => self::$api_password,
|
||||||
'METHOD' => 'DoCapture',
|
'METHOD' => 'DoCapture',
|
||||||
'AUTHORIZATIONID' => $order->get_transaction_id(),
|
'AUTHORIZATIONID' => $order->get_transaction_id(),
|
||||||
'AMT' => number_format( $amount, 2, '.', '' ),
|
'AMT' => number_format( is_null( $amount ) ? $order->get_total() : $amount, 2, '.', '' ),
|
||||||
'CURRENCYCODE' => $order->get_order_currency(),
|
'CURRENCYCODE' => $order->get_order_currency(),
|
||||||
'COMPLETETYPE' => 'Complete',
|
'COMPLETETYPE' => 'Complete',
|
||||||
);
|
);
|
||||||
return apply_filters( 'woocommerce_paypal_capture_request', $request, $order, $amount );
|
return apply_filters( 'woocommerce_paypal_capture_request', $request, $order, $amount );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Capture an authorization.
|
|
||||||
* @param WC_Order $order
|
|
||||||
* @param float $amount
|
|
||||||
* @return object Either an object of name value pairs for a success, or a WP_ERROR object.
|
|
||||||
*/
|
|
||||||
public static function do_capture( $order, $amount ) {
|
|
||||||
$response = wp_safe_remote_post(
|
|
||||||
$sandbox ? 'https://api-3t.sandbox.paypal.com/nvp' : 'https://api-3t.paypal.com/nvp',
|
|
||||||
array(
|
|
||||||
'method' => 'POST',
|
|
||||||
'body' => self::get_capture_request( $order, $amount ),
|
|
||||||
'timeout' => 70,
|
|
||||||
'user-agent' => 'WooCommerce',
|
|
||||||
'httpversion' => '1.1'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
WC_Gateway_Paypal::log( 'DoCapture Response: ' . print_r( $response, true ) );
|
|
||||||
|
|
||||||
if ( empty( $response['body'] ) ) {
|
|
||||||
return new WP_Error( 'paypal-api', 'Empty Response' );
|
|
||||||
} elseif ( is_wp_error( $response ) ) {
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
parse_str( $response['body'], $response_array );
|
|
||||||
|
|
||||||
return (object) $response_array;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Refund an order via PayPal.
|
|
||||||
* @param WC_Order $order
|
|
||||||
* @param float $amount
|
|
||||||
* @param string $reason
|
|
||||||
* @param bool $sandbox
|
|
||||||
* @return array|wp_error The parsed response from paypal, or a WP_Error object
|
|
||||||
*/
|
|
||||||
public static function refund_order( $order, $amount = null, $reason = '', $sandbox = false ) {
|
|
||||||
$response = wp_safe_remote_post(
|
|
||||||
$sandbox ? 'https://api-3t.sandbox.paypal.com/nvp' : 'https://api-3t.paypal.com/nvp',
|
|
||||||
array(
|
|
||||||
'method' => 'POST',
|
|
||||||
'body' => self::get_request( $order, $amount, $reason ),
|
|
||||||
'timeout' => 70,
|
|
||||||
'user-agent' => 'WooCommerce',
|
|
||||||
'httpversion' => '1.1'
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
WC_Gateway_Paypal::log( 'Refund Response: ' . print_r( $response, true ) );
|
|
||||||
|
|
||||||
if ( is_wp_error( $response ) ) {
|
|
||||||
return $response;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( empty( $response['body'] ) ) {
|
|
||||||
return new WP_Error( 'paypal-refunds', 'Empty Response' );
|
|
||||||
}
|
|
||||||
|
|
||||||
parse_str( $response['body'], $response_array );
|
|
||||||
|
|
||||||
return $response_array;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Here for backwards compatibility.
|
|
||||||
* @since 2.7.0
|
|
||||||
*/
|
|
||||||
class WC_Gateway_Paypal_Refund extends WC_Gateway_Paypal_API_Handler {
|
|
||||||
/**
|
/**
|
||||||
* Get refund request args.
|
* Get refund request args.
|
||||||
* @param WC_Order $order
|
* @param WC_Order $order
|
||||||
|
@ -122,7 +52,7 @@ class WC_Gateway_Paypal_Refund extends WC_Gateway_Paypal_API_Handler {
|
||||||
* @param string $reason
|
* @param string $reason
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public static function get_request( $order, $amount = null, $reason = '' ) {
|
public static function get_refund_request( $order, $amount = null, $reason = '' ) {
|
||||||
$request = array(
|
$request = array(
|
||||||
'VERSION' => '84.0',
|
'VERSION' => '84.0',
|
||||||
'SIGNATURE' => self::$api_signature,
|
'SIGNATURE' => self::$api_signature,
|
||||||
|
@ -142,16 +72,86 @@ class WC_Gateway_Paypal_Refund extends WC_Gateway_Paypal_API_Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle response from PayPal API.
|
* Capture an authorization.
|
||||||
|
* @param WC_Order $order
|
||||||
|
* @param float $amount
|
||||||
|
* @return object Either an object of name value pairs for a success, or a WP_ERROR object.
|
||||||
*/
|
*/
|
||||||
public static function handle_response( $response, $order ) {
|
public static function do_capture( $order, $amount = null ) {
|
||||||
|
$raw_response = wp_safe_remote_post(
|
||||||
|
self::$sandbox ? 'https://api-3t.sandbox.paypal.com/nvp' : 'https://api-3t.paypal.com/nvp',
|
||||||
|
array(
|
||||||
|
'method' => 'POST',
|
||||||
|
'body' => self::get_capture_request( $order, $amount ),
|
||||||
|
'timeout' => 70,
|
||||||
|
'user-agent' => 'WooCommerce',
|
||||||
|
'httpversion' => '1.1'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
switch ( strtolower( $response['ACK'] ) ) {
|
WC_Gateway_Paypal::log( 'DoCapture Response: ' . print_r( $raw_response, true ) );
|
||||||
case 'success':
|
|
||||||
case 'successwithwarning':
|
if ( empty( $raw_response['body'] ) ) {
|
||||||
$order->add_order_note( sprintf( __( 'Refunded %s - Refund ID: %s', 'woocommerce' ), $response['GROSSREFUNDAMT'], $response['REFUNDTRANSACTIONID'] ) );
|
return new WP_Error( 'paypal-api', 'Empty Response' );
|
||||||
return true;
|
} elseif ( is_wp_error( $raw_response ) ) {
|
||||||
break;
|
return $raw_response;
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_str( $raw_response['body'], $response );
|
||||||
|
|
||||||
|
return (object) $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refund an order via PayPal.
|
||||||
|
* @param WC_Order $order
|
||||||
|
* @param float $amount
|
||||||
|
* @param string $reason
|
||||||
|
* @return object Either an object of name value pairs for a success, or a WP_ERROR object.
|
||||||
|
*/
|
||||||
|
public static function refund_transaction( $order, $amount = null, $reason = '' ) {
|
||||||
|
$raw_response = wp_safe_remote_post(
|
||||||
|
self::$sandbox ? 'https://api-3t.sandbox.paypal.com/nvp' : 'https://api-3t.paypal.com/nvp',
|
||||||
|
array(
|
||||||
|
'method' => 'POST',
|
||||||
|
'body' => self::get_refund_request( $order, $amount, $reason ),
|
||||||
|
'timeout' => 70,
|
||||||
|
'user-agent' => 'WooCommerce',
|
||||||
|
'httpversion' => '1.1'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
WC_Gateway_Paypal::log( 'Refund Response: ' . print_r( $raw_response, true ) );
|
||||||
|
|
||||||
|
if ( empty( $raw_response['body'] ) ) {
|
||||||
|
return new WP_Error( 'paypal-api', 'Empty Response' );
|
||||||
|
} elseif ( is_wp_error( $raw_response ) ) {
|
||||||
|
return $raw_response;
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_str( $raw_response['body'], $response );
|
||||||
|
|
||||||
|
return (object) $response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Here for backwards compatibility.
|
||||||
|
* @since 2.7.0
|
||||||
|
*/
|
||||||
|
class WC_Gateway_Paypal_Refund extends WC_Gateway_Paypal_API_Handler {
|
||||||
|
public static function get_request( $order, $amount = null, $reason = '' ) {
|
||||||
|
return self::get_refund_request( $order, $amount, $reason );
|
||||||
|
}
|
||||||
|
public static function refund_order( $order, $amount = null, $reason = '', $sandbox = false ) {
|
||||||
|
if ( $sandbox ) {
|
||||||
|
self::$sandbox = $sandbox;
|
||||||
|
}
|
||||||
|
$result = self::refund_transaction( $order, $amount, $reason );
|
||||||
|
if ( is_wp_error( $result ) ) {
|
||||||
|
return $result;
|
||||||
|
} else {
|
||||||
|
return (array) $result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,7 +192,11 @@ class WC_Gateway_Paypal_IPN_Handler extends WC_Gateway_Paypal_Response {
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$this->payment_on_hold( $order, sprintf( __( 'Payment pending: %s', 'woocommerce' ), $posted['pending_reason'] ) );
|
if ( 'authorization' === $posted['pending_reason'] ) {
|
||||||
|
$this->payment_on_hold( $order, __( 'Payment authorized. Change payment status to processing or complete to capture funds.', 'woocommerce' ) );
|
||||||
|
} else {
|
||||||
|
$this->payment_on_hold( $order, sprintf( __( 'Payment pending (%s).', 'woocommerce' ), $posted['pending_reason'] ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,6 +308,12 @@ class WC_Gateway_Paypal_IPN_Handler extends WC_Gateway_Paypal_Response {
|
||||||
if ( ! empty( $posted['payment_type'] ) ) {
|
if ( ! empty( $posted['payment_type'] ) ) {
|
||||||
update_post_meta( $order->id, 'Payment type', wc_clean( $posted['payment_type'] ) );
|
update_post_meta( $order->id, 'Payment type', wc_clean( $posted['payment_type'] ) );
|
||||||
}
|
}
|
||||||
|
if ( ! empty( $posted['txn_id'] ) ) {
|
||||||
|
update_post_meta( $order->id, '_transaction_id', wc_clean( $posted['txn_id'] ) );
|
||||||
|
}
|
||||||
|
if ( ! empty( $posted['payment_status'] ) ) {
|
||||||
|
update_post_meta( $order->id, '_paypal_status', wc_clean( $posted['payment_status'] ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -88,7 +88,13 @@ class WC_Gateway_Paypal_PDT_Handler extends WC_Gateway_Paypal_Response {
|
||||||
|
|
||||||
$transaction_result = $this->validate_transaction( $transaction );
|
$transaction_result = $this->validate_transaction( $transaction );
|
||||||
|
|
||||||
if ( $transaction_result && 'completed' === $status ) {
|
WC_Gateway_Paypal::log( 'PDT Transaction Result: ' . print_r( $transaction_result, true ) );
|
||||||
|
|
||||||
|
update_post_meta( $order->id, '_paypal_status', $status );
|
||||||
|
update_post_meta( $order->id, '_transaction_id', $transaction );
|
||||||
|
|
||||||
|
if ( $transaction_result ) {
|
||||||
|
if ( 'completed' === $status ) {
|
||||||
if ( $order->get_total() != $amount ) {
|
if ( $order->get_total() != $amount ) {
|
||||||
WC_Gateway_Paypal::log( 'Payment error: Amounts do not match (amt ' . $amount . ')' );
|
WC_Gateway_Paypal::log( 'Payment error: Amounts do not match (amt ' . $amount . ')' );
|
||||||
$this->payment_on_hold( $order, sprintf( __( 'Validation error: PayPal amounts do not match (amt %s).', 'woocommerce' ), $amount ) );
|
$this->payment_on_hold( $order, sprintf( __( 'Validation error: PayPal amounts do not match (amt %s).', 'woocommerce' ), $amount ) );
|
||||||
|
@ -112,6 +118,13 @@ class WC_Gateway_Paypal_PDT_Handler extends WC_Gateway_Paypal_Response {
|
||||||
update_post_meta( $order->id, 'Payment type', $transaction_result['payment_type'] );
|
update_post_meta( $order->id, 'Payment type', $transaction_result['payment_type'] );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if ( 'authorization' === $transaction_result['pending_reason'] ) {
|
||||||
|
$this->payment_on_hold( $order, __( 'Payment authorized. Change payment status to processing or complete to capture funds.', 'woocommerce' ) );
|
||||||
|
} else {
|
||||||
|
$this->payment_on_hold( $order, sprintf( __( 'Payment pending (%s).', 'woocommerce' ), $transaction_result['pending_reason'] ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue