HEX
Server: LiteSpeed
System: Linux s3.sitechai.com 4.18.0-553.51.1.lve.1.el8.x86_64 #1 SMP Wed May 14 14:34:57 UTC 2025 x86_64
User: workzeni (2217)
PHP: 8.1.32
Disabled: mail, show_source, system, shell_exec, passthru, exec, eval, shell
Upload Files
File: /home/workzeni/agency-erp-05.workzenix.com/app/Http/Controllers/HotelController.php
<?php

namespace App\Http\Controllers;

use App\Models\CompanyInfo;
use App\Models\Hotel;
use App\Models\Qouta;
use App\Models\Season;
use App\Models\TransactionHistory;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;

class HotelController extends Controller
{
    public function getQuotaByAgency(Request $request)
    {
        $agencyId = $request->query('agency_id');
        $seasonId = $request->query('season_id');

        if (! $agencyId || ! $seasonId) {
            return response()->json(['error' => 'Agency or Season not provided'], 400);
        }

        $quota = Qouta::where('agency_id', $agencyId)
            ->where('season_id', $seasonId)
            ->first();

        if (! $quota) {
            return response()->json(['error' => 'Quota not found for this agency and season'], 404);
        }

        // Makka
        if ($quota->makka_qouta >= $quota->makka_used_qouta) {
            $makka_extra_qouta = $quota->makka_qouta - $quota->makka_used_qouta;
        } else {
            $makka_extra_qouta = $quota->makka_used_qouta - $quota->makka_qouta;
        }

        // modina
        if ($quota->modina_qouta >= $quota->modina_used_qouta) {
            $modina_extra_qouta = $quota->modina_qouta - $quota->modina_used_qouta;
        } else {
            $modina_extra_qouta = $quota->modina_used_qouta - $quota->modina_qouta;
        }

        return response()->json([
            'makka_qouta' => $quota->makka_qouta,
            'makka_used_qouta' => $quota->makka_used_qouta,
            'makka_extra_qouta' => $makka_extra_qouta,
            'modina_qouta' => $quota->modina_qouta,
            'modina_used_qouta' => $quota->modina_used_qouta,
            'modina_extra_qouta' => $modina_extra_qouta,
        ]);
    }

    public function index()
    {
        $hotels = Hotel::latest()->get();

        return view('admin.hotel.list', compact('hotels'));
    }

    public function create()
    {
        $today = now()->toDateString();
        $user = auth()->user();

        $activeSeasons = Season::where('start_date', '<=', $today)
            ->where('end_date', '>=', $today)
            ->get(); // get full objects instead of just IDs

        if (! in_array($user->role, [1, 2, 3])) {
            $authCompanyId = $user->company_id;
            $quotas = Qouta::where('agency_id', $authCompanyId)
                ->whereIn('season_id', $activeSeasons->pluck('id'))
                ->get();
        } else {
            $quotas = Qouta::whereIn('season_id', $activeSeasons->pluck('id'))->get();
        }

        $agencies = CompanyInfo::all();

        return view('admin.hotel.create', compact('agencies', 'quotas', 'activeSeasons'));
    }

    public function store(Request $request)
    {
        // $validator = Validator::make($request->all(), [
        //     'agency_id' => 'nullable|exists:company_infos,id',
        //     'user_id' => 'nullable|exists:users,id',
        //     'city' => 'required|string|max:255',
        //     'season_id' => 'required|string',
        //     'hotel_name' => 'required|string|max:255',
        //     'owner_name' => 'required|string|max:255',
        //     'representative_name' => 'required|string|max:255',
        //     'phone_number' => 'required|string|max:20',
        //     'tasria_owner' => 'required|string|max:255',
        //     'tasria_number' => 'required|string|max:100',
        //     'total_seat' => 'required|integer|min:0',
        //     'double_qty' => 'nullable|integer|min:0',
        //     'triple_qty' => 'nullable|integer|min:0',
        //     'quad_qty' => 'nullable|integer|min:0',
        //     'quintuple_qty' => 'nullable|integer|min:0',
        //     'allocated_seats' => 'nullable|integer|min:0',
        //     'subtotal' => 'nullable|numeric|min:0',
        //     'total_amount' => 'nullable|numeric|min:0',
        // ]);

        // dd($validator);

        // if ($validator->fails()) {
        //     return back()->withErrors($validator)->withInput();
        // }

        // Determine agency/user IDs (fall back to current user’s company & id)
        $agencyID = $request->agency_id ?? optional(auth()->user())->company_id;
        $userID = $request->user_id ?? optional(auth()->user())->id;

        // Seat calculations (default 0 if null)
        $double = (int) $request->double_qty * 2;
        $triple = (int) $request->triple_qty * 3;
        $quad = (int) $request->quad_qty * 4;
        $quint = (int) $request->quintuple_qty * 5;
        $allocated = $double + $triple + $quad + $quint;

        // Validate allocated seats <= total seats
        if ($allocated > (int) $request->total_seat) {
            return back()
                ->withErrors(['allocated_seats' => 'Allocated seats cannot exceed total seats.'])
                ->withInput();
        }

        // check amount
        $mainAmount = $this->determineMainAmount(
            $request->subtotal ?? null,
            $request->total_amount ?? null
        );

        // Update quota if present
        // $today = now()->toDateString();
        // $activeSeasonIds = Season::where('start_date', '<=', $today)
        //     ->where('end_date', '>=', $today)
        //     ->pluck('id');

        // $quota = Qouta::where('agency_id', $agencyID)
        //     ->whereIn('season_id', $activeSeasonIds)
        //     ->first();

        // if ($quota) {
        //     if (strtolower($request->city) === 'makkah') {
        //         $quota->makka_used_qouta = $allocated;
        //     } elseif (strtolower($request->city) === 'madinah') {
        //         $quota->modina_used_qouta = $allocated;
        //     }
        //     $quota->save();
        // }

        // Store hotel
        Hotel::create([
            'agency_id' => $agencyID,
            'user_id' => $userID,
            'city' => $request->city,
            'season_id' => $request->season_id,
            'hotel_name' => $request->hotel_name,
            'owner_name' => $request->owner_name,
            'representative_name' => $request->representative_name,
            'phone_number' => $request->phone_number,
            'tasria_owner' => $request->tasria_owner,
            'tasria_number' => $request->tasria_number,
            'total_seat' => $request->total_seat,
            'double_bed' => $request->double_qty,
            'triple_bed' => $request->triple_qty,
            'quad_bed' => $request->quad_qty,
            'quintuple_bed' => $request->quintuple_qty,
            'allocated_seats' => $allocated,
            'without_tax_amount' => $request->subtotal,
            'with_tax_amount' => $request->total_amount,
            'amount' => $mainAmount,
        ]);

        return redirect()
            ->route('hotel.list')
            ->with('success', 'Hotel booking created successfully!');
    }

    public function show($id)
    {
        $hotel = Hotel::with(['agency', 'user', 'approvedBy'])->findOrFail($id);

        return view('admin.hotel.view', compact('hotel'));
    }

    // public function updateStatus(Request $request, $id)
    // {

    //     $user = auth()->user();
    //     $userRole = $user->role;
    //     $hotel = Hotel::findOrFail($id);
    //     $newStatus = $request->status;

    //     // Approve payment
    //     if ($newStatus === 1) {
    //         if (! in_array($userRole, [1, 2, 3])) {
    //             return back()->with('error', 'You are not authorized to approve payments.');
    //         }

    //         // prevent duplicate transaction
    //         $alreadyApproved = TransactionHistory::where([
    //             ['source_table', 'hotels'],
    //             ['source_id', $hotel->id],
    //         ])->exists();

    //         if ($alreadyApproved) {
    //             return back()->with('error', 'This payment has already been approved and recorded.');
    //         }

    //         $hotel->update([
    //             'status' => 1,
    //             'approved_by' => $user->id,
    //         ]);

    //         $agency = CompanyInfo::find($hotel->agency_id);
    //         $oldBal = $agency?->sar_acct ?? 0;
    //         $newBal = $oldBal - $hotel->amount;

    //         TransactionHistory::create([
    //             'agency_id' => $hotel->agency_id,
    //             'source_table' => 'hotels',
    //             'source_id' => $hotel->id,
    //             'currency' => 'SAR',
    //             'tnx_type' => 'Spend',
    //             'amount' => $hotel->amount,
    //             'note' => sprintf(
    //                 'Payment of SAR %.2f has been successfully approved by %s for hotel booking: %s (%s).',
    //                 $hotel->amount,
    //                 auth()->user()->name,
    //                 $hotel->hotel_name,
    //                 $hotel->city
    //             ),

    //             'old_balance' => $oldBal,
    //             'new_balance' => $newBal,
    //         ]);

    //         if ($agency) {
    //             $agency->update(['sar_acct' => $newBal]);
    //         }

    //         // ✅ NEW: Update quota when approving
    //         $today = now()->toDateString();
    //         $activeSeasonIds = Season::where('start_date', '<=', $today)
    //             ->where('end_date', '>=', $today)
    //             ->pluck('id');

    //         $quota = Qouta::where('agency_id', $hotel->agency_id)
    //             ->whereIn('season_id', $activeSeasonIds)
    //             ->first();

    //         if ($quota) {
    //             $allocated = $hotel->double_bed + $hotel->triple_bed +
    //                          $hotel->quad_bed + $hotel->quintuple_bed;
    //             if (strtolower($hotel->city) === 'makkah') {
    //                 $quota->makka_used_quota = max(0, $quota->makka_used_quota + $allocated);
    //             } elseif (strtolower($hotel->city) === 'madinah') {
    //                 $quota->modina_used_quota = max(0, $quota->modina_used_quota + $allocated);
    //             }

    //             $quota->save();
    //         } else {
    //             // Handle the case where no quota is found
    //             Log::warning('No quota found for the given agency and season.');
    //         }

    //         return $this->statusResponse($hotel);
    //     }

    //     // Reject / deactivate
    //     if (in_array($newStatus, [0, 2])) {
    //         if (in_array($userRole, [1, 2, 3])) {
    //             // If previously approved, rollback transaction
    //             if ($hotel->status == 1) {
    //                 TransactionHistory::where([
    //                     ['source_table', 'hotels'],
    //                     ['source_id', $hotel->id],
    //                 ])->delete();

    //                 if ($agency = CompanyInfo::find($hotel->agency_id)) {
    //                     $agency->increment('sar_acct', $hotel->amount);
    //                 }

    //                 // ✅ NEW: Update quota when panding
    //                 $today = now()->toDateString();
    //                 $activeSeasonIds = Season::where('start_date', '<=', $today)
    //                     ->where('end_date', '>=', $today)
    //                     ->pluck('id');

    //                 $quota = Qouta::where('agency_id', $hotel->agency_id)
    //                     ->whereIn('season_id', $activeSeasonIds)
    //                     ->first();

    //                 if ($quota) {
    //                     $allocated = $hotel->double_bed + $hotel->triple_bed +
    //                         $hotel->quad_bed + $hotel->quintuple_bed;

    //                     if (strtolower($hotel->city) === 'makkah') {
    //                         $quota->makka_used_qouta -= $allocated;
    //                     } elseif (strtolower($hotel->city) === 'madinah') {
    //                         $quota->modina_used_qouta -= $allocated;
    //                     }
    //                     $quota->save();
    //                 }
    //             }

    //             $hotel->update([
    //                 'status' => $newStatus,
    //                 'approved_by' => null,
    //             ]);
    //         } elseif (in_array($userRole, [4, 5])) {
    //             $hotel->update([
    //                 'status' => 0,
    //                 'approved_by' => null,
    //             ]);
    //         } else {
    //             return back()->with('error', 'You are not authorized to change payment status.');
    //         }

    //         return $this->statusResponse($hotel);
    //     }

    //     // fallback (shouldn’t hit due to validation)
    //     return back()->with('error', 'Invalid status.');
    // }

    public function updateStatus(Request $request, $id)
    {
        $request->validate([
            'status' => 'required|in:0,1,2',
        ]);

        $user = auth()->user();
        $userRole = $user->role;
        $hotel = Hotel::findOrFail($id);
        $newStatus = (int) $request->status;

        // Approve payment
        if ($newStatus === 1) {
            if (! in_array($userRole, [1, 2, 3])) {
                return back()->with('error', 'You are not authorized to approve payments.');
            }

            // prevent duplicate transaction
            $alreadyApproved = TransactionHistory::where([
                ['source_table', 'hotels'],
                ['source_id', $hotel->id],
            ])->exists();

            if ($alreadyApproved) {
                return back()->with('error', 'This payment has already been approved.');
            }

            $hotel->update([
                'status' => 1,
                'approved_by' => $user->id,
            ]);

            $agency = CompanyInfo::find($hotel->agency_id);
            $oldBal = $agency?->sar_acct ?? 0;
            $newBal = $oldBal - $hotel->amount;

            TransactionHistory::create([
                'agency_id' => $hotel->agency_id,
                'source_table' => 'hotels',
                'source_id' => $hotel->id,
                'currency' => 'SAR',
                'tnx_type' => 'Spend',
                'amount' => $hotel->amount,
                'note' => sprintf(
                    'Payment of SAR %.2f approved by %s for hotel: %s (%s).',
                    $hotel->amount,
                    $user->name,
                    $hotel->hotel_name,
                    $hotel->city
                ),
                'old_balance' => $oldBal,
                'new_balance' => $newBal,
            ]);

            if ($agency) {
                $agency->update(['sar_acct' => $newBal]);
            }

            // Update quota
            $today = now()->toDateString();
            $activeSeasonIds = Season::where('start_date', '<=', $today)
                ->where('end_date', '>=', $today)
                ->pluck('id');

            $quota = Qouta::where('agency_id', $hotel->agency_id)
                ->whereIn('season_id', $activeSeasonIds)
                ->first();

            if ($quota) {
                $allocated = $hotel->allocated_seats;

                if (strtolower($hotel->city) === 'makkah') {
                    $quota->makka_used_qouta += $allocated;
                } elseif (strtolower($hotel->city) === 'madinah') {
                    $quota->modina_used_qouta += $allocated;
                }

                $quota->save();
            }

            return back()->with('success', 'Status updated to Approved.');
        }

        // Reject / deactivate
        if (in_array($newStatus, [0, 2])) {
            if (in_array($userRole, [1, 2, 3])) {
                // rollback if previously approved
                if ($hotel->status == 1) {
                    TransactionHistory::where([
                        ['source_table', 'hotels'],
                        ['source_id', $hotel->id],
                    ])->delete();

                    if ($agency = CompanyInfo::find($hotel->agency_id)) {
                        $agency->increment('sar_acct', $hotel->amount);
                    }

                    // update quota rollback
                    $today = now()->toDateString();
                    $activeSeasonIds = Season::where('start_date', '<=', $today)
                        ->where('end_date', '>=', $today)
                        ->pluck('id');

                    $quota = Qouta::where('agency_id', $hotel->agency_id)
                        ->whereIn('season_id', $activeSeasonIds)
                        ->first();

                    if ($quota) {
                        $allocated = $hotel->allocated_seats;

                        if (strtolower($hotel->city) === 'makkah') {
                            $quota->makka_used_qouta -= $allocated;
                        } elseif (strtolower($hotel->city) === 'madinah') {
                            $quota->modina_used_qouta -= $allocated;
                        }

                        $quota->save();
                    }
                }

                $hotel->update([
                    'status' => $newStatus,
                    'approved_by' => null,
                ]);
            } elseif (in_array($userRole, [4, 5])) {
                $hotel->update([
                    'status' => 0,
                    'approved_by' => null,
                ]);
            } else {
                return back()->with('error', 'You are not authorized to change status.');
            }

            return back()->with('success', 'Status updated successfully.');
        }

        return back()->with('error', 'Invalid status.');
    }

    private function statusResponse(Hotel $hotel)
    {
        return response()->json([
            'success' => true,
            'message' => 'Status updated successfully.',
            'status_label' => match ($hotel->status) {
                1 => '<span class="badge bg-success">Active</span>',
                2 => '<span class="badge bg-danger">Blocked</span>',
                default => '<span class="badge bg-secondary">Inactive</span>',
            },
        ]);
    }

    /**
     * Decide whether to use subtotal or total_amount.
     *
     * @throws \Illuminate\Validation\ValidationException
     */
    private function determineMainAmount(?float $subtotal, ?float $totalAmount): float
    {
        // Use subtotal if provided and total is empty/zero
        if ($subtotal > 0 && ($totalAmount === null || $totalAmount <= 0)) {
            return $subtotal;
        }

        // Use total if provided and subtotal is empty/zero
        if ($totalAmount > 0 && ($subtotal === null || $subtotal <= 0)) {
            return $totalAmount;
        }

        // Both positive: not allowed
        if ($subtotal > 0 && $totalAmount > 0) {
            throw ValidationException::withMessages([
                'amount' => 'Please enter only one: "Total Amount (without tax & VAT)" or "Total Amount (with tax & VAT)".',
            ]);
        }

        // Neither valid: also not allowed
        throw ValidationException::withMessages([
            'amount' => 'Please provide a positive Subtotal or Total Amount.',
        ]);
    }
}