ReclamationController.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. <?php
  2. namespace App\Http\Controllers;
  3. use App\Http\Requests\CreateReclamationRequest;
  4. use App\Http\Requests\StoreReclamationDetailsRequest;
  5. use App\Http\Requests\StoreReclamationRequest;
  6. use App\Http\Requests\StoreReclamationSparePartsRequest;
  7. use App\Jobs\GenerateFilesPack;
  8. use App\Jobs\GenerateReclamationPack;
  9. use App\Models\File;
  10. use App\Models\Order;
  11. use App\Models\Reclamation;
  12. use App\Models\ReclamationDetail;
  13. use App\Models\ReclamationStatus;
  14. use App\Models\ReclamationView;
  15. use App\Models\Role;
  16. use App\Models\User;
  17. use App\Services\FileService;
  18. use Illuminate\Http\Request;
  19. use Illuminate\Support\Carbon;
  20. use Illuminate\Support\Facades\Storage;
  21. class ReclamationController extends Controller
  22. {
  23. protected array $data = [
  24. 'active' => 'reclamations',
  25. 'title' => 'Рекламации',
  26. 'id' => 'reclamations',
  27. 'header' => [
  28. 'id' => 'ID',
  29. 'user_name' => 'Менеджер',
  30. 'status_name' => 'Статус',
  31. 'district_name' => 'Округ',
  32. 'area_name' => 'Район',
  33. 'object_address' => 'Адрес объекта',
  34. 'create_date' => 'Дата создания',
  35. 'finish_date' => 'Дата завершения',
  36. 'start_work_date' => 'Дата начала работ',
  37. 'work_days' => 'Срок работ, дней',
  38. 'brigadier_name' => 'Бригадир',
  39. 'reason' => 'Причина',
  40. 'guarantee' => 'Гарантии',
  41. 'whats_done' => 'Что сделано',
  42. 'comment' => 'Комментарий',
  43. ],
  44. 'searchFields' => [
  45. 'reason',
  46. 'guarantee',
  47. 'whats_done',
  48. 'comment',
  49. ],
  50. 'ranges' => [],
  51. ];
  52. public function __construct()
  53. {
  54. $this->data['users'] = User::query()->whereIn('role', [Role::MANAGER, Role::ADMIN])->get()->pluck('name', 'id');
  55. $this->data['statuses'] = ReclamationStatus::query()->get()->pluck('name', 'id');
  56. }
  57. public function index(Request $request)
  58. {
  59. session(['gp_reclamations' => $request->all()]);
  60. $model = new ReclamationView();
  61. // fill filters
  62. $this->createFilters($model, 'user_name', 'status_name');
  63. $this->createDateFilters($model, 'create_date', 'finish_date');
  64. $q = $model::query();
  65. $this->acceptFilters($q, $request);
  66. $this->acceptSearch($q, $request);
  67. $this->setSortAndOrderBy($model, $request);
  68. $q->orderBy($this->data['sortBy'], $this->data['orderBy']);
  69. $this->data['reclamations'] = $q->paginate(session('per_page', config('pagination.per_page')))->withQueryString();
  70. return view('reclamations.index', $this->data);
  71. }
  72. public function create(CreateReclamationRequest $request, Order $order)
  73. {
  74. $reclamation = Reclamation::query()->create([
  75. 'order_id' => $order->id,
  76. 'user_id' => $request->user()->id,
  77. 'status_id' => Reclamation::STATUS_NEW,
  78. 'create_date' => Carbon::now(),
  79. 'finish_date' => Carbon::now()->addDays(30),
  80. ]);
  81. $skus = $request->validated('skus');
  82. $reclamation->skus()->attach($skus);
  83. return redirect()->route('reclamations.show', ['reclamation' => $reclamation, 'previous_url' => url()->previous()]);
  84. }
  85. public function show(Request $request, Reclamation $reclamation)
  86. {
  87. $this->data['brigadiers'] = User::query()->where('role', Role::BRIGADIER)->get()->pluck('name', 'id');
  88. $this->data['reclamation'] = $reclamation;
  89. $this->data['previous_url'] = $request->get('previous_url');
  90. return view('reclamations.edit', $this->data);
  91. }
  92. public function update(StoreReclamationRequest $request, Reclamation $reclamation)
  93. {
  94. $data = $request->validated();
  95. $reclamation->update($data);
  96. return redirect()->route('reclamations.show', $reclamation->id);
  97. }
  98. public function delete(Reclamation $reclamation)
  99. {
  100. $reclamation->delete();
  101. return redirect()->route('reclamations.index');
  102. }
  103. public function uploadPhotoBefore(Request $request, Reclamation $reclamation, FileService $fileService)
  104. {
  105. $data = $request->validate([
  106. 'photo.*' => 'mimes:jpeg,jpg,png|max:8192',
  107. ]);
  108. $f = [];
  109. foreach ($data['photo'] as $photo) {
  110. $f[] = $fileService->saveUploadedFile('reclamations/' . $reclamation->id . '/photo_before', $photo);
  111. }
  112. $reclamation->photos_before()->syncWithoutDetaching($f);
  113. return redirect()->route('reclamations.show', ['reclamation' => $reclamation, 'previous_url' => $request->get('previous_url')]);
  114. }
  115. public function uploadPhotoAfter(Request $request, Reclamation $reclamation, FileService $fileService)
  116. {
  117. $data = $request->validate([
  118. 'photo.*' => 'mimes:jpeg,jpg,png|max:8192',
  119. ]);
  120. $f = [];
  121. foreach ($data['photo'] as $photo) {
  122. $f[] = $fileService->saveUploadedFile('reclamations/' . $reclamation->id . '/photo_after', $photo);
  123. }
  124. $reclamation->photos_after()->syncWithoutDetaching($f);
  125. return redirect()->route('reclamations.show', ['reclamation' => $reclamation, 'previous_url' => $request->get('previous_url')]);
  126. }
  127. public function deletePhotoBefore(Request $request, Reclamation $reclamation, File $file, FileService $fileService)
  128. {
  129. $reclamation->photos_before()->detach($file);
  130. Storage::disk('public')->delete($file->path);
  131. $file->delete();
  132. return redirect()->route('reclamations.show', ['reclamation' => $reclamation, 'previous_url' => $request->get('previous_url')]);
  133. }
  134. public function deletePhotoAfter(Request $request, Reclamation $reclamation, File $file, FileService $fileService)
  135. {
  136. $reclamation->photos_after()->detach($file);
  137. Storage::disk('public')->delete($file->path);
  138. $file->delete();
  139. return redirect()->route('reclamations.show', ['reclamation' => $reclamation, 'previous_url' => $request->get('previous_url')]);
  140. }
  141. public function uploadDocument(Request $request, Reclamation $reclamation, FileService $fileService)
  142. {
  143. $data = $request->validate([
  144. 'document.*' => 'file',
  145. ]);
  146. $f = [];
  147. $i = 0;
  148. foreach ($data['document'] as $document) {
  149. if($i++ >= 5) break;
  150. $f[] = $fileService->saveUploadedFile('reclamations/' . $reclamation->id . '/document', $document);
  151. }
  152. $reclamation->documents()->syncWithoutDetaching($f);
  153. return redirect()->route('reclamations.show', ['reclamation' => $reclamation, 'previous_url' => $request->get('previous_url')]);
  154. }
  155. public function deleteDocument(Request $request, Reclamation $reclamation, File $file)
  156. {
  157. $reclamation->documents()->detach($file);
  158. Storage::disk('public')->delete($file->path);
  159. $file->delete();
  160. return redirect()->route('reclamations.show', ['reclamation' => $reclamation, 'previous_url' => $request->get('previous_url')]);
  161. }
  162. public function uploadAct(Request $request, Reclamation $reclamation, FileService $fileService)
  163. {
  164. $data = $request->validate([
  165. 'acts.*' => 'file',
  166. ]);
  167. $f = [];
  168. $i = 0;
  169. foreach ($data['acts'] as $document) {
  170. if($i++ >= 5) break;
  171. $f[] = $fileService->saveUploadedFile('reclamations/' . $reclamation->id . '/act', $document);
  172. }
  173. $reclamation->acts()->syncWithoutDetaching($f);
  174. return redirect()->route('reclamations.show', ['reclamation' => $reclamation, 'previous_url' => $request->get('previous_url')]);
  175. }
  176. public function deleteAct(Request $request, Reclamation $reclamation, File $file)
  177. {
  178. $reclamation->acts()->detach($file);
  179. Storage::disk('public')->delete($file->path);
  180. $file->delete();
  181. return redirect()->route('reclamations.show', ['reclamation' => $reclamation, 'previous_url' => $request->get('previous_url')]);
  182. }
  183. public function updateDetails(StoreReclamationDetailsRequest $request, Reclamation $reclamation)
  184. {
  185. $names = $request->validated('name');
  186. $quantity = $request->validated('quantity');
  187. $withDocuments = $request->validated('with_documents');
  188. $inventoryService = app(\App\Services\SparePartInventoryService::class);
  189. foreach ($names as $key => $name) {
  190. if (!$name) continue;
  191. if ((int)$quantity[$key] >= 1) {
  192. // Проверяем, является ли это запчастью
  193. $sparePart = \App\Models\SparePart::where('article', $name)->first();
  194. if ($sparePart) {
  195. // Автоматическое списание
  196. $withDocs = isset($withDocuments[$key]) && $withDocuments[$key];
  197. $inventoryService->deductForReclamation(
  198. $name,
  199. (int)$quantity[$key],
  200. $withDocs,
  201. $reclamation->id
  202. );
  203. // Сохраняем в pivot
  204. $reclamation->spareParts()->syncWithoutDetaching([
  205. $sparePart->id => [
  206. 'quantity' => $quantity[$key],
  207. 'with_documents' => $withDocs,
  208. ]
  209. ]);
  210. } else {
  211. // Обычная деталь
  212. ReclamationDetail::query()->updateOrCreate(
  213. ['reclamation_id' => $reclamation->id, 'name' => $name],
  214. ['quantity' => $quantity[$key]]
  215. );
  216. }
  217. } else {
  218. // Удаление
  219. ReclamationDetail::query()
  220. ->where('reclamation_id', $reclamation->id)
  221. ->where('name', $name)
  222. ->delete();
  223. }
  224. }
  225. return redirect()->route('reclamations.show', ['reclamation' => $reclamation, 'previous_url' => $request->get('previous_url')]);
  226. }
  227. public function updateSpareParts(StoreReclamationSparePartsRequest $request, Reclamation $reclamation)
  228. {
  229. $rows = $request->validated('rows') ?? [];
  230. $inventoryService = app(\App\Services\SparePartInventoryService::class);
  231. // Получаем текущие привязки для сравнения
  232. $currentSpareParts = $reclamation->spareParts->keyBy('id');
  233. // Собираем новые привязки
  234. $newSpareParts = [];
  235. foreach ($rows as $row) {
  236. $sparePartId = $row['spare_part_id'] ?? null;
  237. if (empty($sparePartId)) continue;
  238. $quantity = (int)($row['quantity'] ?? 0);
  239. if ($quantity < 1) continue;
  240. $withDocs = !empty($row['with_documents']) && $row['with_documents'] != '0';
  241. // Проверяем, изменилось ли количество
  242. $currentQty = $currentSpareParts->get($sparePartId)?->pivot->quantity ?? 0;
  243. $diff = $quantity - $currentQty;
  244. if ($diff > 0) {
  245. // Нужно списать дополнительное количество
  246. $sparePart = \App\Models\SparePart::find($sparePartId);
  247. if ($sparePart) {
  248. $inventoryService->deductForReclamation(
  249. $sparePart->article,
  250. $diff,
  251. $withDocs,
  252. $reclamation->id
  253. );
  254. }
  255. }
  256. $newSpareParts[$sparePartId] = [
  257. 'quantity' => $quantity,
  258. 'with_documents' => $withDocs,
  259. ];
  260. }
  261. // Синхронизируем (заменяем все старые привязки новыми)
  262. $reclamation->spareParts()->sync($newSpareParts);
  263. return redirect()->route('reclamations.show', ['reclamation' => $reclamation, 'previous_url' => $request->get('previous_url')]);
  264. }
  265. public function generateReclamationPack(Request $request, Reclamation $reclamation)
  266. {
  267. GenerateReclamationPack::dispatch($reclamation, auth()->user()->id);
  268. return redirect()->route('reclamations.show', ['reclamation' => $reclamation, 'previous_url' => $request->get('previous_url')])
  269. ->with(['success' => 'Задача генерации документов создана!']);
  270. }
  271. public function generatePhotosBeforePack(Request $request, Reclamation $reclamation)
  272. {
  273. GenerateFilesPack::dispatch($reclamation, $reclamation->photos_before, auth()->user()->id, 'Фото проблемы');
  274. return redirect()->route('reclamations.show', ['reclamation' => $reclamation, 'previous_url' => $request->get('previous_url')])
  275. ->with(['success' => 'Задача архивации создана!']);
  276. }
  277. public function generatePhotosAfterPack(Request $request, Reclamation $reclamation)
  278. {
  279. GenerateFilesPack::dispatch($reclamation, $reclamation->photos_after, auth()->user()->id, 'Фото после');
  280. return redirect()->route('reclamations.show', ['reclamation' => $reclamation, 'previous_url' => $request->get('previous_url')])
  281. ->with(['success' => 'Задача архивации создана!']); }
  282. }