'status', 'execution_type_name' => 'execution_type', 'items_count' => 'id', ]; protected array $data = [ 'active' => 'schedule_orders', 'title' => 'График заказов', 'id' => 'schedule_orders', 'header' => [ 'id' => 'ID', 'order_number' => 'Номер заказа', 'customer_name' => 'Заказчик', 'object_address' => 'Адрес объекта', 'invoice_number' => '№ счёта', 'payment_date' => 'Дата оплаты', 'supply_working_days' => 'Срок поставки', 'contract_shipment_date' => 'Дата отгрузки по договору', 'application_shipment_date' => 'Дата отгрузки по заявке', 'status_name' => 'Статус', 'execution_type_name' => 'Тип', 'manager_id' => 'Менеджер', 'items_count' => 'МАФ', 'note' => 'Примечание', ], 'searchFields' => [ 'order_number', 'customer_name', 'object_address', 'invoice_number', 'contract_number', 'note', ], ]; public function index(Request $request): View { session(['gp_schedule_orders' => $request->query()]); $nav = $this->startNavigationContext($request); $model = new ProductionOrder; $this->data['header'] = array_filter( $this->data['header'], fn (string $field): bool => $request->user()->canViewField( 'schedule-orders', self::FIELD_MAP[$field] ?? $field, ), ARRAY_FILTER_USE_KEY, ); $this->data['searchFields'] = array_values(array_filter( $this->data['searchFields'], fn (string $field): bool => $request->user()->canViewField('schedule-orders', $field), )); $this->createDateFilters( $model, ...array_values(array_intersect([ 'payment_date', 'contract_shipment_date', 'application_shipment_date', ], array_keys($this->data['header']))), ); if (isset($this->data['header']['supply_working_days'])) { $this->createRangeFilters($model, 'supply_working_days'); } foreach (['status_name', 'execution_type_name'] as $field) { if (isset($this->data['header'][$field])) { $this->data['filters'][$field] = [ 'title' => $this->data['header'][$field], 'values' => [], ]; } } $query = ProductionOrder::query()->with('manager')->withCount('items'); $this->acceptFilters($query, $request); $this->acceptSearch($query, $request); $requestedSort = $request->string('sortBy')->toString(); $sortMap = [ 'status_name' => 'status', 'execution_type_name' => 'execution_type', 'items_count' => 'items_count', ]; if (isset($sortMap[$requestedSort])) { $request->merge(['sortBy' => $sortMap[$requestedSort]]); } $this->setSortAndOrderBy($model, $request); if ($requestedSort !== '' && isset($sortMap[$requestedSort])) { $this->data['sortBy'] = $requestedSort; $query->orderBy($sortMap[$requestedSort], $this->data['orderBy']); $query->orderBy('id', $this->data['orderBy']); } else { $this->applyStableSorting($query); } $this->data['orders'] = $query->paginate($this->data['per_page'])->withQueryString(); $this->data['nav'] = $nav; return view('production_orders.index', $this->data); } public function create(Request $request, FieldAccessService $fieldAccess): View { return $this->orderView($request, $fieldAccess); } public function show( Request $request, ProductionOrder $productionOrder, FieldAccessService $fieldAccess, ): View { return $this->orderView( $request, $fieldAccess, $productionOrder->load([ 'manager', 'items.catalogItem.imageFile', 'deliveries.driver', 'installations.brigadier', 'activities.user', ]), ); } public function store( SaveProductionOrderRequest $request, FieldAccessService $fieldAccess, ProductionOrderService $service, ): RedirectResponse { $validated = $request->validated(); $items = $validated['items']; $fields = array_keys(config('access.schedule-orders.fields', [])); $payload = $fieldAccess->filterValidatedPayload( $request->user(), 'schedule-orders', Arr::only($validated, $fields), ); $payload['items'] = $items; $order = $service->create($payload, $request->user()); return redirect()->route('schedule.orders.show', $this->withNav( ['productionOrder' => $order], $this->resolveNavToken($request), ))->with('success', 'Заказ создан.'); } public function update( SaveProductionOrderRequest $request, ProductionOrder $productionOrder, FieldAccessService $fieldAccess, ProductionOrderService $service, ): RedirectResponse { $validated = $request->validated(); $fields = array_keys(config('access.schedule-orders.fields', [])); $payload = $fieldAccess->filterValidatedPayload( $request->user(), 'schedule-orders', Arr::only($validated, $fields), ); $canManageItems = $request->user()->hasPermission('schedule-orders.items.manage'); $editableItemFields = array_values(array_filter( ['factory_number', 'manufacture_date'], fn (string $field): bool => $request->user()->canUpdateField('schedule-orders', $field), )); if (($canManageItems || $editableItemFields !== []) && isset($validated['items'])) { $payload['items'] = $validated['items']; } $service->update( $productionOrder, $payload, $request->user(), $canManageItems, $editableItemFields, ); return redirect()->route('schedule.orders.show', $this->withNav( ['productionOrder' => $productionOrder], $this->resolveNavToken($request), ))->with('success', 'Заказ обновлён.'); } public function destroy(Request $request, ProductionOrder $productionOrder): RedirectResponse { $productionOrder->delete(); return redirect() ->route('schedule.orders', session('gp_schedule_orders')) ->with('success', 'Заказ удалён.'); } public function searchCatalogItems(Request $request): JsonResponse { $validated = $request->validate([ 'q' => ['nullable', 'string', 'max:200'], ]); $search = trim((string) ($validated['q'] ?? '')); if (mb_strlen($search) < 2) { return response()->json([]); } $items = CommonCatalogItem::query() ->where(function ($query) use ($search): void { $query ->where('article', 'like', "%{$search}%") ->orWhere('calculator_name', 'like', "%{$search}%") ->orWhere('print_name', 'like', "%{$search}%"); }) ->orderBy('article') ->limit(50) ->get(['id', 'article', 'calculator_name', 'print_name']) ->map(static fn (CommonCatalogItem $item): array => [ 'id' => $item->id, 'label' => $item->article.' — '.($item->calculator_name ?: $item->print_name ?: 'Без наименования'), ]) ->values(); return response()->json($items); } private function orderView( Request $request, FieldAccessService $fieldAccess, ?ProductionOrder $order = null, ): View { $nav = $this->resolveNavToken($request); $this->rememberNavigation($request, $nav); $fields = array_keys(config('access.schedule-orders.fields', [])); $catalogItemIds = collect($order?->items ?? []) ->pluck('common_catalog_item_id') ->merge(collect($request->old('items', []))->pluck('common_catalog_item_id')) ->filter() ->unique() ->values(); return view('production_orders.edit', [ 'active' => 'schedule_orders', 'title' => $order ? 'Заказ '.$order->order_number : 'Новый заказ', 'order' => $order, 'nav' => $nav, 'back_url' => $this->navigationBackUrl( $request, $nav, route('schedule.orders', session('gp_schedule_orders')), ), 'readableFields' => array_fill_keys( $fieldAccess->filterReadableFields($request->user(), 'schedule-orders', $fields), true, ), 'writableFields' => collect($fields)->mapWithKeys(fn (string $field): array => [ $field => $request->user()->canUpdateField('schedule-orders', $field), ])->all(), 'canManageItems' => $request->user()->hasPermission('schedule-orders.items.manage'), 'canManageDeliveries' => $request->user()->hasPermission('schedule-orders.deliveries.manage'), 'canManageInstallations' => $request->user()->hasPermission('schedule-orders.installations.manage'), 'canUpdateFactoryNumber' => $request->user()->canUpdateField('schedule-orders', 'factory_number'), 'canUpdateManufactureDate' => $request->user()->canUpdateField('schedule-orders', 'manufacture_date'), 'managers' => User::query() ->where('role', Role::MANAGER) ->orderBy('name') ->pluck('name', 'id'), 'drivers' => User::query() ->whereIn('role', [Role::DRIVER, Role::BRIGADIER]) ->orderBy('name') ->pluck('name', 'id'), 'brigadiers' => User::query() ->where('role', Role::BRIGADIER) ->orderBy('name') ->pluck('name', 'id'), 'catalogItems' => CommonCatalogItem::query() ->whereKey($catalogItemIds) ->get(['id', 'article', 'calculator_name', 'print_name']) ->keyBy('id'), 'statuses' => ProductionOrderStatus::options(), 'executionTypes' => ProductionOrderExecutionType::options(), ]); } }