Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
795 lines (657 sloc) 28.7 KB
<?php
//in case the file is loaded directly
if ( ! defined( "ABSPATH" ) ) {
global $isapage;
$isapage = true;
define( 'WP_USE_THEMES', false );
require_once( dirname( __FILE__ ) . '/../../../../wp-load.php' );
}
//uncomment to log requests in logs/ipn.txt
//define('PMPRO_IPN_DEBUG', true);
//some globals
global $wpdb, $gateway_environment, $logstr;
$logstr = ""; //will put debug info here and write to ipnlog.txt
//validate?
if ( ! pmpro_ipnValidate() ) {
//validation failed
pmpro_ipnExit();
}
//assign posted variables to local variables
$txn_type = pmpro_getParam( "txn_type", "POST" );
$subscr_id = pmpro_getParam( "subscr_id", "POST" );
$txn_id = pmpro_getParam( "txn_id", "POST" );
$item_name = pmpro_getParam( "item_name", "POST" );
$item_number = pmpro_getParam( "item_number", "POST" );
$initial_payment_status = pmpro_getParam( "initial_payment_status", "POST" );
$payment_status = pmpro_getParam( "payment_status", "POST" );
$payment_amount = pmpro_getParam( "payment_amount", "POST" );
$payment_currency = pmpro_getParam( "payment_currency", "POST" );
$receiver_email = pmpro_getParam( "receiver_email", "POST", '', 'sanitize_email' );
$business_email = pmpro_getParam( "business", "POST", '', 'sanitize_email' );
$payer_email = pmpro_getParam( "payer_email", "POST", '', 'sanitize_email' );
$recurring_payment_id = pmpro_getParam( "recurring_payment_id", "POST" );
$profile_status = strtolower( pmpro_getParam( "profile_status", "POST" ) );
if ( empty( $subscr_id ) ) {
$subscr_id = $recurring_payment_id;
}
//check the receiver_email
if ( ! pmpro_ipnCheckReceiverEmail( array( strtolower( $receiver_email ), strtolower( $business_email ) ) ) ) {
//not our request
pmpro_ipnExit();
}
/*
PayPal Standard
- we will get txn_type subscr_signup and subscr_payment (or subscr_eot or subscr_failed)
- subscr_signup (if amount1 = 0, then we need to update membership, else ignore and wait for payment. create invoice for $0 with just subscr_id)
- subscr_payment (check if we should update membership, add invoice for amount with subscr_id and payment_id)
- web_accept for 1-time payment only
PayPal Express
- we will get txn_type express_checkout, or recurring_payment_profile_created, or recurring_payment (or recurring_payment_expired, or recurring_payment_skipped)
*/
//PayPal Standard Sign Up
if ( $txn_type == "subscr_signup" ) {
//if there is no amount1, this membership has a trial, and we need to update membership/etc
$amount = pmpro_getParam( "amount1", "POST" );
if ( (float) $amount <= 0 ) {
//trial, get the order
$morder = new MemberOrder( $item_number );
//No order?
if ( empty( $morder ) || empty( $morder->id ) ) {
ipnlog( "ERROR: No order found item_number/code = " . $item_number . "." );
} else {
//get some more order info
$morder->getMembershipLevel();
$morder->getUser();
//no txn_id on these, so let's use the subscr_id
if ( empty( $txn_id ) ) {
$txn_id = $subscr_id;
}
//Check that the corresponding order has a $0 initial payment as well
if ( (float) $amount != (float) $morder->total ) {
ipnlog( "ERROR: PayPal subscription #" . $_POST['subscr_id'] . " initial payment amount (" . $amount . ") is not the same as the PMPro order #" . $morder->code . " (" . $morder->total . ")." );
} else {
//update membership
if ( pmpro_ipnChangeMembershipLevel( $txn_id, $morder ) ) {
ipnlog( "Checkout processed (" . $morder->code . ") success!" );
} else {
ipnlog( "ERROR: Couldn't change level for order (" . $morder->code . ")." );
}
}
}
} else {
//we're ignoring this. we will get a payment notice from IPN and process that
ipnlog( "Going to wait for the first payment to go through." );
}
pmpro_ipnExit();
}
//PayPal Standard Subscription Payment
if ( $txn_type == "subscr_payment" ) {
//is this a first payment?
$last_subscription_order = new MemberOrder();
if ( $last_subscription_order->getLastMemberOrderBySubscriptionTransactionID( $subscr_id ) == false ) {
//first payment, get order
$morder = new MemberOrder( $_POST['item_number'] );
//No order?
if ( empty( $morder ) || empty( $morder->id ) ) {
ipnlog( "ERROR: No order found item_number/code = " . $item_number . "." );
} else {
//get some more order info
$morder->getMembershipLevel();
$morder->getUser();
//Check that the corresponding order has the same amount as what we're getting from PayPal
$amount = $_POST['mc_gross'];
//Adjust gross for tax if provided
if( !empty($_POST['tax']) ) {
$amount = (float)$amount - (float)$_POST['tax'];
//TODO: We should maybe update the order to reflect the tax amount and new total
}
if ( (float) $amount != (float) $morder->total ) {
ipnlog( "ERROR: PayPal transaction #" . $_POST['tnx_id'] . " amount (" . $amount . ") is not the same as the PMPro order #" . $morder->code . " (" . $morder->total . ")." );
} else {
//update membership
if ( pmpro_ipnChangeMembershipLevel( $txn_id, $morder ) ) {
ipnlog( "Checkout processed (" . $morder->code . ") success!" );
} else {
ipnlog( "ERROR: Couldn't change level for order (" . $morder->code . ")." );
}
}
}
pmpro_ipnExit();
} else {
//subscription payment, completed or failure?
if ( $_POST['payment_status'] == "Completed" ) {
pmpro_ipnSaveOrder( $txn_id, $last_subscription_order );
} elseif ( $_POST['payment_status'] == "Failed" ) {
pmpro_ipnFailedPayment( $last_subscription_order );
} else {
ipnlog( 'Payment status is ' . $_POST['payment_status'] . '.' );
}
pmpro_ipnExit();
}
}
//PayPal Standard Single Payment
if ( $txn_type == "web_accept" && ! empty( $item_number ) ) {
//initial payment, get the order
$morder = new MemberOrder( $item_number );
//No order?
if ( empty( $morder ) || empty( $morder->id ) ) {
ipnlog( "ERROR: No order found item_number/code = " . $item_number . "." );
} else {
//get some more order info
$morder->getMembershipLevel();
$morder->getUser();
//Check that the corresponding order has the same amount
$amount = $_POST['mc_gross'];
//Adjust gross for tax if provided
if(!empty($_POST['tax']) ) {
$amount = (float)$amount - (float)$_POST['tax'];
//TODO: We should maybe update the order to reflect the tax amount and new total
}
if ( (float) $amount != (float) $morder->total ) {
ipnlog( "ERROR: PayPal transaction #" . $_POST['txn_id'] . " amount (" . $amount . ") is not the same as the PMPro order #" . $morder->code . " (" . $morder->total . ")." );
} else {
//update membership
if ( pmpro_ipnChangeMembershipLevel( $txn_id, $morder ) ) {
ipnlog( "Checkout processed (" . $morder->code . ") success!" );
} else {
ipnlog( "ERROR: Couldn't change level for order (" . $morder->code . ")." );
}
}
}
pmpro_ipnExit();
}
//PayPal Express Recurring Payments
if ( $txn_type == "recurring_payment" ) {
$last_subscription_order = new MemberOrder();
if ( $last_subscription_order->getLastMemberOrderBySubscriptionTransactionID( $subscr_id ) ) {
//subscription payment, completed or failure?
if ( $_POST['payment_status'] == "Completed" ) {
pmpro_ipnSaveOrder( $txn_id, $last_subscription_order );
} elseif ( $_POST['payment_status'] == "Failed" ) {
pmpro_ipnFailedPayment( $last_subscription_order );
} else {
ipnlog( 'Payment status is ' . $_POST['payment_status'] . '.' );
}
} else {
ipnlog( "ERROR: Couldn't find last order for this recurring payment (" . $subscr_id . ")." );
}
pmpro_ipnExit();
}
if ( $txn_type == "recurring_payment_skipped" ) {
$last_subscription_order = new MemberOrder();
if ( $last_subscription_order->getLastMemberOrderBySubscriptionTransactionID( $subscr_id ) ) {
// the payment failed
pmpro_ipnFailedPayment( $last_subscription_order );
} else {
ipnlog( "ERROR: Couldn't find last order for this recurring payment (" . $subscr_id . ")." );
}
pmpro_ipnExit();
}
if ( $txn_type == "recurring_payment_suspended_due_to_max_failed_payment" && 'suspended' == $profile_status ) {
$last_subscription_order = new MemberOrder();
if ( $last_subscription_order->getLastMemberOrderBySubscriptionTransactionID( $subscr_id ) ) {
// the payment failed
pmpro_ipnFailedPayment( $last_subscription_order );
} else {
ipnlog( "ERROR: Couldn't find last order for this recurring payment (" . $subscr_id . ")." );
}
pmpro_ipnExit();
}
//Recurring Payment Profile Cancelled (PayPal Express)
if ( $txn_type == "recurring_payment_profile_cancel" ) {
//find last order
$last_subscription_order = new MemberOrder();
if ( $last_subscription_order->getLastMemberOrderBySubscriptionTransactionID( $recurring_payment_id ) == false ) {
ipnlog( "ERROR: Couldn't find this order to cancel (subscription_transaction_id=" . $recurring_payment_id . ")." );
pmpro_ipnExit();
} else {
//found order, let's cancel the membership
$user = get_userdata( $last_subscription_order->user_id );
if ( empty( $user ) || empty( $user->ID ) ) {
ipnlog( "ERROR: Could not cancel membership. No user attached to order #" . $last_subscription_order->id . " with subscription transaction id = " . $recurring_payment_id . "." );
} else {
/*
We want to make sure this is a cancel originating from PayPal and not one already handled by PMPro.
For example, if a user cancels on WP/PMPro side, we've already cancelled the membership.
Also, if a user is changing levels, we don't want to cancel their new membership, just the old subscription at PayPal.
So we check 2 things and don't cancel if:
(1) This order already has "cancelled" status.
(2) The user doesn't currently have the level attached to this order.
*/
if ( $last_subscription_order->status == "cancelled" ) {
ipnlog( "We've already processed this cancellation. Probably originated from WP/PMPro. (Order #" . $last_subscription_order->id . ", Subscription Transaction ID #" . $recurring_payment_id . ")" );
} elseif ( ! pmpro_hasMembershipLevel( $last_subscription_order->membership_id, $user->ID ) ) {
ipnlog( "This user has a different level than the one associated with this order. Their membership was probably changed by an admin or through an upgrade/downgrade. (Order #" . $last_subscription_order->id . ", Subscription Transaction ID #" . $recurring_payment_id . ")" );
} else {
//if the initial payment failed, cancel with status error instead of cancelled
if ( $initial_payment_status === "Failed" ) {
pmpro_cancelMembershipLevel( $last_subscription_order->membership_id, $last_subscription_order->user_id, 'error' );
} else {
pmpro_cancelMembershipLevel( $last_subscription_order->membership_id, $last_subscription_order->user_id, 'cancelled' );
}
ipnlog( "Cancelled membership for user with id = " . $last_subscription_order->user_id . ". Subscription transaction id = " . $recurring_payment_id . "." );
//send an email to the member
$myemail = new PMProEmail();
$myemail->sendCancelEmail( $user, $last_subscription_order->membership_id );
//send an email to the admin
$myemail = new PMProEmail();
$myemail->sendCancelAdminEmail( $user, $last_subscription_order->membership_id );
}
}
pmpro_ipnExit();
}
}
//Subscription Cancelled (PayPal Standard)
if ( $txn_type == "subscr_cancel" ) {
//find last order
$last_subscription_order = new MemberOrder();
if ( $last_subscription_order->getLastMemberOrderBySubscriptionTransactionID( $subscr_id ) == false ) {
ipnlog( "ERROR: Couldn't find this order to cancel (subscription_transaction_id=" . $subscr_id . ")." );
pmpro_ipnExit();
} else {
//found order, let's cancel the membership
$user = get_userdata( $last_subscription_order->user_id );
if ( empty( $user ) || empty( $user->ID ) ) {
ipnlog( "ERROR: Could not cancel membership. No user attached to order #" . $last_subscription_order->id . " with subscription transaction id = " . $subscr_id . "." );
} else {
/*
We want to make sure this is a cancel originating from PayPal and not one already handled by PMPro.
For example, if a user cancels on WP/PMPro side, we've already cancelled the membership.
Also, if a user is changing levels, we don't want to cancel their new membership, just the old subscription at PayPal.
So we check 2 things and don't cancel if:
(1) This order already has "cancelled" status.
(2) The user doesn't currently have the level attached to this order.
*/
if ( isset($last_subscription_order->membership_id) && $last_subscription_order->status == "cancelled" ) {
ipnlog( "We've already processed this cancellation. Probably originated from WP/PMPro. (Order #" . $last_subscription_order->id . ", Subscription Transaction ID #" . $subscr_id . ")" );
} elseif ( isset($last_subscription_order->membership_id) && ! pmpro_hasMembershipLevel( $last_subscription_order->membership_id, $user->ID ) ) {
ipnlog( "This user has a different level than the one associated with this order. Their membership was probably changed by an admin or through an upgrade/downgrade. (Order #" . $last_subscription_order->id . ", Subscription Transaction ID #" . $subscr_id . ")" );
} else {
pmpro_changeMembershipLevel( 0, $last_subscription_order->user_id, 'cancelled' );
ipnlog( "Canceled membership for user with id = " . $last_subscription_order->user_id . ". Subscription transaction id = " . $subscr_id . "." );
//send an email to the member
$myemail = new PMProEmail();
$myemail->sendCancelEmail( $user );
//send an email to the admin
$myemail = new PMProEmail();
$myemail->sendCancelAdminEmail( $user, $last_subscription_order->membership_id );
}
}
pmpro_ipnExit();
}
}
//Other
//if we got here, this is a different kind of txn
ipnlog( "No recurring payment id or item number. txn_type = " . $txn_type );
pmpro_ipnExit();
/*
Add message to ipnlog string
*/
function ipnlog( $s ) {
global $logstr;
$logstr .= "\t" . $s . "\n";
}
/*
Output ipnlog and exit;
*/
function pmpro_ipnExit() {
global $logstr;
//for log
if ( $logstr ) {
$logstr = "Logged On: " . date_i18n( "m/d/Y H:i:s" ) . "\n" . $logstr . "\n-------------\n";
echo $logstr;
//log in file or email?
if ( defined( 'PMPRO_IPN_DEBUG' ) && PMPRO_IPN_DEBUG === "log" ) {
//file
$loghandle = fopen( dirname( __FILE__ ) . "/../logs/ipn.txt", "a+" );
fwrite( $loghandle, $logstr );
fclose( $loghandle );
} elseif ( defined( 'PMPRO_IPN_DEBUG' ) ) {
//email
if ( strpos( PMPRO_IPN_DEBUG, "@" ) ) {
$log_email = PMPRO_IPN_DEBUG;
} //constant defines a specific email address
else {
$log_email = get_option( "admin_email" );
}
wp_mail( $log_email, get_option( "blogname" ) . " IPN Log", nl2br( $logstr ) );
}
}
exit;
}
/*
Validate the $_POST with PayPal
*/
function pmpro_ipnValidate() {
//read the post from PayPal system and add 'cmd'
$req = 'cmd=_notify-validate';
//generate string to check with PayPal
foreach ( $_POST as $key => $value ) {
$value = urlencode( stripslashes( $value ) );
$req .= "&$key=$value";
}
//post back to PayPal system to validate
$gateway_environment = pmpro_getOption( "gateway_environment" );
if ( $gateway_environment == "sandbox" ) {
$paypal_url = 'https://www.' . $gateway_environment . '.paypal.com/cgi-bin/webscr';
} else {
$paypal_url = 'https://www.paypal.com/cgi-bin/webscr';
}
$paypal_params = array(
"body" => $req,
"httpversion" => "1.1",
"Host" => "www.paypal.com",
"Connection" => "Close",
"user-agent" => PMPRO_USER_AGENT
);
$fp = wp_remote_post( $paypal_url, $paypal_params );
//log post vars
ipnlog( print_r( $_POST, true ) );
//assume invalid
$r = false;
if ( empty( $fp ) ) {
//HTTP ERROR
ipnlog( "HTTP ERROR" );
$r = false;
} elseif ( ! empty( $fp->errors ) ) {
//error from PayPal
ipnlog( "ERROR" );
ipnlog( "Error Info: " . print_r( $fp->errors, true ) . "\n" );
//log fb object
ipnlog( print_r( $fp, true ) );
$r = false;
} else {
ipnlog( "FP!" );
//log fp object
///ipnlog( print_r( $fp, true ) );
$res = wp_remote_retrieve_body( $fp );
//ipnlog( print_r( $res, true ) );
if ( strcmp( $res, "VERIFIED" ) == 0 ) {
//all good so far
ipnlog( "VERIFIED" );
$r = true;
} else {
//log for manual investigation
ipnlog( "INAVLID" );
$r = false;
}
}
/**
* Filter if an ipn request is valid or not.
*
* @since 1.8.6.3
*
* @param bool $r true or false if the request is valid
* @param mixed $fp remote post object from request to PayPal
*/
$r = apply_filters( 'pmpro_ipn_validate', $r, $fp );
return $r;
}
/*
Check that the email sent by PayPal matches our settings.
*/
function pmpro_ipnCheckReceiverEmail( $email ) {
if ( ! is_array( $email ) ) {
$email = array( $email );
}
if ( ! in_array( strtolower( pmpro_getOption( 'gateway_email' ) ), $email ) ) {
$r = false;
} else {
$r = true;
}
$r = apply_filters( 'pmpro_ipn_check_receiver_email', $r, $email );
if ( $r ) {
return true;
} else {
if ( ! empty( $_POST['receiver_email'] ) ) {
$receiver_email = $_POST['receiver_email'];
} else {
$receiver_email = "N/A";
}
if ( ! empty( $_POST['business'] ) ) {
$business = $_POST['business'];
} else {
$business = "N/A";
}
//not yours
ipnlog( "ERROR: receiver_email (" . $receiver_email . ") and business email (" . $business . ") did not match (" . pmpro_getOption( 'gateway_email' ) . ")" );
return false;
}
}
/*
Change the membership level. We also update the membership order to include filtered valus.
*/
function pmpro_ipnChangeMembershipLevel( $txn_id, &$morder ) {
global $wpdb;
//filter for level
$morder->membership_level = apply_filters( "pmpro_ipnhandler_level", $morder->membership_level, $morder->user_id );
//set the start date to current_time('timestamp') but allow filters (documented in preheaders/checkout.php)
$startdate = apply_filters( "pmpro_checkout_start_date", "'" . current_time( 'mysql' ) . "'", $morder->user_id, $morder->membership_level );
//fix expiration date
if ( ! empty( $morder->membership_level->expiration_number ) ) {
$enddate = "'" . date_i18n( "Y-m-d", strtotime( "+ " . $morder->membership_level->expiration_number . " " . $morder->membership_level->expiration_period, current_time( "timestamp" ) ) ) . "'";
} else {
$enddate = "NULL";
}
//filter the enddate (documented in preheaders/checkout.php)
$enddate = apply_filters( "pmpro_checkout_end_date", $enddate, $morder->user_id, $morder->membership_level, $startdate );
//get discount code
$morder->getDiscountCode();
if ( ! empty( $morder->discount_code ) ) {
//update membership level
$morder->getMembershipLevel( true );
$discount_code_id = $morder->discount_code->id;
} else {
$discount_code_id = "";
}
//custom level to change user to
$custom_level = array(
'user_id' => $morder->user_id,
'membership_id' => $morder->membership_level->id,
'code_id' => $discount_code_id,
'initial_payment' => $morder->membership_level->initial_payment,
'billing_amount' => $morder->membership_level->billing_amount,
'cycle_number' => $morder->membership_level->cycle_number,
'cycle_period' => $morder->membership_level->cycle_period,
'billing_limit' => $morder->membership_level->billing_limit,
'trial_amount' => $morder->membership_level->trial_amount,
'trial_limit' => $morder->membership_level->trial_limit,
'startdate' => $startdate,
'enddate' => $enddate
);
global $pmpro_error;
if ( ! empty( $pmpro_error ) ) {
echo $pmpro_error;
ipnlog( $pmpro_error );
}
//change level and continue "checkout"
if ( pmpro_changeMembershipLevel( $custom_level, $morder->user_id, 'changed' ) !== false ) {
//update order status and transaction ids
$morder->status = "success";
$morder->payment_transaction_id = $txn_id;
if ( ! empty( $_POST['subscr_id'] ) ) {
$morder->subscription_transaction_id = $_POST['subscr_id'];
} else {
$morder->subscription_transaction_id = "";
}
$morder->saveOrder();
//add discount code use
if ( ! empty( $discount_code ) && ! empty( $use_discount_code ) ) {
$wpdb->query(
$wpdb->prepare(
"INSERT INTO {$wpdb->pmpro_discount_codes_uses}
( code_id, user_id, order_id, timestamp )
VALUES( %d, %d, %s, %s )",
$discount_code_id),
$morder->user_id,
$morder->id,
current_time( 'mysql' )
);
}
//save first and last name fields
if ( ! empty( $_POST['first_name'] ) ) {
$old_firstname = get_user_meta( $morder->user_id, "first_name", true );
if ( empty( $old_firstname ) ) {
update_user_meta( $morder->user_id, "first_name", $_POST['first_name'] );
}
}
if ( ! empty( $_POST['last_name'] ) ) {
$old_lastname = get_user_meta( $morder->user_id, "last_name", true );
if ( empty( $old_lastname ) ) {
update_user_meta( $morder->user_id, "last_name", $_POST['last_name'] );
}
}
//hook
do_action( "pmpro_after_checkout", $morder->user_id, $morder );
//setup some values for the emails
if ( ! empty( $morder ) ) {
$invoice = new MemberOrder( $morder->id );
} else {
$invoice = null;
}
$user = get_userdata( $morder->user_id );
$user->membership_level = $morder->membership_level; //make sure they have the right level info
//send email to member
$pmproemail = new PMProEmail();
$pmproemail->sendCheckoutEmail( $user, $invoice );
//send email to admin
$pmproemail = new PMProEmail();
$pmproemail->sendCheckoutAdminEmail( $user, $invoice );
return true;
} else {
return false;
}
}
/*
Send an email RE a failed payment.
$last_order passed in is the previous order for this subscription.
*/
function pmpro_ipnFailedPayment( $last_order ) {
//hook to do other stuff when payments fail
do_action( "pmpro_subscription_payment_failed", $last_order );
//create a blank order for the email
$morder = new MemberOrder();
$morder->user_id = $last_order->user_id;
$user = new WP_User( $last_order->user_id );
$user->membership_level = pmpro_getMembershipLevelForUser( $user->ID );
//add billing information if appropriate
if ( $last_order->gateway == "paypal" ) //website payments pro
{
$morder->billing->name = $_POST['address_name'];
$morder->billing->street = $_POST['address_street'];
$morder->billing->city = $_POST['address_city '];
$morder->billing->state = $_POST['address_state'];
$morder->billing->zip = $_POST['address_zip'];
$morder->billing->country = $_POST['address_country_code'];
$morder->billing->phone = get_user_meta( $morder->user_id, "pmpro_bphone", true );
//get CC info that is on file
$morder->cardtype = get_user_meta( $morder->user_id, "pmpro_CardType", true );
$morder->accountnumber = hideCardNumber( get_user_meta( $morder->user_id, "pmpro_AccountNumber", true ), false );
$morder->expirationmonth = get_user_meta( $morder->user_id, "pmpro_ExpirationMonth", true );
$morder->expirationyear = get_user_meta( $morder->user_id, "pmpro_ExpirationYear", true );
}
// Email the user and ask them to update their credit card information
$pmproemail = new PMProEmail();
$pmproemail->sendBillingFailureEmail( $user, $morder );
// Email admin so they are aware of the failure
$pmproemail = new PMProEmail();
$pmproemail->sendBillingFailureAdminEmail( get_bloginfo( "admin_email" ), $morder );
ipnlog( "Payment failed. Emails sent to " . $user->user_email . " and " . get_bloginfo( "admin_email" ) . "." );
return true;
}
/*
Save a new order from IPN info.
$last_order passed in is the previous order for this subscription.
*/
function pmpro_ipnSaveOrder( $txn_id, $last_order ) {
global $wpdb;
//check that txn_id has not been previously processed
$old_txn = $wpdb->get_var( "SELECT payment_transaction_id FROM $wpdb->pmpro_membership_orders WHERE payment_transaction_id = '" . $txn_id . "' LIMIT 1" );
if ( empty( $old_txn ) ) {
//save order
$morder = new MemberOrder();
$morder->user_id = $last_order->user_id;
$morder->membership_id = $last_order->membership_id;
$morder->payment_transaction_id = $txn_id;
$morder->subscription_transaction_id = $last_order->subscription_transaction_id;
$morder->gateway = $last_order->gateway;
$morder->gateway_environment = $last_order->gateway_environment;
// Payment Status
$morder->status = 'success'; // We have confirmed that and thats the reason we are here.
// Payment Type.
$morder->payment_type = $last_order->payment_type;
//set amount based on which PayPal type
if ( false !== stripos( $last_order->gateway, "paypal" ) ) {
if ( isset( $_POST['amount'] ) && ! empty( $_POST['amount'] ) ) {
$morder->InitialPayment = $_POST['amount']; //not the initial payment, but the class is expecting that
$morder->PaymentAmount = $_POST['amount'];
} elseif ( isset( $_POST['mc_gross'] ) && ! empty( $_POST['mc_gross'] ) ) {
$morder->InitialPayment = $_POST['mc_gross']; //not the initial payment, but the class is expecting that
$morder->PaymentAmount = $_POST['mc_gross'];
} elseif ( isset( $_POST['payment_gross'] ) && ! empty( $_POST['payment_gross' ] ) ) {
$morder->InitialPayment = $_POST['payment_gross']; //not the initial payment, but the class is expecting that
$morder->PaymentAmount = $_POST['payment_gross'];
}
}
$morder->FirstName = $_POST['first_name'];
$morder->LastName = $_POST['last_name'];
$morder->Email = $_POST['payer_email'];
//get address info if appropriate
if ( $last_order->gateway == "paypal" ) //website payments pro
{
$morder->Address1 = get_user_meta( $last_order->user_id, "pmpro_baddress1", true );
$morder->City = get_user_meta( $last_order->user_id, "pmpro_bcity", true );
$morder->State = get_user_meta( $last_order->user_id, "pmpro_bstate", true );
$morder->CountryCode = "US";
$morder->Zip = get_user_meta( $last_order->user_id, "pmpro_bzip", true );
$morder->PhoneNumber = get_user_meta( $last_order->user_id, "pmpro_bphone", true );
$morder->billing->name = $_POST['first_name'] . " " . $_POST['last_name'];
$morder->billing->street = get_user_meta( $last_order->user_id, "pmpro_baddress1", true );
$morder->billing->city = get_user_meta( $last_order->user_id, "pmpro_bcity", true );
$morder->billing->state = get_user_meta( $last_order->user_id, "pmpro_bstate", true );
$morder->billing->zip = get_user_meta( $last_order->user_id, "pmpro_bzip", true );
$morder->billing->country = get_user_meta( $last_order->user_id, "pmpro_bcountry", true );
$morder->billing->phone = get_user_meta( $last_order->user_id, "pmpro_bphone", true );
//get CC info that is on file
$morder->cardtype = get_user_meta( $last_order->user_id, "pmpro_CardType", true );
$morder->accountnumber = hideCardNumber( get_user_meta( $last_order->user_id, "pmpro_AccountNumber", true ), false );
$morder->expirationmonth = get_user_meta( $last_order->user_id, "pmpro_ExpirationMonth", true );
$morder->expirationyear = get_user_meta( $last_order->user_id, "pmpro_ExpirationYear", true );
$morder->ExpirationDate = $morder->expirationmonth . $morder->expirationyear;
$morder->ExpirationDate_YdashM = $morder->expirationyear . "-" . $morder->expirationmonth;
}
//figure out timestamp or default to none (today)
if ( ! empty( $_POST['payment_date'] ) ) {
$morder->timestamp = strtotime( $_POST['payment_date'] );
}
// Save the event ID for the last processed user/IPN (in case we want to be able to replay IPN requests)
$ipn_id = isset($_POST['ipn_track_id']) ? sanitize_text_field( $_POST['ipn_track_id'] ) : null;
// Allow extraction of the IPN Track ID from the order notes (if needed)
$morder->notes = "{$morder->notes} [IPN_ID]{$ipn_id}[/IPN_ID]";
/**
* Post processing for a specific subscription related IPN event ID
*
* @param string $ipn_id - The ipn_track_id from the PayPal IPN request
* @param MemberOrder $morder - The completed Member Order object for the IPN request
*/
do_action('pmpro_subscription_ipn_event_processed', $ipn_id, $morder );
if ( ! is_null( $ipn_id ) ) {
if ( false === update_user_meta( $morder->user_id, "pmpro_last_{$morder->gateway}_ipn_id", $ipn_id )) {
ipnlog( "Unable to save the IPN event ID ({$ipn_id}) to usermeta for {$morder->user_id} " );
}
}
//save
$morder->saveOrder();
$morder->getMemberOrderByID( $morder->id );
//email the user their invoice
$pmproemail = new PMProEmail();
$pmproemail->sendInvoiceEmail( get_userdata( $last_order->user_id ), $morder );
//hook for successful subscription payments
do_action( "pmpro_subscription_payment_completed", $morder );
ipnlog( "New order (" . $morder->code . ") created." );
return true;
} else {
ipnlog( "Duplicate Transaction ID: " . $txn_id );
return false;
}
}
You can’t perform that action at this time.