From 7fc11a2215d3651d024049afdbb4251967ab190e Mon Sep 17 00:00:00 2001 From: kent Date: Fri, 26 Dec 2025 15:48:37 +0900 Subject: [PATCH] =?UTF-8?q?chore:=20Phase=20H,=20I=20API=20=EB=9D=BC?= =?UTF-8?q?=EC=9A=B0=ED=8A=B8=20=EB=B0=8F=20=EA=B3=B5=ED=86=B5=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - routes/api.php: H-1~3, I-2~8 엔드포인트 추가 - error.php: 에러 메시지 키 추가 (en/ko) - TenantUserProfile 모델 업데이트 - LOGICAL_RELATIONSHIPS.md 업데이트 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- LOGICAL_RELATIONSHIPS.md | 82 +++++++++++++++++++++++- app/Models/Tenants/TenantUserProfile.php | 1 + lang/en/error.php | 9 +++ lang/ko/error.php | 22 +++++++ routes/api.php | 16 +++++ 5 files changed, 129 insertions(+), 1 deletion(-) diff --git a/LOGICAL_RELATIONSHIPS.md b/LOGICAL_RELATIONSHIPS.md index 77ccda0..f2dcd76 100644 --- a/LOGICAL_RELATIONSHIPS.md +++ b/LOGICAL_RELATIONSHIPS.md @@ -1,6 +1,6 @@ # 논리적 데이터베이스 관계 문서 -> **자동 생성**: 2025-12-25 00:41:11 +> **자동 생성**: 2025-12-26 15:08:36 > **소스**: Eloquent 모델 관계 분석 ## 📊 모델별 관계 현황 @@ -361,6 +361,45 @@ ### popups - **creator()**: belongsTo → `users` - **updater()**: belongsTo → `users` +### work_orders +**모델**: `App\Models\Production\WorkOrder` + +- **salesOrder()**: belongsTo → `orders` +- **assignee()**: belongsTo → `users` +- **team()**: belongsTo → `departments` +- **creator()**: belongsTo → `users` +- **updater()**: belongsTo → `users` +- **items()**: hasMany → `work_order_items` +- **issues()**: hasMany → `work_order_issues` +- **bendingDetail()**: hasOne → `work_order_bending_details` + +### work_order_bending_details +**모델**: `App\Models\Production\WorkOrderBendingDetail` + +- **workOrder()**: belongsTo → `work_orders` + +### work_order_issues +**모델**: `App\Models\Production\WorkOrderIssue` + +- **workOrder()**: belongsTo → `work_orders` +- **reporter()**: belongsTo → `users` +- **resolver()**: belongsTo → `users` + +### work_order_items +**모델**: `App\Models\Production\WorkOrderItem` + +- **workOrder()**: belongsTo → `work_orders` +- **item()**: belongsTo → `items` + +### work_results +**모델**: `App\Models\Production\WorkResult` + +- **workOrder()**: belongsTo → `work_orders` +- **workOrderItem()**: belongsTo → `work_order_items` +- **worker()**: belongsTo → `users` +- **creator()**: belongsTo → `users` +- **updater()**: belongsTo → `users` + ### prices **모델**: `App\Models\Products\Price` @@ -540,6 +579,13 @@ ### deposits - **bankAccount()**: belongsTo → `bank_accounts` - **creator()**: belongsTo → `users` +### expected_expenses +**모델**: `App\Models\Tenants\ExpectedExpense` + +- **client()**: belongsTo → `clients` +- **bankAccount()**: belongsTo → `bank_accounts` +- **creator()**: belongsTo → `users` + ### leaves **모델**: `App\Models\Tenants\Leave` @@ -547,6 +593,7 @@ ### leaves - **approver()**: belongsTo → `users` - **creator()**: belongsTo → `users` - **updater()**: belongsTo → `users` +- **userProfile()**: hasOne → `tenant_user_profiles` ### leave_balances **모델**: `App\Models\Tenants\LeaveBalance` @@ -559,6 +606,11 @@ ### leave_grants - **user()**: belongsTo → `users` - **creator()**: belongsTo → `users` +### leave_policys +**모델**: `App\Models\Tenants\LeavePolicy` + +- **tenant()**: belongsTo → `tenants` + ### loans **모델**: `App\Models\Tenants\Loan` @@ -601,6 +653,20 @@ ### purchases - **withdrawal()**: belongsTo → `withdrawals` - **creator()**: belongsTo → `users` +### receivings +**모델**: `App\Models\Tenants\Receiving` + +- **item()**: belongsTo → `items` +- **creator()**: belongsTo → `users` + +### salarys +**모델**: `App\Models\Tenants\Salary` + +- **employee()**: belongsTo → `users` +- **creator()**: belongsTo → `users` +- **updater()**: belongsTo → `users` +- **employeeProfile()**: hasOne → `tenant_user_profiles` + ### sales **모델**: `App\Models\Tenants\Sale` @@ -619,6 +685,19 @@ ### sites - **creator()**: belongsTo → `users` - **updater()**: belongsTo → `users` +### stocks +**모델**: `App\Models\Tenants\Stock` + +- **creator()**: belongsTo → `users` +- **lots()**: hasMany → `stock_lots` + +### stock_lots +**모델**: `App\Models\Tenants\StockLot` + +- **stock()**: belongsTo → `stocks` +- **receiving()**: belongsTo → `receivings` +- **creator()**: belongsTo → `users` + ### subscriptions **모델**: `App\Models\Tenants\Subscription` @@ -677,6 +756,7 @@ ### withdrawals - **client()**: belongsTo → `clients` - **bankAccount()**: belongsTo → `bank_accounts` +- **card()**: belongsTo → `cards` - **creator()**: belongsTo → `users` ### user_invitations diff --git a/app/Models/Tenants/TenantUserProfile.php b/app/Models/Tenants/TenantUserProfile.php index f68b6e0..12861b1 100644 --- a/app/Models/Tenants/TenantUserProfile.php +++ b/app/Models/Tenants/TenantUserProfile.php @@ -28,6 +28,7 @@ class TenantUserProfile extends Model 'position_label', 'job_title_label', 'rank', + 'hire_date', ]; protected $fillable = [ diff --git a/lang/en/error.php b/lang/en/error.php index a06801e..a345243 100644 --- a/lang/en/error.php +++ b/lang/en/error.php @@ -95,4 +95,13 @@ 'duplicate_code' => 'Duplicate item code.', ], + // Shipment management related + 'shipment' => [ + 'not_found' => 'Shipment not found.', + 'cannot_edit' => 'Cannot edit in the current status.', + 'cannot_delete' => 'Cannot delete in the current status.', + 'invalid_status' => 'Invalid status.', + 'cannot_ship' => 'Not in a shippable state.', + ], + ]; diff --git a/lang/ko/error.php b/lang/ko/error.php index 139f0c9..a5200f5 100644 --- a/lang/ko/error.php +++ b/lang/ko/error.php @@ -69,6 +69,28 @@ 'in_use_cannot_delete' => '사용 중인 자재는 삭제할 수 없습니다.', ], + // 입고 관리 관련 + 'receiving' => [ + 'not_found' => '입고 정보를 찾을 수 없습니다.', + 'cannot_edit' => '입고완료 상태에서는 수정할 수 없습니다.', + 'cannot_delete' => '입고완료 상태에서는 삭제할 수 없습니다.', + 'cannot_process' => '현재 상태에서는 입고처리할 수 없습니다.', + ], + + // 재고 관리 관련 + 'stock' => [ + 'not_found' => '재고 정보를 찾을 수 없습니다.', + ], + + // 출하 관리 관련 + 'shipment' => [ + 'not_found' => '출하 정보를 찾을 수 없습니다.', + 'cannot_edit' => '현재 상태에서는 수정할 수 없습니다.', + 'cannot_delete' => '현재 상태에서는 삭제할 수 없습니다.', + 'invalid_status' => '유효하지 않은 상태입니다.', + 'cannot_ship' => '출하 가능 상태가 아닙니다.', + ], + // 파일 관리 관련 'file' => [ 'not_found' => '파일을 찾을 수 없습니다.', diff --git a/routes/api.php b/routes/api.php index b4fbf94..4f1fba5 100644 --- a/routes/api.php +++ b/routes/api.php @@ -76,6 +76,7 @@ use App\Http\Controllers\Api\V1\PurchaseController; use App\Http\Controllers\Api\V1\ReceivingController; use App\Http\Controllers\Api\V1\StockController; +use App\Http\Controllers\Api\V1\ShipmentController; use App\Http\Controllers\Api\V1\PushNotificationController; use App\Http\Controllers\Api\V1\QuoteController; use App\Http\Controllers\Api\V1\RefreshController; @@ -618,6 +619,21 @@ Route::get('/{id}', [StockController::class, 'show'])->whereNumber('id')->name('v1.stocks.show'); }); + // Shipment API (출하 관리) + Route::prefix('shipments')->group(function () { + Route::get('', [ShipmentController::class, 'index'])->name('v1.shipments.index'); + Route::get('/stats', [ShipmentController::class, 'stats'])->name('v1.shipments.stats'); + Route::get('/stats-by-status', [ShipmentController::class, 'statsByStatus'])->name('v1.shipments.stats-by-status'); + Route::get('/options/lots', [ShipmentController::class, 'lotOptions'])->name('v1.shipments.options.lots'); + Route::get('/options/logistics', [ShipmentController::class, 'logisticsOptions'])->name('v1.shipments.options.logistics'); + Route::get('/options/vehicle-tonnage', [ShipmentController::class, 'vehicleTonnageOptions'])->name('v1.shipments.options.vehicle-tonnage'); + Route::post('', [ShipmentController::class, 'store'])->name('v1.shipments.store'); + Route::get('/{id}', [ShipmentController::class, 'show'])->whereNumber('id')->name('v1.shipments.show'); + Route::put('/{id}', [ShipmentController::class, 'update'])->whereNumber('id')->name('v1.shipments.update'); + Route::patch('/{id}/status', [ShipmentController::class, 'updateStatus'])->whereNumber('id')->name('v1.shipments.status'); + Route::delete('/{id}', [ShipmentController::class, 'destroy'])->whereNumber('id')->name('v1.shipments.destroy'); + }); + // Barobill Setting API (바로빌 설정) Route::prefix('barobill-settings')->group(function () { Route::get('', [BarobillSettingController::class, 'show'])->name('v1.barobill-settings.show');