'reclamations', 'title' => 'Рекламации', 'id' => 'reclamations', 'header' => [ 'id' => 'ID', 'user_name' => 'Менеджер', 'status_name' => 'Статус', 'district_name' => 'Округ', 'area_name' => 'Район', 'object_address' => 'Адрес объекта', 'create_date' => 'Дата создания', 'finish_date' => 'Дата завершения', 'start_work_date' => 'Дата начала работ', 'work_days' => 'Срок работ, дней', 'brigadier_name' => 'Бригадир', 'reason' => 'Причина', 'guarantee' => 'Гарантии', 'whats_done' => 'Что сделано', 'comment' => 'Комментарий', ], 'searchFields' => [ 'reason', 'guarantee', 'whats_done', 'comment', ], 'ranges' => [], ]; public function __construct() { $this->data['users'] = User::query()->whereIn('role', [Role::MANAGER, Role::ADMIN])->get()->pluck('name', 'id'); $this->data['statuses'] = ReclamationStatus::query()->get()->pluck('name', 'id'); } public function index(Request $request) { session(['gp_reclamations' => $request->all()]); $model = new ReclamationView(); // fill filters $this->createFilters($model, 'user_name', 'status_name'); $this->createDateFilters($model, 'create_date', 'finish_date'); $q = $model::query(); $this->acceptFilters($q, $request); $this->acceptSearch($q, $request); $this->setSortAndOrderBy($model, $request); $q->orderBy($this->data['sortBy'], $this->data['orderBy']); $this->data['reclamations'] = $q->paginate(session('per_page', config('pagination.per_page')))->withQueryString(); return view('reclamations.index', $this->data); } public function create(CreateReclamationRequest $request, Order $order) { $reclamation = Reclamation::query()->create([ 'order_id' => $order->id, 'user_id' => $request->user()->id, 'status_id' => Reclamation::STATUS_NEW, 'create_date' => Carbon::now(), 'finish_date' => Carbon::now()->addDays(30), ]); $skus = $request->validated('skus'); $reclamation->skus()->attach($skus); return redirect()->route('reclamations.show', ['reclamation' => $reclamation, 'previous_url' => url()->previous()]); } public function show(Request $request, Reclamation $reclamation) { $this->data['brigadiers'] = User::query()->where('role', Role::BRIGADIER)->get()->pluck('name', 'id'); $this->data['reclamation'] = $reclamation; $this->data['previous_url'] = $request->get('previous_url'); return view('reclamations.edit', $this->data); } public function update(StoreReclamationRequest $request, Reclamation $reclamation) { $data = $request->validated(); $reclamation->update($data); return redirect()->route('reclamations.show', $reclamation->id); } public function delete(Reclamation $reclamation) { $reclamation->delete(); return redirect()->route('reclamations.index'); } public function uploadPhotoBefore(Request $request, Reclamation $reclamation, FileService $fileService) { $data = $request->validate([ 'photo.*' => 'mimes:jpeg,jpg,png|max:8192', ]); $f = []; foreach ($data['photo'] as $photo) { $f[] = $fileService->saveUploadedFile('reclamations/' . $reclamation->id . '/photo_before', $photo); } $reclamation->photos_before()->syncWithoutDetaching($f); return redirect()->route('reclamations.show', ['reclamation' => $reclamation, 'previous_url' => $request->get('previous_url')]); } public function uploadPhotoAfter(Request $request, Reclamation $reclamation, FileService $fileService) { $data = $request->validate([ 'photo.*' => 'mimes:jpeg,jpg,png|max:8192', ]); $f = []; foreach ($data['photo'] as $photo) { $f[] = $fileService->saveUploadedFile('reclamations/' . $reclamation->id . '/photo_after', $photo); } $reclamation->photos_after()->syncWithoutDetaching($f); return redirect()->route('reclamations.show', ['reclamation' => $reclamation, 'previous_url' => $request->get('previous_url')]); } public function deletePhotoBefore(Request $request, Reclamation $reclamation, File $file, FileService $fileService) { $reclamation->photos_before()->detach($file); Storage::disk('public')->delete($file->path); $file->delete(); return redirect()->route('reclamations.show', ['reclamation' => $reclamation, 'previous_url' => $request->get('previous_url')]); } public function deletePhotoAfter(Request $request, Reclamation $reclamation, File $file, FileService $fileService) { $reclamation->photos_after()->detach($file); Storage::disk('public')->delete($file->path); $file->delete(); return redirect()->route('reclamations.show', ['reclamation' => $reclamation, 'previous_url' => $request->get('previous_url')]); } public function uploadDocument(Request $request, Reclamation $reclamation, FileService $fileService) { $data = $request->validate([ 'document.*' => 'file', ]); $f = []; $i = 0; foreach ($data['document'] as $document) { if($i++ >= 5) break; $f[] = $fileService->saveUploadedFile('reclamations/' . $reclamation->id . '/document', $document); } $reclamation->documents()->syncWithoutDetaching($f); return redirect()->route('reclamations.show', ['reclamation' => $reclamation, 'previous_url' => $request->get('previous_url')]); } public function deleteDocument(Request $request, Reclamation $reclamation, File $file) { $reclamation->documents()->detach($file); Storage::disk('public')->delete($file->path); $file->delete(); return redirect()->route('reclamations.show', ['reclamation' => $reclamation, 'previous_url' => $request->get('previous_url')]); } public function uploadAct(Request $request, Reclamation $reclamation, FileService $fileService) { $data = $request->validate([ 'acts.*' => 'file', ]); $f = []; $i = 0; foreach ($data['acts'] as $document) { if($i++ >= 5) break; $f[] = $fileService->saveUploadedFile('reclamations/' . $reclamation->id . '/act', $document); } $reclamation->acts()->syncWithoutDetaching($f); return redirect()->route('reclamations.show', ['reclamation' => $reclamation, 'previous_url' => $request->get('previous_url')]); } public function deleteAct(Request $request, Reclamation $reclamation, File $file) { $reclamation->acts()->detach($file); Storage::disk('public')->delete($file->path); $file->delete(); return redirect()->route('reclamations.show', ['reclamation' => $reclamation, 'previous_url' => $request->get('previous_url')]); } public function updateDetails(StoreReclamationDetailsRequest $request, Reclamation $reclamation) { $names = $request->validated('name'); $quantity = $request->validated('quantity'); $withDocuments = $request->validated('with_documents'); $inventoryService = app(\App\Services\SparePartInventoryService::class); foreach ($names as $key => $name) { if (!$name) continue; if ((int)$quantity[$key] >= 1) { // Проверяем, является ли это запчастью $sparePart = \App\Models\SparePart::where('article', $name)->first(); if ($sparePart) { // Автоматическое списание $withDocs = isset($withDocuments[$key]) && $withDocuments[$key]; $inventoryService->deductForReclamation( $name, (int)$quantity[$key], $withDocs, $reclamation->id ); // Сохраняем в pivot $reclamation->spareParts()->syncWithoutDetaching([ $sparePart->id => [ 'quantity' => $quantity[$key], 'with_documents' => $withDocs, ] ]); } else { // Обычная деталь ReclamationDetail::query()->updateOrCreate( ['reclamation_id' => $reclamation->id, 'name' => $name], ['quantity' => $quantity[$key]] ); } } else { // Удаление ReclamationDetail::query() ->where('reclamation_id', $reclamation->id) ->where('name', $name) ->delete(); } } return redirect()->route('reclamations.show', ['reclamation' => $reclamation, 'previous_url' => $request->get('previous_url')]); } public function updateSpareParts(StoreReclamationSparePartsRequest $request, Reclamation $reclamation) { $rows = $request->validated('rows') ?? []; $inventoryService = app(\App\Services\SparePartInventoryService::class); // Получаем текущие привязки для сравнения $currentSpareParts = $reclamation->spareParts->keyBy('id'); // Собираем новые привязки $newSpareParts = []; foreach ($rows as $row) { $sparePartId = $row['spare_part_id'] ?? null; if (empty($sparePartId)) continue; $quantity = (int)($row['quantity'] ?? 0); if ($quantity < 1) continue; $withDocs = !empty($row['with_documents']) && $row['with_documents'] != '0'; // Проверяем, изменилось ли количество $currentQty = $currentSpareParts->get($sparePartId)?->pivot->quantity ?? 0; $diff = $quantity - $currentQty; if ($diff > 0) { // Нужно списать дополнительное количество $sparePart = \App\Models\SparePart::find($sparePartId); if ($sparePart) { $inventoryService->deductForReclamation( $sparePart->article, $diff, $withDocs, $reclamation->id ); } } $newSpareParts[$sparePartId] = [ 'quantity' => $quantity, 'with_documents' => $withDocs, ]; } // Синхронизируем (заменяем все старые привязки новыми) $reclamation->spareParts()->sync($newSpareParts); return redirect()->route('reclamations.show', ['reclamation' => $reclamation, 'previous_url' => $request->get('previous_url')]); } public function generateReclamationPack(Request $request, Reclamation $reclamation) { GenerateReclamationPack::dispatch($reclamation, auth()->user()->id); return redirect()->route('reclamations.show', ['reclamation' => $reclamation, 'previous_url' => $request->get('previous_url')]) ->with(['success' => 'Задача генерации документов создана!']); } public function generatePhotosBeforePack(Request $request, Reclamation $reclamation) { GenerateFilesPack::dispatch($reclamation, $reclamation->photos_before, auth()->user()->id, 'Фото проблемы'); return redirect()->route('reclamations.show', ['reclamation' => $reclamation, 'previous_url' => $request->get('previous_url')]) ->with(['success' => 'Задача архивации создана!']); } public function generatePhotosAfterPack(Request $request, Reclamation $reclamation) { GenerateFilesPack::dispatch($reclamation, $reclamation->photos_after, auth()->user()->id, 'Фото после'); return redirect()->route('reclamations.show', ['reclamation' => $reclamation, 'previous_url' => $request->get('previous_url')]) ->with(['success' => 'Задача архивации создана!']); } }