2026-03-26 12:55:30 +00:00

961 lines
37 KiB
PHP

<?php
/*
* Note: For the new API, we use thbe ASP_Process_IPN_NG class.
*/
class AcceptStripePayments_Process_IPN {
protected static $instance = null;
var $aspRedirectURL;
var $sess;
function __construct() {
self::$instance = $this;
add_action( 'init', array( $this, 'init' ) );
}
public static function get_instance() {
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
function init() {
if ( isset( $_POST['asp_action'] ) ) {
//Note: For the new API, we use ASP_Process_IPN_NG::process_ipn( $post_data )
if ( 'process_ipn' === $_POST['asp_action'] ) {
//Check if Legacy API is enabled.
$opt = get_option( 'AcceptStripePayments-settings' );
//if ( isset( $opt['use_old_checkout_api1'] ) && $opt['use_old_checkout_api1'] ) {
if(isset($opt['use_old_checkout_api1'])) {
$opt['use_old_checkout_api1'] = 0;
}
if ( isset( $opt['use_old_checkout_api1'] ) && $opt['use_old_checkout_api1'] ) {
$this->sess = ASP_Session::get_instance();
$this->process_ipn();
} else {
//Legacy API is disabled, but request was made to it
ASP_Debug_Logger::log( 'Legacy API backend accessed while it is disabled.', false );
wp_die( 'Access denied.' );
}
}
}
}
function ipn_completed( $errMsg = '' ) {
if ( ! empty( $errMsg ) ) {
$aspData = array( 'error_msg' => $errMsg );
ASP_Debug_Logger::log( $errMsg, false ); //Log the error
$msg_before_process = __( 'Error occurred before user interacted with payment popup. This might be caused by JavaScript errors on page.', 'stripe-payments' );
$msg_after_process = __( 'Error occurred after user interacted with popup.', 'stripe-payments' );
if ( isset( $_POST['clickProcessed'] ) ) {
$additional_msg = $msg_after_process;
} else {
$additional_msg = $msg_before_process;
}
ASP_Debug_Logger::log( $additional_msg, false );
$this->sess->set_transient_data( 'asp_data', $aspData );
//send email to notify site admin (if option enabled)
$opt = get_option( 'AcceptStripePayments-settings' );
if ( isset( $opt['send_email_on_error'] ) && $opt['send_email_on_error'] ) {
$to = $opt['send_email_on_error_to'];
$from = get_option( 'admin_email' );
$headers = 'From: ' . $from . "\r\n";
$subj = __( 'Stripe Payments Error Details', 'stripe-payments' );
$body = __( 'Following error occurred during payment processing:', 'stripe-payments' ) . "\r\n\r\n";
$body .= $errMsg . "\r\n\r\n";
$body .= $additional_msg . "\r\n";
$body .= __( 'Debug data:', 'stripe-payments' ) . "\r\n";
foreach ( $_POST as $key => $value ) {
$value = is_array( $value ) ? json_encode( $value ) : $value;
$body .= $key . ': ' . $value . "\r\n";
}
wp_mail( $to, $subj, $body, $headers );
}
} else {
ASP_Debug_Logger::log( 'Payment has been processed successfully.' );
}
ASP_Debug_Logger::log( sprintf( 'Redirecting to results page "%s"', $this->aspRedirectURL ) . "\r\n" );
wp_redirect( $this->aspRedirectURL );
exit;
}
function process_ipn() {
$asp_class = AcceptStripePayments::get_instance();
ASP_Debug_Logger::log( 'Payment processing started.' );
$post_thankyou_page_url = isset( $_POST['thankyou_page_url'] ) ? sanitize_text_field( $_POST['thankyou_page_url'] ) : false;
$this->aspRedirectURL = empty( $post_thankyou_page_url ) ? $asp_class->get_setting( 'checkout_url' ) : base64_decode( $post_thankyou_page_url );
ASP_Debug_Logger::log( 'Triggering hook for addons to process posted data if needed.' );
$process_result = apply_filters( 'asp_before_payment_processing', array(), $_POST );
if ( isset( $process_result ) && ! empty( $process_result ) ) {
if ( isset( $process_result['error'] ) && ! empty( $process_result['error'] ) ) {
$this->ipn_completed( $process_result['error'] );
}
}
//Check nonce
ASP_Debug_Logger::log( 'Checking received data.' );
if ( ! isset( $_POST['stripeToken'] ) || empty( $_POST['stripeToken'] ) ) {
$this->ipn_completed( 'Invalid Stripe Token' );
}
if ( ! isset( $_POST['stripeTokenType'] ) || empty( $_POST['stripeTokenType'] ) ) {
$this->ipn_completed( 'Invalid Stripe Token Type' );
}
if ( ! isset( $_POST['stripeEmail'] ) || empty( $_POST['stripeEmail'] ) ) {
$this->ipn_completed( 'Invalid Request' );
}
$got_product_data_from_db = false;
if ( isset( $_POST['stripeProductId'] ) && ! empty( $_POST['stripeProductId'] ) ) {
//got product ID. Let's try to get required data from database instead of $_POST data
$prod_id = intval( $_POST['stripeProductId'] );
ASP_Debug_Logger::log( 'Got product ID: ' . $prod_id . '. Trying to get info from database.' );
$post = get_post( $prod_id );
if ( ! $post || get_post_type( $prod_id ) != ASPMain::$products_slug ) {
//this is not Stripe Payments product
$this->ipn_completed( 'Invalid product ID: ' . $prod_id );
}
$item_name = $post->post_title;
$currency_code = get_post_meta( $prod_id, 'asp_product_currency', true );
$currency_variable = get_post_meta( $prod_id, 'asp_product_currency_variable', true );
if ( $currency_variable ) {
$currency_code = sanitize_text_field( $_POST['stripeCurrency'] );
}
if ( ! $currency_code ) {
$currency_code = $asp_class->get_setting( 'currency_code' );
}
$item_quantity = get_post_meta( $prod_id, 'asp_product_quantity', true );
$item_custom_quantity = get_post_meta( $prod_id, 'asp_product_custom_quantity', true );
if ( $item_custom_quantity ) {
//custom quantity. Let's get the value from $_POST data
$item_custom_quantity = intval( $_POST['stripeCustomQuantity'] );
} else {
$item_custom_quantity = false;
}
$variable = false;
$item_price = get_post_meta( $prod_id, 'asp_product_price', true );
if ( empty( $item_price ) ) {
//this is probably custom price
$variable = true;
$item_price = floatval( $_POST['stripeAmount'] );
}
//get tax and shipping amounts if applicable
$tax = get_post_meta( $prod_id, 'asp_product_tax', true );
$shipping = floatval( get_post_meta( $prod_id, 'asp_product_shipping', true ) );
//let's apply filter so addons can change price, currency and shipping if needed
$price_arr = array(
'price' => $item_price,
'currency' => $currency_code,
'shipping' => empty( $shipping ) ? false : $shipping,
'variable' => $variable,
);
$price_arr = apply_filters( 'asp_modify_price_currency_shipping', $price_arr );
extract( $price_arr, EXTR_OVERWRITE );
$item_price = $price;
$currency_code = $currency;
//handle item url
$item_url = get_post_meta( $prod_id, 'asp_product_upload', true );
if ( ! empty( $item_url ) ) {
$item_url = base64_encode( $item_url );
} else {
$item_url = '';
}
$post_item_url = isset( $_POST['item_url'] ) ? sanitize_text_field( $_POST['item_url'] ) : false;
$button_key = isset( $_POST['stripeButtonKey'] ) ? sanitize_text_field( $_POST['stripeButtonKey'] ) : false;
if ( empty( $button_key ) ) {
//let's generate our own button key
$price = AcceptStripePayments::apply_tax( $item_price, $tax, AcceptStripePayments::is_zero_cents( $currency_code ) );
$price = AcceptStripePayments::apply_shipping( $price, $shipping, AcceptStripePayments::is_zero_cents( $currency_code ) );
$price_in_cents = $price;
if ( ! AcceptStripePayments::is_zero_cents( $currency_code ) ) {
$price_in_cents = $price_in_cents * 100;
}
$button_key = md5( htmlspecialchars_decode( $item_name ) . $price_in_cents );
}
if ( ! empty( $post_item_url ) ) {
if ( $item_url !== $post_item_url ) {
$item_url = $post_item_url;
}
}
$got_product_data_from_db = true;
ASP_Debug_Logger::log( 'Got required product info from database.' );
}
if ( ! $got_product_data_from_db ) {
//couldn't get data from database by product ID for some reason. Getting data from $_POST instead
if ( ! isset( $_POST['item_name'] ) || empty( $_POST['item_name'] ) ) {
$this->ipn_completed( 'Invalid Item name' );
}
if ( ! isset( $_POST['currency_code'] ) || empty( $_POST['currency_code'] ) ) {
$this->ipn_completed( 'Invalid Currency Code' );
}
$item_name = stripslashes( sanitize_text_field( $_POST['item_name'] ) );
$item_quantity = sanitize_text_field( $_POST['item_quantity'] );
$item_custom_quantity = isset( $_POST['stripeCustomQuantity'] ) ? intval( $_POST['stripeCustomQuantity'] ) : false;
$item_url = sanitize_text_field( $_POST['item_url'] );
$button_key = sanitize_text_field( $_POST['stripeButtonKey'] );
$reported_price = sanitize_text_field( $_POST['stripeItemPrice'] );
ASP_Debug_Logger::log( 'Checking price consistency.' );
$calculated_button_key = md5( htmlspecialchars_decode( $item_name ) . $reported_price );
if ( $button_key !== $calculated_button_key ) {
$this->ipn_completed( 'Button Key mismatch. Expected ' . $button_key . ', calculated: ' . $calculated_button_key );
}
$trans_name = 'stripe-payments-' . $button_key;
$trans = get_transient( $trans_name ); //Read the price for this item from the system.
if ( empty( $trans ) ) {
$this->ipn_completed( "Can't check payment validity. Aborting." );
}
$item_price = $trans['price'];
$tax = isset( $trans['tax'] ) ? $trans['tax'] : 0;
$shipping = isset( $trans['shipping'] ) ? $trans['shipping'] : 0;
$currency_code = strtoupper( sanitize_text_field( $_POST['currency_code'] ) );
if ( ! AcceptStripePayments::is_zero_cents( $currency_code ) ) {
$shipping = $shipping / 100;
}
}
if ( empty( $item_price ) ) { //Custom amount
$item_price = floatval( $_POST['stripeAmount'] );
}
if ( ! is_numeric( $item_price ) ) {
$this->ipn_completed( 'Invalid item price: ' . $item_price );
}
$currencyCodeType = strtolower( $currency_code );
$stripeToken = sanitize_text_field( $_POST['stripeToken'] );
$stripeTokenType = sanitize_text_field( $_POST['stripeTokenType'] );
$stripeEmail = sanitize_email( $_POST['stripeEmail'] );
$charge_description = sanitize_text_field( $_POST['charge_description'] );
$orig_item_price = $item_price;
//check if we have variatons selected for the product
$variations = array();
$varApplied = array();
if ( $got_product_data_from_db && isset( $_POST['stripeVariations'] ) ) {
// we got variations posted. Let's get variations from product
$v = new ASPVariations( $prod_id );
if ( ! empty( $v->variations ) ) {
//there are variations configured for the product
$posted_v = filter_var( $_POST['stripeVariations'], FILTER_UNSAFE_RAW, FILTER_REQUIRE_ARRAY );
foreach ( $posted_v as $grp_id => $var_id ) {
$grp_id = sanitize_text_field( stripslashes( $grp_id ));
$var_id = sanitize_text_field( stripslashes( $var_id ));
$var = $v->get_variation( $grp_id, $var_id[0] );
if ( ! empty( $var ) ) {
$item_price = $item_price + $var['price'];
$variations[] = array( $var['group_name'] . ' - ' . $var['name'], $var['price'] );
$varApplied[] = $var;
}
}
} else {
//no variations configured for the product
}
}
//check if we we need to apply coupon
if ( isset( $prod_id ) && ! empty( $_POST['stripeCoupon'] ) ) {
$coupon_code = strtoupper( $_POST['stripeCoupon'] );
ASP_Debug_Logger::log( sprintf( 'Coupon provided "%s"', $coupon_code ) );
$coupon = AcceptStripePayments_CouponsAdmin::get_coupon( $coupon_code );
if ( $coupon['valid'] ) {
if ( ! AcceptStripePayments_CouponsAdmin::is_coupon_allowed_for_product( $coupon['id'], $prod_id ) ) {
//coupon not allowed for this product
ASP_Debug_Logger::log( 'Coupon is not allowed for this product' );
unset( $coupon );
} else {
if ( $coupon['discountType'] === 'perc' ) {
$perc = AcceptStripePayments::is_zero_cents( $currency_code ) ? 0 : 2;
$discount_amount = round( $item_price * ( $coupon['discount'] / 100 ), $perc );
} else {
$discount_amount = $coupon['discount'];
}
ASP_Debug_Logger::log( sprintf( 'Coupon is valid. Discount amount: %s', $discount_amount ) );
$coupon['discountAmount'] = $discount_amount;
$item_price = $item_price - $discount_amount;
}
} else {
ASP_Debug_Logger::log( sprintf( 'Invalid coupon "%s", reason: %s', $coupon_code, $coupon['err_msg'] ) );
unset( $coupon );
}
}
$amount = $item_price;
//apply tax if needed
$tax_amt = AcceptStripePayments::get_tax_amount( $amount, $tax, AcceptStripePayments::is_zero_cents( $currency_code ) );
$amount = AcceptStripePayments::apply_tax( $amount, $tax, AcceptStripePayments::is_zero_cents( $currency_code ) );
if ( $item_custom_quantity !== false ) { //custom quantity
$item_quantity = $item_custom_quantity;
}
if ( empty( $item_quantity ) ) {
$item_quantity = 1;
}
$amount = ( $item_quantity !== 'NA' ? ( $amount * $item_quantity ) : $amount );
//add shipping cost
$amount = AcceptStripePayments::apply_shipping( $amount, $shipping, AcceptStripePayments::is_zero_cents( $currency_code ) );
$amount_in_cents = $amount;
if ( ! AcceptStripePayments::is_zero_cents( $currency_code ) ) {
$amount_in_cents = $amount_in_cents * 100;
}
$opt = get_option( 'AcceptStripePayments-settings' );
$data = array();
$data['product_id'] = isset( $_POST['stripeProductId'] ) && ! empty( $_POST['stripeProductId'] ) ? intval( $_POST['stripeProductId'] ) : '';
$data['is_live'] = $asp_class->get_setting( 'is_live' );
$data['item_name'] = $item_name;
$data['stripeToken'] = $stripeToken;
$data['stripeTokenType'] = $stripeTokenType;
$data['stripeEmail'] = $stripeEmail;
$data['item_quantity'] = $item_quantity;
$data['item_price'] = $orig_item_price;
$data['discount_item_price'] = $item_price;
$data['paid_amount'] = $amount;
$data['amount_in_cents'] = $amount_in_cents;
$data['currency_code'] = $currency_code;
$data['charge_description'] = $charge_description;
$data['addonName'] = isset( $_POST['stripeAddonName'] ) ? sanitize_text_field( $_POST['stripeAddonName'] ) : '';
$data['button_key'] = isset( $button_key ) ? $button_key : '';
//Coupon
if ( isset( $coupon ) ) {
$data['coupon'] = $coupon;
}
//Custom Field
$data['custom_fields'] = array();
if ( isset( $_POST['stripeCustomField'] ) ) {
$data['custom_fields'][] = array(
'name' => sanitize_text_field( $_POST['stripeCustomFieldName'] ),
'value' => sanitize_text_field( $_POST['stripeCustomField'] ),
);
}
$data['custom_fields'] = apply_filters( 'asp_process_custom_fields', $data['custom_fields'], $data );
//Filter so addons can modify applied variations if needed
$variations = apply_filters( 'asp_filter_variations_display', $variations, $data );
ob_start();
ASP_Debug_Logger::log( 'Getting API keys and trying to create a charge.' );
ASP_Utils::load_stripe_lib();
if ( $data['is_live'] ) {
$sec_key = $asp_class->APISecKeyLive;
} else {
$sec_key = $asp_class->APISecKeyTest;
}
\Stripe\Stripe::setApiKey( $sec_key );
//let addons process payment if needed
ASP_Debug_Logger::log( 'Firing pre-payment hook.' );
$data = apply_filters( 'asp_process_charge', $data );
if ( empty( $data['charge'] ) && $amount_in_cents == 0 ) {
//looks like we have zero amount. We won't be really processing the charge as it would result in error,
//so we just make it look like it was actually processed.
$data['charge'] = new stdClass();
$data['charge']->id = 0;
$data['charge']->created = time();
}
if ( empty( $data['charge'] ) ) {
ASP_Debug_Logger::log( 'Processing payment.' );
try {
$charge_opts = array(
'amount' => $amount_in_cents,
'currency' => $currencyCodeType,
'description' => $charge_description,
);
//Check if we need to add Receipt Email parameter
if ( isset( $opt['stripe_receipt_email'] ) && $opt['stripe_receipt_email'] == 1 ) {
$charge_opts['receipt_email'] = $stripeEmail;
}
//Check if we need to add Don't Save Card parameter
if ( $opt['dont_save_card'] == 1 ) {
$charge_opts['source'] = $stripeToken;
} else {
$customer_data = array(
'email' => $stripeEmail,
'card' => $stripeToken,
);
$customer_data = apply_filters( 'asp_customer_data_before_create', $customer_data );
$customer = \Stripe\Customer::create( $customer_data );
$charge_opts['customer'] = $customer->id;
}
$charge_opts['metadata'] = array();
//Check if we need to include custom field in metadata
if ( ! empty( $data['custom_fields'] ) ) {
$cfStr = '';
foreach ( $data['custom_fields'] as $cf ) {
$cfStr .= $cf['name'] . ': ' . $cf['value'] . ' | ';
}
$cfStr = rtrim( $cfStr, ' | ' );
//trim the string as metadata value cannot exceed 500 chars
$cfStr = substr( $cfStr, 0, 499 );
$charge_opts['metadata']['Custom Fields'] = $cfStr;
}
//Check if we need to include variations data into metadata
if ( ! empty( $variations ) ) {
$varStr = '';
foreach ( $variations as $variation ) {
$varStr .= '[' . $variation[0] . '], ';
}
$varStr = rtrim( $varStr, ', ' );
//trim the string as metadata value cannot exceed 500 chars
$varStr = substr( $varStr, 0, 499 );
$charge_opts['metadata']['Variations'] = $varStr;
}
//Shipping address data (if any)
$shipping_address = '';
$shipping_address .= isset( $_POST['stripeShippingName'] ) ? sanitize_text_field( $_POST['stripeShippingName'] ) . "\n" : '';
$shipping_address .= isset( $_POST['stripeShippingAddressLine1'] ) ? sanitize_text_field( $_POST['stripeShippingAddressLine1'] ) . "\n" : '';
$shipping_address .= isset( $_POST['stripeShippingAddressApt'] ) ? sanitize_text_field( $_POST['stripeShippingAddressApt'] ) . "\n" : '';
$shipping_address .= isset( $_POST['stripeShippingAddressZip'] ) ? sanitize_text_field( $_POST['stripeShippingAddressZip'] ) . "\n" : '';
$shipping_address .= isset( $_POST['stripeShippingAddressCity'] ) ? sanitize_text_field( $_POST['stripeShippingAddressCity'] ) . "\n" : '';
$shipping_address .= isset( $_POST['stripeShippingAddressState'] ) ? sanitize_text_field( $_POST['stripeShippingAddressState'] ) . "\n" : '';
$shipping_address .= isset( $_POST['stripeShippingAddressCountry'] ) ? sanitize_text_field( $_POST['stripeShippingAddressCountry'] ) . "\n" : '';
$data['shipping_address'] = $shipping_address;
if ( ! empty( $shipping_address ) ) {
//add shipping address to metadata
$shipping_address = str_replace( "\n", ', ', $shipping_address );
$shipping_address = rtrim( $shipping_address, ', ' );
$charge_opts['metadata']['Shipping Address'] = $shipping_address;
}
$data['charge'] = \Stripe\Charge::create( $charge_opts );
} catch ( Exception $e ) {
//If the charge fails (payment unsuccessful), this code will get triggered.
if ( ! empty( $data['charge']->failure_code ) ) {
$err_msg = $data['charge']->failure_code . ': ' . $data['charge']->failure_message;
} else {
$err_msg = $e->getMessage();
}
$this->ipn_completed( $err_msg );
}
}
//Grab the charge ID and set it as the transaction ID.
$txn_id = $data['charge']->id; //$charge->balance_transaction;
//Core transaction data
$data['txn_id'] = $txn_id; //The Stripe charge ID
$post_data = $data;
//Billing address data (if any)
$billing_address = '';
$billing_address .= isset( $_POST['stripeBillingName'] ) ? sanitize_text_field( $_POST['stripeBillingName'] ) . "\n" : '';
$billing_address .= isset( $_POST['stripeBillingAddressLine1'] ) ? sanitize_text_field( $_POST['stripeBillingAddressLine1'] ) . "\n" : '';
$billing_address .= isset( $_POST['stripeBillingAddressApt'] ) ? sanitize_text_field( $_POST['stripeBillingAddressApt'] ) . "\n" : '';
$billing_address .= isset( $_POST['stripeBillingAddressZip'] ) ? sanitize_text_field( $_POST['stripeBillingAddressZip'] ) . "\n" : '';
$billing_address .= isset( $_POST['stripeBillingAddressCity'] ) ? sanitize_text_field( $_POST['stripeBillingAddressCity'] ) . "\n" : '';
$billing_address .= isset( $_POST['stripeBillingAddressState'] ) ? sanitize_text_field( $_POST['stripeBillingAddressState'] ) . "\n" : '';
$billing_address .= isset( $_POST['stripeBillingAddressCountry'] ) ? sanitize_text_field( $_POST['stripeBillingAddressCountry'] ) . "\n" : '';
if ( empty( $billing_address ) && ( isset( $data['product_id'] ) && get_post_meta( $data['product_id'], 'asp_product_collect_billing_addr', true ) ) ) {
//let's try to fetch billing address from payment data
$billing_address .= ! empty( $data['charge']->source->name ) ? $data['charge']->source->name . "\n" : '';
$_POST['stripeBillingName'] = ! empty( $billing_address ) ? $billing_address : null;
$billing_address .= ! empty( $data['charge']->source->address_line1 ) ? $data['charge']->source->address_line1 . "\n" : '';
$billing_address .= ! empty( $data['charge']->source->address_line2 ) ? $data['charge']->source->address_line2 . "\n" : '';
$billing_address .= ! empty( $data['charge']->source->address_zip ) ? $data['charge']->source->address_zip . "\n" : '';
$billing_address .= ! empty( $data['charge']->source->address_city ) ? $data['charge']->source->address_city . "\n" : '';
$billing_address .= ! empty( $data['charge']->source->address_state ) ? $data['charge']->source->address_state . "\n" : '';
$billing_address .= ! empty( $data['charge']->source->address_country ) ? $data['charge']->source->address_country . "\n" : '';
}
$post_data['billing_address'] = $billing_address;
//get customer name
$name = isset( $_POST['stripeBillingName'] ) ? sanitize_text_field( $_POST['stripeBillingName'] ) : '';
if ( empty( $name ) && ! empty( $data['charge']->source->name ) ) {
$name = $data['charge']->source->name;
}
$post_data['customer_name'] = $name;
$purchase_date = date( 'Y-m-d H:i:s', $data['charge']->created );
$purchase_date = get_date_from_gmt( $purchase_date, get_option( 'date_format' ) . ', ' . get_option( 'time_format' ) );
$post_data['purchase_date'] = $purchase_date;
$post_data['additional_items'] = array();
//check if we need to add variations
if ( ! empty( $variations ) ) {
foreach ( $variations as $variation ) {
$post_data['additional_items'][ $variation[0] ] = $variation[1];
}
}
//check if we need to increase redeem coupon count
if ( isset( $coupon ) && $coupon['valid'] ) {
$curr_redeem_cnt = get_post_meta( $coupon['id'], 'asp_coupon_red_count', true );
$curr_redeem_cnt++;
update_post_meta( $coupon['id'], 'asp_coupon_red_count', $curr_redeem_cnt );
if ( isset( $data['is_trial'] ) ) {
//trial Subscription
$coupon['discountAmount'] = 0;
$data['discount_item_price'] = 0;
}
$post_data['coupon'] = $coupon;
$post_data['additional_items'][ sprintf( __( 'Coupon "%s"', 'stripe-payments' ), $coupon['code'] ) ] = floatval( '-' . $coupon['discountAmount'] );
$post_data['additional_items'][ __( 'Subtotal', 'stripe-payments' ) ] = $data['discount_item_price'];
}
if ( isset( $tax ) && ! empty( $tax ) ) {
$taxStr = apply_filters( 'asp_customize_text_msg', __( 'Tax', 'stripe-payments' ), 'tax_str' );
$post_data['additional_items'][ ucfirst( $taxStr ) ] = $tax_amt;
$post_data['tax_perc'] = $tax;
$post_data['tax'] = $tax_amt;
}
if ( isset( $shipping ) && ! empty( $shipping ) ) {
$shipStr = apply_filters( 'asp_customize_text_msg', __( 'Shipping', 'stripe-payments' ), 'shipping_str' );
$post_data['additional_items'][ ucfirst( $shipStr ) ] = $shipping;
$post_data['shipping'] = $shipping;
}
//Insert the order data to the custom post
$dont_create_order = $asp_class->get_setting( 'dont_create_order' );
if ( ! $dont_create_order ) {
$order = new ASP_Order_Item();
$order->create( empty( $data['product_id'] ) ? 0 : $data['product_id'] );
$order_post_id = $order->update_legacy( $post_data, $data['charge'] );
$order->change_status( 'paid' );
$post_data['order_post_id'] = $order_post_id;
}
// handle download item url
$item_url = apply_filters( 'asp_item_url_process', $item_url, $post_data );
$item_url = base64_decode( $item_url );
$post_data['item_url'] = $item_url;
if ( ! empty( $varApplied ) ) {
//process variations URLs if needed
foreach ( $varApplied as $key => $var ) {
if ( ! empty( $var['url'] ) ) {
$var = apply_filters( 'asp_variation_url_process', $var, $post_data );
$varApplied[ $key ] = $var;
}
}
}
//add variations to the resulting array
$post_data['var_applied'] = $varApplied;
ASP_Debug_Logger::log( 'Firing post-payment hooks.' );
//Action hook with the checkout post data parameters.
do_action( 'asp_stripe_payment_completed', $post_data, $data['charge'] );
//insert payment data into order info
if ( isset( $order_post_id ) ) {
update_post_meta( $order_post_id, 'order_data', $post_data );
update_post_meta( $order_post_id, 'charge_data', $data['charge'] );
}
//Action hook with the order object.
if ( ! $dont_create_order ) {
do_action( 'AcceptStripePayments_payment_completed', $order, $data['charge'] );
}
if ( ! empty( $data['product_id'] ) ) {
//check if we need to deal with stock
if ( get_post_meta( $data['product_id'], 'asp_product_enable_stock', true ) ) {
$stock_items = intval( get_post_meta( $data['product_id'], 'asp_product_stock_items', true ) );
$stock_items = $stock_items - $data['item_quantity'];
if ( $stock_items < 0 ) {
$stock_items = 0;
}
update_post_meta( $data['product_id'], 'asp_product_stock_items', $stock_items );
$data['stock_items'] = $stock_items;
}
}
//Let's handle email sending stuff
if ( isset( $opt['send_emails_to_buyer'] ) ) {
if ( $opt['send_emails_to_buyer'] ) {
$from = $opt['from_email_address'];
$to = $post_data['stripeEmail'];
$subj = $opt['buyer_email_subject'];
$body = asp_apply_dynamic_tags_on_email_body( $opt['buyer_email_body'], $post_data );
$subj = apply_filters( 'asp_buyer_email_subject', $subj, $post_data );
$body = apply_filters( 'asp_buyer_email_body', $body, $post_data );
$from = apply_filters( 'asp_buyer_email_from', $from, $post_data );
$headers = array();
if ( ! empty( $opt['buyer_email_type'] ) && $opt['buyer_email_type'] === 'html' ) {
$headers[] = 'Content-Type: text/html; charset=UTF-8';
$body = nl2br( $body );
}
$headers[] = 'From: ' . $from;
wp_mail( $to, $subj, $body, $headers );
ASP_Debug_Logger::log( 'Notification email sent to buyer: ' . $to . ', From email address used: ' . $from );
}
}
if ( isset( $opt['send_emails_to_seller'] ) ) {
if ( $opt['send_emails_to_seller'] ) {
$from = $opt['from_email_address'];
$to = $opt['seller_notification_email'];
$subj = $opt['seller_email_subject'];
$body = asp_apply_dynamic_tags_on_email_body( $opt['seller_email_body'], $post_data, true );
$subj = apply_filters( 'asp_seller_email_subject', $subj, $post_data );
$body = apply_filters( 'asp_seller_email_body', $body, $post_data );
$from = apply_filters( 'asp_seller_email_from', $from, $post_data );
$headers = array();
if ( ! empty( $opt['seller_email_type'] ) && $opt['seller_email_type'] === 'html' ) {
$headers[] = 'Content-Type: text/html; charset=UTF-8';
$body = nl2br( $body );
}
$headers[] = 'From: ' . $from;
wp_mail( $to, $subj, $body, $headers );
ASP_Debug_Logger::log( 'Notification email sent to seller: ' . $to . ', From email address used: ' . $from );
}
}
$post_data['charge_date_raw'] = $data['charge']->created;
$charge_date = date( 'Y-m-d H:i:s', $data['charge']->created );
$charge_date = get_date_from_gmt( $charge_date, get_option( 'date_format' ) . ', ' . get_option( 'time_format' ) );
$post_data['charge_date'] = $charge_date;
$this->sess->set_transient_data( 'asp_data', $post_data );
$this->ipn_completed();
}
}
AcceptStripePayments_Process_IPN::get_instance();
function asp_apply_dynamic_tags_on_email_body( $body, $post, $seller_email = false ) {
$product_details = __( 'Product Name', 'stripe-payments' ) . ': {item_name}' . "\n";
$product_details .= __( 'Quantity', 'stripe-payments' ) . ': {item_quantity}' . "\n";
$product_details .= __( 'Item Price', 'stripe-payments' ) . ': {item_price_curr}' . "\n";
//check if there are any additional items available like tax and shipping cost
$product_details .= AcceptStripePayments::gen_additional_items( $post );
$product_details .= '--------------------------------' . "\n";
$product_details .= __( 'Total Amount', 'stripe-payments' ) . ': {purchase_amt_curr}' . "\n";
$varUrls = array();
// check if we have variations applied with download links
if ( ! empty( $post['var_applied'] ) ) {
foreach ( $post['var_applied'] as $var ) {
if ( ! empty( $var['url'] ) ) {
$varUrls[] = $var['url'];
}
}
}
$download_str = '';
if ( ! empty( $post['item_url'] ) ) {
$download_str = "\n\n" . __( 'Download link', 'stripe-payments' ) . ': ' . $post['item_url'];
}
if ( ! empty( $varUrls ) ) {
//show variations download link(s)
//those links will replace the one set for the product
if ( count( $varUrls ) === 1 ) {
$download_str = __( 'Download link', 'stripe-payments' ) . ': ';
} else {
$download_str = __( 'Download links', 'stripe-payments' ) . ":\n";
}
foreach ( $varUrls as $url ) {
$download_str .= $url . "\n";
}
}
$product_details .= rtrim( $download_str, "\n" );
//Add link to order info if this is email to the seller
if ( $seller_email && isset( $post['order_post_id'] ) ) {
$product_details .= "\n\n" . __( 'Order Info: ', 'stripe-payments' ) . admin_url( 'post.php?post=' . $post['order_post_id'] . '&action=edit' );
}
$post['product_details'] = $product_details;
//Get the product variations (if any)
$product_variations = AcceptStripePayments::gen_additional_items( $post );
$custom_field = '';
if ( isset( $post['custom_fields'] ) ) {
foreach ( $post['custom_fields'] as $cf ) {
$custom_field .= $cf['name'] . ': ' . $cf['value'] . "\r\n";
}
$custom_field = rtrim( $custom_field, "\r\n" );
}
$curr = $post['currency_code'];
$currencies = AcceptStripePayments::get_currencies();
if ( isset( $currencies[ $curr ] ) ) {
$curr_sym = $currencies[ $curr ][1];
} else {
$curr_sym = '';
}
$item_price = AcceptStripePayments::formatted_price( $post['item_price'], false );
$item_price_curr = AcceptStripePayments::formatted_price( $post['item_price'], $post['currency_code'] );
$post['item_price_curr'] = $item_price_curr;
$purchase_amt = AcceptStripePayments::formatted_price( $post['paid_amount'], false );
$purchase_amt_curr = AcceptStripePayments::formatted_price( $post['paid_amount'], $post['currency_code'] );
$post['purchase_amt_curr'] = $purchase_amt_curr;
$tax = 0;
$tax_amt = 0;
$shipping = 0;
if ( isset( $post['tax_perc'] ) && ! empty( $post['tax_perc'] ) ) {
$tax = $post['tax_perc'] . '%';
}
if ( isset( $post['tax'] ) && ! empty( $post['tax'] ) ) {
$tax_amt = AcceptStripePayments::formatted_price( $post['tax'], $post['currency_code'] );
}
if ( isset( $post['shipping'] ) && ! empty( $post['shipping'] ) ) {
$shipping = AcceptStripePayments::formatted_price( $post['shipping'], $post['currency_code'] );
}
if ( isset( $post['charge']->object ) && 'charge' !== $post['charge']->object ) {
//this is most likely subs product
$ipn = ASP_Process_IPN_NG::get_instance();
if ( isset( $ipn->p_data ) ) {
$obj = $ipn->p_data->get_obj();
if ( isset( $obj->latest_invoice )
&& isset( $obj->latest_invoice->charge )
&& is_object( $obj->latest_invoice->charge ) ) {
$post['charge'] = $obj->latest_invoice->charge;
}
}
}
$pm_type = '';
$card_brand = '';
$card_last4 = '';
if ( isset( $post['charge']->object ) && 'charge' === $post['charge']->object ) {
$pm_type = $post['charge']->payment_method_details->type;
if ( isset( $post['charge']->payment_method_details->card ) ) {
$card_brand = $post['charge']->payment_method_details->card->brand;
$card_last4 = $post['charge']->payment_method_details->card->last4;
}
}
$first_name = isset($post['customer_first_name']) && !empty($post['customer_first_name']) ? $post['customer_first_name'] : '';
$last_name = isset($post['customer_last_name']) && !empty($post['customer_last_name']) ? $post['customer_last_name'] : '';
if (empty($first_name) && empty($last_name)){
// First name, last name explicitly not set. Try to get them from full name.
if ( ! empty( $post['customer_name'] ) ) {
$parts = explode( ' ', $post['customer_name'], 2 );
$first_name = ! empty( $parts[0] ) ? $parts[0] : '';
$last_name = ! empty( $parts[1] ) ? $parts[1] : '';
}
}
$logged_in_user_id = isset($post['logged_in_user_id']) && ! empty( $post['logged_in_user_id'] ) ? $post['logged_in_user_id'] : '';
$logged_in_user_name = isset($post['logged_in_user_name']) && ! empty( $post['logged_in_user_name'] ) ? $post['logged_in_user_name'] : '';
$item_description = '';
$product_url = '';
$surcharge_total_amt = '';
$surcharge_label = '';
if ( isset( $post['product_id'] ) ){
// Retrieve product item from product id.
$product_item = new ASP_Product_Item( $post['product_id'] );
$product_type = $product_item->get_type();
if ( in_array($product_type, array('one_time', 'donation')) ) {
$surcharge_label = $product_item->get_surcharge_label();
if (isset($post['additional_items'][$surcharge_label])) {
$surcharge_total_amt = AcceptStripePayments::formatted_price($post['additional_items'][$surcharge_label], $post['currency_code']);
}
}
$item_description = get_post_field('post_content', $post['product_id']);
$product_url = get_permalink( $post['product_id'] );
}
$tags = array(
'{item_name}',
'{item_short_desc}',
'{item_description}',
'{item_quantity}',
'{item_url}',
'{download_url}',
'{payer_email}',
'{customer_name}',
'{first_name}',
'{last_name}',
'{transaction_id}',
'{item_price}',
'{item_price_curr}',
'{purchase_amt}',
'{purchase_amt_curr}',
'{tax}',
'{tax_amt}',
'{shipping_amt}',
'{currency}',
'{currency_code}',
'{purchase_date}',
'{shipping_address}',
'{billing_address}',
'{custom_field}',
'{coupon_code}',
'{card_brand}',
'{card_last_4}',
'{payment_method}',
'{product_variations}',
'{product_url}',
'{logged_in_user_name}',
'{logged_in_user_id}',
'{surcharge_total_amt}',
'{surcharge_label}',
);
$vals = array(
$post['item_name'],
$post['charge_description'],
$item_description,
$post['item_quantity'],
! empty( $post['item_url'] ) ? $post['item_url'] : '',
! empty( $post['item_url'] ) ? $post['item_url'] : '',
$post['stripeEmail'],
$post['customer_name'],
$first_name,
$last_name,
$post['txn_id'],
$item_price,
$post['item_price_curr'],
$purchase_amt,
$post['purchase_amt_curr'],
$tax,
$tax_amt,
$shipping,
$curr_sym,
$curr,
$post['purchase_date'],
isset( $post['shipping_address'] ) ? $post['shipping_address'] : '',
isset( $post['billing_address'] ) ? $post['billing_address'] : '',
$custom_field,
! empty( $post['coupon_code'] ) ? $post['coupon_code'] : '',
$card_brand,
$card_last4,
$pm_type,
$product_variations,
$product_url,
$logged_in_user_name,
$logged_in_user_id,
$surcharge_total_amt,
$surcharge_label,
);
//let's combine tags and vals into one array so we can apply filters on it
$tags_vals = array(
'tags' => $tags,
'vals' => $vals,
);
$tags_vals = apply_filters( 'asp_email_body_tags_vals_before_replace', $tags_vals, $post );
$tags = $tags_vals['tags'];
$vals = $tags_vals['vals'];
$product_details = str_replace( $tags, $vals, $product_details );
$tags[] = '{product_details}';
$vals[] = $product_details;
$body = stripslashes( str_replace( $tags, $vals, $body ) );
//let's apply a filter for the email body.
$body = apply_filters( 'asp_email_body_after_replace', $body );
//make tags and vals available for checkout results page by storing those in inner session
if ( ! $seller_email ) {
$sess = ASP_Session::get_instance();
$sess->set_transient_data( 'asp_checkout_data_tags', $tags );
$sess->set_transient_data( 'asp_checkout_data_vals', $vals );
}
return $body;
}