value('value') ?: 'xlsx,xls,csv'; $maxMb = max(1, (int) (Setting::where('key', 'import_max_file_size_mb')->value('value') ?: 10)); $request->validate([ 'file' => 'required|file|mimes:'.$allowedTypes.'|max:'.($maxMb * 1024), ], [ 'file.mimes' => 'نوع فایل import مجاز نیست.', 'file.max' => "حجم فایل import نباید بیشتر از {$maxMb} مگابایت باشد.", ]); $file = $request->file('file'); $path = $file->store('imports'); $batch = ImportBatch::create([ 'user_id' => auth()->id(), 'filename' => $file->getClientOriginalName(), 'status' => 'pending', 'can_rollback' => Setting::where('key', 'import_rollback_allowed')->value('value') !== 'false', ]); try { $fullPath = Storage::path($path); $preview = $this->importService->preview($fullPath); // Store rows for later processing $rows = Excel::toArray([], $fullPath)[0] ?? []; $dataRows = array_slice($rows, 1); foreach ($dataRows as $index => $row) { $batch->rows()->create([ 'original_data' => $row, 'status' => 'pending', ]); } $batch->update(['total_rows' => count($dataRows)]); ActivityLogger::log('lead_import_uploaded', "Import batch {$batch->id} uploaded", $batch); return response()->json([ 'batch_id' => $batch->id, 'filename' => $file->getClientOriginalName(), 'headers' => $preview['headers'], 'total_rows' => $preview['total_rows'], 'preview' => $preview['preview'], ]); } catch (\Exception $e) { $batch->update(['status' => 'failed', 'errors' => $e->getMessage()]); return response()->json(['message' => $e->getMessage()], 422); } } public function confirm(Request $request): JsonResponse { $user = auth()->user(); Gate::authorize('import', ImportBatch::class); $validated = $request->validate([ 'batch_id' => 'required|exists:import_batches,id', 'column_mapping' => 'required|array', 'column_mapping.company' => 'required|integer', 'column_mapping.first_name' => 'nullable|integer', 'column_mapping.last_name' => 'nullable|integer', 'column_mapping.phone' => 'required|integer', 'column_mapping.phone_secondary' => 'nullable|integer', 'column_mapping.email' => 'nullable|integer', 'column_mapping.city' => 'nullable|integer', 'column_mapping.province' => 'nullable|integer', 'column_mapping.source' => 'nullable|integer', 'column_mapping.product_interest' => 'nullable|integer', 'column_mapping.priority' => 'nullable|integer', 'column_mapping.lead_score' => 'nullable|integer', 'column_mapping.interest_level' => 'nullable|integer', 'column_mapping.notes' => 'nullable|integer', 'column_mapping.tags' => 'nullable|integer', 'campaign_id' => 'nullable|exists:campaigns,id', 'agent_ids' => 'nullable|array', 'agent_ids.*' => 'exists:users,id', ]); $agentIds = $validated['agent_ids'] ?? null; if ($user?->hasRole('agent')) { $agentIds = [$user->id]; } $pendingBatch = ImportBatch::findOrFail($validated['batch_id']); Gate::authorize('view', $pendingBatch); $batch = $this->importService->confirm( $validated['batch_id'], $validated['column_mapping'], $validated['campaign_id'] ?? null, $agentIds, auth()->id() ); ActivityLogger::log('lead_import_confirmed', "Import batch {$batch->id} confirmed", $batch); return response()->json($batch->load('rows')); } public function rollback(int $batchId): JsonResponse { $batch = ImportBatch::findOrFail($batchId); Gate::authorize('rollback', $batch); $this->importService->rollback($batchId); ActivityLogger::log('lead_import_rolled_back', "Import batch {$batchId} rolled back", $batch); return response()->json(['message' => 'بازگشت import انجام شد']); } public function index(): JsonResponse { Gate::authorize('viewAny', ImportBatch::class); return response()->json( ImportBatch::with('user:id,name') ->orderBy('created_at', 'desc') ->paginate(15) ); } public function template() { Gate::authorize('import', ImportBatch::class); $spreadsheet = new Spreadsheet; $sheet = $spreadsheet->getActiveSheet(); $sheet->fromArray([ ['company', 'phone', 'phone_secondary', 'first_name', 'last_name', 'email', 'city', 'province', 'source', 'product_interest', 'priority', 'lead_score', 'interest_level', 'notes', 'tags'], ['Acme Industrial', '02112345678', '09121234567', 'Ali', 'Karimi', 'ali@example.com', 'Tehran', 'Tehran', 'Website', 'CRM', '5', '70', 'warm', 'Initial import note', 'b2b,website'], ['Pars Co', '02187654321', '', 'Sara', 'Ahmadi', 'sara@example.com', 'Shiraz', 'Fars', 'Exhibition', 'Support', '3', '40', 'cold', '', 'exhibition'], ]); $path = storage_path('app/import-template-b2b.xlsx'); (new Xlsx($spreadsheet))->save($path); return response()->download($path, 'sample-leads-b2b.xlsx')->deleteFileAfterSend(true); } }