Created
July 12, 2019 14:31
-
-
Save ashleyfae/3c193bbcd1dafa490cbeecc6b1afd0ad to your computer and use it in GitHub Desktop.
RCP - PayPal Express webhook processing example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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