Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ashleyfae/3c193bbcd1dafa490cbeecc6b1afd0ad to your computer and use it in GitHub Desktop.
Save ashleyfae/3c193bbcd1dafa490cbeecc6b1afd0ad to your computer and use it in GitHub Desktop.
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