162 خطوط
6.4 KiB
PHP
162 خطوط
6.4 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\ImportBatch;
|
|
use App\Models\Setting;
|
|
use App\Services\ImportService;
|
|
use App\Services\ActivityLogger;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Gate;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
|
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
|
|
|
|
class ImportController extends Controller
|
|
{
|
|
public function __construct(private ImportService $importService) {}
|
|
|
|
public function upload(Request $request): JsonResponse
|
|
{
|
|
Gate::authorize('import', ImportBatch::class);
|
|
|
|
$allowedTypes = Setting::where('key', 'import_allowed_file_types')->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 = \Maatwebsite\Excel\Facades\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);
|
|
}
|
|
}
|