$clientCase::with(['person']) ->when($request->input('search'), fn($que, $search) => $que->whereHas( 'person', fn($q) => $q->where('full_name', 'ilike', '%' . $search . '%') ) ) ->where('active', 1) ->orderByDesc('created_at') ->paginate(15, ['*'], 'client-cases-page') ->withQueryString(), 'filters' => $request->only(['search']) ]); } /** * Show the form for creating a new resource. */ public function create() { // } /** * Store a newly created resource in storage. */ public function store(Request $request) { // $cuuid = $request->input('client_uuid'); $client = \App\Models\Client::where('uuid', $cuuid)->firstOrFail(); if( isset($client->id) ){ \DB::transaction(function() use ($request, $client){ $pq = $request->input('person'); $person = $client->person()->create([ 'nu' => rand(100000,200000), 'first_name' => $pq['first_name'], 'last_name' => $pq['last_name'], 'full_name' => $pq['full_name'], 'gender' => null, 'birthday' => null, 'tax_number' => $pq['tax_number'], 'social_security_number' => $pq['social_security_number'], 'description' => $pq['description'], 'group_id' => 2, 'type_id' => 1 ]); $person->addresses()->create([ 'address' => $pq['address']['address'], 'country' => $pq['address']['country'], 'type_id' => $pq['address']['type_id'] ]); $person->phones()->create([ 'nu' => $pq['phone']['nu'], 'country_code' => $pq['phone']['country_code'], 'type_id' => $pq['phone']['type_id'] ]); $person->clientCase()->create([ 'client_id' => $client->id ]); }); } return to_route('client.show', $client); } public function storeContract(ClientCase $clientCase, Request $request) { \DB::transaction(function() use ($request, $clientCase){ // Create contract $contract = $clientCase->contracts()->create([ 'reference' => $request->input('reference'), 'start_date' => date('Y-m-d', strtotime($request->input('start_date'))), 'type_id' => $request->input('type_id'), 'description' => $request->input('description'), ]); // Optionally create/update related account amounts $initial = $request->input('initial_amount'); $balance = $request->input('balance_amount'); if (!is_null($initial) || !is_null($balance)) { $contract->account()->create([ 'initial_amount' => $initial ?? 0, 'balance_amount' => $balance ?? 0, ]); } }); return to_route('clientCase.show', $clientCase); } public function updateContract(ClientCase $clientCase, String $uuid, Request $request) { $contract = Contract::where('uuid', $uuid)->firstOrFail(); \DB::transaction(function() use ($request, $contract){ $contract->update([ 'reference' => $request->input('reference'), 'type_id' => $request->input('type_id'), 'description' => $request->input('description'), 'start_date' => $request->filled('start_date') ? date('Y-m-d', strtotime($request->input('start_date'))) : $contract->start_date, ]); $initial = $request->input('initial_amount'); $balance = $request->input('balance_amount'); if (!is_null($initial) || !is_null($balance)) { $accountData = [ 'initial_amount' => $initial ?? 0, 'balance_amount' => $balance ?? 0, ]; if ($contract->account) { $contract->account->update($accountData); } else { $contract->account()->create($accountData); } } }); return to_route('clientCase.show', $clientCase); } public function storeActivity(ClientCase $clientCase, Request $request) { try { $attributes = $request->validate([ 'due_date' => 'nullable|date', 'amount' => 'nullable|decimal:0,4', 'note' => 'nullable|string', 'action_id' => 'exists:\App\Models\Action,id', 'decision_id' => 'exists:\App\Models\Decision,id', 'contract_uuid' => 'nullable|uuid', ]); // Map contract_uuid to contract_id within the same client case, if provided $contractId = null; if (!empty($attributes['contract_uuid'])) { $contract = $clientCase->contracts()->where('uuid', $attributes['contract_uuid'])->firstOrFail('id'); if ($contract) { $contractId = $contract->id; } } // Create activity $row = $clientCase->activities()->create([ 'due_date' => $attributes['due_date'] ?? null, 'amount' => $attributes['amount'] ?? null, 'note' => $attributes['note'] ?? null, 'action_id' => $attributes['action_id'], 'decision_id' => $attributes['decision_id'], 'contract_id' => $contractId, ]); /*foreach ($activity->decision->events as $e) { $class = '\\App\\Events\\' . $e->name; event(new $class($clientCase)); }*/ logger()->info('Activity successfully inserted', $attributes); return to_route('clientCase.show', $clientCase)->with('success', 'Successful created!'); } catch (QueryException $e) { logger()->error('Database error occurred:', ['error' => $e->getMessage()]); return back()->with('error', 'Failed to insert activity. ' . $e->getMessage()); } catch (Exception $e) { logger()->error('An unexpected error occurred:', ['error' => $e->getMessage()]); // Return a generic error response return back()->with('error', 'An unexpected error occurred. Please try again later.'); } } public function deleteContract(ClientCase $clientCase, String $uuid, Request $request) { $contract = Contract::where('uuid', $uuid)->firstOrFail(); \DB::transaction(function() use ($request, $contract){ $contract->delete(); }); return to_route('clientCase.show', $clientCase); } public function storeDocument(ClientCase $clientCase, Request $request) { $validated = $request->validate([ 'file' => 'required|file|max:25600|mimes:doc,docx,pdf,txt,csv,xls,xlsx,jpeg,png', // 25MB and allowed types 'name' => 'nullable|string|max:255', 'description' => 'nullable|string', 'is_public' => 'sometimes|boolean', ]); $file = $validated['file']; $disk = 'public'; $directory = 'cases/' . $clientCase->uuid . '/documents'; $path = $file->store($directory, $disk); $doc = new Document([ 'name' => $validated['name'] ?? pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME), 'description' => $validated['description'] ?? null, 'user_id' => optional($request->user())->id, 'disk' => $disk, 'path' => $path, 'file_name' => basename($path), 'original_name' => $file->getClientOriginalName(), 'extension' => $file->getClientOriginalExtension(), 'mime_type' => $file->getMimeType(), 'size' => $file->getSize(), 'checksum' => null, 'is_public' => (bool)($validated['is_public'] ?? false), ]); $clientCase->documents()->save($doc); // Generate preview immediately for Office docs to avoid first-view delay $ext = strtolower($doc->extension ?? pathinfo($doc->original_name ?? $doc->file_name, PATHINFO_EXTENSION)); if (in_array($ext, ['doc','docx'])) { \App\Jobs\GenerateDocumentPreview::dispatch($doc->id); } return back()->with('success', 'Document uploaded.'); } public function viewDocument(ClientCase $clientCase, Document $document, Request $request) { // Ensure the document belongs to this client case if ($document->documentable_type !== ClientCase::class || $document->documentable_id !== $clientCase->id) { abort(404); } // Optional: add authz checks here (e.g., policies) $disk = $document->disk ?: 'public'; // If a preview exists (e.g., PDF generated for doc/docx), stream that $previewDisk = config('files.preview_disk', 'public'); if ($document->preview_path && Storage::disk($previewDisk)->exists($document->preview_path)) { $stream = Storage::disk($previewDisk)->readStream($document->preview_path); if ($stream === false) abort(404); return response()->stream(function () use ($stream) { fpassthru($stream); }, 200, [ 'Content-Type' => $document->preview_mime ?: 'application/pdf', 'Content-Disposition' => 'inline; filename="' . addslashes(($document->original_name ?: $document->file_name) . '.pdf') . '"', 'Cache-Control' => 'private, max-age=0, no-cache', 'Pragma' => 'no-cache', ]); } // If it's a DOC/DOCX and no preview yet, queue generation and show 202 Accepted $ext = strtolower(pathinfo($document->original_name ?: $document->file_name, PATHINFO_EXTENSION)); if (in_array($ext, ['doc','docx'])) { \App\Jobs\GenerateDocumentPreview::dispatch($document->id); return response('Preview is being generated. Please try again shortly.', 202); } if (!Storage::disk($disk)->exists($document->path)) { abort(404); } $stream = Storage::disk($disk)->readStream($document->path); if ($stream === false) { abort(404); } return response()->stream(function () use ($stream) { fpassthru($stream); }, 200, [ 'Content-Type' => $document->mime_type ?: 'application/octet-stream', 'Content-Disposition' => 'inline; filename="' . addslashes($document->original_name ?: $document->file_name) . '"', 'Cache-Control' => 'private, max-age=0, no-cache', 'Pragma' => 'no-cache', ]); } public function downloadDocument(ClientCase $clientCase, Document $document, Request $request) { if ($document->documentable_type !== ClientCase::class || $document->documentable_id !== $clientCase->id) { abort(404); } $disk = $document->disk ?: 'public'; if (!Storage::disk($disk)->exists($document->path)) { abort(404); } $name = $document->original_name ?: $document->file_name; $stream = Storage::disk($disk)->readStream($document->path); if ($stream === false) { abort(404); } return response()->stream(function () use ($stream) { fpassthru($stream); }, 200, [ 'Content-Type' => $document->mime_type ?: 'application/octet-stream', 'Content-Disposition' => 'attachment; filename="' . addslashes($name) . '"', 'Cache-Control' => 'private, max-age=0, no-cache', 'Pragma' => 'no-cache', ]); } /** * Display the specified resource. */ public function show(ClientCase $clientCase) { $case = $clientCase::with([ 'person' => fn($que) => $que->with(['addresses', 'phones']) ])->where('active', 1)->findOrFail($clientCase->id); $types = [ 'address_types' => \App\Models\Person\AddressType::all(), 'phone_types' => \App\Models\Person\PhoneType::all() ]; return Inertia::render('Cases/Show', [ 'client' => $case->client()->with('person', fn($q) => $q->with(['addresses', 'phones']))->firstOrFail(), 'client_case' => $case, 'contracts' => $case->contracts() ->with(['type', 'account', 'objects']) ->orderByDesc('created_at')->get(), 'activities' => $case->activities()->with(['action', 'decision', 'contract:id,uuid,reference']) ->orderByDesc('created_at') ->paginate(20, ['*'], 'activities'), 'documents' => $case->documents()->orderByDesc('created_at')->get(), 'contract_types' => \App\Models\ContractType::whereNull('deleted_at')->get(), 'actions' => \App\Models\Action::with('decisions')->get(), 'types' => $types ]); } /** * Show the form for editing the specified resource. */ public function edit(string $id) { // } /** * Update the specified resource in storage. */ public function update(Request $request, string $id) { // } /** * Remove the specified resource from storage. */ public function destroy(string $id) { // } }