Files
kulakpos_web/public/restaurant/config/restaurant-delivery.php

666 lines
24 KiB
PHP

<?php
declare(strict_types=1);
return [
/*
|--------------------------------------------------------------------------
| Module Enable/Disable
|--------------------------------------------------------------------------
*/
'enabled' => env('RESTAURANT_DELIVERY_ENABLED', true),
/*
|--------------------------------------------------------------------------
| Firebase Configuration
|--------------------------------------------------------------------------
| All Firebase credentials are loaded from environment variables.
| See .env.example for required variables.
*/
'firebase' => [
'enabled' => env('FIREBASE_ENABLED', false),
// Firebase Credentials - Two options:
// Option 1: Path to service account JSON file
'credentials_path' => env('FIREBASE_CREDENTIALS', storage_path('app/firebase/firebase_credentials.json')),
// Option 2: Inline credentials (JSON string from env - useful for Heroku/Docker)
'credentials_json' => env('FIREBASE_CREDENTIALS_JSON'),
// Firebase Project Settings (from Firebase Console)
'project_id' => env('FIREBASE_PROJECT_ID'),
'database_url' => env('FIREBASE_DATABASE_URL'),
'storage_bucket' => env('FIREBASE_STORAGE_BUCKET'),
// Firebase Web Config (for client-side SDK - pass to frontend)
'web_config' => [
'api_key' => env('FIREBASE_API_KEY'),
'auth_domain' => env('FIREBASE_AUTH_DOMAIN'),
'database_url' => env('FIREBASE_DATABASE_URL'),
'project_id' => env('FIREBASE_PROJECT_ID'),
'storage_bucket' => env('FIREBASE_STORAGE_BUCKET'),
'messaging_sender_id' => env('FIREBASE_MESSAGING_SENDER_ID'),
'app_id' => env('FIREBASE_APP_ID'),
'measurement_id' => env('FIREBASE_MEASUREMENT_ID'),
],
// Firebase Cloud Messaging (FCM) for Push Notifications
'fcm' => [
'server_key' => env('FIREBASE_SERVER_KEY'),
'sender_id' => env('FIREBASE_MESSAGING_SENDER_ID'),
],
// Realtime Database paths (customizable via env)
'paths' => [
'riders_location' => env('FIREBASE_PATH_RIDERS_LOCATION', 'riders/{rider_id}/live_location'),
'delivery_tracking' => env('FIREBASE_PATH_DELIVERY_TRACKING', 'deliveries/{delivery_id}/tracking'),
'rider_status' => env('FIREBASE_PATH_RIDER_STATUS', 'riders/{rider_id}/status'),
'delivery_status' => env('FIREBASE_PATH_DELIVERY_STATUS', 'deliveries/{delivery_id}/status'),
'rider_assignments' => env('FIREBASE_PATH_RIDER_ASSIGNMENTS', 'riders/{rider_id}/assignments'),
],
// Location update settings
'location' => [
'update_interval' => env('FIREBASE_LOCATION_INTERVAL', 5), // seconds
'stale_threshold' => env('FIREBASE_STALE_THRESHOLD', 30), // seconds
'offline_threshold' => env('FIREBASE_OFFLINE_THRESHOLD', 120), // seconds
'accuracy_threshold' => env('FIREBASE_ACCURACY_THRESHOLD', 50), // meters
'min_distance_change' => env('FIREBASE_MIN_DISTANCE', 10), // meters
],
// Firestore collections (if using Firestore instead of Realtime DB)
'firestore' => [
'enabled' => env('FIRESTORE_ENABLED', false),
'collections' => [
'deliveries' => env('FIRESTORE_COLLECTION_DELIVERIES', 'deliveries'),
'riders' => env('FIRESTORE_COLLECTION_RIDERS', 'riders'),
'tracking_history' => env('FIRESTORE_COLLECTION_TRACKING', 'tracking_history'),
'ratings' => env('FIRESTORE_COLLECTION_RATINGS', 'ratings'),
],
],
],
/*
|--------------------------------------------------------------------------
| Maps Configuration
|--------------------------------------------------------------------------
| All map API credentials are loaded from environment variables.
| Google Maps: Enable APIs at https://console.cloud.google.com/
| Mapbox: Get token at https://www.mapbox.com/
*/
'maps' => [
'enabled' => env('GOOGLE_ENABLED', false),
'provider' => env('MAPS_PROVIDER', 'google'), // google, mapbox
'google' => [
// Google Maps API Key - Enable: Maps JS, Directions, Distance Matrix, Geocoding
'api_key' => env('GOOGLE_MAPS_API_KEY'),
// Server-side API Key (optional - for backend operations)
'server_api_key' => env('GOOGLE_MAPS_SERVER_KEY', env('GOOGLE_MAPS_API_KEY')),
// API Features
'directions_api' => env('GOOGLE_MAPS_DIRECTIONS_API', true),
'distance_matrix_api' => env('GOOGLE_MAPS_DISTANCE_MATRIX_API', true),
'geocoding_api' => env('GOOGLE_MAPS_GEOCODING_API', true),
'places_api' => env('GOOGLE_MAPS_PLACES_API', false),
// Client config (for frontend)
'client_config' => [
'api_key' => env('GOOGLE_MAPS_API_KEY'),
'libraries' => ['places', 'geometry', 'drawing'],
'region' => env('GOOGLE_MAPS_REGION', 'BD'),
'language' => env('GOOGLE_MAPS_LANGUAGE', 'en'),
],
],
'mapbox' => [
'access_token' => env('MAPBOX_ACCESS_TOKEN'),
'public_token' => env('MAPBOX_PUBLIC_TOKEN', env('MAPBOX_ACCESS_TOKEN')),
'directions_api' => env('MAPBOX_DIRECTIONS_API', true),
'style' => env('MAPBOX_STYLE', 'mapbox://styles/mapbox/streets-v11'),
],
// Route settings
'route' => [
'cache_duration' => env('MAPS_ROUTE_CACHE_DURATION', 300), // 5 minutes
'alternatives' => env('MAPS_ROUTE_ALTERNATIVES', true),
'traffic_model' => env('MAPS_TRAFFIC_MODEL', 'best_guess'), // best_guess, pessimistic, optimistic
'avoid' => env('MAPS_ROUTE_AVOID', ''), // tolls, highways, ferries
],
],
/*
|--------------------------------------------------------------------------
| Distance Configuration
|--------------------------------------------------------------------------
*/
'distance' => [
'unit' => env('RESTAURANT_DELIVERY_DISTANCE_UNIT', 'km'), // km, miles
'calculation_method' => env('RESTAURANT_DELIVERY_DISTANCE_METHOD', 'google_api'), // haversine, google_api, mapbox_api
'earth_radius_km' => 6371,
'earth_radius_miles' => 3959,
],
/*
|--------------------------------------------------------------------------
| Real-Time Tracking Animation
|--------------------------------------------------------------------------
*/
'tracking' => [
'animation' => [
'enabled' => true,
'interpolation_points' => 10, // smooth animation points between updates
'animation_duration' => 1000, // ms per animation step
'easing' => 'linear', // linear, ease-in-out
],
'map' => [
'default_zoom' => 15,
'tracking_zoom' => 17,
'auto_center' => true,
'show_route_polyline' => true,
'show_eta' => true,
'show_distance' => true,
],
'markers' => [
'rider' => [
'icon' => '/images/markers/rider.png',
'size' => [40, 40],
'anchor' => [20, 40],
],
'restaurant' => [
'icon' => '/images/markers/restaurant.png',
'size' => [40, 40],
'anchor' => [20, 40],
],
'customer' => [
'icon' => '/images/markers/customer.png',
'size' => [40, 40],
'anchor' => [20, 40],
],
],
'polyline' => [
'color' => '#4A90D9',
'weight' => 4,
'opacity' => 0.8,
'completed_color' => '#10B981',
],
],
/*
|--------------------------------------------------------------------------
| Delivery Flow Configuration
|--------------------------------------------------------------------------
*/
'delivery_flow' => [
'statuses' => [
'pending' => [
'label' => 'Order Placed',
'description' => 'Waiting for restaurant confirmation',
'color' => '#6B7280',
],
'confirmed' => [
'label' => 'Order Confirmed',
'description' => 'Restaurant is preparing your food',
'color' => '#3B82F6',
],
'preparing' => [
'label' => 'Preparing',
'description' => 'Your food is being prepared',
'color' => '#F59E0B',
],
'ready_for_pickup' => [
'label' => 'Ready for Pickup',
'description' => 'Food is ready, waiting for rider',
'color' => '#8B5CF6',
],
'rider_assigned' => [
'label' => 'Rider Assigned',
'description' => 'A rider has been assigned',
'color' => '#06B6D4',
],
'rider_at_restaurant' => [
'label' => 'Rider at Restaurant',
'description' => 'Rider has arrived at restaurant',
'color' => '#14B8A6',
],
'picked_up' => [
'label' => 'Picked Up',
'description' => 'Rider has picked up your order',
'color' => '#22C55E',
],
'on_the_way' => [
'label' => 'On The Way',
'description' => 'Rider is on the way to you',
'color' => '#10B981',
],
'arrived' => [
'label' => 'Arrived',
'description' => 'Rider has arrived at your location',
'color' => '#059669',
],
'delivered' => [
'label' => 'Delivered',
'description' => 'Order has been delivered',
'color' => '#047857',
],
'cancelled' => [
'label' => 'Cancelled',
'description' => 'Order has been cancelled',
'color' => '#EF4444',
],
'failed' => [
'label' => 'Failed',
'description' => 'Delivery failed',
'color' => '#DC2626',
],
],
'auto_status_updates' => [
'geofence_radius' => 100, // meters - auto update status when rider enters this radius
'arrival_confirmation' => true, // require rider to confirm arrival
],
],
/*
|--------------------------------------------------------------------------
| Rider Assignment Configuration
|--------------------------------------------------------------------------
*/
'assignment' => [
'auto_assign' => env('RESTAURANT_DELIVERY_AUTO_ASSIGN', true),
'assignment_radius' => env('RESTAURANT_DELIVERY_ASSIGNMENT_RADIUS', 5), // km
'max_concurrent_orders' => env('RESTAURANT_DELIVERY_MAX_CONCURRENT', 3),
'assignment_timeout' => env('RESTAURANT_DELIVERY_ASSIGNMENT_TIMEOUT', 60), // seconds
'max_reassignments' => 3,
// Scoring weights for auto-assignment
'scoring' => [
'distance_weight' => 40, // Closer is better
'rating_weight' => 25, // Higher rating is better
'acceptance_rate_weight' => 15,
'current_orders_weight' => 10, // Fewer current orders is better
'experience_weight' => 10, // More deliveries is better
],
// Broadcast assignment to multiple riders
'broadcast' => [
'enabled' => true,
'max_riders' => 5,
'accept_timeout' => 30, // seconds
],
],
/*
|--------------------------------------------------------------------------
| Rating System Configuration
|--------------------------------------------------------------------------
*/
'rating' => [
'enabled' => true,
'min_rating' => 1,
'max_rating' => 5,
'allow_review' => true,
'review_max_length' => 500,
'rating_window' => 72, // hours after delivery to submit rating
'anonymous_reviews' => false,
// Rating categories
'categories' => [
'overall' => ['label' => 'Overall Experience', 'required' => true],
'speed' => ['label' => 'Delivery Speed', 'required' => false],
'communication' => ['label' => 'Communication', 'required' => false],
'food_condition' => ['label' => 'Food Condition', 'required' => false],
'professionalism' => ['label' => 'Professionalism', 'required' => false],
],
// Rating impact thresholds
'thresholds' => [
'minimum_for_assignment' => 3.5, // Minimum rating to receive orders
'warning_threshold' => 3.0, // Send warning notification
'suspension_threshold' => 2.5, // Auto-suspend rider
'minimum_ratings_for_threshold' => 10, // Min ratings before thresholds apply
],
// Rating display
'display' => [
'show_on_tracking' => true,
'show_review_count' => true,
'show_recent_reviews' => 3,
],
],
/*
|--------------------------------------------------------------------------
| Tip System Configuration
|--------------------------------------------------------------------------
*/
'tip' => [
'enabled' => true,
'allow_pre_delivery' => true, // Tip at checkout
'allow_post_delivery' => true, // Tip after delivery
'post_delivery_window' => 24, // hours
// Pre-set tip options
'preset_amounts' => [20, 50, 100, 200], // In local currency
'preset_percentages' => [5, 10, 15, 20], // Of order total
'default_type' => 'amount', // amount, percentage
// Custom tip limits
'min_tip' => 10,
'max_tip' => 1000,
'max_percentage' => 50,
// Tip distribution
'rider_share' => 100, // Percentage of tip that goes to rider
'platform_share' => 0,
// Display
'show_suggested' => true,
'suggested_message' => 'Show appreciation for great service!',
],
/*
|--------------------------------------------------------------------------
| Pricing Configuration
|--------------------------------------------------------------------------
*/
'pricing' => [
'currency' => env('RESTAURANT_DELIVERY_CURRENCY', 'BDT'),
'currency_symbol' => env('RESTAURANT_DELIVERY_CURRENCY_SYMBOL', '৳'),
'default' => [
'base_fare' => 30.00,
'minimum_fare' => 30.00,
'per_km_charge' => 8.00,
'free_distance' => 0.5, // First 0.5 km free
'max_distance' => 20.00,
],
// Surge pricing
'surge' => [
'enabled' => true,
'auto_calculate' => true,
'min_multiplier' => 1.0,
'max_multiplier' => 3.0,
// Surge triggers
'triggers' => [
'high_demand' => [
'threshold' => 0.8, // 80% of riders busy
'multiplier' => 1.5,
],
'very_high_demand' => [
'threshold' => 0.95,
'multiplier' => 2.0,
],
'bad_weather' => [
'enabled' => true,
'multiplier' => 1.3,
],
],
],
// Peak hours
'peak_hours' => [
'enabled' => true,
'multiplier' => 1.3,
'slots' => [
['start' => '12:00', 'end' => '14:00', 'days' => [1, 2, 3, 4, 5, 6, 7]],
['start' => '19:00', 'end' => '22:00', 'days' => [1, 2, 3, 4, 5, 6, 7]],
],
],
// Late night
'late_night' => [
'enabled' => true,
'multiplier' => 1.25,
'start' => '23:00',
'end' => '06:00',
],
// Small order fee
'small_order' => [
'enabled' => true,
'threshold' => 200, // Order total below this
'fee' => 15,
],
// Restaurant-specific pricing override
'restaurant_override' => true, // Allow restaurants to set custom delivery fees
],
/*
|--------------------------------------------------------------------------
| Rider Earnings Configuration
|--------------------------------------------------------------------------
*/
'earnings' => [
// Commission models
'commission_models' => [
'fixed' => [
'label' => 'Fixed per delivery',
'default_rate' => 30,
],
'percentage' => [
'label' => 'Percentage of delivery fee',
'default_rate' => 70, // Rider gets 70%
],
'per_km' => [
'label' => 'Per kilometer',
'default_rate' => 8,
],
'hybrid' => [
'label' => 'Base + per km',
'base_rate' => 20,
'per_km_rate' => 5,
],
],
// Bonuses
'bonuses' => [
'peak_hour_bonus' => [
'enabled' => true,
'amount' => 10,
'type' => 'fixed', // fixed, percentage
],
'rain_bonus' => [
'enabled' => true,
'amount' => 15,
'type' => 'fixed',
],
'consecutive_delivery_bonus' => [
'enabled' => true,
'threshold' => 5, // After 5 consecutive deliveries
'amount' => 50,
],
'rating_bonus' => [
'enabled' => true,
'min_rating' => 4.8,
'amount' => 5, // Per delivery
],
'weekly_target_bonus' => [
'enabled' => true,
'targets' => [
['deliveries' => 50, 'bonus' => 500],
['deliveries' => 100, 'bonus' => 1200],
['deliveries' => 150, 'bonus' => 2000],
],
],
],
// Penalties
'penalties' => [
'cancellation' => [
'enabled' => true,
'amount' => 20,
'free_cancellations' => 2, // Per day
],
'late_delivery' => [
'enabled' => true,
'threshold' => 15, // Minutes late
'amount' => 10,
],
],
// Payout settings
'payout' => [
'frequency' => 'weekly', // daily, weekly, monthly
'minimum_amount' => 500,
'auto_payout' => true,
'payout_day' => 'monday', // For weekly
'payment_methods' => ['bank_transfer', 'bkash', 'nagad', 'rocket'],
],
],
/*
|--------------------------------------------------------------------------
| Notifications Configuration
|--------------------------------------------------------------------------
*/
'notifications' => [
'channels' => ['database', 'push', 'sms'],
'push' => [
'provider' => env('PUSH_PROVIDER', 'firebase'), // firebase, onesignal
'firebase_server_key' => env('FIREBASE_SERVER_KEY'),
],
'sms' => [
'provider' => env('SMS_PROVIDER', 'twilio'),
'enabled_for' => ['rider_assigned', 'out_for_delivery', 'delivered'],
],
// Customer notifications
'customer' => [
'order_confirmed' => true,
'rider_assigned' => true,
'rider_at_restaurant' => true,
'out_for_delivery' => true,
'arrived' => true,
'delivered' => true,
'delayed' => true,
],
// Rider notifications
'rider' => [
'new_order' => true,
'order_cancelled' => true,
'customer_message' => true,
'bonus_earned' => true,
'payout_processed' => true,
],
// Restaurant notifications
'restaurant' => [
'new_order' => true,
'rider_arriving' => true,
'rider_picked_up' => true,
'delivery_completed' => true,
'rating_received' => true,
],
],
/*
|--------------------------------------------------------------------------
| Edge Case Handling
|--------------------------------------------------------------------------
*/
'edge_cases' => [
// GPS issues
'gps_off' => [
'detection_timeout' => 60, // seconds
'action' => 'notify_rider', // notify_rider, reassign, pause_tracking
'max_offline_duration' => 300, // 5 minutes before reassignment
],
// Rider offline
'rider_offline' => [
'grace_period' => 120, // seconds
'auto_reassign' => true,
'notify_customer' => true,
],
// Route deviation
'route_deviation' => [
'enabled' => true,
'threshold' => 500, // meters off route
'action' => 'notify_customer', // notify_customer, notify_admin
],
// Delivery timeout
'delivery_timeout' => [
'enabled' => true,
'threshold' => 60, // minutes
'action' => 'escalate', // escalate, auto_refund
],
// Contact failure
'contact_failure' => [
'max_attempts' => 3,
'wait_time' => 300, // 5 minutes
'action' => 'return_to_restaurant',
],
],
/*
|--------------------------------------------------------------------------
| Cache Configuration
|--------------------------------------------------------------------------
*/
'cache' => [
'driver' => env('RESTAURANT_DELIVERY_CACHE_DRIVER', 'redis'),
'prefix' => 'restaurant_delivery_',
'ttl' => [
'rider_location' => 30, // seconds
'zone_pricing' => 3600, // 1 hour
'route_calculation' => 300, // 5 minutes
'rider_stats' => 300, // 5 minutes
'surge_pricing' => 60, // 1 minute
],
],
/*
|--------------------------------------------------------------------------
| Queue Configuration
|--------------------------------------------------------------------------
*/
'queue' => [
'connection' => env('RESTAURANT_DELIVERY_QUEUE_CONNECTION', 'redis'),
'queues' => [
'assignment' => 'restaurant-delivery-assignment',
'tracking' => 'restaurant-delivery-tracking',
'notifications' => 'restaurant-delivery-notifications',
'earnings' => 'restaurant-delivery-earnings',
'analytics' => 'restaurant-delivery-analytics',
],
],
/*
|--------------------------------------------------------------------------
| Logging Configuration
|--------------------------------------------------------------------------
*/
'logging' => [
'channel' => env('RESTAURANT_DELIVERY_LOG_CHANNEL', 'restaurant-delivery'),
'level' => env('RESTAURANT_DELIVERY_LOG_LEVEL', 'info'),
'log_location_updates' => false, // Can generate a lot of logs
'log_api_requests' => true,
],
/*
|--------------------------------------------------------------------------
| API Configuration
|--------------------------------------------------------------------------
*/
'api' => [
'prefix' => 'api/v1/restaurant-delivery',
'middleware' => ['api', 'auth:sanctum'],
'rate_limit' => env('RESTAURANT_DELIVERY_API_RATE_LIMIT', 60),
'throttle' => [
'location_update' => '120,1', // 120 requests per minute for location
'general' => '60,1',
],
],
];