vernova/app/Http/Controllers/LetterController.php
2026-07-26 19:58:27 +03:30

259 lines
7.7 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Models\Letter;
use App\Models\LetterAttachment;
use App\Models\Project;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
class LetterController extends Controller
{
/**
* Display a listing of letters with filters.
*/
public function index(Request $request)
{
$this->authorize('viewAny', Letter::class);
$query = Letter::with(['project', 'attachments']);
if ($request->filled('type')) {
$query->byType($request->type);
}
if ($request->filled('status')) {
$query->byStatus($request->status);
}
if ($request->filled('project_id')) {
$query->where('project_id', $request->project_id);
}
if ($request->filled('search')) {
$query->search($request->search);
}
$letters = $query->orderBy('letter_date', 'desc')
->orderBy('created_at', 'desc')
->paginate(20)
->appends($request->query());
$projects = Project::all();
$types = ['incoming', 'outgoing'];
$statuses = ['draft', 'sent', 'received', 'archived'];
return view('letters.index', compact('letters', 'projects', 'types', 'statuses'));
}
/**
* Show the form for creating a new letter.
*/
public function create(Request $request)
{
$this->authorize('create', Letter::class);
$projects = Project::all();
$letters = Letter::orderBy('letter_date', 'desc')->limit(50)->get();
$letter = null;
// Pre-fill parent_letter_id if provided
$preselectedParent = $request->get('parent_letter_id');
return view('letters.form', compact('projects', 'letters', 'letter', 'preselectedParent'));
}
/**
* Store a newly created letter in storage.
*/
public function store(Request $request)
{
$this->authorize('create', Letter::class);
$validated = $request->validate([
'type' => 'required|in:incoming,outgoing',
'subject' => 'required|string|max:255',
'sender' => 'required|string|max:255',
'recipient' => 'required|string|max:255',
'letter_date' => 'required|date',
'reference_number' => 'nullable|string|max:100',
'project_id' => 'nullable|exists:projects,id',
'parent_letter_id' => 'nullable|exists:letters,id',
'status' => 'required|in:draft,sent,received,archived',
'content' => 'nullable|string',
'attachments.*' => 'nullable|file|mimes:jpg,jpeg,png,pdf|max:10240',
]);
// Convert jalali date if needed
if (!empty($validated['letter_date'])) {
$validated['letter_date'] = \App\Helpers\CalendarHelper::parseDate($validated['letter_date']);
}
$validated['tenant_id'] = $this->getTenantId();
$letter = Letter::create($validated);
// Handle file attachments
if ($request->hasFile('attachments')) {
foreach ($request->file('attachments') as $file) {
$this->storeAttachment($letter, $file);
}
}
// Remove checked attachments (for edit, but safe to check)
if ($request->has('remove_attachments')) {
foreach ($request->remove_attachments as $attachmentId) {
$this->removeAttachment($attachmentId, $letter);
}
}
return redirect()
->route('letters.show', $letter)
->with('success', __('letter.created_successfully'));
}
/**
* Display the specified letter.
*/
public function show(Letter $letter)
{
$this->authorize('view', $letter);
$letter->load(['project', 'parentLetter', 'replies', 'attachments']);
return view('letters.show', compact('letter'));
}
/**
* Show the form for editing the specified letter.
*/
public function edit(Letter $letter)
{
$this->authorize('update', $letter);
$letter->load('attachments');
$projects = Project::all();
$letters = Letter::where('id', '!=', $letter->id)
->orderBy('letter_date', 'desc')
->limit(50)
->get();
return view('letters.form', compact('letter', 'projects', 'letters'));
}
/**
* Update the specified letter in storage.
*/
public function update(Request $request, Letter $letter)
{
$this->authorize('update', $letter);
$validated = $request->validate([
'type' => 'required|in:incoming,outgoing',
'subject' => 'required|string|max:255',
'sender' => 'required|string|max:255',
'recipient' => 'required|string|max:255',
'letter_date' => 'required|date',
'reference_number' => 'nullable|string|max:100',
'project_id' => 'nullable|exists:projects,id',
'parent_letter_id' => 'nullable|exists:letters,id',
'status' => 'required|in:draft,sent,received,archived',
'content' => 'nullable|string',
'attachments.*' => 'nullable|file|mimes:jpg,jpeg,png,pdf|max:10240',
]);
// Convert jalali date if needed
if (!empty($validated['letter_date'])) {
$validated['letter_date'] = \App\Helpers\CalendarHelper::parseDate($validated['letter_date']);
}
$letter->update($validated);
// Handle file attachments
if ($request->hasFile('attachments')) {
foreach ($request->file('attachments') as $file) {
$this->storeAttachment($letter, $file);
}
}
// Remove checked attachments
if ($request->has('remove_attachments')) {
foreach ($request->remove_attachments as $attachmentId) {
$this->removeAttachment($attachmentId, $letter);
}
}
return redirect()
->route('letters.show', $letter)
->with('success', __('letter.updated_successfully'));
}
/**
* Remove the specified letter from storage.
*/
public function destroy(Letter $letter)
{
$this->authorize('delete', $letter);
// Delete attachments from storage
foreach ($letter->attachments as $attachment) {
Storage::disk('public')->delete($attachment->file_path);
}
$letter->delete();
return redirect()
->route('letters.index')
->with('success', __('letter.deleted_successfully'));
}
/**
* Archive the specified letter.
*/
public function archive(Letter $letter)
{
$this->authorize('update', $letter);
$letter->update(['status' => 'archived']);
return response()->json([
'success' => true,
'message' => __('letter.archived_successfully'),
]);
}
/**
* Store a file attachment for a letter.
*/
private function storeAttachment(Letter $letter, $file): void
{
$path = $file->store('letters/' . $letter->id, 'public');
LetterAttachment::create([
'letter_id' => $letter->id,
'file_name' => $file->getClientOriginalName(),
'file_path' => $path,
'file_size' => $file->getSize(),
'mime_type' => $file->getMimeType(),
]);
}
/**
* Remove a letter attachment.
*/
private function removeAttachment(int $attachmentId, Letter $letter): void
{
$attachment = LetterAttachment::where('id', $attachmentId)
->where('letter_id', $letter->id)
->first();
if ($attachment) {
Storage::disk('public')->delete($attachment->file_path);
$attachment->delete();
}
}
}