Equipment::class, 'equipment_part' => EquipmentPart::class, 'part_catalog' => PartCatalog::class, ]; public function index(Request $request) { $business = $this->resolveBusiness($request); if (! $business) { return $this->jsonError('کسب‌وکار یافت نشد.', 404); } $request->validate([ 'documentable_type' => ['required', 'string', 'in:equipment,equipment_part,part_catalog'], 'documentable_id' => ['required', 'integer'], ]); $model = $this->resolveDocumentable($request->get('documentable_type'), (int) $request->get('documentable_id')); if (! $model || $model->business_id !== $business->id) { return $this->jsonError('مورد یافت نشد.', 404); } $docs = AssetDocument::where('business_id', $business->id) ->where('documentable_type', $model->getMorphClass()) ->where('documentable_id', $model->id) ->orderBy('sort_order') ->get(); return $this->jsonSuccess(['items' => $docs]); } public function store(Request $request) { $business = $this->resolveBusiness($request); if (! $business) { return $this->jsonError('کسب‌وکار یافت نشد.', 404); } $data = $request->validate([ 'documentable_type' => ['required', 'string', 'in:equipment,equipment_part,part_catalog'], 'documentable_id' => ['required', 'integer'], 'doc_type' => ['required', 'string', 'max:50'], 'title' => ['required', 'string', 'max:255'], 'file' => ['nullable', 'file', 'max:51200'], 'file_url' => ['nullable', 'url', 'max:500'], 'language' => ['nullable', 'string', 'max:10'], 'version' => ['nullable', 'string', 'max:50'], 'effective_date' => ['nullable', 'date'], 'notes' => ['nullable', 'string'], 'sort_order' => ['nullable', 'integer', 'min:0'], ]); $model = $this->resolveDocumentable($data['documentable_type'], (int) $data['documentable_id']); if (! $model || $model->business_id !== $business->id) { return $this->jsonError('مورد یافت نشد.', 404); } $filePath = null; $mimeType = null; if ($request->hasFile('file')) { $file = $request->file('file'); $filePath = $file->store("maintenance/docs/{$business->id}", 'public'); $mimeType = $file->getMimeType(); } $doc = AssetDocument::create([ 'business_id' => $business->id, 'documentable_type' => $model->getMorphClass(), 'documentable_id' => $model->id, 'doc_type' => $data['doc_type'], 'title' => $data['title'], 'file_path' => $filePath, 'file_url' => $data['file_url'] ?? null, 'mime_type' => $mimeType, 'language' => $data['language'] ?? 'fa', 'version' => $data['version'] ?? null, 'effective_date' => $data['effective_date'] ?? null, 'uploaded_by' => $request->user()?->id, 'notes' => $data['notes'] ?? null, 'sort_order' => $data['sort_order'] ?? 0, ]); return $this->jsonSuccess($doc, 'سند ثبت شد.', 201); } public function destroy(Request $request, AssetDocument $assetDocument) { if (! $this->ensureBusinessOwnership($request, $assetDocument->business_id)) { return $this->jsonError('دسترسی ندارید.', 403); } if ($assetDocument->file_path) { Storage::disk('public')->delete($assetDocument->file_path); } $assetDocument->delete(); return $this->jsonSuccess(null, 'سند حذف شد.'); } private function resolveDocumentable(string $type, int $id): ?object { $class = self::TYPE_MAP[$type] ?? null; if (! $class) { return null; } return $class::find($id); } }