stripe = \Stripe\Stripe::setApiKey(@$credential->perameter_3); $this->customerService = $customerService; } public function webhook() { // This is your Stripe CLI webhook secret for testing your endpoint locally. //$endpoint_secret = 'whsec_Gyr6d2lzXXF3goYZVyNyxPWg4ZumlPrb'; // live .app $endpoint_secret = 'whsec_3EeUyDnEVgmUGLL4wqxXGh6Hp74sqeDz'; // live .com //$endpoint_secret = 'whsec_8713fc6dfb985a0a56eaa2dce9fa5e836b2480189f49865431a0fd529a6a7087'; // testing $payload = @file_get_contents('php://input'); $sig_header = $_SERVER['HTTP_STRIPE_SIGNATURE']; $event = null; try { $event = \Stripe\Webhook::constructEvent( $payload, $sig_header, $endpoint_secret ); } catch(\UnexpectedValueException $e) { // Invalid payload http_response_code(400); exit(); } catch(\Stripe\Exception\SignatureVerificationException $e) { // Invalid signature http_response_code(400); exit(); } $response = $event->data->object; \Log::debug(json_encode($response)); if($event->type == 'charge.captured' && $response['status'] == 'succeeded' && $response['captured'] == true){ $this->updateCustomerSubscription('active','succeeded', true, $response, $event->type); } else if($event->type == 'charge.expired'){ $this->updateCustomerSubscription('expired','expired', false, $response, $event->type); } else if($event->type == 'charge.failed'){ $this->updateCustomerSubscription('inactive','failed', false, $response, $event->type); } else if($event->type == 'charge.refunded'){ $this->updateCustomerSubscription('inactive','refunded', false, $response, $event->type); } else if($event->type == 'charge.succeeded' && $response['status'] == 'succeeded' && $response['captured'] == true){ $this->updateCustomerSubscription('active','succeeded', true, $response, $event->type); } else if($event->type == 'customer.subscription.deleted'){ $this->updateCustomerSubscription('cancelled', 'cancelled', false, $response, $event->type); } else if($event->type == 'customer.subscription.paused'){ $this->updateCustomerSubscription('paused','paused', false, $response, $event->type); } else if($event->type == 'customer.subscription.resumed'){ $this->updateCustomerSubscription('active','succeeded', true, $response, $event->type); } else if($event->type == 'customer.subscription.updated'){ if($response['status'] != 'trialing'){ $status = $response['status']; $payment_status = $status == 'active' ? 'succeeded' : 'failed'; $paid = $status == 'active' ? true : false; $this->updateCustomerSubscription($status, $payment_status, $paid, $response, $event->type); } } else if($event->type == 'invoice.paid'){ $this->updateCustomerSubscription('active','succeeded', true, $response, $event->type); } else if($event->type == 'invoice.payment_failed'){ $this->updateCustomerSubscription('inactive','failed', false, $response, $event->type); } else if($event->type == 'checkout.session.completed') { if($response->mode == 'setup'){ $checkout_session = \Stripe\Checkout\Session::retrieve([ 'id' => $response->id ]); //lets retrieve setup intent $setup_intent = \Stripe\SetupIntent::retrieve([ 'id' => $checkout_session['setup_intent'] ]); $planPrice = SubscriptionPlanPrice::where('stripe_price_id',$setup_intent['metadata']['subscription_plan_price_id'])->first(); if($planPrice){ //lets create the customer $customer = \Stripe\Customer::create([ 'name' => $setup_intent['metadata']['user_name'], 'email' => $setup_intent['metadata']['user_email'], 'payment_method' => $setup_intent['payment_method'], 'invoice_settings' => [ 'default_payment_method' => $setup_intent['payment_method'] ] ]); $customer_id = $setup_intent['metadata']['user_id']; $subscriptionData = [ 'customer' => $customer['id'], 'items' => [ [ 'price_data' => [ 'unit_amount_decimal' => $planPrice->payment == 'monthly' ? round(($planPrice->price / $planPrice->custom_interval) * 100,2) : round($planPrice->price * 100,2), 'currency' => 'usd', 'product' => $planPrice->plan->stripe_product_id, 'recurring' => [ 'interval' => $planPrice->payment == 'monthly' ? 'month' : 'year' ], ] ], ], //'cancel_at' => Carbon::now()->addMonths($planPrice->custom_interval)->addDays($planPrice->trial_period > 0 ? $planPrice->trial_duration : 7)->timestamp, 'trial_period_days' => $planPrice->trial_period > 0 ? $planPrice->trial_duration : 7 ]; if(isset($setup_intent['metadata']['coupon_id'])){ $subscriptionData['coupon'] = $setup_intent['metadata']['coupon_id']; } $prorate_discount = (float)$setup_intent['metadata']['prorate_discount']; if($prorate_discount > 0){ //lets create coupon for the prorate discount $response = \Stripe\Coupon::create([ 'amount_off' => $prorate_discount * 100, 'currency' => getCurrencyCode(), 'name' => 'Prorated Discount', 'applies_to' => [ 'products' => [$planPrice->plan->stripe_product_id] ], 'max_redemptions' => 1, ]); $coupon = new SubscriptionCoupon(); $coupon->fill([ 'subscription_plan_price_id' => $planPrice->id, 'stripe_coupon_id' => $response['id'], 'name' => $response['name'], 'code' => $response['id'], 'type' => 'Amount', 'applied_to' => 'subscription', 'payment_mode' => 'Monthly', 'discount' => $prorate_discount, 'duration' => 'Once', 'max_redemptions' => 1, 'active' => 1 ]); $coupon->save(); $subscriptionData['coupon'] = $response['id']; } $subscription = \Stripe\Subscription::create($subscriptionData); if(isset($subscription['id'])){ $customer_subscription = new CustomerSubscription(); $customer_subscription->customer_id = $customer_id; $customer_subscription->txn_id = $subscription['id']; $customer_subscription->subscription_plan_price_id = $planPrice->id; $customer_subscription->payment_mode = $planPrice->payment == 'monthly' ? 'Monthly' :'All'; $customer_subscription->paid_invoice = 0; $customer_subscription->status = $subscription['status']; $customer_subscription->payment_status = 'uncaptured'; $customer_subscription->is_paid = false; $customer_subscription->next_payment_at = $planPrice->billing_type == 'Recurring' ? Carbon::createFromTimestamp($subscription['billing_cycle_anchor'])->format('Y-m-d H:i:s') : null; $customer_subscription->expired_at = Carbon::createFromTimestamp($subscription['trial_end'])->format('Y-m-d H:i:s'); $customer_subscription->last_payment_date = Carbon::now()->format('Y-m-d'); $customer_subscription->save(); if($subscription['discount'] != null && isset($subscription['discount']['coupon'])){ $coupon = SubscriptionCoupon::where('stripe_coupon_id',$subscription['discount']['coupon']['id'])->first(); if($coupon){ $coupon_redemption = new SubscriptionCouponRedemption; $coupon_redemption->subscription_coupon_id = $coupon->id; $coupon_redemption->customer_id = $customer_id; $coupon_redemption->subscription_id = $customer_subscription->id; $coupon_redemption->save(); } } $user = $customer_subscription->user; $this->sendSubscriptionPendingApproval($user, $user->company_details['storefront']); } } else { Log::debug('Subscription Plan Price not found: '. $setup_intent['metadata']['subscription_plan_price_id']); } } else if($response->mode == 'subscription'){ $checkout_session = \Stripe\Checkout\Session::retrieve([ 'id' => $response->id, 'expand' => ['subscription'], ]); $planPrice = SubscriptionPlanPrice::find($checkout_session['subscription']['metadata']['subscription_plan_id']); if($planPrice){ $subscription = \Stripe\Subscription::update($checkout_session['subscription']['id'],[ 'cancel_at' => Carbon::now()->addMonths($planPrice->custom_interval)->addDays($planPrice->trial_period ? $planPrice->trial_duration : 7)->timestamp ]); $customer_subscription = new CustomerSubscription(); $customer_subscription->customer_id = $response->client_reference_id; $customer_subscription->txn_id = $checkout_session['subscription']['id']; $customer_subscription->subscription_plan_price_id = $planPrice->id; $customer_subscription->payment_mode = $planPrice->payment == 'monthly' ? 'Monthly' :'All'; $customer_subscription->paid_invoice = 1; $customer_subscription->status = $checkout_session['subscription']['status']; $customer_subscription->payment_status = 'uncaptured'; $customer_subscription->is_paid = false; $customer_subscription->next_payment_at = $planPrice->billing_type == 'Recurring' ? Carbon::createFromTimestamp($checkout_session['subscription']['billing_cycle_anchor'])->format('Y-m-d H:i:s') : null; $customer_subscription->expired_at = Carbon::createFromTimestamp($checkout_session['subscription']['trial_end'])->format('Y-m-d H:i:s'); $customer_subscription->last_payment_date = Carbon::now()->format('Y-m-d'); $customer_subscription->save(); if($checkout_session['subscription']['discount'] != null && isset($checkout_session['subscription']['discount']['coupon'])){ $coupon = SubscriptionCoupon::where('stripe_coupon_id',$checkout_session['subscription']['discount']['coupon']['id'])->first(); if($coupon){ $coupon_redemption = new SubscriptionCouponRedemption; $coupon_redemption->subscription_coupon_id = $coupon->id; $coupon_redemption->customer_id = $response->client_reference_id; $coupon_redemption->subscription_id = $customer_subscription->id; $coupon_redemption->save(); } } } else { Log::debug('Subscription Plan Price not found: '. $checkout_session['subscription']['metadata']['subscription_plan_id']); } } else { Log::debug('Mode is not subscription'); } } else { echo 'Received unknown event type ' . $event->type; Log::debug(json_encode($response)); } http_response_code(200); } public function updateCustomerSubscription($status, $payment_status, $paid, $response, $event) { if($event == 'invoice.paid'){ $subscription = CustomerSubscription::with('planPrice')->where('txn_id',$response['subscription'])->first(); if($subscription){ Log::debug('Subscription found, event: '.$event.' id: '.$response['subscription']); if($subscription->planPrice->billing_type == 'Recurring' && isset($response['lines']['data'][0]['period']['end'])) { $period_end = $response['lines']['data'][0]['period']['end']; $subscription->expired_at = Carbon::createFromTimestamp($period_end)->toDateTimeString(); $subscription->next_payment_at = Carbon::createFromTimestamp($period_end)->toDateTimeString(); $subscription->last_payment_date = Carbon::createFromTimestamp($response['effective_at'])->format('Y-m-d'); } if(isset($response['charge']) && $response['charge'] != null){ $user_credits = UserCredit::firstOrCreate(['user_id' => $subscription->customer_id]); if($subscription->paid_invoice == 1){ $old_subscription = CustomerSubscription::where('customer_id',$subscription->customer_id)->where('status','cancelled')->where('payment_status','cancelled')->where('paid_invoice','>',1)->latest()->first(); //for flex plan downgrade remove unused credits if($old_subscription && $subscription->planPrice->payment == 'upfront' && $user_credits->subscription_credits > 0 ){ $before_credits = $this->customerService->credits($user_credits->user_id); $subscription_credits = $user_credits->subscription_credits - $before_credits['total_available_credits']['subscription']; $user_credits->subscription_credits = $subscription_credits; $user_credits->save(); $after_credits = $this->customerService->credits($user_credits->user_id); $user_credits_history = new UserCreditHistory; $user_credits_history->user_id = $user_credits->user_id; $user_credits_history->subscription_credits_from = $before_credits['total_available_credits']['subscription']; $user_credits_history->subscription_credits_to = $after_credits['total_available_credits']['subscription']; $user_credits_history->alacarte_credits_from = $before_credits['total_available_credits']['alacarte'];; $user_credits_history->alacarte_credits_to = $after_credits['total_available_credits']['alacarte']; $user_credits_history->details = 'Remove unused subscription credits because of downgrade to Flex Plan'; $user_credits_history->save(); } if($old_subscription){ $paid_months = $old_subscription->paid_invoice; $plan_credits = $old_subscription->planPrice->total_credits; $months = $old_subscription->planPrice->custom_interval; if($old_subscription->planPrice->payment == 'monthly' && $subscription->planPrice->payment == 'monthly'){ $prorate_credits = $subscription->planPrice->total_credits - (( $plan_credits / $months ) * ($months - $paid_months)); $prorate_credits = $prorate_credits >= 0 ? floor($prorate_credits) : -1 * floor(abs($prorate_credits)); $subscription_credits = $user_credits->subscription_credits + $prorate_credits; $user_credits_history_details = 'Prorated Credits from '.$old_subscription->planPrice->plan->title.' to '.$subscription->planPrice->plan->title; } else { $subscription_credits = $user_credits->subscription_credits + $subscription->planPrice->total_credits; $user_credits_history_details = 'Added Total Plan Credits of '.$subscription->planPrice->plan->title; } } else { $subscription_credits = $user_credits->subscription_credits + $subscription->planPrice->total_credits; $user_credits_history_details = 'Added Total Plan Credits of '.$subscription->planPrice->plan->title; } $before_credits = $this->customerService->credits($user_credits->user_id); $user_credits->subscription_credits = $subscription_credits; $user_credits->save(); $after_credits = $this->customerService->credits($user_credits->user_id); $user_credits_history = new UserCreditHistory; $user_credits_history->user_id = $user_credits->user_id; $user_credits_history->subscription_credits_from = $before_credits['total_available_credits']['subscription']; $user_credits_history->subscription_credits_to = $after_credits['total_available_credits']['subscription']; $user_credits_history->alacarte_credits_from = $before_credits['total_available_credits']['alacarte'];; $user_credits_history->alacarte_credits_to = $after_credits['total_available_credits']['alacarte']; $user_credits_history->details = $user_credits_history_details; $user_credits_history->save(); } else if($subscription->paid_invoice >= 1){ if($subscription->planPrice->payment == 'monthly'){ //per month $subscription_credits = $user_credits->subscription_credits + $subscription->planPrice->per_month_credits; $details = 'Added Monthly Credits'; } else { //yearly $subscription_credits = $user_credits->subscription_credits + $subscription->planPrice->total_credits; $details = 'Added Yearly Credits'; } $before_credits = $this->customerService->credits($user_credits->user_id); $user_credits->subscription_credits = $subscription_credits; $user_credits->save(); $after_credits = $this->customerService->credits($user_credits->user_id); $user_credits_history = new UserCreditHistory; $user_credits_history->user_id = $user_credits->user_id; $user_credits_history->subscription_credits_from = $before_credits['total_available_credits']['subscription']; $user_credits_history->subscription_credits_to = $after_credits['total_available_credits']['subscription']; $user_credits_history->alacarte_credits_from = $before_credits['total_available_credits']['alacarte'];; $user_credits_history->alacarte_credits_to = $after_credits['total_available_credits']['alacarte']; $user_credits_history->details = $details; $user_credits_history->save(); } $subscription->status = $status; $subscription->payment_status = $payment_status; $subscription->is_paid = $paid; if($this->stripe == null){ $credential = getPaymentInfoViaSellerId(1, 4); $stripe = new \Stripe\StripeClient($credential->perameter_3); $charge_response = $stripe->charges->retrieve($response['charge'], []); } else { $charge_response = $this->stripe->charges->retrieve($response['charge'],[]); } if($charge_response && isset($charge_response['amount_captured']) && isset($charge_response['receipt_url'])){ $this->sendInvoicePaid($subscription->user->email, $charge_response['amount_captured'],$charge_response['receipt_url']); } $subscription->approved = 1; } $subscription->paid_invoice++; $subscription->save(); } else { Log::debug('Subscription not found, event: '.$event.' id: '.$response['id']); } } else if($event == 'invoice.payment_failed'){ $subscription = CustomerSubscription::with('planPrice')->where('txn_id',$response['subscription'])->first(); if($subscription){ $this->sendPaymentFailed($subscription->user->email, $response['number'], $response['hosted_invoice_url']); $this->sendPaymentFailedForSales($subscription->user->email, $response['number'], $response['hosted_invoice_url'], $response['amount_due']); if($this->stripe == null){ $credential = getPaymentInfoViaSellerId(1, 4); $stripe = new \Stripe\StripeClient($credential->perameter_3); $charge_response = $stripe->charges->retrieve($response['charge'], []); } else { $charge_response = $this->stripe->charges->retrieve($response['charge'],[]); } if($charge_response && isset($charge_response['failure_message'])){ $subscription->message = $charge_response['failure_message']; } $subscription->status = $status; $subscription->payment_status = $payment_status; $subscription->is_paid = $paid; $subscription->save(); } } else { $subscription = CustomerSubscription::with('planPrice')->where('txn_id',$response['id'])->first(); if($subscription){ if($subscription->planPrice->billing_type == 'Recurring' && isset($response['current_period_end'])) { $period_end = $response['current_period_end']; $subscription->expired_at = Carbon::createFromTimestamp($period_end)->toDateTimeString(); $subscription->next_payment_at = Carbon::createFromTimestamp($period_end)->toDateTimeString(); $subscription->last_payment_date = Carbon::createFromTimestamp($response['effective_at'])->format('Y-m-d'); } $subscription->status = $status; $subscription->payment_status = $payment_status; $subscription->is_paid = $paid; $subscription->save(); if($event == 'customer.subscription.deleted'){ $this->sendSubscriptionCancelled($subscription->user->email, $subscription->planPrice->plan->title); $this->sendSubscriptionCancelledForSales($subscription->user->email, $subscription->planPrice->plan->title); } else if($event == 'customer.subscription.updated'){ if($subscription->discount == null && isset($response['discount']) && $response['discount'] != null){ $coupon_data = $response['discount']['coupon']; $coupon = SubscriptionCoupon::firstOrCreate( [ 'stripe_coupon_id' => $coupon_data['id'] ], [ 'subscription_plan_price_id' => [$subscription->planPrice->id], 'name' => $coupon_data['name'], 'code' => $coupon_data['id'], 'type' => $coupon_data['percent_off'] != null ? 'Percentage' : 'Amount', 'applied_to' => 'subscription', 'payment_mode' => 'Monthly', 'discount' => $coupon_data['percent_off'] != null ? $coupon_data['percent_off'] : $coupon_data['amount_off'] / 100, 'duration' => ucfirst($coupon_data['duration']), 'max_redemptions' => $coupon_data['max_redemptions'] ] ); $coupon_redemption = new SubscriptionCouponRedemption; $coupon_redemption->subscription_coupon_id = $coupon->id; $coupon_redemption->customer_id = $subscription->customer_id; $coupon_redemption->subscription_id = $subscription->id; $coupon_redemption->save(); } } } else { Log::debug('Subscription not found, event: '.$event.' id: '.$response['id']); } } } }