reportData = $reportData; // Debug: Log the structure of report data Log::info('StockProductsExport constructor', [ 'has_data' => isset($reportData['data']), 'has_dealers' => isset($reportData['dealers']), 'data_count' => isset($reportData['data']) ? count($reportData['data']) : 0, 'dealers_count' => isset($reportData['dealers']) ? count($reportData['dealers']) : 0, 'dealers' => isset($reportData['dealers']) ? $reportData['dealers']->pluck('name')->toArray() : [] ]); } public function collection() { try { $data = collect(); $no = 1; foreach ($this->reportData['data'] as $row) { $exportRow = [ 'no' => $no++, 'kode_produk' => $row['product_code'] ?? '', 'nama_produk' => $row['product_name'] ?? '', 'kategori' => $row['category_name'] ?? '', 'satuan' => $row['unit'] ?? '' ]; // Add dealer columns foreach ($this->reportData['dealers'] as $dealer) { try { $dealerKey = "dealer_{$dealer->id}"; // Clean dealer name for array key to avoid special characters $cleanDealerName = $this->cleanDealerName($dealer->name); $exportRow[$cleanDealerName] = $row[$dealerKey] ?? 0; Log::info('Processing dealer column', [ 'original_name' => $dealer->name, 'clean_name' => $cleanDealerName, 'dealer_key' => $dealerKey, 'value' => $row[$dealerKey] ?? 0 ]); } catch (\Exception $e) { Log::error('Error processing dealer column', [ 'dealer_id' => $dealer->id, 'dealer_name' => $dealer->name, 'error' => $e->getMessage() ]); // Use a safe fallback name $exportRow['Dealer_' . $dealer->id] = $row["dealer_{$dealer->id}"] ?? 0; } } // Add total stock $exportRow['total_stok'] = $row['total_stock'] ?? 0; $data->push($exportRow); } return $data; } catch (\Exception $e) { Log::error('Error in collection method', [ 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); // Return empty collection as fallback return collect(); } } public function headings(): array { try { $headings = [ 'No', 'Kode Produk', 'Nama Produk', 'Kategori', 'Satuan' ]; // Add dealer headings foreach ($this->reportData['dealers'] as $dealer) { try { $cleanName = $this->cleanDealerName($dealer->name); $headings[] = $cleanName; Log::info('Processing dealer heading', [ 'original_name' => $dealer->name, 'clean_name' => $cleanName ]); } catch (\Exception $e) { Log::error('Error processing dealer heading', [ 'dealer_id' => $dealer->id, 'dealer_name' => $dealer->name, 'error' => $e->getMessage() ]); // Use a safe fallback name $headings[] = 'Dealer_' . $dealer->id; } } // Add total heading $headings[] = 'Total Stok'; return $headings; } catch (\Exception $e) { Log::error('Error in headings method', [ 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); // Return basic headings as fallback return ['No', 'Kode Produk', 'Nama Produk', 'Kategori', 'Satuan', 'Total Stok']; } } public function styles(Worksheet $sheet) { try { $lastColumn = $sheet->getHighestColumn(); $lastRow = $sheet->getHighestRow(); // Validate column and row values if (!$lastColumn || !$lastRow || $lastRow < 1) { Log::warning('Invalid sheet dimensions', ['lastColumn' => $lastColumn, 'lastRow' => $lastRow]); return $sheet; } // Style header row $sheet->getStyle('A1:' . $lastColumn . '1')->applyFromArray([ 'font' => [ 'bold' => true, 'color' => ['rgb' => 'FFFFFF'], ], 'fill' => [ 'fillType' => Fill::FILL_SOLID, 'startColor' => ['rgb' => '4472C4'], ], 'alignment' => [ 'horizontal' => Alignment::HORIZONTAL_CENTER, 'vertical' => Alignment::VERTICAL_CENTER, ], ]); // Style all cells $sheet->getStyle('A1:' . $lastColumn . $lastRow)->applyFromArray([ 'borders' => [ 'allBorders' => [ 'borderStyle' => Border::BORDER_THIN, 'color' => ['rgb' => '000000'], ], ], 'alignment' => [ 'vertical' => Alignment::VERTICAL_CENTER, ], ]); // Center align specific columns $sheet->getStyle('A:A')->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER); $sheet->getStyle('D:D')->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER); // Right align numeric columns (dealer columns and total) $dealerStartCol = 'E'; $dealerCount = count($this->reportData['dealers']); if ($dealerCount > 0) { $dealerEndCol = chr(ord('E') + $dealerCount - 1); $totalCol = chr(ord($dealerStartCol) + $dealerCount); // Validate column letters if (ord($dealerEndCol) <= ord('Z') && ord($totalCol) <= ord('Z')) { $sheet->getStyle($dealerStartCol . ':' . $dealerEndCol)->getAlignment()->setHorizontal(Alignment::HORIZONTAL_RIGHT); $sheet->getStyle($totalCol . ':' . $totalCol)->getAlignment()->setHorizontal(Alignment::HORIZONTAL_RIGHT); // Bold total column $sheet->getStyle($totalCol . '1:' . $totalCol . $lastRow)->getFont()->setBold(true); } } // Auto-size columns safely foreach (range('A', $lastColumn) as $column) { try { $sheet->getColumnDimension($column)->setAutoSize(true); } catch (\Exception $e) { Log::warning('Failed to auto-size column', ['column' => $column, 'error' => $e->getMessage()]); } } return $sheet; } catch (\Exception $e) { Log::error('Error in styles method', [ 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return $sheet; } } public function columnWidths(): array { try { $widths = [ 'A' => 8, // No 'B' => 15, // Kode Produk 'C' => 30, // Nama Produk 'D' => 15, // Kategori 'E' => 10, // Satuan ]; // Add dealer column widths safely $currentCol = 'F'; $dealerCount = count($this->reportData['dealers']); for ($i = 0; $i < $dealerCount; $i++) { // Validate column letter if (ord($currentCol) <= ord('Z')) { $widths[$currentCol] = 15; $currentCol = chr(ord($currentCol) + 1); } else { Log::warning('Too many dealer columns, stopping at column Z'); break; } } // Add total column width if we haven't exceeded Z if (ord($currentCol) <= ord('Z')) { $widths[$currentCol] = 15; } return $widths; } catch (\Exception $e) { Log::error('Error in columnWidths method', [ 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); // Return basic widths as fallback return [ 'A' => 8, // No 'B' => 15, // Kode Produk 'C' => 30, // Nama Produk 'D' => 15, // Kategori 'E' => 10, // Satuan 'F' => 15 // Total Stok ]; } } /** * Clean dealer name to make it safe for array keys and Excel headers */ private function cleanDealerName($dealerName) { // Remove or replace special characters that can cause issues with Excel $cleanName = preg_replace('/[^a-zA-Z0-9\s\-_]/', '', $dealerName); $cleanName = trim($cleanName); // If name becomes empty, use a default if (empty($cleanName)) { $cleanName = 'Dealer'; } // Limit length to avoid Excel issues if (strlen($cleanName) > 31) { $cleanName = substr($cleanName, 0, 31); } return $cleanName; } }