getDealersBasedOnUserRole(); // Get all active products $products = Product::where('active', true) ->with(['category']) ->orderBy('name') ->get(); $data = []; foreach ($products as $product) { $row = [ 'product_id' => $product->id, 'product_code' => $product->code, 'product_name' => $product->name, 'category_name' => $product->category ? $product->category->name : '-', 'unit' => $product->unit ?? '-', 'total_stock' => 0 ]; // Calculate stock for each dealer on the target date foreach ($dealers as $dealer) { $stockOnDate = $this->getStockOnDate($product->id, $dealer->id, $targetDate); $row["dealer_{$dealer->id}"] = $stockOnDate; $row['total_stock'] += $stockOnDate; } $data[] = $row; } return [ 'data' => $data, 'dealers' => $dealers ]; } /** * Get stock quantity for a specific product and dealer on a given date */ public function getStockOnDate($productId, $dealerId, $targetDate) { // Get the latest stock log entry before or on the target date $latestStockLog = StockLog::whereHas('stock', function($query) use ($productId, $dealerId) { $query->where('product_id', $productId) ->where('dealer_id', $dealerId); }) ->where('created_at', '<=', $targetDate->endOfDay()) ->orderBy('created_at', 'desc') ->first(); if ($latestStockLog) { // Return the new_quantity from the latest log entry return $latestStockLog->new_quantity; } // If no stock log found, check if there's a current stock record $currentStock = Stock::where('product_id', $productId) ->where('dealer_id', $dealerId) ->first(); if ($currentStock) { // Check if the stock was created before or on the target date if ($currentStock->created_at <= $targetDate) { return $currentStock->quantity; } } // No stock data available for this date return 0; } /** * Get optimized stock data using a single query approach */ public function getOptimizedStockReportData($targetDate = null) { $targetDate = $targetDate ? Carbon::parse($targetDate) : now(); // Get dealers based on user role $dealers = $this->getDealersBasedOnUserRole(); // Get all active products with their stock data $products = Product::where('active', true) ->with(['category', 'stocks.dealer']) ->orderBy('name') ->get(); $data = []; foreach ($products as $product) { $row = [ 'product_id' => $product->id, 'product_code' => $product->code, 'product_name' => $product->name, 'category_name' => $product->category ? $product->category->name : '-', 'unit' => $product->unit ?? '-', 'total_stock' => 0 ]; // Calculate stock for each dealer on the target date foreach ($dealers as $dealer) { $stockOnDate = $this->getOptimizedStockOnDate($product->id, $dealer->id, $targetDate); $row["dealer_{$dealer->id}"] = $stockOnDate; $row['total_stock'] += $stockOnDate; } $data[] = $row; } return [ 'data' => $data, 'dealers' => $dealers ]; } /** * Get dealers based on logged-in user's role */ public function getDealersBasedOnUserRole() { // Get current authenticated user $user = Auth::user(); if (!$user) { Log::warning('No authenticated user found, returning all dealers'); return Dealer::whereNull('deleted_at')->orderBy('name')->get(); } Log::info('Getting dealers for user:', [ 'user_id' => $user->id, 'user_role_id' => $user->role_id, 'user_dealer_id' => $user->dealer_id ]); // If user has role, check role type and dealer access if ($user->role_id) { $role = Role::with(['dealers' => function($query) { $query->whereNull('dealers.deleted_at'); // Only active dealers }])->find($user->role_id); if ($role) { // Check if role is admin type if ($this->isAdminRole($role)) { // Admin role - check if has pivot dealers if ($role->dealers->count() > 0) { // Admin with pivot dealers - return pivot dealers only Log::info('Admin role with pivot dealers, returning pivot dealers only'); $dealers = $role->dealers()->whereNull('dealers.deleted_at')->orderBy('name')->get(); Log::info('Returning pivot dealers for admin:', $dealers->pluck('name')->toArray()); return $dealers; } else { // Admin without pivot dealers - return all dealers Log::info('Admin role without pivot dealers, returning all dealers'); $allDealers = Dealer::whereNull('deleted_at')->orderBy('name')->get(); Log::info('Returning all dealers for admin:', $allDealers->pluck('name')->toArray()); return $allDealers; } } // Non-admin role - return dealers from role pivot if ($role->dealers->count() > 0) { Log::info('Non-admin role with dealers, returning role dealers'); $dealers = $role->dealers()->whereNull('dealers.deleted_at')->orderBy('name')->get(); Log::info('Returning dealers from role:', $dealers->pluck('name')->toArray()); return $dealers; } } } // If user has specific dealer_id but no role dealers, check if they can access their dealer_id if ($user->dealer_id) { Log::info('User has specific dealer_id:', ['dealer_id' => $user->dealer_id]); if ($user->role_id) { $role = Role::with(['dealers' => function($query) { $query->whereNull('dealers.deleted_at'); // Only active dealers }])->find($user->role_id); if ($role && $role->hasDealer($user->dealer_id)) { Log::info('User can access their dealer_id, returning single dealer'); $dealer = Dealer::where('id', $user->dealer_id)->whereNull('deleted_at')->orderBy('name')->get(); Log::info('Returning dealer:', $dealer->pluck('name')->toArray()); return $dealer; } else { Log::info('User cannot access their dealer_id'); } } Log::info('User has dealer_id but no role or no access, returning empty'); return collect(); } // Fallback: return all dealers if no restrictions Log::info('No restrictions found, returning all dealers'); $allDealers = Dealer::whereNull('deleted_at')->orderBy('name')->get(); Log::info('Returning all dealers:', $allDealers->pluck('name')->toArray()); return $allDealers; } /** * Check if role is admin type (should show all dealers if no pivot) */ private function isAdminRole($role) { // Define admin role names that should have access to all dealers $adminRoleNames = [ 'admin' ]; // Check if role name contains admin keywords (but not "area") $roleName = strtolower(trim($role->name)); foreach ($adminRoleNames as $adminName) { if (strpos($roleName, $adminName) !== false && strpos($roleName, 'area') === false) { Log::info('Role identified as admin type:', ['role_name' => $role->name]); return true; } } // Role with "area" in name should use pivot dealers, not all dealers if (strpos($roleName, 'area') !== false) { Log::info('Role contains "area", treating as area role (use pivot dealers):', ['role_name' => $role->name]); return false; } Log::info('Role is not admin type:', ['role_name' => $role->name]); return false; } /** * Optimized method to get stock on date using subquery */ private function getOptimizedStockOnDate($productId, $dealerId, $targetDate) { try { // Use a subquery to get the latest stock log entry efficiently $latestStockLog = DB::table('stock_logs') ->join('stocks', 'stock_logs.stock_id', '=', 'stocks.id') ->where('stocks.product_id', $productId) ->where('stocks.dealer_id', $dealerId) ->where('stock_logs.created_at', '<=', $targetDate->endOfDay()) ->orderBy('stock_logs.created_at', 'desc') ->select('stock_logs.new_quantity') ->first(); if ($latestStockLog) { return $latestStockLog->new_quantity; } // If no stock log found, check current stock $currentStock = Stock::where('product_id', $productId) ->where('dealer_id', $dealerId) ->first(); if ($currentStock && $currentStock->created_at <= $targetDate) { return $currentStock->quantity; } return 0; } catch (\Exception $e) { // Log error and return 0 Log::error('Error getting stock on date: ' . $e->getMessage(), [ 'product_id' => $productId, 'dealer_id' => $dealerId, 'target_date' => $targetDate ]); return 0; } } }