mirror of
https://github.com/Bigherollc/wticreatorstudio.git
synced 2026-01-16 19:05:08 -05:00
347 lines
16 KiB
PHP
347 lines
16 KiB
PHP
<?php
|
|
|
|
namespace Modules\Subscription\Http\Controllers;
|
|
|
|
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Routing\Controller;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Modules\Subscription\Entities\SubscriptionSetting;
|
|
use Modules\Subscription\Entities\CustomerSubscription;
|
|
use Modules\Subscription\Entities\UserCredit;
|
|
use Modules\Subscription\Entities\UserCreditHistory;
|
|
use Modules\Subscription\Entities\SubscriptionPlanPrice;
|
|
use Modules\Subscription\Entities\SubscriptionPlanPricePaypal;
|
|
use Modules\Subscription\Entities\SubscriptionCoupon;
|
|
use Modules\Subscription\Entities\SubscriptionCouponRedemption;
|
|
use Modules\FrontendCMS\Entities\SubsciptionPaymentInfo;
|
|
use Modules\Customer\Services\CustomerService;
|
|
use Modules\Subscription\Services\PaypalPaymentService;
|
|
use App\Traits\SendMail;
|
|
use Carbon\Carbon;
|
|
use Exception;
|
|
|
|
|
|
class PaypalWebhookController extends Controller
|
|
{
|
|
use SendMail;
|
|
|
|
protected $paypal;
|
|
protected $customerService;
|
|
|
|
public function __construct(CustomerService $customerService){
|
|
$this->paypal = new PaypalPaymentService();
|
|
$this->customerService = $customerService;
|
|
}
|
|
|
|
protected function isValidWebhook()
|
|
{
|
|
// get request headers
|
|
$headers = apache_request_headers();
|
|
Log::info($headers);
|
|
|
|
// get http payload
|
|
$body = file_get_contents('php://input');
|
|
|
|
$webhook_id = '2HD41882U7087321C'; //live
|
|
|
|
$data =
|
|
$headers['PAYPAL-TRANSMISSION-ID'] . '|' .
|
|
$headers['PAYPAL-TRANSMISSION-TIME'] . '|' .
|
|
$webhook_id . '|' . crc32($body);
|
|
|
|
|
|
// load certificate and extract public key
|
|
$pubKey = openssl_pkey_get_public(file_get_contents($headers['PAYPAL-CERT-URL']));
|
|
$key = openssl_pkey_get_details($pubKey)['key'];
|
|
|
|
// verify data against provided signature
|
|
$result = openssl_verify(
|
|
$data,
|
|
base64_decode($headers['PAYPAL-TRANSMISSION-SIG']),
|
|
$key,
|
|
'sha256WithRSAEncryption'
|
|
);
|
|
|
|
|
|
if ($result == 1) {
|
|
// webhook notification is verified
|
|
Log::info('webhook verified');
|
|
return true;
|
|
} elseif ($result == 0) {
|
|
// webhook notification is NOT verified
|
|
Log::info('webhook not verified');
|
|
return false;
|
|
} else {
|
|
// there was an error verifying this
|
|
Log::info('webhook verification error');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public function webhook(Request $request) {
|
|
|
|
// Verify that the webhook is authentic
|
|
if (!$this->isValidWebhook()) {
|
|
Log::error('Received invalid webhook');
|
|
return response('Invalid webhook', 400);
|
|
exit();
|
|
}
|
|
|
|
// Get the webhook data from the request
|
|
$webhookData = $request->all();
|
|
$event_type = $webhookData["event_type"];
|
|
|
|
// Handle the event based on its type
|
|
switch ($event_type) {
|
|
case "BILLING.SUBSCRIPTION.ACTIVATED":
|
|
$this->updateCustomerSubscription($webhookData);
|
|
break;
|
|
case "BILLING.SUBSCRIPTION.CREATED":
|
|
$this->onSubscriptionCreate($webhookData);
|
|
break;
|
|
case "BILLING.SUBSCRIPTION.CANCELLED":
|
|
$this->updateCustomerSubscription($webhookData);
|
|
break;
|
|
case "PAYMENT.SALE.COMPLETED":
|
|
$this->updateCustomerSubscription($webhookData);
|
|
break;
|
|
case "BILLING.SUBSCRIPTION.PAYMENT.FAILED":
|
|
$this->updateCustomerSubscription($webhookData);
|
|
break;
|
|
// case "BILLING.SUBSCRIPTION.SUSPENDED":
|
|
// $this->onSubscriptionSuspended($webhookData);
|
|
// break;
|
|
}
|
|
}
|
|
|
|
|
|
protected function onSubscriptionCreate(array $webhookData)
|
|
{
|
|
|
|
Log::info($webhookData);
|
|
|
|
$planPrice = SubscriptionPlanPrice::where('paypal_price_id', $webhookData['resource']['plan_id'])->first();
|
|
if(!$planPrice){
|
|
//lets try to search on paypal prices
|
|
$paypalPlanPrice = SubscriptionPlanPricePaypal::where('paypal_price_id', $webhookData['resource']['plan_id'])->first();
|
|
if($paypalPlanPrice){
|
|
$planPrice = $paypalPlanPrice->planPrice;
|
|
}
|
|
}
|
|
|
|
if($planPrice){
|
|
|
|
$user_data = json_decode($webhookData['resource']['custom_id']);
|
|
|
|
if(isset($user_data->user_id)){
|
|
|
|
$customer_id = (int)$user_data->user_id;
|
|
|
|
$customer_subscription = new CustomerSubscription();
|
|
$customer_subscription->customer_id = $customer_id;
|
|
$customer_subscription->txn_id = $webhookData['resource']['id'];
|
|
$customer_subscription->payment_method = 'paypal';
|
|
$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 = 'waiting for approval';
|
|
$customer_subscription->payment_status = 'uncaptured';
|
|
$customer_subscription->is_paid = false;
|
|
$customer_subscription->next_payment_at = null;
|
|
$customer_subscription->expired_at = null;
|
|
$customer_subscription->last_payment_date = Carbon::now()->format('Y-m-d');
|
|
$customer_subscription->save();
|
|
|
|
if(isset($user_data->coupon_id)){
|
|
$coupon_id = $user_data->coupon_id;
|
|
Log::info('Coupon ID: '.$coupon_id);
|
|
$coupon = SubscriptionCoupon::where('stripe_coupon_id',$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();
|
|
}
|
|
}
|
|
|
|
Log::info('Subscription Created');
|
|
}
|
|
|
|
} else {
|
|
Log::info('Subscription Cannot Created, plan ID not found');
|
|
}
|
|
}
|
|
|
|
protected function updateCustomerSubscription(array $webhookData) {
|
|
|
|
|
|
Log::info($webhookData);
|
|
|
|
$event = $webhookData['event_type'];
|
|
|
|
if($event == 'PAYMENT.SALE.COMPLETED'){
|
|
|
|
$subscription = CustomerSubscription::with('planPrice')->where('txn_id',$webhookData['resource']['billing_agreement_id'])->first();
|
|
if($subscription){
|
|
|
|
$paypal_subscription = $this->paypal->showSubscription($subscription->txn_id);
|
|
if($paypal_subscription){
|
|
|
|
if($subscription->planPrice->billing_type == 'Recurring' && isset($paypal_subscription->billing_info->next_billing_time)) {
|
|
$period_end = $paypal_subscription->billing_info->next_billing_time;
|
|
$subscription->expired_at = Carbon::parse($period_end)->toDateTimeString();
|
|
$subscription->next_payment_at = Carbon::parse($period_end)->toDateTimeString();
|
|
$subscription->last_payment_date = Carbon::parse($paypal_subscription->billing_info->last_payment->time)->format('Y-m-d');
|
|
}
|
|
|
|
// first payment
|
|
if($paypal_subscription->billing_info->cycle_executions[0]->cycles_completed == 1){
|
|
|
|
$user_credits = UserCredit::firstOrCreate(['user_id' => $subscription->customer_id]);
|
|
|
|
$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->paid_invoice++;
|
|
$subscription->status = 'active';
|
|
$subscription->payment_status = 'succeeded';
|
|
$subscription->is_paid = 1;
|
|
$subscription->save();
|
|
}
|
|
|
|
} else {
|
|
|
|
Log::debug('Subscription not found, event: '.$event);
|
|
}
|
|
|
|
} else if($event == 'BILLING.SUBSCRIPTION.ACTIVATED'){
|
|
|
|
$subscription = CustomerSubscription::with('planPrice')->where('txn_id',$webhookData['resource']['id'])->first();
|
|
if($subscription){
|
|
|
|
if($subscription->planPrice->billing_type == 'Recurring' && isset($webhookData['billing_info']['next_billing_time'])) {
|
|
$period_end = $webhookData['billing_info']['next_billing_time'];
|
|
$subscription->expired_at = Carbon::parse($period_end)->toDateTimeString();
|
|
$subscription->next_payment_at = Carbon::parse($period_end)->toDateTimeString();
|
|
$subscription->last_payment_date = isset($webhookData['billing_info']['last_payment']['time']) ? Carbon::parse($webhookData['billing_info']['last_payment']['time'])->format('Y-m-d') : null;
|
|
$subscription->save();
|
|
}
|
|
|
|
}
|
|
} else {
|
|
|
|
$subscription = CustomerSubscription::with('planPrice')->where('txn_id',$webhookData['resource']['id'])->first();
|
|
if($subscription){
|
|
|
|
|
|
if($event == 'BILLING.SUBSCRIPTION.PAYMENT.FAILED'){
|
|
|
|
$subscription->status = 'inactive';
|
|
$subscription->payment_status = 'failed';
|
|
|
|
$this->sendPaymentFailed($subscription->user->email, null, null);
|
|
$this->sendPaymentFailedForSales($subscription->user->email, null, null, $response['amount_due']);
|
|
|
|
} else if($event == 'BILLING.SUBSCRIPTION.CANCELLED'){
|
|
|
|
$subscription->status = 'cancelled';
|
|
$subscription->payment_status = 'cancelled';
|
|
|
|
$this->sendSubscriptionCancelled($subscription->user->email, $subscription->planPrice->plan->title);
|
|
$this->sendSubscriptionCancelledForSales($subscription->user->email, $subscription->planPrice->plan->title);
|
|
}
|
|
|
|
$subscription->save();
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|