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_password = $this->get_option( 'api_password' );
|
||||
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();
|
||||
|
||||
$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 ) ) {
|
||||
$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 ) );
|
||||
|
||||
switch ( strtolower( $result['ACK'] ) ) {
|
||||
switch ( strtolower( $result->ACK ) ) {
|
||||
case 'success':
|
||||
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;
|
||||
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 ) {
|
||||
$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();
|
||||
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 */
|
||||
public static $api_signature;
|
||||
|
||||
/** @var string API Signature */
|
||||
public static $sandbox = false;
|
||||
|
||||
/**
|
||||
* Get capture request args.
|
||||
* 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,
|
||||
'METHOD' => 'DoCapture',
|
||||
'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(),
|
||||
'COMPLETETYPE' => 'Complete',
|
||||
);
|
||||
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.
|
||||
* @param WC_Order $order
|
||||
|
@ -122,7 +52,7 @@ class WC_Gateway_Paypal_Refund extends WC_Gateway_Paypal_API_Handler {
|
|||
* @param string $reason
|
||||
* @return array
|
||||
*/
|
||||
public static function get_request( $order, $amount = null, $reason = '' ) {
|
||||
public static function get_refund_request( $order, $amount = null, $reason = '' ) {
|
||||
$request = array(
|
||||
'VERSION' => '84.0',
|
||||
'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'] ) ) {
|
||||
case 'success':
|
||||
case 'successwithwarning':
|
||||
$order->add_order_note( sprintf( __( 'Refunded %s - Refund ID: %s', 'woocommerce' ), $response['GROSSREFUNDAMT'], $response['REFUNDTRANSACTIONID'] ) );
|
||||
return true;
|
||||
break;
|
||||
WC_Gateway_Paypal::log( 'DoCapture 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
$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'] ) ) {
|
||||
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,28 +88,41 @@ class WC_Gateway_Paypal_PDT_Handler extends WC_Gateway_Paypal_Response {
|
|||
|
||||
$transaction_result = $this->validate_transaction( $transaction );
|
||||
|
||||
if ( $transaction_result && 'completed' === $status ) {
|
||||
if ( $order->get_total() != $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 ) );
|
||||
} else {
|
||||
$this->payment_complete( $order, $transaction, __( 'PDT payment completed', 'woocommerce' ) );
|
||||
WC_Gateway_Paypal::log( 'PDT Transaction Result: ' . print_r( $transaction_result, true ) );
|
||||
|
||||
// Log paypal transaction fee and other meta data.
|
||||
if ( ! empty( $transaction_result['mc_fee'] ) ) {
|
||||
update_post_meta( $order->id, 'PayPal Transaction Fee', $transaction_result['mc_fee'] );
|
||||
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 ) {
|
||||
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 ) );
|
||||
} else {
|
||||
$this->payment_complete( $order, $transaction, __( 'PDT payment completed', 'woocommerce' ) );
|
||||
|
||||
// Log paypal transaction fee and other meta data.
|
||||
if ( ! empty( $transaction_result['mc_fee'] ) ) {
|
||||
update_post_meta( $order->id, 'PayPal Transaction Fee', $transaction_result['mc_fee'] );
|
||||
}
|
||||
if ( ! empty( $transaction_result['payer_email'] ) ) {
|
||||
update_post_meta( $order->id, 'Payer PayPal address', $transaction_result['payer_email'] );
|
||||
}
|
||||
if ( ! empty( $transaction_result['first_name'] ) ) {
|
||||
update_post_meta( $order->id, 'Payer first name', $transaction_result['first_name'] );
|
||||
}
|
||||
if ( ! empty( $transaction_result['last_name'] ) ) {
|
||||
update_post_meta( $order->id, 'Payer last name', $transaction_result['last_name'] );
|
||||
}
|
||||
if ( ! empty( $transaction_result['payment_type'] ) ) {
|
||||
update_post_meta( $order->id, 'Payment type', $transaction_result['payment_type'] );
|
||||
}
|
||||
}
|
||||
if ( ! empty( $transaction_result['payer_email'] ) ) {
|
||||
update_post_meta( $order->id, 'Payer PayPal address', $transaction_result['payer_email'] );
|
||||
}
|
||||
if ( ! empty( $transaction_result['first_name'] ) ) {
|
||||
update_post_meta( $order->id, 'Payer first name', $transaction_result['first_name'] );
|
||||
}
|
||||
if ( ! empty( $transaction_result['last_name'] ) ) {
|
||||
update_post_meta( $order->id, 'Payer last name', $transaction_result['last_name'] );
|
||||
}
|
||||
if ( ! empty( $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