# 🏪 RESTAURANT MANAGEMENT MODULE

## ✅ Complete Implementation

---

## 📦 1. Database Migration

**File:** `database/migrations/2024_01_01_000001_create_restaurants_table.php`

```php
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('restaurants', function (Blueprint $table) {
            $table->id();
            $table->foreignId('user_id')->constrained()->onDelete('cascade');
            $table->string('name');
            $table->string('slug')->unique();
            $table->text('description')->nullable();
            $table->string('phone');
            $table->string('email')->nullable();
            $table->text('address');
            $table->decimal('latitude', 10, 7);
            $table->decimal('longitude', 10, 7);
            $table->decimal('delivery_radius', 8, 2)->default(5);
            $table->decimal('minimum_order', 10, 2)->default(0);
            $table->decimal('delivery_fee', 10, 2)->default(0);
            $table->decimal('service_charge_percentage', 5, 2)->default(0);
            $table->decimal('tax_percentage', 5, 2)->default(0);
            $table->time('opening_time')->nullable();
            $table->time('closing_time')->nullable();
            $table->enum('status', ['pending', 'approved', 'suspended', 'rejected'])->default('pending');
            $table->enum('operational_status', ['open', 'closed', 'busy'])->default('closed');
            $table->string('logo')->nullable();
            $table->string('cover_image')->nullable();
            $table->json('images')->nullable();
            $table->decimal('rating', 3, 2)->default(0);
            $table->integer('total_reviews')->default(0);
            $table->boolean('is_featured')->default(false);
            $table->timestamps();
            $table->softDeletes();
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('restaurants');
    }
};
```

**Run Migration:**
```bash
php artisan migrate
```

---

## 🎯 2. Restaurant Model

**File:** `app/Models/Restaurant.php`

```php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphMany;

class Restaurant extends Model
{
    use SoftDeletes;

    protected $fillable = [
        'user_id', 'name', 'slug', 'description', 'phone', 'email', 'address',
        'latitude', 'longitude', 'delivery_radius', 'minimum_order', 'delivery_fee',
        'service_charge_percentage', 'tax_percentage', 'opening_time', 'closing_time',
        'status', 'operational_status', 'logo', 'cover_image', 'images', 'rating',
        'total_reviews', 'is_featured'
    ];

    protected $casts = [
        'images' => 'array',
        'latitude' => 'decimal:7',
        'longitude' => 'decimal:7',
        'delivery_radius' => 'decimal:2',
        'minimum_order' => 'decimal:2',
        'delivery_fee' => 'decimal:2',
        'service_charge_percentage' => 'decimal:2',
        'tax_percentage' => 'decimal:2',
        'rating' => 'decimal:2',
        'is_featured' => 'boolean',
    ];

    // Relationships
    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }

    public function products(): HasMany
    {
        return $this->hasMany(Product::class);
    }

    public function orders(): HasMany
    {
        return $this->hasMany(Order::class);
    }

    public function reviews(): MorphMany
    {
        return $this->morphMany(Review::class, 'reviewable');
    }

    // Scopes
    public function scopeApproved($query)
    {
        return $query->where('status', 'approved');
    }

    public function scopeOpen($query)
    {
        return $query->where('operational_status', 'open');
    }
}
```

---

## 🎮 3. Restaurant Controller

**File:** `app/Http/Controllers/API/RestaurantController.php`

```php
<?php

namespace App\Http\Controllers\API;

use App\Http\Controllers\Controller;
use App\Models\Restaurant;
use Illuminate\Http\Request;
use Illuminate\Support\Str;

class RestaurantController extends Controller
{
    // Public: List approved restaurants
    public function index(Request $request)
    {
        $query = Restaurant::with('user')->where('status', 'approved');

        if ($request->search) {
            $query->where('name', 'like', "%{$request->search}%");
        }

        if ($request->is_featured) {
            $query->where('is_featured', true);
        }

        $restaurants = $query->paginate(12);

        return response()->json($restaurants);
    }

    // Public: Get restaurant details
    public function show($id)
    {
        $restaurant = Restaurant::with(['products.category', 'products.variations', 'products.addons'])
            ->findOrFail($id);

        return response()->json($restaurant);
    }

    // Manager: Create restaurant
    public function store(Request $request)
    {
        $validated = $request->validate([
            'name' => 'required|string|max:255',
            'description' => 'nullable|string',
            'phone' => 'required|string|max:20',
            'email' => 'nullable|email',
            'address' => 'required|string',
            'latitude' => 'required|numeric|between:-90,90',
            'longitude' => 'required|numeric|between:-180,180',
            'delivery_radius' => 'nullable|numeric|min:0',
            'opening_time' => 'nullable|date_format:H:i',
            'closing_time' => 'nullable|date_format:H:i',
        ]);

        $restaurant = Restaurant::create([
            'user_id' => $request->user()->id,
            'name' => $validated['name'],
            'slug' => Str::slug($validated['name']),
            'description' => $validated['description'] ?? null,
            'phone' => $validated['phone'],
            'email' => $validated['email'] ?? null,
            'address' => $validated['address'],
            'latitude' => $validated['latitude'],
            'longitude' => $validated['longitude'],
            'delivery_radius' => $validated['delivery_radius'] ?? 5,
            'opening_time' => $validated['opening_time'] ?? null,
            'closing_time' => $validated['closing_time'] ?? null,
            'status' => 'pending', // Requires admin approval
        ]);

        return response()->json([
            'message' => 'Restaurant created successfully. Awaiting admin approval.',
            'restaurant' => $restaurant
        ], 201);
    }

    // Manager: Update own restaurant
    public function update(Request $request, $id)
    {
        $restaurant = Restaurant::findOrFail($id);

        // Check if user owns this restaurant
        if ($restaurant->user_id !== $request->user()->id && !$request->user()->hasRole('admin')) {
            return response()->json(['message' => 'Unauthorized'], 403);
        }

        $validated = $request->validate([
            'name' => 'sometimes|string|max:255',
            'description' => 'nullable|string',
            'phone' => 'sometimes|string|max:20',
            'email' => 'nullable|email',
            'address' => 'sometimes|string',
            'latitude' => 'sometimes|numeric|between:-90,90',
            'longitude' => 'sometimes|numeric|between:-180,180',
            'delivery_radius' => 'nullable|numeric|min:0',
            'opening_time' => 'nullable|date_format:H:i',
            'closing_time' => 'nullable|date_format:H:i',
            'operational_status' => 'sometimes|in:open,closed,busy',
        ]);

        if (isset($validated['name'])) {
            $validated['slug'] = Str::slug($validated['name']);
        }

        $restaurant->update($validated);

        return response()->json([
            'message' => 'Restaurant updated successfully',
            'restaurant' => $restaurant
        ]);
    }

    // Manager: Delete own restaurant
    public function destroy(Request $request, $id)
    {
        $restaurant = Restaurant::findOrFail($id);

        if ($restaurant->user_id !== $request->user()->id && !$request->user()->hasRole('admin')) {
            return response()->json(['message' => 'Unauthorized'], 403);
        }

        $restaurant->delete();

        return response()->json(['message' => 'Restaurant deleted successfully']);
    }

    // Manager: Get my restaurants
    public function myRestaurants(Request $request)
    {
        $restaurants = Restaurant::where('user_id', $request->user()->id)->get();

        return response()->json($restaurants);
    }

    // Manager: Update operational status
    public function updateStatus(Request $request, $id)
    {
        $restaurant = Restaurant::findOrFail($id);

        if ($restaurant->user_id !== $request->user()->id) {
            return response()->json(['message' => 'Unauthorized'], 403);
        }

        $validated = $request->validate([
            'operational_status' => 'required|in:open,closed,busy',
        ]);

        $restaurant->update($validated);

        return response()->json([
            'message' => 'Status updated successfully',
            'restaurant' => $restaurant
        ]);
    }
}
```

---

## 👑 4. Admin Controller (Restaurant Management)

**File:** `app/Http/Controllers/API/AdminController.php`

```php
<?php

namespace App\Http\Controllers\API;

use App\Http\Controllers\Controller;
use App\Models\Restaurant;
use Illuminate\Http\Request;

class AdminController extends Controller
{
    // Get pending restaurants
    public function pendingRestaurants()
    {
        $restaurants = Restaurant::where('status', 'pending')
            ->with('user')
            ->latest()
            ->get();

        return response()->json($restaurants);
    }

    // Approve restaurant
    public function approveRestaurant($id)
    {
        $restaurant = Restaurant::findOrFail($id);
        $restaurant->update(['status' => 'approved']);

        return response()->json([
            'message' => 'Restaurant approved successfully',
            'restaurant' => $restaurant
        ]);
    }

    // Suspend restaurant
    public function suspendRestaurant($id)
    {
        $restaurant = Restaurant::findOrFail($id);
        $restaurant->update(['status' => 'suspended']);

        return response()->json([
            'message' => 'Restaurant suspended successfully',
            'restaurant' => $restaurant
        ]);
    }

    // Reject restaurant
    public function rejectRestaurant(Request $request, $id)
    {
        $restaurant = Restaurant::findOrFail($id);
        $restaurant->update(['status' => 'rejected']);

        return response()->json([
            'message' => 'Restaurant rejected',
            'restaurant' => $restaurant
        ]);
    }

    // Get all restaurants (admin view)
    public function allRestaurants(Request $request)
    {
        $query = Restaurant::with('user');

        if ($request->status) {
            $query->where('status', $request->status);
        }

        $restaurants = $query->latest()->paginate(20);

        return response()->json($restaurants);
    }
}
```

---

## 🛣️ 5. API Routes

**File:** `routes/api.php`

```php
<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\API\RestaurantController;
use App\Http\Controllers\API\AdminController;

// Public routes
Route::get('/restaurants', [RestaurantController::class, 'index']);
Route::get('/restaurants/{id}', [RestaurantController::class, 'show']);

// Protected routes
Route::middleware('auth:sanctum')->group(function () {
    
    // Manager routes
    Route::middleware('role:manager')->group(function () {
        Route::post('/restaurants', [RestaurantController::class, 'store']);
        Route::put('/restaurants/{id}', [RestaurantController::class, 'update']);
        Route::delete('/restaurants/{id}', [RestaurantController::class, 'destroy']);
        Route::get('/my-restaurants', [RestaurantController::class, 'myRestaurants']);
        Route::patch('/restaurants/{id}/status', [RestaurantController::class, 'updateStatus']);
    });

    // Admin routes
    Route::middleware('role:admin')->group(function () {
        Route::get('/admin/restaurants', [AdminController::class, 'allRestaurants']);
        Route::get('/admin/restaurants/pending', [AdminController::class, 'pendingRestaurants']);
        Route::post('/admin/restaurants/{id}/approve', [AdminController::class, 'approveRestaurant']);
        Route::post('/admin/restaurants/{id}/suspend', [AdminController::class, 'suspendRestaurant']);
        Route::post('/admin/restaurants/{id}/reject', [AdminController::class, 'rejectRestaurant']);
    });
});
```

---

## 📡 API Examples

### 1. List Restaurants (Public)
```http
GET /api/restaurants?search=pizza&is_featured=1
```

**Response:**
```json
{
  "data": [
    {
      "id": 1,
      "name": "Pizza Palace",
      "address": "123 Main St",
      "latitude": 6.9271,
      "longitude": 79.8612,
      "delivery_radius": 5,
      "opening_time": "10:00",
      "closing_time": "22:00",
      "status": "approved",
      "operational_status": "open",
      "rating": 4.5
    }
  ]
}
```

---

### 2. Create Restaurant (Manager)
```http
POST /api/restaurants
Authorization: Bearer {manager_token}
Content-Type: application/json

{
  "name": "Burger House",
  "description": "Best burgers in town",
  "phone": "0771234567",
  "email": "info@burgerhouse.com",
  "address": "456 Food Street, Colombo",
  "latitude": 6.9271,
  "longitude": 79.8612,
  "delivery_radius": 10,
  "opening_time": "11:00",
  "closing_time": "23:00"
}
```

**Response (201):**
```json
{
  "message": "Restaurant created successfully. Awaiting admin approval.",
  "restaurant": {
    "id": 2,
    "name": "Burger House",
    "status": "pending",
    ...
  }
}
```

---

### 3. Update Restaurant (Manager)
```http
PUT /api/restaurants/2
Authorization: Bearer {manager_token}
Content-Type: application/json

{
  "opening_time": "10:00",
  "closing_time": "00:00",
  "operational_status": "open"
}
```

**Response:**
```json
{
  "message": "Restaurant updated successfully",
  "restaurant": {...}
}
```

---

### 4. Get My Restaurants (Manager)
```http
GET /api/my-restaurants
Authorization: Bearer {manager_token}
```

**Response:**
```json
[
  {
    "id": 2,
    "name": "Burger House",
    "status": "pending",
    ...
  }
]
```

---

### 5. Approve Restaurant (Admin)
```http
POST /api/admin/restaurants/2/approve
Authorization: Bearer {admin_token}
```

**Response:**
```json
{
  "message": "Restaurant approved successfully",
  "restaurant": {
    "id": 2,
    "status": "approved"
  }
}
```

---

### 6. Get Pending Restaurants (Admin)
```http
GET /api/admin/restaurants/pending
Authorization: Bearer {admin_token}
```

**Response:**
```json
[
  {
    "id": 2,
    "name": "Burger House",
    "status": "pending",
    "user": {
      "name": "Manager User"
    }
  }
]
```

---

## ✅ Features Implemented

- ✅ Create restaurant (Manager)
- ✅ Update restaurant (Manager/Admin)
- ✅ Delete restaurant (Manager/Admin)
- ✅ List approved restaurants (Public)
- ✅ View restaurant details (Public)
- ✅ Get my restaurants (Manager)
- ✅ Update operational status (Manager)
- ✅ Approve restaurant (Admin)
- ✅ Suspend restaurant (Admin)
- ✅ Reject restaurant (Admin)
- ✅ List pending restaurants (Admin)
- ✅ Search & filter restaurants
- ✅ Role-based access control
- ✅ Validation rules
- ✅ Soft deletes

---

## 🔒 Access Control

| Action | Admin | Manager | Customer |
|--------|-------|---------|----------|
| List restaurants | ✅ | ✅ | ✅ |
| View details | ✅ | ✅ | ✅ |
| Create | ✅ | ✅ | ❌ |
| Update own | ✅ | ✅ | ❌ |
| Delete own | ✅ | ✅ | ❌ |
| Approve | ✅ | ❌ | ❌ |
| Suspend | ✅ | ❌ | ❌ |

---

## 🧪 Testing

```bash
# 1. Login as manager
POST /api/login
{"email": "manager@test.com", "password": "password"}

# 2. Create restaurant
POST /api/restaurants
{...restaurant data...}

# 3. Login as admin
POST /api/login
{"email": "admin@test.com", "password": "password"}

# 4. Approve restaurant
POST /api/admin/restaurants/{id}/approve
```

---

**RESTAURANT MANAGEMENT MODULE COMPLETE!** 🏪✅
