feat: [quality] 품질관리서 파일 업로드/삭제 API

- POST /{id}/upload-file: 1건당 1파일, 기존 파일 교체
- DELETE /{id}/file: 파일 soft delete
- QualityDocument.file() relation 추가
- R2 저장 경로: {tenant_id}/quality-documents/{year}/{month}

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-13 10:14:00 +09:00
parent ef591074c7
commit 597aecb5e8
4 changed files with 106 additions and 0 deletions

View File

@@ -2,6 +2,7 @@
namespace App\Services;
use App\Models\Commons\File;
use App\Models\Documents\Document;
use App\Models\Documents\DocumentData;
use App\Models\Documents\DocumentTemplate;
@@ -13,7 +14,9 @@
use App\Models\Qualitys\QualityDocumentLocation;
use App\Models\Qualitys\QualityDocumentOrder;
use App\Services\Audit\AuditLogger;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
@@ -1248,4 +1251,78 @@ private function formatInspectionPeriod(array $options): string
return $start ?: $end ?: '';
}
// =========================================================================
// 파일 업로드/삭제
// =========================================================================
/**
* 품질관리서 파일 업로드 (1건당 1파일, 기존 파일 있으면 교체)
*/
public function uploadFile(int $id, UploadedFile $uploadedFile): array
{
$tenantId = $this->tenantId();
$userId = $this->apiUserId();
$doc = QualityDocument::where('tenant_id', $tenantId)->findOrFail($id);
// 기존 파일이 있으면 물리 삭제 (교체)
$existingFile = $doc->file;
if ($existingFile) {
$existingFile->permanentDelete();
}
// 저장 경로: {tenant_id}/quality-documents/{year}/{month}/{stored_name}
$date = now();
$storedName = bin2hex(random_bytes(16)).'.'.$uploadedFile->getClientOriginalExtension();
$filePath = sprintf(
'%d/quality-documents/%s/%s/%s',
$tenantId,
$date->format('Y'),
$date->format('m'),
$storedName
);
// R2에 파일 저장
Storage::disk('r2')->put($filePath, file_get_contents($uploadedFile->getPathname()));
// DB 레코드 생성
$file = File::create([
'tenant_id' => $tenantId,
'document_type' => QualityDocument::class,
'document_id' => $doc->id,
'display_name' => $uploadedFile->getClientOriginalName(),
'stored_name' => $storedName,
'file_path' => $filePath,
'file_size' => $uploadedFile->getSize(),
'mime_type' => $uploadedFile->getClientMimeType(),
'uploaded_by' => $userId,
'created_by' => $userId,
]);
return [
'id' => $file->id,
'display_name' => $file->display_name,
'file_size' => $file->file_size,
'mime_type' => $file->mime_type,
'created_at' => $file->created_at?->toIso8601String(),
];
}
/**
* 품질관리서 파일 삭제
*/
public function deleteFile(int $id): void
{
$tenantId = $this->tenantId();
$doc = QualityDocument::where('tenant_id', $tenantId)->findOrFail($id);
$file = $doc->file;
if (! $file) {
throw new NotFoundHttpException(__('error.not_found'));
}
$file->softDeleteFile($this->apiUserId());
}
}