<?php
/**
 * The Braintree webhook handler
 *
 * @since 1.9.5 - Various updates to how we log & process requests from Braintree
 */

use Braintree\WebhookNotification as Braintree_WebhookNotification;

// If loading directly, make sure we return a 200 HTTP status
global $isapage;
$isapage = true;

//in case the file is loaded directly
if ( ! defined( "ABSPATH" ) ) {
	define( 'WP_USE_THEMES', false );
	require_once( dirname( __FILE__ ) . '/../../../../wp-load.php' );
}

//globals
global $wpdb;

// Debug log
global $logstr;
$logstr = array( "Logged On: " . date_i18n( "m/d/Y H:i:s", current_time( 'timestamp' ) ) );

// Don't run this with wrong PHP version
if ( version_compare( PHP_VERSION, '5.4.45', '<' ) ) {
	return;
}

//load Braintree library, gateway class constructor does config
if ( ! class_exists( '\Braintree' ) ) {
	require_once( PMPRO_DIR . "/classes/gateways/class.pmprogateway_braintree.php" );
}

$gateway             = new PMProGateway_braintree();
$webhookNotification = null;

if ( empty( $_REQUEST['bt_payload'] ) ) {
	$logstr[] = "No payload in request?!? " . print_r( $_REQUEST, true );
	pmpro_braintreeWebhookExit();
}

if ( isset( $_POST['bt_signature'] ) && ! isset( $_POST['bt_payload'] ) ) {
	$logstr[] = "No payload and signature included in the request!";
	pmpro_braintreeWebhookExit();
}

//get notification
try {
	/**
	 * @since 1.9.5 - BUG FIX: Unable to identify Braintree Webhook messages
	 * Expecting Braintree library to sanitize signature & payload 
	 * since using sanitize_text_field() breaks Braintree parser
	 */
	$webhookNotification = Braintree_WebhookNotification::parse( $_POST['bt_signature'], $_POST['bt_payload'] );
} catch ( Exception $e ) {
	$logstr[] = "Couldn't extract notification from payload: {$_REQUEST['bt_payload']}";
	$logstr[] = "Error message: " . $e->getMessage();
	
	pmpro_braintreeWebhookExit();
}

/**
 * @since 1.9.5 - ENHANCEMENT: Log if notification object has unexpected format
 */
if ( ! isset( $webhookNotification->kind ) ) {
	$logstr[] = "Unexpected webhook message: " . print_r( $webhookNotification, true ) . "\n";
	pmpro_braintreeWebhookExit();
}

/**
 * Only verifying?
 * @since 1.9.5 - Log Webhook tests with webhook supplied timestamp (verifies there's no caching).
 */
if ( $webhookNotification->kind === Braintree_WebhookNotification::CHECK ) {	
	$when = $webhookNotification->timestamp->format( 'Y-m-d H:i:s.u' );
	
	$logstr[] = "Since you are just testing the URL, check that the timestamp updates on refresh to make sure this isn't being cached.";
	$logstr[] = "Braintree gateway timestamp: {$when}";
	pmpro_braintreeWebhookExit();
}

//subscription charged sucessfully
if ( $webhookNotification->kind === Braintree_WebhookNotification::SUBSCRIPTION_CHARGED_SUCCESSFULLY ) {
	$logstr[] = "The Braintree gateway received payment for a recurring billing plan";
	
	//need a subscription id
	if ( empty( $webhookNotification->subscription->id ) ) {
		$logstr[] = "No subscription ID.";
		pmpro_braintreeWebhookExit();
	}
	
	//figure out which order to attach to
	$old_order = new \MemberOrder();
	$old_order->getLastMemberOrderBySubscriptionTransactionID( $webhookNotification->subscription->id );

	//no order?
	if ( empty( $old_order ) ) {
		$logstr[] = "Couldn't find the original subscription with ID={$webhookNotification->subscription->id}.";
		pmpro_braintreeWebhookExit();
	}
	
	//create new order
	$user_id                = $old_order->user_id;
	$user                   = get_userdata( $user_id );
	
	if ( empty( $user ) ) {
		$logstr[] = "Couldn't find the old order's user. Order ID = {$old_order->id}.";
		pmpro_braintreeWebhookExit();
	} else {
		$user->membership_level = pmpro_getMembershipLevelForUser( $user_id );
	}
	
	//data about this transaction
	$transaction = $webhookNotification->subscription->transactions[0];

	//alright. create a new order/invoice
	$morder                              = new \MemberOrder();
	$morder->user_id                     = $old_order->user_id;
	$morder->membership_id               = $old_order->membership_id;
	$morder->InitialPayment              = $transaction->amount;    //not the initial payment, but the order class is expecting this
	$morder->PaymentAmount               = $transaction->amount;
	$morder->payment_transaction_id      = $transaction->id;
	$morder->subscription_transaction_id = $webhookNotification->subscription->id;
	
	$morder->gateway             = $old_order->gateway;
	$morder->gateway_environment = $old_order->gateway_environment;
	
	$morder->billing = new stdClass();
	
	if (! empty( $transaction->billing_details) ) {
		$morder->FirstName = $transaction->billing_details->first_name;
		$morder->LastName  = $transaction->billing_details->last_name;
		$morder->Email     = $wpdb->get_var( "SELECT user_email FROM $wpdb->users WHERE ID = '" . $old_order->user_id . "' LIMIT 1" );
		$morder->Address1  = $transaction->billing_details->street_address;
		$morder->City      = $transaction->billing_details->locality;
		$morder->State     = $transaction->billing_details->region;
		//$morder->CountryCode = $old_order->billing->city;
		$morder->Zip         = $transaction->billing_details->postal_code;
		
		$morder->billing->name    = trim( $transaction->billing_details->first_name . " " . $transaction->billing_details->last_name );
		$morder->billing->street  = $transaction->billing_details->street_address;
		$morder->billing->city    = $transaction->billing_details->locality;
		$morder->billing->state   = $transaction->billing_details->region;
		$morder->billing->zip     = $transaction->billing_details->postal_code;
		$morder->billing->country = $transaction->billing_details->country_code_alpha2;	
	} else {
		$morder->FirstName = $old_order->FirstName;
		$morder->LastName = $old_order->LastName;
		$morder->Email = $user->user_email;
		$morder->Address1 = $old_order->Address1;
		$morder->City = $old_order->billing->city;
		$morder->State = $old_order->billing->state;
		$morder->Zip = $old_order->billing->zip;
		
		$morder->billing->name    = $old_order->billing->name;
		$morder->billing->street  = $old_order->billing->street;
		$morder->billing->city    = $old_order->billing->city;
		$morder->billing->state   = $old_order->billing->state;
		$morder->billing->zip     = $old_order->billing->zip;
		$morder->billing->country = $old_order->billing->country;
	}
	
	$morder->PhoneNumber = $old_order->billing->phone;
	$morder->billing->phone   = $old_order->billing->phone;
	
	//get CC info that is on file
	$morder->cardtype              = get_user_meta( $user_id, "pmpro_CardType", true );
	$morder->accountnumber         = hideCardNumber( get_user_meta( $user_id, "pmpro_AccountNumber", true ), false );
	$morder->expirationmonth       = get_user_meta( $user_id, "pmpro_ExpirationMonth", true );
	$morder->expirationyear        = get_user_meta( $user_id, "pmpro_ExpirationYear", true );
	$morder->ExpirationDate        = $morder->expirationmonth . $morder->expirationyear;
	$morder->ExpirationDate_YdashM = $morder->expirationyear . "-" . $morder->expirationmonth;
	
	//save
	$morder->status = "success";
	$morder->saveOrder();
	$morder->getMemberOrderByID( $morder->id );
	
	//email the user their invoice
	$pmproemail = new \PMProEmail();
	$pmproemail->sendInvoiceEmail( $user, $morder );
	
	do_action( 'pmpro_subscription_payment_completed', $morder );
	
	$logstr[] = "Triggered pmpro_subscription_payment_completed actions and returned";
	
	/**
	 * @since 1.9.5 - Didn't terminate & save debug loggins for Webhook
	 */
	pmpro_braintreeWebhookExit();
}

/*
	Note here: These next three checks all work the same way and send the same
	"billing failed" email, but kick off different actions based on the kind.
*/

//subscription charged unsuccessfully
if ( $webhookNotification->kind === Braintree_WebhookNotification::SUBSCRIPTION_CHARGED_UNSUCCESSFULLY ) {
	$logstr[] = "The Braintree gateway let us know there's a problem with the payment";
	
	//need a subscription id
	if ( empty( $webhookNotification->subscription->id ) ) {
		$logstr[] = "No subscription ID.";
		pmpro_braintreeWebhookExit();
	}
	
	//figure out which order to attach to
	$old_order = new \MemberOrder();
	$old_order->getLastMemberOrderBySubscriptionTransactionID( $webhookNotification->subscription->id );
	
	if ( empty( $old_order ) ) {
		$logstr[] = "Couldn't find old order for failed payment with subscription id={$webhookNotification->subscription->id}";
		pmpro_braintreeWebhookExit();
	}
	
	$user_id                = $old_order->user_id;
	$user                   = get_userdata( $user_id );
	$user->membership_level = pmpro_getMembershipLevelForUser( $user_id );
	
	//generate billing failure email
	do_action( "pmpro_subscription_payment_failed", $old_order );
	
	$transaction = isset( $webhookNotification->transactions ) && is_array( $webhookNotification->transactions ) ?
		$webhookNotification->transactions[0] :
		null;
	
	if ( empty( $transaction ) || ! isset( $transaction->billing_details ) ) {
		// Get billing address info from either old order or billing meta
		$old_order->billing = pmpro_braintreeAddressInfo( $user_id, $old_order );
	}
	
	//prep this order for the failure emails
	$morder          = new \MemberOrder();
	$morder->user_id = $user_id;
	
	$morder->billing->name = isset( $transaction->billing_details->first_name ) && isset( $transaction->billing_details->last_name ) ?
		trim( $transaction->billing_details->first_name . " " . $transaction->billing_details->first_name ) :
		$old_order->billing->name;
	
	$morder->billing->street = isset( $transaction->billing_details->street_address ) ?
		$transaction->billing_details->street_address :
		$old_order->billing->street;
	
	$morder->billing->city = isset( $transaction->billing_details->locality ) ?
		$transaction->billing_details->locality :
		$old_order->billing->city;
	
	$morder->billing->state = isset( $transaction->billing_details->region ) ?
		$transaction->billing_details->region :
		$old_order->billing->state;
	
	$morder->billing->zip = isset( $transaction->billing_details->postal_code ) ?
		$transaction->billing_details->postal_code :
		$old_order->billing->zip;
	
	$morder->billing->country = isset( $transaction->billing_details->country_code_alpha2 ) ?
		$transaction->billing_details->country_code_alpha2 :
		$old_order->billing->country;
	
	$morder->billing->phone = $old_order->billing->phone;
	
	//get CC info that is on file
	$morder->cardtype        = get_user_meta( $user_id, "pmpro_CardType", true );
	$morder->accountnumber   = hideCardNumber( get_user_meta( $user_id, "pmpro_AccountNumber", true ), false );
	$morder->expirationmonth = get_user_meta( $user_id, "pmpro_ExpirationMonth", true );
	$morder->expirationyear  = get_user_meta( $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 );
	
	$logstr[] = "Sent email to the member and site admin. Thanks.";
	pmpro_braintreeWebhookExit();
}

//subscription went past due
if ( $webhookNotification->kind === Braintree_WebhookNotification::SUBSCRIPTION_WENT_PAST_DUE ) {
	
	$logstr[] = "The Braintree gateway informed us the subscription payment is past due";
	
	//need a subscription id
	if ( empty( $webhookNotification->subscription->id ) ) {
		$logstr[] = "No subscription ID.";
		pmpro_braintreeWebhookExit();
	}
	
	//figure out which order to attach to
	$old_order = new \MemberOrder();
	$old_order->getLastMemberOrderBySubscriptionTransactionID( $webhookNotification->subscription->id );
	
	if ( empty( $old_order ) ) {
		$logstr[] = "Couldn't find old order for failed payment with subscription id=" . $webhookNotification->subscription->id;
		pmpro_braintreeWebhookExit();
	}
	
	$user_id                = $old_order->user_id;
	$user                   = get_userdata( $user_id );
	$user->membership_level = pmpro_getMembershipLevelForUser( $user_id );
	
	//generate billing failure email
	do_action( "pmpro_subscription_payment_failed", $old_order );
	do_action( "pmpro_subscription_payment_went_past_due", $old_order );
	
	$transaction = isset( $webhookNotification->transactions ) && is_array( $webhookNotification->transactions ) ?
		$webhookNotification->transactions[0] :
		null;
	
	if ( empty( $transaction ) || ! isset( $transaction->billing_details ) ) {
		// Get billing address info from either old order or billing meta
		$old_order->billing = pmpro_braintreeAddressInfo( $user_id, $old_order );
	}
	
	//prep this order for the failure emails
	$morder          = new \MemberOrder();
	$morder->user_id = $user_id;
	
	$morder->billing->name = isset( $transaction->billing_details->first_name ) && isset( $transaction->billing_details->last_name ) ?
		trim( $transaction->billing_details->first_name . " " . $transaction->billing_details->first_name ) :
		$old_order->billing->name;
	
	$morder->billing->street = isset( $transaction->billing_details->street_address ) ?
		$transaction->billing_details->street_address :
		$old_order->billing->street;
	
	$morder->billing->city = isset( $transaction->billing_details->locality ) ?
		$transaction->billing_details->locality :
		$old_order->billing->city;
	
	$morder->billing->state = isset( $transaction->billing_details->region ) ?
		$transaction->billing_details->region :
		$old_order->billing->state;
	
	$morder->billing->zip = isset( $transaction->billing_details->postal_code ) ?
		$transaction->billing_details->postal_code :
		$old_order->billing->zip;
	
	$morder->billing->country = isset( $transaction->billing_details->country_code_alpha2 ) ?
		$transaction->billing_details->country_code_alpha2 :
		$old_order->billing->country;
	
	$morder->billing->phone = $old_order->billing->phone;
	
	//get CC info that is on file
	$morder->cardtype        = get_user_meta( $user_id, "pmpro_CardType", true );
	$morder->accountnumber   = hideCardNumber( get_user_meta( $user_id, "pmpro_AccountNumber", true ), false );
	$morder->expirationmonth = get_user_meta( $user_id, "pmpro_ExpirationMonth", true );
	$morder->expirationyear  = get_user_meta( $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 );
	
	$logstr[] = "Sent email to the member and site admin. Thanks.";
	pmpro_braintreeWebhookExit();
}

//subscription expired
if ( $webhookNotification->kind === Braintree_WebhookNotification::SUBSCRIPTION_EXPIRED ) {
	$logstr[] = "The Braintree gateway informed us the recurring payment plan has completed its required number of payments";
	
	//need a subscription id
	if ( empty( $webhookNotification->subscription->id ) ) {
		$logstr[] = "No subscription ID.";
		pmpro_braintreeWebhookExit();
	}
	
	//figure out which order to attach to
	$old_order = new \MemberOrder();
	$old_order->getLastMemberOrderBySubscriptionTransactionID( $webhookNotification->subscription->id );
	
	if ( empty( $old_order ) ) {
		$logstr[] = "Couldn't find old order for failed payment with subscription id=" . $webhookNotification->subscription->id;
		pmpro_braintreeWebhookExit();
	}
	
	$user_id                = $old_order->user_id;
	$user                   = get_userdata( $user_id );
	$user->membership_level = pmpro_getMembershipLevelForUser( $user_id );
	
	//generate billing failure email
	do_action( "pmpro_subscription_expired", $old_order );
	
	$transaction = isset( $webhookNotification->transactions ) && is_array( $webhookNotification->transactions ) ?
		$webhookNotification->transactions[0] :
		null;
	
	if ( empty( $transaction ) || ! isset( $transaction->billing_details ) ) {
		// Get billing address info from either old order or billing meta
		$old_order->billing = pmpro_braintreeAddressInfo( $user_id, $old_order );
	}
	
	//prep this order for the failure emails
	$morder          = new \MemberOrder();
	$morder->user_id = $user_id;
	
	$morder->billing->name = isset( $transaction->billing_details->first_name ) && isset( $transaction->billing_details->last_name ) ?
		trim( $transaction->billing_details->first_name . " " . $transaction->billing_details->first_name ) :
		$old_order->billing->name;
	
	$morder->billing->street = isset( $transaction->billing_details->street_address ) ?
		$transaction->billing_details->street_address :
		$old_order->billing->street;
	
	$morder->billing->city = isset( $transaction->billing_details->locality ) ?
		$transaction->billing_details->locality :
		$old_order->billing->city;
	
	$morder->billing->state = isset( $transaction->billing_details->region ) ?
		$transaction->billing_details->region :
		$old_order->billing->state;
	
	$morder->billing->zip = isset( $transaction->billing_details->postal_code ) ?
		$transaction->billing_details->postal_code :
		$old_order->billing->zip;
	
	$morder->billing->country = isset( $transaction->billing_details->country_code_alpha2 ) ?
		$transaction->billing_details->country_code_alpha2 :
		$old_order->billing->country;
	
	$morder->billing->phone = $old_order->billing->phone;
	
	//get CC info that is on file
	$morder->cardtype        = get_user_meta( $user_id, "pmpro_CardType", true );
	$morder->accountnumber   = hideCardNumber( get_user_meta( $user_id, "pmpro_AccountNumber", true ), false );
	$morder->expirationmonth = get_user_meta( $user_id, "pmpro_ExpirationMonth", true );
	$morder->expirationyear  = get_user_meta( $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 );
	
	$logstr[] = "Sent email to the member and site admin. Thanks.";
	pmpro_braintreeWebhookExit();
}

//subscription cancelled (they used one l canceled)
if ( Braintree_WebhookNotification::SUBSCRIPTION_CANCELED === $webhookNotification->kind ) {
	
	$logstr[] = "The Braintree gateway cancelled the subscription plan";
	
	//need a subscription id
	if ( empty( $webhookNotification->subscription->id ) ) {
		$logstr[] = "No subscription ID.";
		pmpro_braintreeWebhookExit();
	}
	
	//figure out which order to attach to
	$old_order = new \MemberOrder();
	$old_order->getLastMemberOrderBySubscriptionTransactionID( $webhookNotification->subscription->id );
	
	if ( empty( $old_order ) ) {
		$logstr[] = "Couldn't find old order for failed payment with subscription id={$webhookNotification->subscription->id}";
		pmpro_braintreeWebhookExit();
	}
	
	/**
	 * @since v1.9.5+ - BUG FIX: Don't process previously handled subscription cancellation
	 */
	if ( isset( $old_order->status ) && 'cancelled' == $old_order->status ) {
		$logstr[] = "Order for subscription id {$webhookNotification->subscription->id} is cancelled already";
		pmpro_braintreeWebhookExit();
	}
	
	$user_id                = $old_order->user_id;
	$user                   = get_userdata( $user_id );
	$user->membership_level = pmpro_getMembershipLevelForUser( $user_id,true );
	
	/**
	 * @since 1.9.5 - BUG FIX: Erroneously triggering warning email
	 *                Happens when a user cancels their membership (and Braintree) sends a webhook notifying us
	 *                of the fact that the user cancelled their subscription plan (SUBSCRIPTION_CANCELED event).
	 */
	if ( empty( $user->membership_level ) ) {
		
		$logstr[] = "Membership for user (ID: {$user_id}) is cancelled already. Probably a duplicate webhook notification. Exiting!";
		pmpro_braintreeWebhookExit();
	}
	
	// Trigger subscription cancelled action
	do_action( "pmpro_subscription_cancelled", $old_order );
	
	$transaction = isset( $webhookNotification->transactions ) && is_array( $webhookNotification->transactions ) ?
		$webhookNotification->transactions[0] :
		null;
	
	if ( empty( $transaction ) || ! isset( $transaction->billing_details ) ) {
		// Get billing address info from either old order or billing meta
		$old_order->billing = pmpro_braintreeAddressInfo( $user_id, $old_order );
	}
	
	//prep this order for the failure emails
	$morder          = new \MemberOrder();
	$morder->user_id = $user_id;
	
	$morder->billing->name = isset( $transaction->billing_details->first_name ) && isset( $transaction->billing_details->last_name ) ?
		trim( $transaction->billing_details->first_name . " " . $transaction->billing_details->first_name ) :
		$old_order->billing->name;
	
	$morder->billing->street = isset( $transaction->billing_details->street_address ) ?
		$transaction->billing_details->street_address :
		$old_order->billing->street;
	
	$morder->billing->city = isset( $transaction->billing_details->locality ) ?
		$transaction->billing_details->locality :
		$old_order->billing->city;
	
	$morder->billing->state = isset( $transaction->billing_details->region ) ?
		$transaction->billing_details->region :
		$old_order->billing->state;
	
	$morder->billing->zip = isset( $transaction->billing_details->postal_code ) ?
		$transaction->billing_details->postal_code :
		$old_order->billing->zip;
	
	$morder->billing->country = isset( $transaction->billing_details->country_code_alpha2 ) ?
		$transaction->billing_details->country_code_alpha2 :
		$old_order->billing->country;
	
	$morder->billing->phone = $old_order->billing->phone;
	
	//get CC info that is on file
	$morder->cardtype        = get_user_meta( $user_id, "pmpro_CardType", true );
	$morder->accountnumber   = hideCardNumber( get_user_meta( $user_id, "pmpro_AccountNumber", true ), false );
	$morder->expirationmonth = get_user_meta( $user_id, "pmpro_ExpirationMonth", true );
	$morder->expirationyear  = get_user_meta( $user_id, "pmpro_ExpirationYear", true );
	
	// Email the user and let them know the membership was cancelled
	$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 );
	
	// Send email
	$logstr[] = "Sent billing failure email to the member and site admin. Thanks.";
	pmpro_braintreeWebhookExit();
}

/**
 * @since 1.9.5 - BUG FIX: Didn't terminate & save debug log for webhook event
 */
pmpro_braintreeWebhookExit();

/**
 * Fix address info for order/transaction
 *
 * @param int          $user_id
 * @param \MemberOrder $old_order
 *
 * @return \stdClass
 */
function pmpro_braintreeAddressInfo( $user_id, $old_order ) {
	
	
	// Grab billing info from the saved metadata as needed
	
	if ( ! isset( $old_order->billing ) ) {
		$old_order->billing = new \stdClass();
	}
	
	if ( empty ( $old_order->billing->name ) ) {
		$first_name = get_user_meta( $user_id, 'pmpro_bfirstname', true );
		$last_name  = get_user_meta( $user_id, 'pmpro_blastname', true );
		
		if ( ! empty( $first_name ) && ! empty( $last_name ) ) {
			$old_order->billing->name = trim( "{$first_name} {$last_name}" );
		}
	}
	
	if ( empty( $old_order->billing->street ) ) {
		$address1                   = get_user_meta( $user_id, 'pmpro_baddress', true );
		$address2                   = get_user_meta( $user_id, 'pmpro_baddress2', true );
		$old_order->billing->street = ! empty( $address1 ) ? trim( $address1 ) : '';
		$old_order->billing->street .= ! empty( $address2 ) ? "\n" . trim( $address2 ) : '';
	}
	
	if ( empty( $old_order->billing->city ) ) {
		$city                     = get_user_meta( $user_id, 'pmpro_bcity', true );
		$old_order->billing->city = ! empty( $city ) ? trim( $city ) : '';
	}
	
	if ( empty( $old_order->billing->state ) ) {
		$state                     = get_user_meta( $user_id, 'pmpro_bstate', true );
		$old_order->billing->state = ! empty( $state ) ? trim( $state ) : '';
	}
	
	if ( empty( $old_order->billing->zip ) ) {
		$zip                     = get_user_meta( $user_id, 'pmpro_bzipcode', true );
		$old_order->billing->zip = ! empty( $zip ) ? trim( $zip ) : '';
	}
	
	if ( empty( $old_order->billing->country ) ) {
		$country                     = get_user_meta( $user_id, 'pmpro_bcountry', true );
		$old_order->billing->country = ! empty( $country ) ? trim( $country ) : '';
	}
	
	$old_order->updateBilling();
	
	return $old_order->billing;
}

/**
 * Exit the Webhook handler, and save the debug log (if needed)
 */
function pmpro_braintreeWebhookExit() {
	
	global $logstr;
	
	//Log the info (if there is any)
	if ( ! empty( $logstr ) ) {
		
		$logstr[] = "\n-------------\n";
		
		$debuglog = implode( "\n", $logstr );
		
		//log in file or email?
		if ( defined( 'PMPRO_BRAINTREE_WEBHOOK_DEBUG' ) && PMPRO_BRAINTREE_WEBHOOK_DEBUG === "log" ) {
			//file
			$loghandle = fopen( dirname( __FILE__ ) . "/../logs/braintree-webhook.txt", "a+" );
			fwrite( $loghandle, $debuglog );
			fclose( $loghandle );
		} else if ( defined( 'PMPRO_BRAINTREE_WEBHOOK_DEBUG' ) ) {
			/**
			 * @since 1.9.5 - BUG FIX: We specifically care about errors, not strings at position 0
			 */
			//email
			if ( false !== strpos( PMPRO_BRAINTREE_WEBHOOK_DEBUG, "@" ) ) {
				$log_email = PMPRO_BRAINTREE_WEBHOOK_DEBUG;    //constant defines a specific email address
			} else {
				$log_email = get_option( "admin_email" );
			}
			
			wp_mail( $log_email, get_option( "blogname" ) . " Braintree Webhook Log", nl2br( $debuglog ) );
		}
	}
	
	exit;
}
