diff --git a/LOGICAL_RELATIONSHIPS.md b/LOGICAL_RELATIONSHIPS.md index be019cff..4983f5a0 100644 --- a/LOGICAL_RELATIONSHIPS.md +++ b/LOGICAL_RELATIONSHIPS.md @@ -1,6 +1,6 @@ # 논리적 데이터베이스 관계 문서 -> **자동 생성**: 2026-03-12 13:58:25 +> **자동 생성**: 2026-03-17 13:34:26 > **소스**: Eloquent 모델 관계 분석 ## 📊 모델별 관계 현황 @@ -374,6 +374,8 @@ ### esign_signers ### equipments **모델**: `App\Models\Equipment\Equipment` +- **manager()**: belongsTo → `users` +- **subManager()**: belongsTo → `users` - **inspectionTemplates()**: hasMany → `equipment_inspection_templates` - **inspections()**: hasMany → `equipment_inspections` - **repairs()**: hasMany → `equipment_repairs` @@ -384,6 +386,7 @@ ### equipment_inspections **모델**: `App\Models\Equipment\EquipmentInspection` - **equipment()**: belongsTo → `equipments` +- **inspector()**: belongsTo → `users` - **details()**: hasMany → `equipment_inspection_details` ### equipment_inspection_details @@ -407,6 +410,7 @@ ### equipment_repairs **모델**: `App\Models\Equipment\EquipmentRepair` - **equipment()**: belongsTo → `equipments` +- **repairer()**: belongsTo → `users` ### estimates **모델**: `App\Models\Estimate\Estimate` @@ -429,6 +433,12 @@ ### file_share_links - **file()**: belongsTo → `files` - **tenant()**: belongsTo → `tenants` +### corporate_vehicles +**모델**: `App\Models\Tenants\CorporateVehicle` + +- **logs()**: hasMany → `vehicle_logs` +- **maintenances()**: hasMany → `vehicle_maintenances` + ### folders **모델**: `App\Models\Folder` @@ -713,6 +723,11 @@ ### process_steps - **process()**: belongsTo → `processes` +### bending_item_mappings +**모델**: `App\Models\Production\BendingItemMapping` + +- **item()**: belongsTo → `items` + ### work_orders **모델**: `App\Models\Production\WorkOrder` @@ -898,6 +913,7 @@ ### quality_documents - **documentOrders()**: hasMany → `quality_document_orders` - **locations()**: hasMany → `quality_document_locations` - **performanceReport()**: hasOne → `performance_reports` +- **file()**: hasOne → `files` ### quality_document_locations **모델**: `App\Models\Qualitys\QualityDocumentLocation` @@ -1232,6 +1248,7 @@ ### shipments - **order()**: belongsTo → `orders` - **workOrder()**: belongsTo → `work_orders` +- **client()**: belongsTo → `clients` - **creator()**: belongsTo → `users` - **updater()**: belongsTo → `users` - **items()**: hasMany → `shipment_items` @@ -1242,6 +1259,7 @@ ### shipment_items - **shipment()**: belongsTo → `shipments` - **stockLot()**: belongsTo → `stock_lots` +- **orderItem()**: belongsTo → `order_items` ### shipment_vehicle_dispatchs **모델**: `App\Models\Tenants\ShipmentVehicleDispatch` @@ -1353,6 +1371,16 @@ ### today_issues - **reader()**: belongsTo → `users` - **targetUser()**: belongsTo → `users` +### vehicle_logs +**모델**: `App\Models\Tenants\VehicleLog` + +- **vehicle()**: belongsTo → `corporate_vehicles` + +### vehicle_maintenances +**모델**: `App\Models\Tenants\VehicleMaintenance` + +- **vehicle()**: belongsTo → `corporate_vehicles` + ### withdrawals **모델**: `App\Models\Tenants\Withdrawal` diff --git a/app/Models/Documents/DocumentTemplateSection.php b/app/Models/Documents/DocumentTemplateSection.php index de149e6a..03f569f3 100644 --- a/app/Models/Documents/DocumentTemplateSection.php +++ b/app/Models/Documents/DocumentTemplateSection.php @@ -12,7 +12,8 @@ * @property int $id * @property int $template_id * @property string $title 섹션 제목 - * @property string|null $image_path 검사 기준 이미지 경로 + * @property string|null $image_path 검사 기준 이미지 경로 (R2 key) + * @property int|null $file_id 도해 이미지 파일 ID (files 테이블 참조) * @property int $sort_order 정렬 순서 */ class DocumentTemplateSection extends Model @@ -24,6 +25,7 @@ class DocumentTemplateSection extends Model 'title', 'description', 'image_path', + 'file_id', 'sort_order', ]; diff --git a/app/Services/ClientService.php b/app/Services/ClientService.php index 197ee8ac..3716c763 100644 --- a/app/Services/ClientService.php +++ b/app/Services/ClientService.php @@ -53,7 +53,7 @@ public function index(array $params) $query->whereDate('created_at', '<=', $endDate); } - $query->orderBy('client_code')->orderBy('id'); + $query->orderBy('id', 'desc'); $paginator = $query->paginate($size, ['*'], 'page', $page); @@ -304,10 +304,14 @@ public function stats(): array { $tenantId = $this->tenantId(); - $total = Client::where('tenant_id', $tenantId)->count(); + $base = Client::where('tenant_id', $tenantId); + + $total = (clone $base)->count(); + $active = (clone $base)->where('is_active', true)->count(); + $inactive = $total - $active; // 거래처 유형별 통계 - $typeCounts = Client::where('tenant_id', $tenantId) + $typeCounts = (clone $base) ->selectRaw('client_type, COUNT(*) as count') ->groupBy('client_type') ->pluck('count', 'client_type') @@ -321,12 +325,14 @@ public function stats(): array ->distinct('client_id') ->pluck('client_id'); - $badDebtCount = Client::where('tenant_id', $tenantId) + $badDebtCount = (clone $base) ->whereIn('id', $badDebtClientIds) ->count(); return [ 'total' => $total, + 'active' => $active, + 'inactive' => $inactive, 'sales' => $typeCounts['SALES'] ?? 0, 'purchase' => $typeCounts['PURCHASE'] ?? 0, 'both' => $typeCounts['BOTH'] ?? 0, diff --git a/app/Services/DocumentService.php b/app/Services/DocumentService.php index b0a4a66f..bf11cef9 100644 --- a/app/Services/DocumentService.php +++ b/app/Services/DocumentService.php @@ -982,6 +982,7 @@ public function formatTemplateForReact(DocumentTemplate $template): array 'name' => $section->title, 'title' => $section->title, 'image_path' => $section->image_path, + 'file_id' => $section->file_id, 'sort_order' => $section->sort_order, 'items' => $section->items->map(function ($item) use ($methodCodes) { // method 코드를 한글 이름으로 변환 diff --git a/database/migrations/2026_03_12_120000_add_file_id_to_document_template_sections.php b/database/migrations/2026_03_12_120000_add_file_id_to_document_template_sections.php new file mode 100644 index 00000000..219ecbd4 --- /dev/null +++ b/database/migrations/2026_03_12_120000_add_file_id_to_document_template_sections.php @@ -0,0 +1,32 @@ +unsignedBigInteger('file_id')->nullable()->after('image_path') + ->comment('도해 이미지 파일 ID (files 테이블 참조)'); + }); + + // 기존 image_path → file_id 백필 (files.file_path와 매칭) + DB::statement(' + UPDATE document_template_sections dts + INNER JOIN files f ON f.file_path = dts.image_path AND f.deleted_at IS NULL + SET dts.file_id = f.id + WHERE dts.image_path IS NOT NULL AND dts.file_id IS NULL + '); + } + + public function down(): void + { + Schema::table('document_template_sections', function (Blueprint $table) { + $table->dropColumn('file_id'); + }); + } +}; \ No newline at end of file diff --git a/routes/web.php b/routes/web.php index d72b935f..be32c254 100644 --- a/routes/web.php +++ b/routes/web.php @@ -38,14 +38,19 @@ ]); })->where('path', '.*'); -// R2 테넌트 파일 프록시 (문서 템플릿 이미지 등, 인증 불필요, 캐시 1일) -Route::get('/storage/tenants/{path}', function (string $path) { - if (! Storage::disk('r2')->exists($path)) { +// R2 파일 프록시 (file_id 기반, 인증 불필요, 캐시 1일) +Route::get('/files/{id}/view', function (int $id) { + $file = \App\Models\File::find($id); + if (! $file || ! $file->file_path) { abort(404); } - $mime = Storage::disk('r2')->mimeType($path); - $stream = Storage::disk('r2')->readStream($path); + if (! Storage::disk('r2')->exists($file->file_path)) { + abort(404); + } + + $mime = Storage::disk('r2')->mimeType($file->file_path); + $stream = Storage::disk('r2')->readStream($file->file_path); return response()->stream(function () use ($stream) { fpassthru($stream); @@ -56,7 +61,7 @@ 'Content-Type' => $mime, 'Cache-Control' => 'public, max-age=86400', ]); -})->where('path', '.*'); +}); // Swagger 설정 Route::get('/docs/api-docs.json', function () {