validate([ 'kilometer' => 'required|numeric|min:0', 'pressure_high' => 'required|numeric|min:0', 'pressure_low' => 'nullable|numeric|min:0', 'cabin_temperature' => 'nullable|numeric', 'cabin_temperature_image' => 'nullable|image|mimes:jpeg,png,jpg|max:2048', 'ac_condition' => 'nullable|in:' . implode(',', Postcheck::getAcConditionOptions()), 'ac_image' => 'nullable|image|mimes:jpeg,png,jpg|max:2048', 'blower_condition' => 'nullable|in:' . implode(',', Postcheck::getBlowerConditionOptions()), 'blower_image' => 'nullable|image|mimes:jpeg,png,jpg|max:2048', 'evaporator_condition' => 'nullable|in:' . implode(',', Postcheck::getEvaporatorConditionOptions()), 'evaporator_image' => 'nullable|image|mimes:jpeg,png,jpg|max:2048', 'compressor_condition' => 'nullable|in:' . implode(',', Postcheck::getCompressorConditionOptions()), 'postcheck_notes' => 'nullable|string', 'front_image' => 'required|image|mimes:jpeg,png,jpg|max:2048', ]); $data = [ 'transaction_id' => $transaction->id, 'postcheck_by' => auth()->id(), 'postcheck_at' => now(), 'police_number' => $transaction->police_number, 'spk_number' => $transaction->spk, 'kilometer' => $request->kilometer, 'pressure_high' => $request->pressure_high, 'pressure_low' => $request->pressure_low, 'cabin_temperature' => $request->cabin_temperature, 'ac_condition' => $request->ac_condition, 'blower_condition' => $request->blower_condition, 'evaporator_condition' => $request->evaporator_condition, 'compressor_condition' => $request->compressor_condition, 'postcheck_notes' => $request->postcheck_notes, ]; // Handle file uploads $imageFields = [ 'front_image', 'cabin_temperature_image', 'ac_image', 'blower_image', 'evaporator_image' ]; foreach ($imageFields as $field) { if ($request->hasFile($field) && $request->file($field)->isValid()) { try { $file = $request->file($field); // Generate unique filename with transaction ID $filename = time() . '_' . uniqid() . '_' . $transaction->id . '_' . $field . '.' . $file->getClientOriginalExtension(); // Create directory path: transactions/{transaction_id}/postcheck/ $directory = 'transactions/' . $transaction->id . '/postcheck'; // Ensure base storage directory exists $this->ensureStorageDirectoryExists(); // Ensure transactions directory exists if (!Storage::disk('public')->exists('transactions')) { Storage::disk('public')->makeDirectory('transactions', 0755, true); Log::info('Created transactions directory'); } // Ensure transaction ID directory exists $transactionDir = 'transactions/' . $transaction->id; if (!Storage::disk('public')->exists($transactionDir)) { Storage::disk('public')->makeDirectory($transactionDir, 0755, true); Log::info('Created transaction directory: ' . $transactionDir); } // Ensure postcheck directory exists if (!Storage::disk('public')->exists($directory)) { Storage::disk('public')->makeDirectory($directory, 0755, true); Log::info('Created postcheck directory: ' . $directory); } // Store file in organized directory structure $path = $file->storeAs($directory, $filename, 'public'); // Store file path $data[$field] = $path; // Store metadata $data[$field . '_metadata'] = [ 'original_name' => $file->getClientOriginalName(), 'size' => $file->getSize(), 'mime_type' => $file->getMimeType(), 'uploaded_at' => now()->toISOString(), 'transaction_id' => $transaction->id, 'filename' => $filename, ]; Log::info('File uploaded successfully: ' . $path); } catch (\Exception $e) { // Log error for debugging Log::error('File upload failed: ' . $e->getMessage(), [ 'field' => $field, 'file' => $file->getClientOriginalName(), 'transaction_id' => $transaction->id, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return back()->withErrors(['error' => 'Gagal mengupload file: ' . $field . '. Error: ' . $e->getMessage()]); } } } try { Postcheck::create($data); return redirect()->route('transaction')->with('success', 'Postcheck berhasil disimpan'); } catch (\Exception $e) { Log::error('Postcheck creation failed: ' . $e->getMessage()); return back()->withErrors(['error' => 'Gagal menyimpan data postcheck. Silakan coba lagi.']); } } /** * Ensure the base storage directory exists */ private function ensureStorageDirectoryExists() { $storagePath = storage_path('app/public'); if (!is_dir($storagePath)) { if (!mkdir($storagePath, 0755, true)) { Log::error('Failed to create storage directory: ' . $storagePath); throw new \Exception('Cannot create storage directory: ' . $storagePath . '. Please run: php fix_permissions.php or manually create the directory.'); } Log::info('Created storage directory: ' . $storagePath); } // Check if directory is writable if (!is_writable($storagePath)) { Log::error('Storage directory is not writable: ' . $storagePath); throw new \Exception( 'Storage directory is not writable: ' . $storagePath . '. ' . 'Please run one of these commands from your project root: ' . '1) php fix_permissions.php ' . '2) chmod -R 775 storage/ ' . '3) mkdir -p storage/app/public/transactions/{transaction_id}/postcheck' ); } // Check if we can create subdirectories $testDir = $storagePath . '/test_' . time(); if (!mkdir($testDir, 0755, true)) { Log::error('Cannot create subdirectories in storage: ' . $storagePath); throw new \Exception( 'Cannot create subdirectories in storage. ' . 'Please check permissions and run: php fix_permissions.php' ); } // Clean up test directory rmdir($testDir); Log::info('Storage directory is properly configured: ' . $storagePath); } }