PaypalController
Sat Aug 17 2024 00:54:26 GMT+0000 (Coordinated Universal Time)
Saved by @mebean #flutter #laravel #api #http #2lancer
<?php namespace App\Http\Controllers\Callback; use App\Models\Gig; use App\Models\User; use App\Models\Order; use App\Models\OrderItem; use App\Models\GigUpgrade; use Illuminate\Support\Str; use App\Models\OrderInvoice; use Illuminate\Http\Request; use App\Models\DepositWebhook; use App\Models\CheckoutWebhook; use App\Models\OrderItemUpgrade; use App\Models\DepositTransaction; use App\Http\Controllers\Controller; use App\Models\AffiliateTransaction; use App\Models\AffiliateRegisteration; use App\Models\AutomaticPaymentGateway; use App\Notifications\User\Buyer\OrderPlaced; use App\Notifications\User\Seller\PendingOrder; use Srmklive\PayPal\Services\PayPal as PayPalClient; class PaypalController extends Controller { public $gateway = "paypal"; public $status = "paid"; public $settings; /** * Payment gateway callback * * @param Request $request * @return mixed */ public function callback(Request $request) { try { // Get payment gateway settings $settings = AutomaticPaymentGateway::where('slug', $this->gateway) ->where('is_active', true) ->firstOrFail(); // Set settings $this->settings = $settings; // Get transaction id $transaction_id = $request->get('order'); // Check webhook event if ( $transaction_id ) { // Check if payment succeeded $response = $this->verify($transaction_id); // Check if payment succeeded if ( is_array($response) && $response['success'] === TRUE) { // Get order id $order_id = $response['response']['purchase_units'][0]['payments']['captures'][0]['invoice_id']; // Check if deposit callback if (Str::startsWith($order_id, "D-")) { // Get saved webhook data in our database $data = DepositWebhook::where('payment_id', $order_id) ->where('payment_method', $this->gateway) ->where('status', 'pending') ->firstOrFail(); // Handle deposit callback $this->deposit($data->user_id, $data->amount, $order_id); // Delete saved webhook data in our database $data->delete(); // Redirecting return $this->redirect('deposit'); } // Check if checkout callback if (Str::startsWith($order_id, "G-")) { // Get saved webhook data in our database $data = CheckoutWebhook::where('payment_id', $order_id) ->where('payment_method', $this->gateway) ->where('status', 'pending') ->firstOrFail(); // Get cart $cart = $data->data['cart']; // Get user $user = User::where('id', $data->data['buyer_id'])->firstOrFail(); // Handle deposit callback $this->checkout($cart, $user, $order_id); // Delete saved webhook data in our database $data->delete(); // Redirecting return $this->redirect('gigs'); } } } // In case failed redirect to home page return redirect('/'); } catch (\Throwable $th) { // Error throw $th; } } /** * Verify if payment succeeded * * @param string $id * @return array */ private function verify($id) { // Get payment gateway keys $client_id = $this->settings?->settings['client_id']; $client_secret = $this->settings?->settings['client_secret']; $env = $this->settings?->settings['env']; // Set gateway config $config = [ 'mode' => 'sandbox' , 'live' => [ 'client_id' => $client_id, 'client_secret' => $client_secret, 'app_id' => '', ], 'sandbox' => [ 'client_id' => $client_id, 'client_secret' => $client_secret, 'app_id' => '', ], 'payment_action' => 'Sale', 'currency' => $this->settings?->currency, 'notify_url' => 'https://2lancer.ma/paypal/notify', 'locale' => 'en_US', 'validate_ssl' => true, ]; // Set paypal provider and config $client = new PayPalClient(); // Set client credentials $client->setApiCredentials($config); // Get paypal access token $client->getAccessToken(); // Capture this order $order = $client->capturePaymentOrder($id); // Check if payment succeeded if ( is_array($order) && isset($order['status']) && $order['status'] === 'COMPLETED' ) { // Done return [ 'success' => true, 'response' => $order ]; } else { // Failed return [ 'success' => false, 'message' => __('messages.t_error_stripe_payment_failed') ]; } } /** * Deposit funds into user's account * * @param int $user_id * @param mixed $amount * @param string $payment_id * @return void */ private function deposit($user_id, $amount, $payment_id) { try { // Set amount $amount = convertToNumber($amount); // Calculate fee from this amount $fee = convertToNumber($this->fee('deposit', $amount)); // Make transaction $deposit = new DepositTransaction(); $deposit->user_id = $user_id; $deposit->transaction_id = $payment_id; $deposit->payment_method = $this->gateway; $deposit->amount_total = $amount; $deposit->amount_fee = $fee; $deposit->amount_net = $amount - $fee; $deposit->currency = $this->settings->currency; $deposit->exchange_rate = $this->settings->exchange_rate; $deposit->status = $this->status; $deposit->ip_address = request()->ip(); $deposit->save(); // Get user $user = User::where('id', $user_id)->firstOrFail(); // Add funds $user->balance_available = convertToNumber($user->balance_available) + convertToNumber($deposit->amount_net); $user->save(); // Send a notification $this->notification('deposit', $user); } catch (\Throwable $th) { // Error throw $th; } } /** * Checkout * * @param array $cart * @param object $user * @param string $payment_id * @return void */ private function checkout($cart, $user, $payment_id) { try { // Set empty variables $subtotal = 0; $total = 0; $tax = 0; $fee = 0; // Loop through items in cart foreach ($cart as $key => $item) { // Add gig price to subtotal $subtotal += convertToNumber($item['gig']['price']) * convertToNumber($item['quantity']); // Check if item has upgrades $upgrades = $item['upgrades']; // Loop through upgrades if ( isset($upgrades) && is_array($upgrades) && count($upgrades) ) { // Loop through upgrades foreach ($upgrades as $j => $upgrade) { // Check if upgrade checked if ( isset($upgrade['checked']) && $upgrade['checked'] == 1 ) { // Add upgrade price to subtotal $subtotal += convertToNumber($upgrade['price']) * convertToNumber($item['quantity']); } } } } // Get commission settings $commission_settings = settings('commission'); // Check if taxes enabled if ($commission_settings->enable_taxes) { // Check if type of taxes percentage if ($commission_settings->tax_type === 'percentage') { // Set tax amount $tax = convertToNumber(bcmul($subtotal, $commission_settings->tax_value) / 100); } else { // Set tax amount $tax = convertToNumber($commission_settings->tax_value); } } // Calculate payment gateway fee $fee = convertToNumber($this->fee( 'gigs', $subtotal )); // Calculate total price $total = $subtotal + $tax + $fee; // Get user billing address $billing_info = $user->billing; // Set unique id for this order $uid = uid(); // Get buyer id $buyer_id = $user->id; // Save order $order = new Order(); $order->uid = $uid; $order->buyer_id = $buyer_id; $order->total_value = $total; $order->subtotal_value = $subtotal; $order->taxes_value = $tax; $order->save(); // Loop through items in cart foreach ($cart as $key => $item) { // Get gig $gig = Gig::where('uid', $item['id'])->with('owner')->active()->first(); // Check if gig exists if ($gig) { // Set quantity $quantity = isset($item['quantity']) ? convertToNumber($item['quantity']) : 1; // Set gig upgrades $upgrades = isset($item['upgrades']) && is_array($item['upgrades']) && count($item['upgrades']) ? $item['upgrades'] : []; // Set empty variable $upgrades_amount = 0; // Loop through upgrades foreach ($upgrades as $index => $upgrade) { // Check if upgrade is selected if ( isset($upgrade['checked']) && $upgrade['checked'] == 1 ) { $upgrades_amount += convertToNumber($upgrade['price']) * $quantity; } } // Set item total price $item_total = $upgrades_amount + ( convertToNumber($item['gig']['price']) * $quantity ); // Calculate commission first if ($commission_settings->commission_from === 'orders') { // Check commission type if ($commission_settings->commission_type === 'percentage') { // Calculate commission $commission = convertToNumber($commission_settings->commission_value) * $item_total / 100; } else { // Fixed amount $commission = convertToNumber($commission_settings->commission_value); } } else { // No commission $commission = 0; } // Save order item $order_item = new OrderItem(); $order_item->uid = uid(); $order_item->order_id = $order->id; $order_item->gig_id = $gig->id; $order_item->owner_id = $gig->user_id; $order_item->quantity = $quantity; $order_item->has_upgrades = count($upgrades) ? true : false; $order_item->total_value = $item_total; $order_item->profit_value = $item_total - $commission; $order_item->commission_value = $commission; $order_item->save(); // Loop through upgrades again foreach ($upgrades as $index => $value) { // Check if upgrade is selected if ( isset($upgrade['checked']) && $upgrade['checked'] == 1 ) { // Get upgrade $upgrade = GigUpgrade::where('uid', $value['id'])->where('gig_id', $gig->id)->first(); // Check if upgrade exists if ($upgrade) { // Save item upgrade $order_item_upgrade = new OrderItemUpgrade(); $order_item_upgrade->item_id = $order_item->id; $order_item_upgrade->title = $upgrade->title; $order_item_upgrade->price = $upgrade->price; $order_item_upgrade->extra_days = $upgrade->extra_days; $order_item_upgrade->save(); } } } // Update seller pending balance $gig->owner()->update([ 'balance_pending' => convertToNumber($gig->owner->balance_pending) + convertToNumber($order_item->profit_value) ]); // Increment orders in queue $gig->increment('orders_in_queue'); // Order item placed successfully // Let's notify the seller about new order $gig->owner->notify( (new PendingOrder($order_item))->locale(config('app.locale')) ); // Check user's level check_user_level($buyer_id); // Send notification notification([ 'text' => 't_u_received_new_order_seller', 'action' => url('seller/orders/details', $order_item->uid), 'user_id' => $order_item->owner_id ]); } } // Save invoice $invoice = new OrderInvoice(); $invoice->order_id = $order->id; $invoice->payment_method = $this->gateway; $invoice->payment_id = $payment_id; $invoice->firstname = $billing_info->firstname ?? $user->username; $invoice->lastname = $billing_info->lastname ?? $user->username; $invoice->email = $user->email; $invoice->company = !empty($billing_info->company) ? clean($billing_info->company) : null; $invoice->address = !empty($billing_info->address) ? clean($billing_info->address) : "NA"; $invoice->status = 'paid'; $invoice->save(); // Update balance $user->update([ 'balance_purchases' => convertToNumber($user->balance_purchases) + convertToNumber($total) ]); // Now everything succeeded // Let's empty the cart session()->forget('cart'); // Now let's notify the buyer that his order has been placed $user->notify( (new OrderPlaced($order, $total))->locale(config('app.locale')) ); //check for affiliate registeration and check if expired if(settings('affiliate')->is_enabled) { $affiliate_register =AffiliateRegisteration::where('user_id', $buyer_id) ->where('expires_at','>',now()) ->first() ; if($affiliate_register){ // get referral user $referral_user = User::where('id', $affiliate_register->referral_id)->first(); // calculate referral earning $referral_earning =(convertToNumber(settings('affiliate')->profit_percentage)/100)*convertToNumber($total); // add credit to referral wallet $referral_balance = convertToNumber($referral_user->balance_available) + $referral_earning; $referral_user->update(['balance_available'=>$referral_balance]); // create new affiliate transaction $affiliate_transaction = new AffiliateTransaction(); $affiliate_transaction->user_id = $buyer_id ; $affiliate_transaction->referral_id = $referral_user->id ; $affiliate_transaction->order_id = $order->id ; $affiliate_transaction->referral_earning = $referral_earning ; $affiliate_transaction->save(); } } } catch (\Throwable $th) { // Error throw $th; } } /** * Calculate fee value * * @param string $type * @param mixed $amount * @return mixed */ private function fee($type, $amount = null) { try { // Set amount for deposit $amount = convertToNumber($amount) * $this->settings?->exchange_rate / settings('currency')->exchange_rate; // Remove long decimal $amount = convertToNumber( number_format($amount, 2, '.', '') ); // Check fee type switch ($type) { // Deposit case 'deposit': // Get deposit fixed fee if (isset($this->settings->fixed_fee['deposit'])) { // Set fixed fee $fee_fixed = convertToNumber($this->settings->fixed_fee['deposit']); } else { // No fixed fee $fee_fixed = 0; } // Get deposit percentage fee if (isset($this->settings->percentage_fee['deposit'])) { // Set percentage fee $fee_percentage = convertToNumber($this->settings->percentage_fee['deposit']); } else { // No percentage fee $fee_percentage = 0; } // Calculate percentage of this amount $fee_percentage_amount = $this->exchange( $fee_percentage * $amount / 100, $this->settings->exchange_rate ); // Calculate exchange rate of this fixed fee $fee_fixed_exchange = $this->exchange( $fee_fixed, $this->settings->exchange_rate); // Calculate fee value and visible text if ($fee_fixed > 0 && $fee_percentage > 0) { // Calculate fee value $fee_value = convertToNumber($fee_percentage_amount) + convertToNumber($fee_fixed_exchange); } else if (!$fee_fixed && $fee_percentage > 0) { // Calculate fee value $fee_value = convertToNumber($fee_percentage_amount); } else if ($fee_fixed > 0 && !$fee_percentage) { // Calculate fee value $fee_value = convertToNumber($fee_fixed_exchange); } else if (!$fee_percentage && !$fee_fixed) { // Calculate fee value $fee_value = 0; } // Return fee value return number_format($fee_value, 2, '.', ''); break; // Gigs case 'gigs': // Get gigs fixed fee if (isset($this->settings->fixed_fee['gigs'])) { // Set fixed fee $fee_fixed = convertToNumber($this->settings->fixed_fee['gigs']); } else { // No fixed fee $fee_fixed = 0; } // Get gigs percentage fee if (isset($this->settings->percentage_fee['gigs'])) { // Set percentage fee $fee_percentage = convertToNumber($this->settings->percentage_fee['gigs']); } else { // No percentage fee $fee_percentage = 0; } // Calculate percentage of this amount $fee_percentage_amount = $this->exchange( $fee_percentage * $amount / 100, $this->settings->exchange_rate ); // Calculate exchange rate of this fixed fee $fee_fixed_exchange = $this->exchange( $fee_fixed, $this->settings->exchange_rate); // Calculate fee value and visible text if ($fee_fixed > 0 && $fee_percentage > 0) { // Calculate fee value $fee_value = convertToNumber($fee_percentage_amount) + convertToNumber($fee_fixed_exchange); } else if (!$fee_fixed && $fee_percentage > 0) { // Calculate fee value $fee_value = convertToNumber($fee_percentage_amount); } else if ($fee_fixed > 0 && !$fee_percentage) { // Calculate fee value $fee_value = convertToNumber($fee_fixed_exchange); } else if (!$fee_percentage && !$fee_fixed) { // Calculate fee value $fee_value = 0; } // Return fee value return $fee_value; break; } } catch (\Throwable $th) { // Something went wrong return 0; } } /** * Calculate exchange rate * * @param mixed $amount * @param mixed $exchange_rate * @param boolean $formatted * @param string $currency * @return mixed */ private function exchange($amount, $exchange_rate, $formatted = false, $currency = null) { try { // Convert amount to number $amount = convertToNumber($amount); // Get currency settings $currency_settings = settings('currency'); // Get default currency exchange rate $default_exchange_rate = convertToNumber($currency_settings->exchange_rate); // Get exchanged amount $exchanged_amount = convertToNumber( $amount * $default_exchange_rate / $exchange_rate ); // Check if we have to return a formatted value if ($formatted) { return money( $exchanged_amount, $currency, true )->format(); } // Return max deposit return convertToNumber(number_format( $exchanged_amount, 2, '.', '' )); } catch (\Throwable $th) { // Something went wrong return $amount; } } /** * Send a notification to user * * @param string $type * @param object $user * @return void */ private function notification($type, $user) { try { // Check notification type switch ($type) { // Deposit funds case 'deposit': break; // Gig checkout case 'gig': break; // Project payment case 'project': break; // Bid payment case 'bid': break; } } catch (\Throwable $th) { // Something went wrong return; } } /** * Redirecting * * @param string $type * @param string $status * @return void */ private function redirect($type, $status = 'success') { // Check where to redirect switch ($type) { // Deposit history case 'deposit': // Check if payment succeeded if ($status === 'success') { // Redirect to deposit history page return redirect('account/deposit/history')->with('success', __('messages.t_ur_transaction_has_completed')); } else if ($status === 'pending') { // Redirect to deposit history page return redirect('account/deposit/history')->with('success', __('messages.t_mollie_payment_pending')); } break; // Gigs order case 'gigs': // Check if payment succeeded if ($status === 'success') { // Redirect to deposit history page return redirect('account/orders')->with('success', __('messages.t_submit_ur_info_now_seller_start_order')); } else if ($status === 'pending') { // Redirect to deposit history page return redirect('account/orders')->with('success', __('messages.t_mollie_payment_pending')); } break; } } }
Comments