diff --git a/app/Http/Controllers/Api/V1/StockController.php b/app/Http/Controllers/Api/V1/StockController.php index 4d2eca28..1fdfd9d7 100644 --- a/app/Http/Controllers/Api/V1/StockController.php +++ b/app/Http/Controllers/Api/V1/StockController.php @@ -8,6 +8,7 @@ use App\Services\StockService; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; +use Illuminate\Support\Facades\DB; class StockController extends Controller { @@ -126,4 +127,95 @@ public function storeAdjustment(int $id, StoreStockAdjustmentRequest $request): return ApiResponse::error(__('error.stock.not_found'), 404); } } + + /** + * 재고 거래이력 (사용현황) + * GET /api/v1/stocks/{id}/transactions + */ + public function transactions(int $id): JsonResponse + { + $tenantId = app('tenant_id'); + + $stock = DB::table('stocks') + ->where('tenant_id', $tenantId) + ->where('item_id', $id) + ->first(); + + if (! $stock) { + // item_id로 직접 검색 + $stock = DB::table('stocks') + ->where('tenant_id', $tenantId) + ->where('id', $id) + ->first(); + } + + $stockId = $stock?->id; + $itemCode = $stock?->item_code; + + $transactions = DB::table('stock_transactions') + ->where('tenant_id', $tenantId) + ->where(function ($q) use ($stockId, $itemCode) { + if ($stockId) { + $q->where('stock_id', $stockId); + } + if ($itemCode) { + $q->orWhere('item_code', $itemCode); + } + }) + ->orderByDesc('created_at') + ->limit(100) + ->get([ + 'id', 'type', 'qty', 'balance_qty', 'reference_type', 'reference_id', + 'lot_no', 'reason', 'remark', 'item_code', 'item_name', 'created_by', 'created_at', + ]); + + // 참조 정보 보강 (work_order 번호 등) + $woIds = $transactions->where('reference_type', 'work_order_input') + ->pluck('reference_id')->unique()->values(); + $woMap = []; + if ($woIds->isNotEmpty()) { + $woMap = DB::table('work_orders') + ->whereIn('id', $woIds) + ->pluck('work_order_no', 'id') + ->toArray(); + } + + $data = $transactions->map(function ($tx) use ($woMap) { + $refLabel = match ($tx->reference_type) { + 'work_order_input' => '자재투입', + 'work_order_input_cancel' => '자재투입 취소', + 'work_order_input_replace' => '자재투입 교체', + 'receiving' => '입고', + 'adjustment' => '재고조정', + 'shipment' => '출하', + default => $tx->reference_type ?? '-', + }; + $refNo = $woMap[$tx->reference_id] ?? null; + + return [ + 'id' => $tx->id, + 'type' => $tx->type, + 'type_label' => $refLabel, + 'qty' => (float) $tx->qty, + 'balance_qty' => (float) $tx->balance_qty, + 'reference_type' => $tx->reference_type, + 'reference_id' => $tx->reference_id, + 'reference_no' => $refNo, + 'lot_no' => $tx->lot_no, + 'reason' => $tx->reason, + 'remark' => $tx->remark, + 'item_code' => $tx->item_code, + 'item_name' => $tx->item_name, + 'created_at' => $tx->created_at, + ]; + }); + + return ApiResponse::success([ + 'item_code' => $stock?->item_code, + 'item_name' => $stock?->item_name, + 'current_qty' => (float) ($stock?->stock_qty ?? 0), + 'available_qty' => (float) ($stock?->available_qty ?? 0), + 'transactions' => $data, + ]); + } } diff --git a/routes/api/v1/inventory.php b/routes/api/v1/inventory.php index bcb2bb2f..115e7eaf 100644 --- a/routes/api/v1/inventory.php +++ b/routes/api/v1/inventory.php @@ -115,6 +115,7 @@ Route::put('/{id}', [StockController::class, 'update'])->whereNumber('id')->name('v1.stocks.update'); Route::get('/{id}/adjustments', [StockController::class, 'adjustments'])->whereNumber('id')->name('v1.stocks.adjustments'); Route::post('/{id}/adjustments', [StockController::class, 'storeAdjustment'])->whereNumber('id')->name('v1.stocks.adjustments.store'); + Route::get('/{id}/transactions', [StockController::class, 'transactions'])->whereNumber('id')->name('v1.stocks.transactions'); }); // Shipment API (출하 관리)