/** * @Route("/stripe", name="stripe_handler") */ public function StripeHandlerAction(Request $request) { $upgradeBusiness = $this->findBusiness('dashboard.upgrade.business'); $event = json_decode($request->getContent(), true); $stripeEvent = \Stripe_Event::retrieve($event['id']); if ($stripeEvent && isset($stripeEvent->type)) { switch ($stripeEvent->type) { case 'invoice.payment_succeeded': $upgradeBusiness->renewPlan($stripeEvent); break; } } return new Response('Successfully'); }
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(); }
/** * Get last (n) events up to at least last 30 days worth. Data returned is sorted with most recent first. * Maximum is 100 items, per Stripe * * @param int $num_events number of events to retrieve * @param int $offset offset in the event list * @param string $type event type, or * for all * @param string $created either exact UTC timestamp, or associative array with gt, gte, lt, lte and timestamp * for filtering on time (i.e. array('gt' => 1000) would be all records later than 1000 UTC timestamp * @return array - function returns associative array from stripe, we cant get objects */ public function get_all($num_events = 100, $offset = 0, $type = '*', $created = FALSE) { try { $ch = Stripe_Event::all(array('count' => $num_events, 'offset' => $offset, 'type' => $type, 'created' => $created ? $created : array('gt' => 0))); return $ch; } catch (Exception $e) { $this->error = TRUE; $this->message = $e->getMessage(); $this->code = $e->getCode(); return FALSE; } }
public function index() { // when ACL is ready //$this->checkAccess( __CLASS__, __FUNCTION__ ); //TODO we sync the objects into the collections than we filter and search through them like normal $events = \Stripe_Event::all(); foreach ($events['data'] as $event) { //$data = array_filter((array)$event->data->object); $item = $this->getModel(); $item->set('event.id', $event->id); $item->set('event.created', $event->created); $item->set('event.type', $event->type); //$item->set('data', $cleaned); $item->save(); } $model = $this->getModel(); $state = $model->populateState()->getState(); $this->app->set('state', $state); $paginated = $model->paginate(); $this->app->set('paginated', $paginated); /*$categories_db = (array) $this->getModel( "categories" )->getItems(); $categories = array( array( 'text' => 'All Categories', 'value' => ' ' ), array( 'text' => '- Uncategorized -', 'value' => '--' ), ); array_walk( $categories_db, function($cat) use(&$categories) { $categories []= array( 'text' => $cat->title, 'value' => (string)$cat->slug, ); } ); $this->app->set('categories', $categories ); */ /* $all_tags = array( array( 'text' => 'All Tags', 'value' => ' ' ), array( 'text' => '- Untagged -', 'value' => '--' ), ); $tags = (array) $this->getModel()->getTags(); array_walk( $tags, function($tag) use(&$all_tags) { $all_tags []= array( 'text' => $tag, 'value' => $tag ); } ); $this->app->set('all_tags', $all_tags ); */ $this->app->set('meta.title', 'Events'); $view = \Dsc\System::instance()->get('theme'); echo $view->render('Striper/Admin/Views::events/list.php'); }
/** * Assign summary template */ public function webhook() { $stripe = new StripeJs(); if ($stripe->active) { if (Tools::getIsset('token') && Configuration::get('STRIPE_WEBHOOK_TOKEN') == Tools::getValue('token')) { include $this->module->getLocalPath() . 'lib/Stripe.php'; Stripe::setApiKey(Configuration::get('STRIPE_MODE') ? Configuration::get('STRIPE_PRIVATE_KEY_LIVE') : Configuration::get('STRIPE_PRIVATE_KEY_TEST')); $event_json = Tools::jsonDecode(@Tools::file_get_contents('php://input')); if (isset($event_json->id)) { /* In case there is an issue with the event, Stripe throw an exception, just ignore it. */ try { /* To double-check and for more security, we retrieve the original event directly from Stripe */ $event = Stripe_Event::retrieve($event_json->id); /* We are only handling chargebacks, other events are ignored */ if ($event->type == 'charge.dispute.created') { $id_order = (int) Db::getInstance()->getValue('SELECT id_order FROM ' . _DB_PREFIX_ . 'stripe_transaction WHERE id_stripe_transaction = \'' . pSQL($event->id) . '\' AND `charge_back` = 0'); if ($id_order) { $order = new Order((int) $id_order); if (Validate::isLoadedObject($order)) { if (Configuration::get('STRIPE_CHARGEBACKS_ORDER_STATUS') != -1) { if ($order->getCurrentState() != Configuration::get('STRIPE_CHARGEBACKS_ORDER_STATUS')) { $order->changeIdOrderState((int) Configuration::get('STRIPE_CHARGEBACKS_ORDER_STATUS'), (int) $id_order); Db::getInstance()->getValue('UPDATE `' . _DB_PREFIX_ . 'stipe_transaction` SET `charge_back` = 1 WHERE `id_stripe_transaction` = \'' . pSQL($event->id) . '\' AND `charge_back` = 0'); } } $message = new Message(); $message->message = $stripe->l('A chargeback occured on this order and was reported by Stripe on') . ' ' . date('Y-m-d H:i:s'); $message->id_order = (int) $order->id; $message->id_employee = 1; $message->private = 1; $message->date_add = date('Y-m-d H:i:s'); $message->add(); } } } } catch (Exception $e) { header('HTTP/1.1 200 OK'); exit; } header('HTTP/1.1 200 OK'); exit; } } } header('HTTP/1.1 200 OK'); exit; }
/** * */ static function server_callback() { global $wpdb; //** Get request body */ $body = @file_get_contents('php://input'); $event_object = json_decode($body); switch ($event_object->type) { //** Used only for subscriptions since single payments processed without Webhook */ case 'charge.succeeded': $post_id = $wpdb->get_col("SELECT post_id\r\n FROM {$wpdb->postmeta}\r\n WHERE meta_key = '_stripe_customer_id'\r\n AND meta_value = '{$event_object->data->object->customer}'"); $invoice_object = new WPI_Invoice(); $invoice_object->load_invoice("id=" . $post_id[0]); if (empty($invoice_object->data['ID'])) { die("Can't load invoice"); } if (!class_exists('Stripe')) { require_once WPI_Path . '/third-party/stripe/lib/Stripe.php'; } $pk = trim($invoice_object->data['billing']['wpi_stripe']['settings'][$invoice_object->data['billing']['wpi_stripe']['settings']['mode']['value'] . '_secret_key']['value']); Stripe::setApiKey($pk); $event = Stripe_Event::retrieve($event_object->id); if ($event->data->object->paid == 1) { $event_amount = (double) ($event->data->object->amount / 100); $event_note = WPI_Functions::currency_format(abs($event_amount), $invoice_object->data['invoice_id']) . ' ' . __('Stripe Subscription Payment', WPI); $event_type = 'add_payment'; $invoice_object->add_entry("attribute=balance¬e={$event_note}&amount={$event_amount}&type={$event_type}"); $invoice_object->save_invoice(); } break; case 'customer.subscription.deleted': $post_id = $wpdb->get_col("SELECT post_id\r\n FROM {$wpdb->postmeta}\r\n WHERE meta_key = '_stripe_customer_id'\r\n AND meta_value = '{$event_object->data->object->customer}'"); $invoice_object = new WPI_Invoice(); $invoice_object->load_invoice("id=" . $post_id[0]); if (empty($invoice_object->data['ID'])) { die("Can't load invoice"); } if (!class_exists('Stripe')) { require_once WPI_Path . '/third-party/stripe/lib/Stripe.php'; } $pk = trim($invoice_object->data['billing']['wpi_stripe']['settings'][$invoice_object->data['billing']['wpi_stripe']['settings']['mode']['value'] . '_secret_key']['value']); Stripe::setApiKey($pk); $event = Stripe_Event::retrieve($event_object->id); if ($event->data->object->status == 'canceled') { $invoice_object->add_entry("attribute=invoice¬e=" . __('Stripe Subscription has been canceled', WPI) . "&type=update"); $invoice_object->save_invoice(); wp_invoice_mark_as_paid($invoice_object->data['invoice_id']); } break; default: break; } }
public function get_stripe_event($event_id) { $this->include_stripe_api(); $event = Stripe_Event::retrieve($event_id); return $event; }
include dirname(__FILE__) . '/stripejs.php'; if (!defined('_PS_VERSION_')) { exit; } /* Check that the module is active and that we have the token */ $stripe = new StripeJs(); if ($stripe->active) { if (Tools::getIsset('token') && Configuration::get('STRIPE_WEBHOOK_TOKEN') == Tools::getValue('token')) { include dirname(__FILE__) . '/lib/Stripe.php'; Stripe::setApiKey(Configuration::get('STRIPE_MODE') ? Configuration::get('STRIPE_PRIVATE_KEY_LIVE') : Configuration::get('STRIPE_PRIVATE_KEY_TEST')); $event_json = Tools::jsonDecode(@Tools::file_get_contents('php://input')); if (isset($event_json->id)) { /* In case there is an issue with the event, Stripe throw an exception, just ignore it. */ try { /* To double-check and for more security, we retrieve the original event directly from Stripe */ $event = Stripe_Event::retrieve($event_json->id); /* We are only handling chargebacks, other events are ignored */ if ($event->type == 'charge.disputed') { $id_order = (int) Db::getInstance()->getValue('SELECT id_order FROM ' . _DB_PREFIX_ . 'stripe_transaction WHERE id_stripe_transaction = \'' . pSQL($event->id) . '\' AND `charge_back` = 0'); if ($id_order) { $order = new Order((int) $id_order); if (Validate::isLoadedObject($order)) { if (Configuration::get('STRIPE_CHARGEBACKS_ORDER_STATUS') != -1) { if ($order->getCurrentState() != Configuration::get('STRIPE_CHARGEBACKS_ORDER_STATUS')) { $order->changeIdOrderState((int) Configuration::get('STRIPE_CHARGEBACKS_ORDER_STATUS'), (int) $id_order); Db::getInstance()->getValue('UPDATE `' . _DB_PREFIX_ . 'stipe_transaction` SET `charge_back` = 1 WHERE `id_stripe_transaction` = \'' . pSQL($event->id) . '\' AND `charge_back` = 0'); } } $message = new Message(); $message->message = $stripe->l('A chargeback occured on this order and was reported by Stripe on') . ' ' . date('Y-m-d H:i:s'); $message->id_order = (int) $order->id;
/** * Receives a Stripe Webhook event object instance. * * @package s2Member\Stripe * @since 140617 * * @return Stripe_Event|string Stripe event object; else error message. */ public static function get_event() { if (empty($_REQUEST['s2member_pro_stripe_notify'])) { return ''; } // Not applicable. $input = @file_get_contents('php://input'); $event = json_decode($input); $input_time = time(); // Initialize. $input_vars = array('event_id' => $event->id); require_once dirname(__FILE__) . '/stripe-sdk/lib/Stripe.php'; Stripe::setApiKey($GLOBALS['WS_PLUGIN__']['s2member']['o']['pro_stripe_api_secret_key']); try { if (!is_object($event) || empty($event->id)) { throw new exception('Missing event ID.'); } $event = Stripe_Event::retrieve($event->id); self::log_entry(__FUNCTION__, $input_time, $input_vars, time(), $event); return $event; // Stripe event object. } catch (exception $exception) { self::log_entry(__FUNCTION__, $input_time, $input_vars, time(), $exception); return self::error_message($exception); } }
/** * Stripe IPN */ private function _ipn_stripe() { // Set your secret key: remember to change this to your live secret key in production // See your keys here https://manage.stripe.com/account // Add Stripe library require_once app_path() . "/libraries/stripe-php-1.9.0/lib/Stripe.php"; // Add Stripe library Stripe::setApiKey(Config::get('project.stripe_secret_key')); // Retrieve the request's body and parse it as JSON $body = @file_get_contents('php://input'); $event_json = json_decode($body); // For extra security, retrieve from the Stripe API try { $event_id = $event_json->id; $event_json = Stripe_Event::retrieve($event_id); } catch (Exception $e) { exit($e->getMessage()); } // Do something with $event_json if (isset($event_json->type)) { // Customer and Affiliate // Get user_id $customer_id = !empty($event_json->data->object->customer) ? $event_json->data->object->customer : NULL; if ($customer_id) { try { $customer = Stripe_Customer::retrieve($customer_id); $email = $customer->email; $dkData = $customer->metadata; $buyer = Buyer::where('email', '=', $email)->first(); $affiliate_id = !empty($dkData['affiliate_id']) ? $dkData['affiliate_id'] : NULL; // $buyer->affiliate_id $first_name = !empty($dkData['first_name']) ? $dkData['first_name'] : NULL; $last_name = !empty($dkData['last_name']) ? $dkData['last_name'] : NULL; // Get Product Info $product = Product::where('id', '=', $dkData['product_id'])->first(); } catch (Exception $e) { header('HTTP/1.1 400 Bad Request', true, 400); exit("Not able to fetch customer"); } } else { // No customer ID was found, stop the process here exit('Customer was not found in object'); } // If No buyer was found if (empty($buyer)) { exit($event_json->type . ' : Buyer was not found'); } // If No product was found if (empty($product)) { exit($event_json->type . ' : Product was not found'); } // Create subscription if ($event_json->type == "customer.subscription.created") { $plan_code = $event_json->data->object->plan->id; // Remove word "_split" from it $plan_code = str_replace('_split', '', $plan_code); // Get Plan and Product $plan = Plan::where('stripe_id', '=', $plan_code)->first(); // Push IPN to product IPN URL $ipn_data = array("type" => "sales", "password" => isset($dkData['password']) ? $dkData['password'] : NULL, "plan" => $plan->code, "amount" => $plan->price, "email" => $email, "first_name" => $first_name, "last_name" => $last_name); // Add an encrypted key to the request $ipn_data['key'] = $this->_generateHash($ipn_data, $product->api_key); $this->_push_ipn($product->ipn_url, $ipn_data); } // Successful Charge if ($event_json->type == "charge.succeeded") { // Delay 10 seconds, so purchase can be added to database sleep(10); $pay_id = $event_json->data->object->id; $paid_amount = $event_json->data->object->amount / 100; // Check if Pay ID already exist if (Transaction::where('pay_id', '=', $pay_id)->first()) { echo "Transaction was already recorded."; return; } $chargeMetadata = $event_json->data->object->metadata; if (empty($chargeMetadata->plan_id)) { $plan_id = $dkData['plan_id']; } else { $plan_id = !empty($chargeMetadata->plan_id) ? $chargeMetadata->plan_id : NULL; } // Get Plan and Product $plan = Plan::where('id', '=', $plan_id)->first(); $purchase = Purchase::where('product_id', '=', $product->id)->where('buyer_id', '=', $buyer->id)->first(); if (!$purchase) { header('HTTP/1.1 400 Bad Request', true, 400); echo "Purchase was not found"; // Delete InfusionSoft Invoice //$this->_delete_infusion_invoice($invoice_id); return; } // User all transactions $user_transactions = Transaction::where('purchase_id', '=', $purchase->id)->where('plan_id', '=', $plan->id)->get(); // If Split payment installment is received if ($plan->has_split_pay) { if (count($user_transactions) + 1 >= $plan->total_installments) { // Cancel the subscription $params['stripe_customer_id'] = $customer_id; $params['plan_id'] = $plan->stripe_id . '_split'; Log::info('Stripe Split Not Cancelled', array('product' => $product->code, 'plan' => $plan->code)); $this->_cancelSubscription('Stripe', $params); } } // Add payment in InfusionSoft if ($invoice_id = $this->_infusion_sales($product, $plan, $email, $first_name, $last_name, $affiliate_id, $paid_amount)) { if (!$buyer->last_used_ip) { $buyer = Buyer::where('id', '=', $buyer->id)->first(); } // Record Sales Transaction $transaction = new Transaction(); $transaction->purchase_id = $purchase->id; $transaction->plan_id = $plan->id; $transaction->amount = $paid_amount; //$plan->price; $transaction->invoice_id = $invoice_id; $transaction->pay_id = $pay_id; $transaction->pay_data = ''; //json_encode($event_json); $transaction->buyer_ip = $buyer->last_used_ip; $transaction->save(); // Do not generate license key if this is recurring charge $license_key = NULL; if (count($user_transactions) + 1 === 1) { // Generate and Save License Key $license_key = $this->_generate_license($product, $plan, $transaction->id); } // Email Receipt $this->_send_email_receipt($product->name, $plan->name, $email, $pay_id, $paid_amount, $license_key); } // Push IPN to product IPN URL $ipn_data = array("type" => "sales", "password" => isset($dkData['password']) ? $dkData['password'] : NULL, "plan" => $plan->code, "pay_id" => $event_json->data->object->id, "amount" => $plan->price, "email" => $email, "first_name" => $first_name, "last_name" => $last_name); // Add an encrypted key to the request $ipn_data['key'] = $this->_generateHash($ipn_data, $product->api_key); $this->_push_ipn($product->ipn_url, $ipn_data); } // Update subscription if ($event_json->type == "customer.subscription.updated") { // $event_json->data->object->cancel_at_period_end $stripe_plan_code = $event_json->data->object->plan->id; // Remove word "_split" from it $stripe_plan_code = str_replace('_split', '', $stripe_plan_code); $plan = Plan::where('stripe_id', '=', $stripe_plan_code)->first(); // Update Customer Metadata in Stripe try { $metadata = $customer->metadata; $metadata['plan_id'] = $plan->id; $customer->metadata = $metadata; $customer->save(); } catch (Exception $e) { header('HTTP/1.1 400 Bad Request', true, 400); echo "Customer was not update"; return; } // Push to IPN $ipn_data = array("type" => "sub-update", "plan" => $plan->code, "email" => $buyer->email); // Add an encrypted key to the request $ipn_data['key'] = $this->_generateHash($ipn_data, $product->api_key); $this->_push_ipn($product->ipn_url, $ipn_data); } // Delete Subscription if ($event_json->type == "customer.subscription.deleted") { $stripe_plan_code = $event_json->data->object->plan->id; // Remove word "_split" from it $stripe_plan_code = str_replace('_split', '', $stripe_plan_code); $plan = Plan::where('stripe_id', '=', $stripe_plan_code)->first(); // If Split payment installment is received if ($plan->has_split_pay) { $purchase = Purchase::where('product_id', '=', $product->id)->where('buyer_id', '=', $buyer->id)->first(); $total_paid_installments = Transaction::where('purchase_id', '=', $purchase->id)->where('plan_id', '=', $plan->id)->get(); if (count($total_paid_installments) >= $plan->total_installments) { // Do not push IPN, its fine user has paid all installments Log::info('Stripe Split Cancelled', array('product' => $product->code, 'plan' => $plan->code)); return; } } // Push to IPN $ipn_data = array("type" => "sub-cancel", "plan" => $plan->code, "email" => $buyer->email); // Add an encrypted key to the request $ipn_data['key'] = $this->_generateHash($ipn_data, $product->api_key); $this->_push_ipn($product->ipn_url, $ipn_data); } // Charge Failed if ($event_json->type == "charge.failed") { // Charge failed, ask customer to update card via email // @TODO: Ask Mark to enable some tries after failure } // Charge refunded if ($event_json->type == "charge.refunded") { // Check if transaction has not been refunded from UI, then go ahead // Else stop process $pay_id = $event_json->data->object->id; $transaction = Transaction::where('pay_id', '=', $pay_id)->first(); if ($transaction->is_refunded) { return; } // Push to IPN $ipn_data = array("type" => "refund", "plan" => $transaction->plan->code, "email" => $buyer->email); // Add an encrypted key to the request $ipn_data['key'] = $this->_generateHash($ipn_data, $product->api_key); $this->_push_ipn($product->ipn_url, $ipn_data); } if (isset($error)) { header('HTTP/1.1 400 Bad Request', true, 400); echo "Unsuccessful event"; return; } } }
require_once '../civicrm.config.php'; require_once 'CRM/Core/Config.php'; $config =& CRM_Core_Config::singleton(); //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();
/** * Listen for Stripe events, primarily recurring payments * * @access public * @since 1.5 * @return void */ function edds_stripe_event_listener() { if (!class_exists('EDD_Recurring')) { return; } if (isset($_GET['edd-listener']) && $_GET['edd-listener'] == 'stripe') { global $edd_options; if (!class_exists('Stripe')) { require_once EDDS_PLUGIN_DIR . '/Stripe/Stripe.php'; } $secret_key = edd_is_test_mode() ? trim($edd_options['test_secret_key']) : trim($edd_options['live_secret_key']); Stripe::setApiKey($secret_key); // retrieve the request's body and parse it as JSON $body = @file_get_contents('php://input'); $event_json = json_decode($body); // for extra security, retrieve from the Stripe API $event_id = $event_json->id; if (isset($event_json->id)) { status_header(200); $event = Stripe_Event::retrieve($event_json->id); $invoice = $event->data->object; switch ($event->type) { case 'invoice.payment_succeeded': // Process a subscription payment // retrieve the customer who made this payment (only for subscriptions) $user_id = EDD_Recurring_Customer::get_user_id_by_customer_id($invoice->customer); // retrieve the customer ID from WP database $customer_id = EDD_Recurring_Customer::get_customer_id($user_id); // check to confirm this is a stripe subscriber if ($user_id && $customer_id) { $cu = Stripe_Customer::retrieve($customer_id); // Get all subscriptions of this customer $plans = $cu->subscriptions->data; $subscriptions = wp_list_pluck($plans, 'plan'); $subscription_ids = !empty($subscriptions) ? wp_list_pluck($subscriptions, 'id') : array(); // Make sure this charge is for the user's subscription if (!empty($subscription_ids) && !in_array($invoice->lines->data[0]->plan->id, $subscription_ids)) { die('-3'); } // Retrieve the original payment details $parent_payment_id = EDD_Recurring_Customer::get_customer_payment_id($user_id); if (false !== get_transient('_edd_recurring_payment_' . $parent_payment_id)) { die('2'); // This is the initial payment } try { // Store the payment EDD_Recurring()->record_subscription_payment($parent_payment_id, $invoice->total / 100, $invoice->charge); // Set the customer's status to active EDD_Recurring_Customer::set_customer_status($user_id, 'active'); // Calculate the customer's new expiration date $new_expiration = EDD_Recurring_Customer::calc_user_expiration($user_id, $parent_payment_id); // Set the customer's new expiration date EDD_Recurring_Customer::set_customer_expiration($user_id, $new_expiration); } catch (Exception $e) { die('3'); // Something not as expected } } break; case 'customer.subscription.deleted': // Process a cancellation // retrieve the customer who made this payment (only for subscriptions) $user_id = EDD_Recurring_Customer::get_user_id_by_customer_id($invoice->customer); $parent_payment_id = EDD_Recurring_Customer::get_customer_payment_id($user_id); // Set the customer's status to active EDD_Recurring_Customer::set_customer_status($user_id, 'cancelled'); edd_update_payment_status($parent_payment_id, 'cancelled'); break; } do_action('edds_stripe_event_' . $event->type, $event); die('1'); // Completed successfully } else { status_header(500); die('-1'); // Failed } die('-2'); // Failed } }
/** * Get a stripe event object * @param string $event_id * @return Stripe_Event|false */ public function getEvent($event_id = '') { try { return Stripe_Event::retrieve($event_id, $this->access_token); } catch (Exception $ex) { $this->log($ex); return false; } }
public function external_hook($hook) { switch ($hook) { case 'event_ipn': require_once 'includes/plugin_paymethod_stripe/stripe-php/lib/Stripe.php'; $stripe = array("secret_key" => module_config::c('payment_method_stripe_secret_key'), "publishable_key" => module_config::c('payment_method_stripe_publishable_key')); Stripe::setApiKey($stripe['secret_key']); $body = @file_get_contents('php://input'); $event_json = json_decode($body); ob_start(); // echo "INPUT: <br>\n"; // print_r($body); // echo "<br><br>\n"; echo "UCM STRIPE DEBUG:<br><br>JSON: <br>\n"; print_r($event_json); echo "<br><br>\n"; $event_id = $event_json->id; try { $event = Stripe_Event::retrieve($event_id); // This will send receipts on succesful invoices if ($event->type == 'charge.succeeded' && $event->data->object->invoice) { $paid_amount = $event->data->object->amount / 100; // get the invoice. $invoice = Stripe_Invoice::retrieve($event->data->object->invoice); echo "INVOICE: <br>\n"; print_r($invoice); echo "<br><br>\n"; if ($invoice && $invoice->subscription && $invoice->paid) { // this payment was for a subscription! which one though? $customer = Stripe_Customer::retrieve($invoice->customer); echo "CUSTOMER: <br>\n"; print_r($customer); echo "<br><br>\n"; $subscription = $customer->subscriptions->retrieve($invoice->subscription); echo "SUBSCRIPTION: <br>\n"; print_r($subscription); echo "<br><br>\n"; // now we have the Customer and Subscription we can look through our invoice_payment_subscription table for those values. /*update_insert('invoice_payment_subscription_id',$invoice_payment_subscription_id,'invoice_payment_subscription',array( 'status' => _INVOICE_SUBSCRIPTION_ACTIVE, 'date_start' => date('Y-m-d'), // we also have to store the stripe details here so we can easily search for them later on. 'stripe_customer' => $stripe_customer->id, 'stripe_subscription' => $stripe_subscription->id, ));*/ $invoice_payment_subscription = get_single('invoice_payment_subscription', array('stripe_customer', 'stripe_subscription'), array($customer->id, $subscription->id)); if ($invoice_payment_subscription) { // FIND THE linked invoice_payment for this original invoice payment subscription, this allows us to perform the same creatE_new_invoice as paypal below: $invoice_payment_subscription_id = $invoice_payment_subscription['invoice_payment_subscription_id']; $invoice_payment = get_single('invoice_payment', 'invoice_payment_subscription_id', $invoice_payment_subscription_id); if ($invoice_payment) { $payment_id = $invoice_payment['invoice_payment_id']; $invoice_id = $invoice_payment['invoice_id']; // we have a subscription payment. woo! // this gets a bit tricky, we have to work out if the invoice has been generated for this subscription yet. // if this invoice hasn't been generated yet then we have to generate it. // pass this back to the invoice class so we can reuse this feature in the future. $data = module_invoice::create_new_invoice_for_subscription_payment($invoice_id, $payment_id, $invoice_payment_subscription_id); if ($data && $data['invoice_id'] && $data['invoice_payment_id']) { $next_time = time(); $next_time = strtotime('+' . abs((int) $invoice_payment_subscription['days']) . ' days', $next_time); $next_time = strtotime('+' . abs((int) $invoice_payment_subscription['months']) . ' months', $next_time); $next_time = strtotime('+' . abs((int) $invoice_payment_subscription['years']) . ' years', $next_time); update_insert('invoice_payment_subscription_id', $invoice_payment_subscription_id, 'invoice_payment_subscription', array('date_last_pay' => date('Y-m-d'), 'date_next' => date('Y-m-d', $next_time))); update_insert("invoice_payment_id", $data['invoice_payment_id'], "invoice_payment", array('date_paid' => date('Y-m-d'), 'amount' => $paid_amount, 'method' => 'Stripe (Subscription)', 'invoice_payment_subscription_id' => $invoice_payment_subscription_id)); module_paymethod_stripe::add_payment_data($data['invoice_payment_id'], 'log', "Payment Received via Webhook: " . var_export(array('event.type' => $event->type, 'invoice.id' => $invoice->id, 'subscription.id' => $subscription->id, 'customer.id' => $customer->id, '$invoice_payment_subscription_id' => $invoice_payment_subscription_id, '$invoice_payment_id' => $payment_id), true)); module_invoice::save_invoice($data['invoice_id'], array()); echo "Successful Subscription Payment For Invoice " . $data['invoice_id']; } else { send_error("Stripe Webhook Subscription Error (failed to generate new invoice!) " . var_export($data, true)); } } else { echo 'Failed to find matching invoice payment in db'; } } else { echo 'Failed to find matching subscription payment in db'; } } } } catch (Exception $e) { $body = $e->getJsonBody(); $err = $body['error']; $error = "Sorry: Webhook failed. <br><br>\n\n"; $error .= $err['message']; $error .= "\n\n\n" . var_export($e, true); echo $error; } $debug = ob_get_clean(); //mail('*****@*****.**','Stripe Webhook debug',$debug); if (module_config::c('stripe_payment_debug', 0)) { echo $debug; } echo "Thanks! (set stripe_payment_debug to 1 in UCM to see more data here)"; exit; break; case 'pay_subscription': $invoice_id = isset($_REQUEST['invoice_id']) ? $_REQUEST['invoice_id'] : false; $invoice_payment_id = isset($_REQUEST['invoice_payment_id']) ? $_REQUEST['invoice_payment_id'] : false; $invoice_payment_subscription_id = isset($_REQUEST['invoice_payment_subscription_id']) ? $_REQUEST['invoice_payment_subscription_id'] : false; $stripe_plan_id = isset($_REQUEST['stripe_plan_id']) ? $_REQUEST['stripe_plan_id'] : false; $user_id = isset($_REQUEST['user_id']) ? $_REQUEST['user_id'] : false; if ($invoice_id && $invoice_payment_id && $stripe_plan_id && $invoice_payment_subscription_id && $user_id && isset($_POST['stripeToken'])) { $user_data = module_user::get_user($user_id); $email = isset($_REQUEST['stripeEmail']) && strlen($_REQUEST['stripeEmail']) ? $_REQUEST['stripeEmail'] : $user_data['email']; if (!$email || !strpos($email, '@')) { die('Please ensure your user account has a valid email address before paying with stripe'); } $invoice_payment = get_single('invoice_payment', 'invoice_payment_id', $invoice_payment_id); $invoice_payment_subscription = get_single('invoice_payment_subscription', 'invoice_payment_subscription_id', $invoice_payment_subscription_id); if (!$invoice_payment || !$invoice_payment_subscription || $invoice_payment['invoice_id'] != $invoice_id || $invoice_payment['invoice_payment_subscription_id'] != $invoice_payment_subscription_id) { die('Invalid invoice payment subscription id'); } $invoice_payment_data = module_invoice::get_invoice_payment($invoice_payment_id); $invoice_data = module_invoice::get_invoice($invoice_id); if ($invoice_payment_data && $invoice_data && $invoice_id == $invoice_data['invoice_id'] && $invoice_payment_data['invoice_id'] == $invoice_data['invoice_id']) { $currency = module_config::get_currency($invoice_payment_data['currency_id']); $currency_code = $currency['code']; $description = isset($_REQUEST['description']) ? $_REQUEST['description'] : 'N/A'; $template = new module_template(); ob_start(); require_once 'includes/plugin_paymethod_stripe/stripe-php/lib/Stripe.php'; $stripe = array("secret_key" => module_config::c('payment_method_stripe_secret_key'), "publishable_key" => module_config::c('payment_method_stripe_publishable_key')); Stripe::setApiKey($stripe['secret_key']); try { // todo- search for existing customer based on email address??? // todo: check if adding new plan to existing customer work?? $stripe_customer = Stripe_Customer::create(array("card" => $_POST['stripeToken'], "email" => $email, 'metadata' => array('user_id' => $user_id))); if ($stripe_customer && $stripe_customer->id) { //} && $stripe_customer->subscriptions){ $stripe_subscription = $stripe_customer->subscriptions->create(array('plan' => $stripe_plan_id)); if ($stripe_subscription && $stripe_subscription->id) { update_insert('invoice_payment_subscription_id', $invoice_payment_subscription_id, 'invoice_payment_subscription', array('status' => _INVOICE_SUBSCRIPTION_ACTIVE, 'date_start' => date('Y-m-d'), 'stripe_customer' => $stripe_customer->id, 'stripe_subscription' => $stripe_subscription->id)); module_paymethod_stripe::add_payment_data($invoice_payment_id, 'log', "Started Stripe Subscription: " . var_export(array('customer.id' => $stripe_customer->id, 'plan.id' => $stripe_plan_id, 'subscription.id' => $stripe_subscription->id), true)); // success! // redirect to receipt page. redirect_browser(module_invoice::link_public_payment_complete($invoice_id)); } else { echo 'Failed to create subscription with stripe'; } } $error = "Something went wrong during stripe payment. Please confirm invoice payment went through: " . htmlspecialchars($description); send_error($error); echo $error; } catch (Stripe_CardError $e) { // The card has been declined $body = $e->getJsonBody(); $err = $body['error']; $error = "Sorry: Payment failed. <br><br>\n\n" . htmlspecialchars($description) . ". <br><br>\n\n"; $error .= $err['message']; echo $error; $error .= "\n\n\n" . var_export($err, true); send_error($error); } catch (Exception $e) { $body = $e->getJsonBody(); $err = $body['error']; $error = "Sorry: Payment failed. <br><br>\n\n" . htmlspecialchars($description) . ". <br><br>\n\n"; $error .= $err['message']; echo $error; $error .= "\n\n\n" . var_export($err, true); send_error($error); } $template->content = ob_get_clean(); echo $template->render('pretty_html'); exit; } } echo 'Error paying via Stripe'; exit; case 'pay': $invoice_id = isset($_REQUEST['invoice_id']) ? $_REQUEST['invoice_id'] : false; $invoice_payment_id = isset($_REQUEST['invoice_payment_id']) ? $_REQUEST['invoice_payment_id'] : false; if ($invoice_id && $invoice_payment_id && isset($_POST['stripeToken'])) { $invoice_payment_data = module_invoice::get_invoice_payment($invoice_payment_id); $invoice_data = module_invoice::get_invoice($invoice_id); if ($invoice_payment_data && $invoice_data && $invoice_id == $invoice_data['invoice_id'] && $invoice_payment_data['invoice_id'] == $invoice_data['invoice_id']) { $currency = module_config::get_currency($invoice_payment_data['currency_id']); $currency_code = $currency['code']; $description = _l('Payment for invoice %s', $invoice_data['name']); $template = new module_template(); ob_start(); include module_theme::include_ucm('includes/plugin_paymethod_stripe/pages/stripe_form.php'); $template->content = ob_get_clean(); echo $template->render('pretty_html'); exit; } } echo 'Error paying via Stripe'; exit; } }
/** * Process callback * * @param \XLite\Model\Payment\Transaction $transaction Callback-owner transaction * * @return void */ public function processCallback(\XLite\Model\Payment\Transaction $transaction) { parent::processCallback($transaction); $this->includeStripeLibrary(); try { $event = \Stripe_Event::retrieve($this->eventId); if ($event) { $name = 'processEvent' . \XLite\Core\Converter::convertToCamelCase(str_replace('.', '_', $event->type)); if (method_exists($this, $name)) { // $name assembled from 'processEvent' + event type $this->{$name}($event); \XLite\Core\Database::getEM()->flush(); } \XLite\Logger::getInstance()->logCustom('stripe', 'Event handled: ' . $event->type . ' # ' . $this->eventId . PHP_EOL . 'Processed: ' . (method_exists($this, $name) ? 'Yes' : 'No')); } } catch (\Exception $e) { } }
// retrieve the request's body and parse it as JSON if (empty($_REQUEST['event_id'])) { $body = @file_get_contents('php://input'); $post_event = json_decode($body); //get the id if (!empty($post_event)) { $event_id = $post_event->id; } } else { $event_id = $_REQUEST['event_id']; } //get the event through the API now if (!empty($event_id)) { try { global $pmpro_stripe_event; $pmpro_stripe_event = Stripe_Event::retrieve($event_id); } catch (Exception $e) { $logstr .= "Could not find an event with ID #" . $event_id . ". " . $e->getMessage(); pmpro_stripeWebhookExit(); //$pmpro_stripe_event = $post_event; //for testing you may want to assume that the passed in event is legit } } global $wpdb; //real event? if (!empty($pmpro_stripe_event->id)) { //check what kind of event it is if ($pmpro_stripe_event->type == "charge.succeeded") { //do we have this order yet? (check status too) $order = getOrderFromInvoiceEvent($pmpro_stripe_event); //no? create it if (empty($order->id)) {
Stripe::setApiKey(pmpro_getOption("stripe_secretkey")); // retrieve the request's body and parse it as JSON if (empty($_REQUEST['event_id'])) { $body = @file_get_contents('php://input'); $post_event = json_decode($body); //get the id if (!empty($post_event)) { $event_id = $post_event->id; } } else { $event_id = $_REQUEST['event_id']; } //get the event through the API now if (!empty($event_id)) { try { $event = Stripe_Event::retrieve($event_id); } catch (Exception $e) { $logstr .= "Could not find an event with ID #" . $event_id . ". " . $e->getMessage(); pmpro_stripeWebhookExit(); //$event = $post_event; //for testing you may want to assume that the passed in event is legit } } global $wpdb; //real event? if (!empty($event->id)) { //check what kind of event it is if ($event->type == "charge.succeeded") { //do we have this order yet? (check status too) $order = getOrderFromInvoiceEvent($event); //no? create it if (empty($order->id)) {
public function sync($data = array()) { $this->wlm->SyncMembership(); $obj = json_decode(file_get_contents('php://input')); $id = null; $action = null; Stripe::setApiKey($this->wlm->GetOption('stripeapikey')); //Request for the stripe event object to //make sure this is a legit stripe notification $obj = Stripe_Event::retrieve($obj->id); switch ($obj->type) { // do not handler creates anymore // case 'customer.subscription.created': // $cust_id = $obj->data->object->customer; // $plan_id = $obj->data->object->plan->id; // $id = $cust_id . "-" . $plan_id; // $action = 'move'; // break; case 'customer.subscription.deleted': $cust_id = $obj->data->object->customer; $plan_id = $obj->data->object->plan->id; $id = $cust_id . "-" . $plan_id; $action = 'deactivate'; break; case 'customer.subscription.updated': $cust_id = $obj->data->object->customer; $plan_id = $obj->data->object->plan->id; $id = $cust_id . "-" . $plan_id; switch ($obj->data->object->status) { case 'trialing': case 'past_due': $action = 'reactivate'; break; case 'active': $action = 'reactivate'; if (!empty($obj->data->previous_attributes->plan->id)) { //we are changing subscriptions $prev_id = sprintf("%s-%s", $cust_id, $obj->data->previous_attributes->plan->id); $action = 'move'; } break; case 'unpaid': case 'cancelled': default: $action = 'deactivate'; break; } //This is an active subscription //reactivate? No need break; case 'invoice.payment_failed': //no need, we'll also be able to catch this under charge_failed break; case 'customer.deleted': $cust_id = $obj->data->object->id; $user_id = $this->wlm->Get_UserID_From_UserMeta('stripe_cust_id', $cust_id); $levels = $this->wlm->GetMembershipLevels($user_id, null, true, null, true); if (empty($levels)) { return; } $id = $this->wlm->GetMembershipLevelsTxnID($user_id, $levels[0]); $action = 'deactivate'; break; case 'charge.refunded': $id = $obj->data->object->id; $action = 'deactivate'; break; case 'charge.failed': // no need to handle as failed charges are handled // in the merchant site // $cust_id = $obj->data->object->customer; // $customer = Stripe_Customer::retrieve($cust_id); // if (empty($customer->plan)) { // return; // } // $id = sprintf("%s-%s", $cust_id, $customer->plan->id); // $action = 'deactivate'; // break; } $_POST['sctxnid'] = $id; switch ($action) { case 'deactivate': echo 'info(deact): deactivating subscription: ' . $id; $_POST['sctxnid'] = $id; $this->wlm->ShoppingCartDeactivate(); break; case 'reactivate': echo 'info(react): reactivating subscription: ' . $id; $_POST['sctxnid'] = $id; $_POST['sc_type'] = 'Stripe'; do_action('wlm_shoppingcart_rebill', $_POST); $this->wlm->ShoppingCartReactivate(); break; case 'move': //activate the new one $connections = $this->wlm->GetOption('stripeconnections'); //get the correct level $wpm_level = $this->stripe_plan_id_to_sku($connections, $obj->data->object->plan->id); $prev_wpm_level = $this->stripe_plan_id_to_sku($connections, $obj->data->previous_attributes->plan->id); //get the correct user $user_id = $this->wlm->Get_UserID_From_UserMeta('stripe_cust_id', $cust_id); if (!empty($wpm_level) && !empty($user_id)) { //remove from previous level $current_levels = $this->wlm->GetMembershipLevels($user_id, null, null, true); $levels = array_diff($current_levels, array($prev_wpm_level)); echo 'removing from ' . $prev_wpm_level; $this->wlm->SetMembershipLevels($user_id, $levels); echo "info(move): moving user:{$user_id} to new subscription:{$wpm_level} with tid:{$id}"; $this->add_to_level($user_id, $wpm_level, $id); } break; } echo "\n"; }