GOOD SHELL MAS BOY
Server: Apache/2.4.52 (Ubuntu)
System: Linux vmi1836763.contaboserver.net 5.15.0-130-generic #140-Ubuntu SMP Wed Dec 18 17:59:53 UTC 2024 x86_64
User: www-data (33)
PHP: 8.4.10
Disabled: NONE
Upload Files
File: /var/www/console.fixgini.com/app/Http/Controllers/BookingPaymentController.php
<?php

namespace App\Http\Controllers;

use Carbon\Carbon;
use App\Models\Gig;
use App\Models\User;
use App\Models\BookingForm;
use App\Models\Transaction;
use Illuminate\Http\Request;
use App\Models\BookingPayment;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Auth;

class BookingPaymentController extends Controller
{
     

   // new method

   public function store(Request $request)
    {
        // validate input
        $request->validate([
            'booking_id' => 'required|integer|exists:booking_forms,id',
            'amount' => 'required|numeric|min:1',
        ]);

        // generate unique transaction reference
        $tx_ref = Str::uuid();

        // create payment record in DB
        $payment = BookingPayment::create([
            'tx_ref' => $tx_ref,
            'booking_id' => $request->booking_id,
            'amount' => $request->amount,
            'payment_status' => 'pending',
        ]);

        return response()->json([
            'tx_ref' => $tx_ref,
            'amount' => $payment->amount,
            'currency' => 'NGN',
            'public_key' => config('flutterwave.public_key'), // send to frontend for checkout
        ]);
    }

   // new method


    public function FluttewaveWebhook(Request $request)
    {   
        $flutterwaveSignature = $request->header('verif-hash');

        //$localSignature = env('FLUTTERWAVE_SECRET_HASH');

         $localSignature   =  config('flutterwave.secret_hash');

        // Check if the signature matches to prevent unauthorized requests
        if ($flutterwaveSignature !== $localSignature) {
            return response()->json(['status' => 'error', 'message' => 'Unauthorized request'], 403);
        }
        $payload = $request->all();

        Log::info('Incoming flutterwave webhook :', $payload);


        // Check if the payment status is successful
        if (isset($payload['data']['status']) && $payload['data']['status'] === 'successful') {
            $tx_ref = $payload['data']['tx_ref'];
            $amount = $payload['data']['amount'];

            // Find the booking payment record using the tx_ref
            $bookingPayment = BookingPayment::where('tx_ref', $tx_ref)->first();
            
            if ($bookingPayment) {
                $bookingPayment->update([
                    'payment_status' => 'completed',
                    'amount' => $amount,
                ]);
                
                // Retrieve the associated booking details using the booking_id
                $booking = BookingForm::where('id', $bookingPayment->booking_id)->first();

                if (!$booking) {
                    return response()->json(['status' => 'error', 'message' => 'Booking not found'], 404);
                }

                // Update the booking status to 'ongoing'
                $booking->update([
                    'status' => 'ongoing',  // Set the status to ongoing meaning payment is completed
                ]);

                //update the transaction using tx_ref
                $transx = Transaction::where('tx_ref', $tx_ref)->first();
                $transx->update([
                    'status' => 'completed',
                    'amount' => $amount,
                    'description' => "Booking payment for {$booking->gig->title} is completed successfully",
                ]);

                // Get the service provider and customer details
                $serviceProvider = User::where('id', $booking->service_provider_id)->first();  // Assuming service_provider_id exists
                $customer = User::where('id', $booking->customer_id)->first();

                // Ensure the wallet relationships are loaded for both the service provider and customer
                $serviceProviderWallet = $serviceProvider->wallet;
                $customerWallet = $customer->wallet;

                if (!$serviceProvider || !$customer) {
                    info('Service provider or customer not found');
                    return response()->json(['status' => 'error', 'message' => 'Service provider or customer not found'], 404);
                }

                if (!$serviceProviderWallet || !$customerWallet) {
                    info('Wallet not found for provider or customer');
                    return response()->json(['status' => 'error', 'message' => 'Wallet not found for provider or customer'], 404);
                }


                // Update the customer's withdraw wallet amount
                $customerWallet->withdraw += $amount;  // Deduct from the pending balance (add to withdraw of the customer)
                $customerWallet->save();  // Save the changes

                // Update the service provider's pending wallet amount
                // $serviceProviderWallet->pending += $amount;  // Add the payment amount to the wallet
                // $serviceProviderWallet->save();  // Don't forget to save the changes

                $this->updateFirestore($booking, $tx_ref);
                info('Booking form and payment status updated. task is now ongoing');

                return response()->json(['status' => 'success', 'message' => 'Payment updated successfully'], 200);
            } else {
                return response()->json(['status' => 'error', 'message' => 'Booking payment not found'], 404);
            }
        }

        return response()->json(['status' => 'error', 'message' => 'Payment failed or incomplete'], 400);
    } 

    private function updateFirestore($booking, $tx_ref)
    {
        try {
            // Retrieve the chatRoomId and chatId from the session
            $chatRoomId = $booking->chat_room_id;
            $chatId = $booking->chat_id;
            $currentTime = Carbon::now()->format('Y-m-d\TH:i:s.u\Z');

            // Prepare the update data with chatId added to the fields (Optional, might not need the same data again)
            $updateChatData = [
                'fields' => [
                    'chatId' => [
                        'stringValue' => $chatId,  // Adding the chatId to the payload
                    ],
                    'lastMessage' => [
                        'stringValue' => 'Payment successful. Engagement ongoing!',
                    ],
                    'lastMessageAt' => [
                        'stringValue' => $currentTime,
                    ],
                    'lastSenderId' => [
                        'stringValue' => (string) $booking->customer_id,
                    ],
                    'chatRoomStatus' => [
                        'stringValue' => 'active',
                    ],
                    'participants' => [
                        'arrayValue' => [
                            'values' => [
                                [
                                    'mapValue' => [
                                        'fields' => [
                                            'firstName' => [
                                                'stringValue' => $booking->customer->name ?? '',
                                            ],
                                            'userPhoto' => [
                                                'stringValue' => $booking->customer->profile_photo_url,
                                            ],
                                            'userUID' => [
                                                'stringValue' => (string) $booking->customer_id,
                                            ],
                                        ],
                                    ],
                                ],
                                [
                                    'mapValue' => [
                                        'fields' => [
                                            'firstName' => [
                                                'stringValue' => $booking->gig->user->name ?? '',
                                            ],
                                            'userPhoto' => [
                                                'stringValue' => $booking->gig->user->profile_photo_url,
                                            ],
                                            'userUID' => [
                                                'stringValue' => (string) $booking->service_provider_id,
                                            ],
                                        ],
                                    ],
                                ],
                            ],
                        ],
                    ],
                    'participantsUIDs' => [
                        'arrayValue' => [
                            'values' => [
                                [
                                    'stringValue' => (string) $booking->customer_id,
                                ],
                                [
                                    'stringValue' => (string) $booking->service_provider_id,
                                ],
                            ],
                        ],
                    ],
                ],
            ];

            // Send the data to Firestore using PATCH to update the existing document with chatId
            $client = new \GuzzleHttp\Client();
            $updateChatId = 'https://firestore.googleapis.com/v1/projects/fixgini/databases/(default)/documents/chats/' . $chatId;
            $client->patch($updateChatId, [
                'json' => $updateChatData,
            ]);



            $updateChatRoomData = [
                'fields' => [
                    'chatId' => [
                        'stringValue' => $chatId,  // The actual chat ID
                    ],
                    'message' => [
                        'stringValue' => 'Payment successful. Engagement ongoing!',
                    ],
                    'messageId' => [
                        'stringValue' => $chatRoomId,
                    ],
                    'sentBy' => [
                        'stringValue' => (string) $booking->customer_id,  // The ID of the user who sent the message
                    ],
                    'time' => [
                        'stringValue' => $currentTime,
                    ],
                    'participants' => [
                        'arrayValue' => [
                            'values' => [
                                [
                                    'stringValue' => (string) $booking->customer_id,  // User's ID
                                ],
                                [
                                    'stringValue' => (string) $booking->service_provider_id,  // Provider's ID
                                ],
                            ],
                        ],
                    ],


                    'chatHire' => [
                        'mapValue' => [
                            'fields' => [
                                'acceptTime' => [
                                    'stringValue' => $currentTime
                                ],
                                'paid' => [
                                    'booleanValue' => true,
                                ],
                                'paidTime' => [
                                    'stringValue' => $currentTime,
                                ],
                                'trxRef' => [
                                    'stringValue' => $tx_ref,
                                ],
                                'accepted' => [
                                    'booleanValue' => true, // Use booleanValue for boolean
                                ],
                                'completed' => [
                                    'booleanValue' => false, // Use booleanValue for boolean
                                ],
                                'completedTime' => [
                                    'nullValue' => null, // Use nullValue instead of an empty string
                                ],
                                'confirmCompleted' => [
                                    'booleanValue' => false, // Use booleanValue for boolean
                                ],
                                'reasonForConfirmDecline' => [
                                    'nullValue' => null, // Use nullValue for empty fields
                                ],
                                'reasonForDecline' => [
                                    'nullValue' => null, // Use nullValue for empty fields
                                ],
                                'rejected' => [
                                    'booleanValue' => false, // Use booleanValue for boolean
                                ],
                                'bookingId' => [
                                    'stringValue' => (string) $booking->id, // Keep as stringValue if it's not numeric
                                ],
                                'price' => [
                                    'doubleValue' => (float) $booking->agreed_amount, // Use doubleValue for decimal values
                                ],
                                'gigId' => [
                                    'stringValue' => (string) $booking->gig_id, // Keep as stringValue
                                ],
                                'gigName' => [
                                    'stringValue' => (string) $booking->gig->title,  // Gig title
                                ],
                                'gigCurrency' => [
                                    'stringValue' => (string) $booking->gig->currency,  // Gig currency
                                ],
                                'time' => [
                                    'stringValue' => $currentTime,
                                ],
                                'paymentLink' => [
                                    'nullValue' => null, // Use nullValue instead of an empty string
                                ],
                                'start' => [
                                    'stringValue' => Carbon::parse($booking->start_time)->format('Y-m-d\TH:i:s.u\Z'), // Use stringValue
                                ],
                                'end' => [
                                    'stringValue' => Carbon::parse($booking->end_time)->format('Y-m-d\TH:i:s.u\Z'), // Use stringValue
                                ],
                                'sentBy' => [
                                    'stringValue' => (string) $booking->customer_id, // Keep as stringValue
                                ],
                            ],
                        ],
                    ],

                ],
            ];

            // Firestore URL to create a new message in the chat room
            $updatedChatRoomID = "https://firestore.googleapis.com/v1/projects/fixgini/databases/(default)/documents/chats/{$chatId}/chat_room/{$chatRoomId}";
            // Send the message data to Firestore using PATCH to update the message
            $client = new \GuzzleHttp\Client();
            $client->patch($updatedChatRoomID, [
                'json' => $updateChatRoomData,
            ]);

            // update the booking form table
            info('Chat room message updated with payment info successfully with MessageId in chat_room.');
            // $this->sendFcmNotification($receiver, $validatedData['message']);

            return response()->json([
                'status' => 'success',
                'message' => 'Chat room message id recorded successfully.',
            ], 200);
        } catch (\Throwable $th) {
            Log::error("Failed to record chat room message in Firestore: {$th->getMessage()}");
            return response()->json(['status' => 'error', 'message' => 'Failed to record chat room in Firebase.'], 500);
        }
    }

    public function sellerPaymentHistory()
    {
        try {
            $user = Auth::user();
            $gigIds = Gig::where('user_id', $user->id)->pluck('id');
            $bookingIds = BookingForm::whereIn('gig_id', $gigIds)->pluck('id');
            $payments = BookingPayment::with(['booking.gig.user'])->whereIn('booking_id', $bookingIds)->latest()->limit(10)->get();
            $transactions = Transaction::where('user_id', $user->id)->latest()->limit(10)->get();
            if ($payments->isEmpty()) {
                return response()->json(['status' => 'error', 'message' => 'Payments not found'], 404);
            } else {
                return response()->json(['status' => 'success', 'message' => 'Payments are found', 'data' => $payments, 'transactions' => $transactions], 200);
            }
        } catch (\Throwable $th) {
            return response()->json(['status' => 'error', 'message' => 'An error occurred', 'data' => $th->getMessage()], 500);
        }
    }

    public function buyerPaymentHistory()
    {
        try {
            $user = Auth::user();
            $payments = BookingPayment::with(['booking.gig.user'])->where('customer_id', $user->id)->latest()->limit(10)->get();
            if ($payments->isEmpty()) {
                return response()->json(['status' => 'error', 'message' => 'Payments not found'], 404);
            } else {
                return response()->json(['status' => 'success', 'message' => 'Payments are found', 'data' => $payments], 200);
            }
        } catch (\Throwable $th) {
            return response()->json(['status' => 'error', 'message' => 'An error occurred', 'data' => $th->getMessage()], 400);
        }
    }
}