function run() { //Get the data from stripe $data_raw = file_get_contents("php://input"); $data = json_decode($data_raw); if (!$data) { CRM_Core_Error::Fatal("Stripe Callback: cannot json_decode data, exiting. <br /> {$data}"); } $test_mode = !$data->livemode; $stripe_key = CRM_Core_DAO::singleValueQuery("SELECT user_name FROM civicrm_payment_processor WHERE payment_processor_type = 'Stripe' AND is_test = '{$test_mode}'"); require_once "packages/stripe-php/lib/Stripe.php"; Stripe::setApiKey($stripe_key); //Retrieve Event from Stripe using ID even though we already have the values now. //This is for extra security precautions mentioned here: https://stripe.com/docs/webhooks $stripe_event_data = Stripe_Event::retrieve($data->id); $customer_id = $stripe_event_data->data->object->customer; switch ($stripe_event_data->type) { //Successful recurring payment case 'invoice.payment_succeeded': //Get the Stripe charge object try { $charge = Stripe_Charge::retrieve($stripe_event_data->data->object->charge); } catch (Exception $e) { CRM_Core_Error::Fatal("Failed to retrieve Stripe charge. Message: " . $e->getMessage()); break; } //Find the recurring contribution in CiviCRM by mapping it from Stripe $rel_info_query = CRM_Core_DAO::executeQuery("SELECT invoice_id, end_time FROM civicrm_stripe_subscriptions WHERE customer_id = '{$customer_id}'"); if (!empty($rel_info_query)) { $rel_info_query->fetch(); $invoice_id = $rel_info_query->invoice_id; $end_time = $rel_info_query->end_time; } else { CRM_Core_Error::Fatal("Error relating this customer ({$customer_id}) to the one in civicrm_stripe_subscriptions"); } //Compare against now + 24hrs to prevent charging 1 extra day. $time_compare = time() + 86400; //Fetch Civi's info about this recurring object $recur_contrib_query = CRM_Core_DAO::executeQuery("SELECT id, contact_id, currency, contribution_status_id, is_test, contribution_type_id, payment_instrument_id, campaign_id FROM civicrm_contribution_recur WHERE invoice_id = '{$invoice_id}'"); if (!empty($recur_contrib_query)) { $recur_contrib_query->fetch(); } else { CRM_Core_Error::Fatal("ERROR: Stripe triggered a Webhook on an invoice not found in civicrm_contribution_recur: " . $stripe_event_data); } //Build some params $stripe_customer = Stripe_Customer::retrieve($customer_id); $recieve_date = date("Y-m-d H:i:s", $charge->created); $total_amount = $charge->amount / 100; $fee_amount = $charge->fee / 100; $net_amount = $total_amount - $fee_amount; $transaction_id = $charge->id; $new_invoice_id = $stripe_event_data->data->object->id; if (empty($recur_contrib_query->campaign_id)) { $recur_contrib_query->campaign_id = 'NULL'; } $first_contrib_check = CRM_Core_DAO::singleValueQuery("SELECT id FROM civicrm_contribution WHERE invoice_id = '{$invoice_id}' AND contribution_status_id = '2'"); if (!empty($first_contrib_check)) { CRM_Core_DAO::executeQuery("UPDATE civicrm_contribution SET contribution_status_id = '1' WHERE id = '{$first_contrib_check}'"); return; } //Create this instance of the contribution for accounting in CiviCRM CRM_Core_DAO::executeQuery("\n \tINSERT INTO civicrm_contribution (\n \tcontact_id, contribution_type_id, payment_instrument_id, receive_date, \n \ttotal_amount, fee_amount, net_amount, trxn_id, invoice_id, currency,\n \tcontribution_recur_id, is_test, contribution_status_id, campaign_id\n \t) VALUES (\n \t'{$recur_contrib_query->contact_id}', '{$recur_contrib_query->contribution_type_id}', '{$recur_contrib_query->payment_instrument_id}', '{$recieve_date}', \n \t'{$total_amount}', '{$fee_amount}', '{$net_amount}', '{$transaction_id}', '{$new_invoice_id}', '{$recur_contrib_query->currency}', \n \t'{$recur_contrib_query->id}', '{$recur_contrib_query->is_test}', '1', {$recur_contrib_query->campaign_id}\n \t)"); if ($time_compare > $end_time) { $end_date = date("Y-m-d H:i:s", $end_time); //Final payment. Recurring contribution complete $stripe_customer->cancelSubscription(); CRM_Core_DAO::executeQuery("DELETE FROM civicrm_stripe_subscriptions WHERE invoice_id = '{$invoice_id}'"); CRM_Core_DAO::executeQuery("UPDATE civicrm_contribution_recur SET end_date = '{$end_date}', contribution_status_id = '1' WHERE invoice_id = '{$invoice_id}'"); return; } //Successful charge & more to come so set recurring contribution status to In Progress if ($recur_contrib_query->contribution_status_id != 5) { CRM_Core_DAO::executeQuery("UPDATE civicrm_contribution_recur SET contribution_status_id = 5 WHERE invoice_id = '{$invoice_id}'"); return; } break; //Failed recurring payment //Failed recurring payment case 'invoice.payment_failed': //Get the Stripe charge object try { $charge = Stripe_Charge::retrieve($stripe_event_data->data->object->charge); } catch (Exception $e) { CRM_Core_Error::Fatal("Failed to retrieve Stripe charge. Message: " . $e->getMessage()); break; } //Find the recurring contribution in CiviCRM by mapping it from Stripe $invoice_id = CRM_Core_DAO::singleValueQuery("SELECT invoice_id FROM civicrm_stripe_subscriptions WHERE customer_id = '{$customer_id}'"); if (empty($invoice_id)) { CRM_Core_Error::Fatal("Error relating this customer ({$customer_id}) to the one in civicrm_stripe_subscriptions"); } //Fetch Civi's info about this recurring object $recur_contrib_query = CRM_Core_DAO::executeQuery("SELECT id, contact_id, currency, contribution_status_id, is_test, contribution_type_id, payment_instrument_id, campaign_id FROM civicrm_contribution_recur WHERE invoice_id = '{$invoice_id}'"); if (!empty($recur_contrib_query)) { $recur_contrib_query->fetch(); } else { CRM_Core_Error::Fatal("ERROR: Stripe triggered a Webhook on an invoice not found in civicrm_contribution_recur: " . $stripe_event_data); } //Build some params $recieve_date = date("Y-m-d H:i:s", $charge->created); $total_amount = $charge->amount / 100; $fee_amount = $charge->fee / 100; $net_amount = $total_amount - $fee_amount; $transaction_id = $charge->id; if (empty($recur_contrib_query->campaign_id)) { $recur_contrib_query->campaign_id = 'NULL'; } //Create this instance of the contribution for accounting in CiviCRM CRM_Core_DAO::executeQuery("\n \tINSERT INTO civicrm_contribution (\n \tcontact_id, contribution_type_id, payment_instrument_id, receive_date, \n \ttotal_amount, fee_amount, net_amount, trxn_id, invoice_id, currency,\n \tcontribution_recur_id, is_test, contribution_status_id, campaign_id\n \t) VALUES (\n \t'{$recur_contrib_query->contact_id}', '{$recur_contrib_query->contribution_type_id}', '{$recur_contrib_query->payment_instrument_id}', '{$recieve_date}', \n \t'{$total_amount}', '{$fee_amount}', '{$net_amount}', '{$transaction_id}', '{$invoice_id}', '{$recur_contrib_query->currency}', \n \t'{$recur_contrib_query->id}', '{$recur_contrib_query->is_test}', '4', {$recur_contrib_query->campaign_id}\n \t)"); //Failed charge. Set to status to: Failed if ($recur_contrib_query->contribution_status_id != 4) { CRM_Core_DAO::executeQuery("UPDATE civicrm_contribution_recur SET contribution_status_id = 4 WHERE invoice_id = '{$invoice_id}'"); return; } else { //This has failed more than once. Now what? } break; //One-time donation and per invoice payment //One-time donation and per invoice payment case 'charge.succeeded': //Not implemented break; } parent::run(); }
$charge = Stripe_Charge::retrieve($stripe_event_data->data->object->charge); } catch (Exception $e) { CRM_Core_Error::Fatal("Failed to retrieve Stripe charge. Message: " . $e->getMessage()); break; } //Find the recurring contribution in CiviCRM by mapping it from Stripe $invoice_id = CRM_Core_DAO::singleValueQuery("SELECT invoice_id FROM civicrm_stripe_subscriptions WHERE customer_id = '{$customer_id}'"); if (empty($invoice_id)) { CRM_Core_Error::Fatal("Error relating this customer ({$customer_id}) to the one in civicrm_stripe_subscriptions"); } //Fetch Civi's info about this recurring object $recur_contrib_query = CRM_Core_DAO::executeQuery("SELECT id, contact_id, currency, contribution_status_id, is_test, contribution_type_id, payment_instrument_id, campaign_id FROM civicrm_contribution_recur WHERE invoice_id = '{$invoice_id}'"); if (!empty($recur_contrib_query)) { $recur_contrib_query->fetch(); } else { CRM_Core_Error::Fatal("ERROR: Stripe triggered a Webhook on an invoice not found in civicrm_contribution_recur: " . $stripe_event_data); } //Build some params $recieve_date = date("Y-m-d H:i:s", $charge->created); $total_amount = $charge->amount / 100; $fee_amount = $charge->fee / 100; $net_amount = $total_amount - $fee_amount; $transaction_id = $charge->id; if (empty($recur_contrib_query->campaign_id)) { $recur_contrib_query->campaign_id = 'NULL'; } //Create this instance of the contribution for accounting in CiviCRM CRM_Core_DAO::executeQuery("\r\n \tINSERT INTO civicrm_contribution (\r\n \tcontact_id, contribution_type_id, payment_instrument_id, receive_date, \r\n \ttotal_amount, fee_amount, net_amount, trxn_id, invoice_id, currency,\r\n \tcontribution_recur_id, is_test, contribution_status_id, campaign_id\r\n \t) VALUES (\r\n \t'{$recur_contrib_query->contact_id}', '{$recur_contrib_query->contribution_type_id}', '{$recur_contrib_query->payment_instrument_id}', '{$recieve_date}', \r\n \t'{$total_amount}', '{$fee_amount}', '{$net_amount}', '{$transaction_id}', '{$invoice_id}', '{$recur_contrib_query->currency}', \r\n \t'{$recur_contrib_query->id}', '{$recur_contrib_query->is_test}', '4', {$recur_contrib_query->campaign_id}\r\n \t)"); //Failed charge. Set to status to: Failed if ($recur_contrib_query->contribution_status_id != 4) { CRM_Core_DAO::executeQuery("UPDATE civicrm_contribution_recur SET contribution_status_id = 4 WHERE invoice_id = '{$invoice_id}'");