// ============================================================================ // STRIPE INTEGRATION CLASS // ============================================================================ require_once 'vendor/autoload.php'; // Composer autoload for Stripe class StripeManager { private $stripe; private $db; public function __construct() { $this->db = Database::getInstance(); // Get Stripe keys from system settings $secretKey = $this->getSystemSetting('stripe_secret_key'); \Stripe\Stripe::setApiKey($secretKey); $this->stripe = new \Stripe\StripeClient($secretKey); } public function createCustomer($companyId, $email, $name) { try { $customer = $this->stripe->customers->create([ 'email' => $email, 'name' => $name, 'metadata' => [ 'company_id' => $companyId, 'platform' => 'thryve' ] ]); // Store in database $this->db->insert('stripe_customers', [ 'company_id' => $companyId, 'stripe_customer_id' => $customer->id, 'email' => $email ]); return $customer; } catch (Exception $e) { error_log("Stripe customer creation failed: " . $e->getMessage()); return false; } } public function createSubscription($companyId, $customerId, $planName, $quantity = 1, $currency = 'CAD') { try { $plan = Config::PLANS[$planName]; $amount = Config::getPriceInCurrency($planName, $currency) * 100; // Convert to cents // Create price object $price = $this->stripe->prices->create([ 'unit_amount' => $amount, 'currency' => strtolower($currency), 'recurring' => ['interval' => 'month'], 'product_data' => [ 'name' => "Thryve {$plan['name']} Plan", 'metadata' => ['plan' => $planName] ] ]); // Create subscription $subscription = $this->stripe->subscriptions->create([ 'customer' => $customerId, 'items' => [['price' => $price->id, 'quantity' => $quantity]], 'trial_period_days' => $this->getSystemSetting('default_trial_days', 14), 'metadata' => [ 'company_id' => $companyId, 'plan_name' => $planName ] ]); // Store in database $this->db->insert('subscriptions', [ 'company_id' => $companyId, 'stripe_subscription_id' => $subscription->id, 'stripe_customer_id' => $customerId, 'plan_name' => $planName, 'status' => $subscription->status, 'current_period_start' => date('Y-m-d H:i:s', $subscription->current_period_start), 'current_period_end' => date('Y-m-d H:i:s', $subscription->current_period_end), 'trial_end' => $subscription->trial_end ? date('Y-m-d H:i:s', $subscription->trial_end) : null, 'currency' => $currency, 'amount' => $amount / 100, 'quantity' => $quantity ]); return $subscription; } catch (Exception $e) { error_log("Stripe subscription creation failed: " . $e->getMessage()); return false; } } public function cancelSubscription($subscriptionId, $atPeriodEnd = true) { try { $subscription = $this->stripe->subscriptions->update($subscriptionId, [ 'cancel_at_period_end' => $atPeriodEnd ]); if (!$atPeriodEnd) { $subscription = $this->stripe->subscriptions->cancel($subscriptionId); } // Update database $this->db->update('subscriptions', [ 'status' => $subscription->status, 'cancel_at_period_end' => $atPeriodEnd ], 'stripe_subscription_id = ?', [$subscriptionId]); return $subscription; } catch (Exception $e) { error_log("Stripe subscription cancellation failed: " . $e->getMessage()); return false; } } public function updateSubscription($subscriptionId, $newPlanName, $quantity = null) { try { $subscription = $this->stripe->subscriptions->retrieve($subscriptionId); $subscriptionItem = $subscription->items->data[0]; $plan = Config::PLANS[$newPlanName]; $currency = $this->db->fetchOne( "SELECT currency FROM subscriptions WHERE stripe_subscription_id = ?", [$subscriptionId] )['currency']; $amount = Config::getPriceInCurrency($newPlanName, $currency) * 100; // Create new price $price = $this->stripe->prices->create([ 'unit_amount' => $amount, 'currency' => strtolower($currency), 'recurring' => ['interval' => 'month'], 'product_data' => [ 'name' => "Thryve {$plan['name']} Plan", 'metadata' => ['plan' => $newPlanName] ] ]); // Update subscription $updatedSubscription = $this->stripe->subscriptions->update($subscriptionId, [ 'items' => [[ 'id' => $subscriptionItem->id, 'price' => $price->id, 'quantity' => $quantity ?: $subscriptionItem->quantity ]], 'proration_behavior' => 'create_prorations' ]); // Update database $this->db->update('subscriptions', [ 'plan_name' => $newPlanName, 'amount' => $amount / 100, 'quantity' => $quantity ?: $subscriptionItem->quantity ], 'stripe_subscription_id = ?', [$subscriptionId]); return $updatedSubscription; } catch (Exception $e) { error_log("Stripe subscription update failed: " . $e->getMessage()); return false; } } public function getCustomerPaymentMethods($customerId) { try { return $this->stripe->paymentMethods->all([ 'customer' => $customerId, 'type' => 'card' ]); } catch (Exception $e) { error_log("Failed to retrieve payment methods: " . $e->getMessage()); return false; } } public function handleWebhook($payload, $signature) { try { $event = \Stripe\Webhook::constructEvent( $payload, $signature, $this->getSystemSetting('stripe_webhook_secret') ); switch ($event->type) { case 'invoice.payment_succeeded': $this->handleInvoicePaymentSucceeded($event->data->object); break; case 'invoice.payment_failed': $this->handleInvoicePaymentFailed($event->data->object); break; case 'customer.subscription.updated': $this->handleSubscriptionUpdated($event->data->object); break; case 'customer.subscription.deleted': $this->handleSubscriptionDeleted($event->data->object); break; } return true; } catch (Exception $e) { error_log("Webhook handling failed: " . $e->getMessage()); return false; } } private function handleInvoicePaymentSucceeded($invoice) { $this->db->insert('invoices', [ 'company_id' => $this->getCompanyIdFromCustomer($invoice->customer), 'stripe_invoice_id' => $invoice->id, 'stripe_subscription_id' => $invoice->subscription, 'amount_paid' => $invoice->amount_paid / 100, 'amount_due' => $invoice->amount_due / 100, 'currency' => strtoupper($invoice->currency), 'status' => $invoice->status, 'invoice_pdf' => $invoice->invoice_pdf, 'hosted_invoice_url' => $invoice->hosted_invoice_url, 'invoice_date' => date('Y-m-d H:i:s', $invoice->created), 'due_date' => $invoice->due_date ? date('Y-m-d H:i:s', $invoice->due_date) : null, 'paid_at' => date('Y-m-d H:i:s', $invoice->status_transitions->paid_at) ]); } private function getCompanyIdFromCustomer($customerId) { $result = $this->db->fetchOne( "SELECT company_id FROM stripe_customers WHERE stripe_customer_id = ?", [$customerId] ); return $result ? $result['company_id'] : null; } private function getSystemSetting($key, $default = null) { $result = $this->db->fetchOne( "SELECT setting_value FROM system_settings WHERE setting_key = ?", [$key] ); return $result ? $result['setting_value'] : $default; } }