RCP - PayPal Express webhook processing example
<?php | |
/** | |
* Process PayPal IPN | |
* | |
* @access public | |
* @since 2.1 | |
* @return void | |
*/ | |
public function process_webhooks() { | |
if( ! isset( $_GET['listener'] ) || strtoupper( $_GET['listener'] ) != 'EIPN' ) { | |
return; | |
} | |
rcp_log( 'Starting to process PayPal Express IPN.' ); | |
$user_id = 0; | |
$posted = apply_filters('rcp_ipn_post', $_POST ); // allow $_POST to be modified | |
$membership = false; | |
$custom = ! empty( $posted['custom'] ) ? explode( '|', $posted['custom'] ) : false; | |
if( ! empty( $posted['recurring_payment_id'] ) ) { | |
$membership = rcp_get_membership_by( 'gateway_subscription_id', $posted['recurring_payment_id'] ); | |
} | |
if( empty( $membership ) && ! empty( $custom[1] ) ) { | |
$membership = rcp_get_membership( absint( $custom[1] ) ); | |
} | |
if( empty( $membership ) || ! $membership->get_id() > 0 ) { | |
rcp_log( 'Exiting PayPal Express IPN - membership ID not found.', true ); | |
die( 'no membership found' ); | |
} | |
rcp_log( sprintf( 'Processing IPN for membership #%d.', $membership->get_id() ) ); | |
if ( empty( $user_id ) ) { | |
$user_id = $membership->get_customer()->get_user_id(); | |
} | |
$member = new RCP_Member( $membership->get_customer()->get_user_id() ); // for backwards compatibility | |
$membership_level_id = $membership->get_object_id(); | |
if( ! $membership_level_id ) { | |
rcp_log( 'Exiting PayPal Express IPN - no membership level ID.', true ); | |
die( 'no membership level found' ); | |
} | |
if( ! $membership_level = rcp_get_subscription_details( $membership_level_id ) ) { | |
rcp_log( 'Exiting PayPal Express IPN - no membership level found.', true ); | |
die( 'no membership level found' ); | |
} | |
$amount = isset( $posted['mc_gross'] ) ? number_format( (float) $posted['mc_gross'], 2, '.', '' ) : false; | |
$membership_gateway = $membership->get_gateway(); | |
// setup the payment info in an array for storage | |
$payment_data = array( | |
'subscription' => $membership_level->name, | |
'payment_type' => $posted['txn_type'], | |
'subscription_key' => $membership->get_subscription_key(), | |
'user_id' => $user_id, | |
'customer_id' => $membership->get_customer()->get_id(), | |
'membership_id' => $membership->get_id(), | |
'status' => 'complete', | |
'gateway' => ! empty( $membership_gateway ) && 'paypal_pro' == $membership_gateway ? 'paypal_pro' : 'paypal_express' | |
); | |
if ( false !== $amount ) { | |
$payment_data['amount'] = $amount; | |
} | |
if ( ! empty( $posted['payment_date'] ) ) { | |
$payment_data['date'] = date( 'Y-m-d H:i:s', strtotime( $posted['payment_date'] ) ); | |
} | |
if ( ! empty( $posted['txn_id'] ) ) { | |
$payment_data['transaction_id'] = sanitize_text_field( $posted['txn_id'] ); | |
} | |
do_action( 'rcp_valid_ipn', $payment_data, $user_id, $posted ); | |
/* now process the kind of subscription/payment */ | |
$rcp_payments = new RCP_Payments(); | |
$pending_payment_id = rcp_get_membership_meta( $membership->get_id(), 'pending_payment_id', true ); | |
// Subscriptions | |
switch ( $posted['txn_type'] ) : | |
case "recurring_payment_profile_created": | |
rcp_log( 'Processing PayPal Express recurring_payment_profile_created IPN.' ); | |
if ( isset( $posted['initial_payment_txn_id'] ) ) { | |
$transaction_id = ( 'Completed' == $posted['initial_payment_status'] ) ? $posted['initial_payment_txn_id'] : ''; | |
} else { | |
$transaction_id = $posted['ipn_track_id']; | |
} | |
if ( empty( $transaction_id ) || $rcp_payments->payment_exists( $transaction_id ) ) { | |
rcp_log( sprintf( 'Breaking out of PayPal Express IPN recurring_payment_profile_created. Transaction ID not given or payment already exists. TXN ID: %s', $transaction_id ), true ); | |
break; | |
} | |
// setup the payment info in an array for storage | |
$payment_data['date'] = date( 'Y-m-d H:i:s', strtotime( $posted['time_created'] ) ); | |
$payment_data['amount'] = number_format( (float) $posted['initial_payment_amount'], 2, '.', '' ); | |
$payment_data['transaction_id'] = sanitize_text_field( $transaction_id ); | |
if ( ! empty( $pending_payment_id ) ) { | |
$payment_id = $pending_payment_id; | |
// This activates the membership. | |
$rcp_payments->update( $pending_payment_id, $payment_data ); | |
} else { | |
$payment_data['subtotal'] = $payment_data['amount']; | |
$payment_id = $rcp_payments->insert( $payment_data ); | |
$expiration = date( 'Y-m-d 23:59:59', strtotime( $posted['next_payment_date'] ) ); | |
$membership->renew( $membership->is_recurring(), 'active', $expiration ); | |
} | |
do_action( 'rcp_webhook_recurring_payment_profile_created', $member, $this ); | |
do_action( 'rcp_gateway_payment_processed', $member, $payment_id, $this ); | |
break; | |
case "recurring_payment" : | |
rcp_log( 'Processing PayPal Express recurring_payment IPN.' ); | |
// when a user makes a recurring payment | |
update_user_meta( $user_id, 'rcp_paypal_subscriber', $posted['payer_id'] ); | |
$membership->set_gateway_subscription_id( $posted['recurring_payment_id'] ); | |
if ( 'failed' == strtolower( $posted['payment_status'] ) ) { | |
// Recurring payment failed. | |
$membership->add_note( sprintf( __( 'Transaction ID %s failed in PayPal.', 'rcp' ), $posted['txn_id'] ) ); | |
die( 'Subscription payment failed' ); | |
} elseif ( 'pending' == strtolower( $posted['payment_status'] ) ) { | |
// Recurring payment pending (such as echeck). | |
$pending_reason = ! empty( $posted['pending_reason'] ) ? $posted['pending_reason'] : __( 'unknown', 'rcp' ); | |
$membership->add_note( sprintf( __( 'Transaction ID %s is pending in PayPal for reason: %s', 'rcp' ), $posted['txn_id'], $pending_reason ) ); | |
die( 'Subscription payment pending' ); | |
} | |
// Recurring payment succeeded. | |
$membership->renew( true ); | |
$payment_data['transaction_type'] = 'renewal'; | |
// record this payment in the database | |
$payment_id = $rcp_payments->insert( $payment_data ); | |
do_action( 'rcp_ipn_subscr_payment', $user_id ); | |
do_action( 'rcp_webhook_recurring_payment_processed', $member, $payment_id, $this ); | |
do_action( 'rcp_gateway_payment_processed', $member, $payment_id, $this ); | |
die( 'successful recurring_payment' ); | |
break; | |
case "recurring_payment_profile_cancel" : | |
rcp_log( 'Processing PayPal Express recurring_payment_profile_cancel IPN.' ); | |
if( ! $member->just_upgraded() ) { | |
if( isset( $posted['initial_payment_status'] ) && 'Failed' == $posted['initial_payment_status'] ) { | |
// Initial payment failed, so set the user back to pending. | |
$membership->set_status( 'pending' ); | |
$membership->add_note( __( 'Initial payment failed in PayPal Express.', 'rcp' ) ); | |
$this->error_message = __( 'Initial payment failed.', 'rcp' ); | |
do_action( 'rcp_registration_failed', $this ); | |
do_action( 'rcp_paypal_express_initial_payment_failed', $member, $posted, $this ); | |
} else { | |
// If this is a completed payment plan, we can skip any cancellation actions. This is handled in renewals. | |
if ( $membership->has_payment_plan() && $membership->at_maximum_renewals() ) { | |
rcp_log( sprintf( 'Membership #%d has completed its payment plan - not cancelling.', $membership->get_id() ) ); | |
die( 'membership payment plan completed' ); | |
} | |
// user is marked as cancelled but retains access until end of term | |
$membership->cancel(); | |
$membership->add_note( __( 'Membership cancelled via PayPal Express IPN.', 'rcp' ) ); | |
// set the use to no longer be recurring | |
delete_user_meta( $user_id, 'rcp_paypal_subscriber' ); | |
do_action( 'rcp_ipn_subscr_cancel', $user_id ); | |
do_action( 'rcp_webhook_cancel', $member, $this ); | |
} | |
die( 'successful recurring_payment_profile_cancel' ); | |
} | |
break; | |
case "recurring_payment_failed" : | |
case "recurring_payment_suspended_due_to_max_failed_payment" : | |
rcp_log( 'Processing PayPal Express recurring_payment_failed or recurring_payment_suspended_due_to_max_failed_payment IPN.' ); | |
if( 'cancelled' !== $membership->get_status() ) { | |
$membership->set_status( 'expired' ); | |
} | |
if ( ! empty( $posted['txn_id'] ) ) { | |
$this->webhook_event_id = sanitize_text_field( $posted['txn_id'] ); | |
} elseif ( ! empty( $posted['ipn_track_id'] ) ) { | |
$this->webhook_event_id = sanitize_text_field( $posted['ipn_track_id'] ); | |
} | |
do_action( 'rcp_ipn_subscr_failed' ); | |
do_action( 'rcp_recurring_payment_failed', $member, $this ); | |
die( 'successful recurring_payment_failed or recurring_payment_suspended_due_to_max_failed_payment' ); | |
break; | |
case "web_accept" : | |
rcp_log( sprintf( 'Processing PayPal Express web_accept IPN. Payment status: %s', $posted['payment_status'] ) ); | |
switch ( strtolower( $posted['payment_status'] ) ) : | |
case 'completed' : | |
if ( empty( $payment_data['transaction_id'] ) || $rcp_payments->payment_exists( $payment_data['transaction_id'] ) ) { | |
rcp_log( sprintf( 'Not inserting PayPal Express web_accept payment. Transaction ID not given or payment already exists. TXN ID: %s', $payment_data['transaction_id'] ), true ); | |
} else { | |
$rcp_payments->insert( $payment_data ); | |
} | |
// Member was already activated. | |
break; | |
case 'denied' : | |
case 'expired' : | |
case 'failed' : | |
case 'voided' : | |
if ( $membership->is_active() ) { | |
$membership->cancel(); | |
} else { | |
rcp_log( sprintf( 'Membership #%d is not active - not cancelling account.', $membership->get_id() ) ); | |
} | |
break; | |
endswitch; | |
die( 'successful web_accept' ); | |
break; | |
endswitch; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment