swpm-stripe-sca-subscription-ipn.php 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. <?php
  2. require SIMPLE_WP_MEMBERSHIP_PATH . 'ipn/swpm_handle_subsc_ipn.php';
  3. class SwpmStripeSCASubscriptionIpnHandler {
  4. public function __construct() {
  5. $this->handle_stripe_ipn();
  6. }
  7. public function handle_stripe_ipn() {
  8. //This will get executed only for direct post (not webhooks). So it is executed at the time of payment in the browser (via HTTP POST). When the "hook" query arg is not set.
  9. //The webhooks are handled by the "swpm-stripe-subscription-ipn.php" script.
  10. SwpmLog::log_simple_debug( 'Stripe SCA Subscription IPN (HTTP POST) received. Processing request...', true );
  11. // SwpmLog::log_simple_debug(print_r($_REQUEST, true), true);//Useful for debugging purpose
  12. // Read and sanitize the request parameters.
  13. $ref_id = filter_input( INPUT_GET, 'ref_id', FILTER_SANITIZE_STRING );
  14. if ( empty( $ref_id ) ) {
  15. //no ref id provided, cannot proceed
  16. SwpmLog::log_simple_debug( 'Fatal Error! No ref_id provied.', false );
  17. wp_die( esc_html( 'Fatal Error! No ref_id provied.' ) );
  18. }
  19. $trans_info = explode( '|', $ref_id );
  20. $button_id = isset( $trans_info[1] ) ? absint( $trans_info[1] ) : false;
  21. // Retrieve the CPT for this button
  22. $button_cpt = get_post( $button_id );
  23. if ( ! $button_cpt ) {
  24. // Fatal error. Could not find this payment button post object.
  25. SwpmLog::log_simple_debug( 'Fatal Error! Failed to retrieve the payment button post object for the given button ID: ' . $button_id, false );
  26. wp_die( esc_html( sprintf( 'Fatal Error! Payment button (ID: %d) does not exist. This request will fail.', $button_id ) ) );
  27. }
  28. $settings = SwpmSettings::get_instance();
  29. $sandbox_enabled = $settings->get_value( 'enable-sandbox-testing' );
  30. //API keys
  31. $api_keys = SwpmMiscUtils::get_stripe_api_keys_from_payment_button( $button_id, ! $sandbox_enabled );
  32. // Include the Stripe library.
  33. SwpmMiscUtils::load_stripe_lib();
  34. try {
  35. \Stripe\Stripe::setApiKey( $api_keys['secret'] );
  36. $events = \Stripe\Event::all(
  37. array(
  38. 'type' => 'checkout.session.completed',
  39. 'created' => array(
  40. 'gte' => time() - 60 * 60,
  41. ),
  42. )
  43. );
  44. $sess = false;
  45. foreach ( $events->autoPagingIterator() as $event ) {
  46. $session = $event->data->object;
  47. if ( isset( $session->client_reference_id ) && $session->client_reference_id === $ref_id ) {
  48. $sess = $session;
  49. break;
  50. }
  51. }
  52. if ( false === $sess ) {
  53. // Can't find session.
  54. $error_msg = sprintf( "Fatal error! Payment with ref_id %s can't be found", $ref_id );
  55. SwpmLog::log_simple_debug( $error_msg, false );
  56. wp_die( esc_html( $error_msg ) );
  57. }
  58. $sub_id = $sess->subscription;
  59. $sub = \Stripe\Subscription::retrieve( $sub_id );
  60. } catch ( Exception $e ) {
  61. $error_msg = 'Error occurred: ' . $e->getMessage();
  62. SwpmLog::log_simple_debug( $error_msg, false );
  63. wp_die( esc_html( $error_msg ) );
  64. }
  65. $pm = \Stripe\PaymentMethod::retrieve( $sub->default_payment_method );
  66. // Grab the charge ID and set it as the transaction ID.
  67. $txn_id = $sub->customer;
  68. // The charge ID can be used to retrieve the transaction details using hte following call.
  69. // \Stripe\Charge::retrieve($charge->$data[0]->id);
  70. //check if this payment has already been processed
  71. $payment = get_posts(
  72. array(
  73. 'meta_key' => 'txn_id',
  74. 'meta_value' => $txn_id,
  75. 'posts_per_page' => 1,
  76. 'offset' => 0,
  77. 'post_type' => 'swpm_transactions',
  78. )
  79. );
  80. wp_reset_postdata();
  81. if ( $payment ) {
  82. //payment has already been processed. Redirecting user to return_url
  83. $return_url = get_post_meta( $button_id, 'return_url', true );
  84. if ( empty( $return_url ) ) {
  85. $return_url = SIMPLE_WP_MEMBERSHIP_SITE_HOME_URL;
  86. }
  87. SwpmMiscUtils::redirect_to_url( $return_url );
  88. return;
  89. }
  90. $price_in_cents = $sub->plan->amount;
  91. $currency_code = strtoupper( $sub->plan->currency );
  92. $zero_cents = unserialize( SIMPLE_WP_MEMBERSHIP_STRIPE_ZERO_CENTS );
  93. if ( in_array( $currency_code, $zero_cents, true ) ) {
  94. $payment_amount = $price_in_cents;
  95. } else {
  96. $payment_amount = $price_in_cents / 100;// The amount (in cents). This value is used in Stripe API.
  97. }
  98. $payment_amount = floatval( $payment_amount );
  99. $payment_amount = apply_filters( 'swpm_payment_amount_filter', $payment_amount, $button_id );
  100. $membership_level_id = get_post_meta( $button_id, 'membership_level_id', true );
  101. // Everything went ahead smoothly with the charge.
  102. SwpmLog::log_simple_debug( 'Stripe SCA Subscription charge successful.', true );
  103. $customer = \Stripe\Customer::retrieve( $txn_id );
  104. $stripe_email = $customer->email;
  105. $user_ip = SwpmUtils::get_user_ip_address();
  106. //Custom field data
  107. $custom_field_value = 'subsc_ref=' . $membership_level_id;
  108. $custom_field_value .= '&user_ip=' . $user_ip;
  109. if ( SwpmMemberUtils::is_member_logged_in() ) {
  110. $custom_field_value .= '&swpm_id=' . SwpmMemberUtils::get_logged_in_members_id();
  111. }
  112. $custom_field_value = apply_filters( 'swpm_custom_field_value_filter', $custom_field_value );
  113. $custom = $custom_field_value;
  114. $custom_var = SwpmTransactions::parse_custom_var( $custom );
  115. $swpm_id = isset( $custom_var['swpm_id'] ) ? $custom_var['swpm_id'] : '';
  116. // Let's try to get first_name and last_name from full name
  117. $name = $pm->billing_details->name;
  118. $last_name = ( strpos( $name, ' ' ) === false ) ? '' : preg_replace( '#.*\s([\w-]*)$#', '$1', $name );
  119. $first_name = trim( preg_replace( '#' . $last_name . '#', '', $name ) );
  120. // Create the $ipn_data array.
  121. $ipn_data = array();
  122. $ipn_data['mc_gross'] = $payment_amount;
  123. $ipn_data['first_name'] = $first_name;
  124. $ipn_data['last_name'] = $last_name;
  125. $ipn_data['payer_email'] = $stripe_email;
  126. $ipn_data['membership_level'] = $membership_level_id;
  127. $ipn_data['txn_id'] = $txn_id;
  128. $ipn_data['subscr_id'] = $sub_id;
  129. $ipn_data['swpm_id'] = $swpm_id;
  130. $ipn_data['ip'] = $custom_var['user_ip'];
  131. $ipn_data['custom'] = $custom;
  132. $ipn_data['gateway'] = 'stripe-sca-subs';
  133. $ipn_data['status'] = 'completed';
  134. $bd_addr = $pm->billing_details->address;
  135. $ipn_data['address_street'] = isset( $bd_addr->line1 ) ? $bd_addr->line1 : '';
  136. $ipn_data['address_city'] = isset( $bd_addr->city ) ? $bd_addr->city : '';
  137. $ipn_data['address_state'] = isset( $bd_addr->state ) ? $bd_addr->state : '';
  138. $ipn_data['address_zipcode'] = isset( $bd_addr->postal_code ) ? $bd_addr->postal_code : '';
  139. $ipn_data['address_country'] = isset( $bd_addr->country ) ? $bd_addr->country : '';
  140. $ipn_data['payment_button_id'] = $button_id;
  141. $ipn_data['is_live'] = ! $sandbox_enabled;
  142. // Handle the membership signup related tasks.
  143. swpm_handle_subsc_signup_stand_alone( $ipn_data, $membership_level_id, $txn_id, $swpm_id );
  144. // Save the transaction record
  145. SwpmTransactions::save_txn_record( $ipn_data );
  146. SwpmLog::log_simple_debug( 'Transaction data saved.', true );
  147. // Trigger the stripe IPN processed action hook (so other plugins can can listen for this event).
  148. do_action( 'swpm_stripe_sca_ipn_processed', $ipn_data );
  149. do_action( 'swpm_payment_ipn_processed', $ipn_data );
  150. // Redirect the user to the return URL (or to the homepage if a return URL is not specified for this payment button).
  151. $return_url = get_post_meta( $button_id, 'return_url', true );
  152. if ( empty( $return_url ) ) {
  153. $return_url = SIMPLE_WP_MEMBERSHIP_SITE_HOME_URL;
  154. }
  155. SwpmLog::log_simple_debug( 'Redirecting customer to: ' . $return_url, true );
  156. SwpmLog::log_simple_debug( 'End of Stripe SCA Subscription IPN processing.', true, true );
  157. SwpmMiscUtils::redirect_to_url( $return_url );
  158. }
  159. }
  160. new SwpmStripeSCASubscriptionIpnHandler();