From 6563d977ee98ec298ab3206700f901a81885f599 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=ED=98=81=EC=84=B1?= Date: Wed, 18 Mar 2026 23:15:47 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20[shipment]=20=EB=B0=B0=EC=B0=A8=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=EB=A5=BC=20shipment=5Fvehicle=5Fdispatches?= =?UTF-8?q?=EB=A1=9C=20=EC=9D=BC=EC=9B=90=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - shipments 테이블에서 배차 관련 컬럼 8개 삭제 (vehicle_no, driver_name 등) - shipping 전환 시 배차 정보를 vehicle_dispatches에 저장 - delivery_method ENUM → VARCHAR 변경 (common_codes 기반) - VehicleDispatchService에 수주/작성자 관계 로딩 추가 - Swagger delivery_method enum 제약 제거 Co-Authored-By: Claude Opus 4.6 (1M context) --- .../Shipment/ShipmentStoreRequest.php | 11 ----- .../Shipment/ShipmentUpdateRequest.php | 11 ----- app/Models/Tenants/Shipment.php | 13 ----- app/Services/ShipmentService.php | 47 ++++++------------- app/Services/VehicleDispatchService.php | 6 +-- app/Swagger/v1/ShipmentApi.php | 6 +-- ...remove_dispatch_columns_from_shipments.php | 42 +++++++++++++++++ ...e_shipments_delivery_method_to_varchar.php | 24 ++++++++++ 8 files changed, 87 insertions(+), 73 deletions(-) create mode 100644 database/migrations/2026_03_18_150736_remove_dispatch_columns_from_shipments.php create mode 100644 database/migrations/2026_03_18_203210_change_shipments_delivery_method_to_varchar.php diff --git a/app/Http/Requests/Shipment/ShipmentStoreRequest.php b/app/Http/Requests/Shipment/ShipmentStoreRequest.php index c384e415..cf90c8f3 100644 --- a/app/Http/Requests/Shipment/ShipmentStoreRequest.php +++ b/app/Http/Requests/Shipment/ShipmentStoreRequest.php @@ -41,17 +41,6 @@ public function rules(): array 'loading_manager' => 'nullable|string|max:50', 'loading_time' => 'nullable|date', - // 물류/배차 정보 - 'logistics_company' => 'nullable|string|max:50', - 'vehicle_tonnage' => 'nullable|string|max:20', - 'shipping_cost' => 'nullable|numeric|min:0', - - // 차량/운전자 정보 - 'vehicle_no' => 'nullable|string|max:20', - 'driver_name' => 'nullable|string|max:50', - 'driver_contact' => 'nullable|string|max:50', - 'expected_arrival' => 'nullable|date', - // 기타 'remarks' => 'nullable|string', diff --git a/app/Http/Requests/Shipment/ShipmentUpdateRequest.php b/app/Http/Requests/Shipment/ShipmentUpdateRequest.php index 43b4b144..444ab1b3 100644 --- a/app/Http/Requests/Shipment/ShipmentUpdateRequest.php +++ b/app/Http/Requests/Shipment/ShipmentUpdateRequest.php @@ -39,17 +39,6 @@ public function rules(): array 'loading_manager' => 'nullable|string|max:50', 'loading_time' => 'nullable|date', - // 물류/배차 정보 - 'logistics_company' => 'nullable|string|max:50', - 'vehicle_tonnage' => 'nullable|string|max:20', - 'shipping_cost' => 'nullable|numeric|min:0', - - // 차량/운전자 정보 - 'vehicle_no' => 'nullable|string|max:20', - 'driver_name' => 'nullable|string|max:50', - 'driver_contact' => 'nullable|string|max:50', - 'expected_arrival' => 'nullable|date', - // 기타 'remarks' => 'nullable|string', diff --git a/app/Models/Tenants/Shipment.php b/app/Models/Tenants/Shipment.php index 44afd600..18d0cd6f 100644 --- a/app/Models/Tenants/Shipment.php +++ b/app/Models/Tenants/Shipment.php @@ -42,16 +42,6 @@ class Shipment extends Model 'loading_manager', 'loading_completed_at', 'loading_time', - // 물류/배차 정보 - 'logistics_company', - 'vehicle_tonnage', - 'shipping_cost', - // 차량/운전자 정보 - 'vehicle_no', - 'driver_name', - 'driver_contact', - 'expected_arrival', - 'confirmed_arrival', // 기타 'remarks', 'created_by', @@ -66,9 +56,6 @@ class Shipment extends Model 'invoice_issued' => 'boolean', 'loading_completed_at' => 'datetime', 'loading_time' => 'datetime', - 'expected_arrival' => 'datetime', - 'confirmed_arrival' => 'datetime', - 'shipping_cost' => 'decimal:0', 'order_id' => 'integer', 'work_order_id' => 'integer', 'client_id' => 'integer', diff --git a/app/Services/ShipmentService.php b/app/Services/ShipmentService.php index 896c5fdb..b6c1e073 100644 --- a/app/Services/ShipmentService.php +++ b/app/Services/ShipmentService.php @@ -239,15 +239,6 @@ public function store(array $data): Shipment // 상차 정보 'loading_manager' => $data['loading_manager'] ?? null, 'loading_time' => $data['loading_time'] ?? null, - // 물류/배차 정보 - 'logistics_company' => $data['logistics_company'] ?? null, - 'vehicle_tonnage' => $data['vehicle_tonnage'] ?? null, - 'shipping_cost' => $data['shipping_cost'] ?? null, - // 차량/운전자 정보 - 'vehicle_no' => $data['vehicle_no'] ?? null, - 'driver_name' => $data['driver_name'] ?? null, - 'driver_contact' => $data['driver_contact'] ?? null, - 'expected_arrival' => $data['expected_arrival'] ?? null, // 기타 'remarks' => $data['remarks'] ?? null, 'created_by' => $userId, @@ -299,15 +290,6 @@ public function update(int $id, array $data): Shipment // 상차 정보 'loading_manager' => $data['loading_manager'] ?? $shipment->loading_manager, 'loading_time' => $data['loading_time'] ?? $shipment->loading_time, - // 물류/배차 정보 - 'logistics_company' => $data['logistics_company'] ?? $shipment->logistics_company, - 'vehicle_tonnage' => $data['vehicle_tonnage'] ?? $shipment->vehicle_tonnage, - 'shipping_cost' => $data['shipping_cost'] ?? $shipment->shipping_cost, - // 차량/운전자 정보 - 'vehicle_no' => $data['vehicle_no'] ?? $shipment->vehicle_no, - 'driver_name' => $data['driver_name'] ?? $shipment->driver_name, - 'driver_contact' => $data['driver_contact'] ?? $shipment->driver_contact, - 'expected_arrival' => $data['expected_arrival'] ?? $shipment->expected_arrival, // 기타 'remarks' => $data['remarks'] ?? $shipment->remarks, 'updated_by' => $userId, @@ -360,25 +342,26 @@ public function updateStatus(int $id, string $status, ?array $additionalData = n } else { $updateData['loading_completed_at'] = now(); } - - if (isset($additionalData['vehicle_no'])) { - $updateData['vehicle_no'] = $additionalData['vehicle_no']; - } - if (isset($additionalData['driver_name'])) { - $updateData['driver_name'] = $additionalData['driver_name']; - } - if (isset($additionalData['driver_contact'])) { - $updateData['driver_contact'] = $additionalData['driver_contact']; - } - } - - if ($status === 'completed' && isset($additionalData['confirmed_arrival'])) { - $updateData['confirmed_arrival'] = $additionalData['confirmed_arrival']; } $previousStatus = $shipment->status; $shipment->update($updateData); + // shipping 전환 시 배차 정보를 shipment_vehicle_dispatches에 저장 + if ($status === 'shipping' && $additionalData) { + $nextSeq = $shipment->vehicleDispatches()->max('seq') ?? 0; + ShipmentVehicleDispatch::create([ + 'tenant_id' => $tenantId, + 'shipment_id' => $shipment->id, + 'seq' => $nextSeq + 1, + 'vehicle_no' => $additionalData['vehicle_no'] ?? null, + 'driver_contact' => $additionalData['driver_contact'] ?? null, + 'logistics_company' => $additionalData['logistics_company'] ?? null, + 'tonnage' => $additionalData['vehicle_tonnage'] ?? null, + 'arrival_datetime' => $additionalData['confirmed_arrival'] ?? null, + ]); + } + // 재고 차감 비활성화: 수주생산은 재고 미경유, 선생산 완성품은 자재 투입 시 차감됨 // TODO: 선생산 로직 검증 후 재검토 (decreaseStockForShipment) diff --git a/app/Services/VehicleDispatchService.php b/app/Services/VehicleDispatchService.php index cfae5fbc..e72454de 100644 --- a/app/Services/VehicleDispatchService.php +++ b/app/Services/VehicleDispatchService.php @@ -16,7 +16,7 @@ public function index(array $params): LengthAwarePaginator $query = ShipmentVehicleDispatch::query() ->where('tenant_id', $tenantId) - ->with('shipment'); + ->with(['shipment.order.client', 'shipment.order.writer', 'shipment.creator']); // 검색어 필터 if (! empty($params['search'])) { @@ -98,7 +98,7 @@ public function show(int $id): ShipmentVehicleDispatch return ShipmentVehicleDispatch::query() ->where('tenant_id', $tenantId) - ->with('shipment') + ->with(['shipment.order.client', 'shipment.order.writer', 'shipment.creator']) ->findOrFail($id); } @@ -114,7 +114,7 @@ public function update(int $id, array $data): ShipmentVehicleDispatch ->findOrFail($id); // options에 저장할 필드 분리 - $optionFields = ['freight_cost_type', 'supply_amount', 'vat', 'total_amount', 'status']; + $optionFields = ['freight_cost_type', 'supply_amount', 'vat', 'total_amount']; $directFields = ['logistics_company', 'arrival_datetime', 'tonnage', 'vehicle_no', 'driver_contact', 'remarks']; // 기존 options 유지하면서 업데이트 diff --git a/app/Swagger/v1/ShipmentApi.php b/app/Swagger/v1/ShipmentApi.php index 077f1419..17455825 100644 --- a/app/Swagger/v1/ShipmentApi.php +++ b/app/Swagger/v1/ShipmentApi.php @@ -20,7 +20,7 @@ * @OA\Property(property="status_label", type="string", example="출고예정", description="상태 라벨"), * @OA\Property(property="priority", type="string", enum={"urgent","normal","low"}, example="normal", description="우선순위"), * @OA\Property(property="priority_label", type="string", example="보통", description="우선순위 라벨"), - * @OA\Property(property="delivery_method", type="string", enum={"pickup","direct","logistics"}, example="pickup", description="배송방식"), + * @OA\Property(property="delivery_method", type="string", example="pickup", description="배송방식 (common_codes delivery_method 참조)"), * @OA\Property(property="delivery_method_label", type="string", example="상차", description="배송방식 라벨"), * @OA\Property(property="client_id", type="integer", nullable=true, description="거래처 ID"), * @OA\Property(property="customer_name", type="string", example="(주)고객사", nullable=true, description="발주처명"), @@ -147,7 +147,7 @@ * @OA\Property(property="scheduled_date", type="string", format="date", example="2025-12-26", description="출고예정일"), * @OA\Property(property="status", type="string", enum={"scheduled","ready","shipping","completed"}, example="scheduled", description="상태"), * @OA\Property(property="priority", type="string", enum={"urgent","normal","low"}, example="normal", description="우선순위"), - * @OA\Property(property="delivery_method", type="string", enum={"pickup","direct","logistics"}, example="pickup", description="배송방식"), + * @OA\Property(property="delivery_method", type="string", example="pickup", description="배송방식 (common_codes delivery_method 참조)"), * @OA\Property(property="client_id", type="integer", description="거래처 ID"), * @OA\Property(property="customer_name", type="string", example="(주)고객사", description="발주처명"), * @OA\Property(property="site_name", type="string", example="서울현장", description="현장명"), @@ -232,7 +232,7 @@ class ShipmentApi * @OA\Parameter(name="search", in="query", description="검색어 (출하번호, LOT번호, 발주처명, 현장명)", @OA\Schema(type="string")), * @OA\Parameter(name="status", in="query", description="상태", @OA\Schema(type="string", enum={"scheduled","ready","shipping","completed"})), * @OA\Parameter(name="priority", in="query", description="우선순위", @OA\Schema(type="string", enum={"urgent","normal","low"})), - * @OA\Parameter(name="delivery_method", in="query", description="배송방식", @OA\Schema(type="string", enum={"pickup","direct","logistics"})), + * @OA\Parameter(name="delivery_method", in="query", description="배송방식 (common_codes delivery_method 참조)", @OA\Schema(type="string")), * @OA\Parameter(name="scheduled_from", in="query", description="예정일 시작", @OA\Schema(type="string", format="date")), * @OA\Parameter(name="scheduled_to", in="query", description="예정일 종료", @OA\Schema(type="string", format="date")), * @OA\Parameter(name="can_ship", in="query", description="출하가능 여부", @OA\Schema(type="boolean")), diff --git a/database/migrations/2026_03_18_150736_remove_dispatch_columns_from_shipments.php b/database/migrations/2026_03_18_150736_remove_dispatch_columns_from_shipments.php new file mode 100644 index 00000000..8d4b797b --- /dev/null +++ b/database/migrations/2026_03_18_150736_remove_dispatch_columns_from_shipments.php @@ -0,0 +1,42 @@ +dropColumn([ + 'logistics_company', + 'vehicle_tonnage', + 'shipping_cost', + 'vehicle_no', + 'driver_name', + 'driver_contact', + 'expected_arrival', + 'confirmed_arrival', + ]); + }); + } + + public function down(): void + { + Schema::table('shipments', function (Blueprint $table) { + $table->string('logistics_company', 50)->nullable()->after('loading_time'); + $table->string('vehicle_tonnage', 20)->nullable()->after('logistics_company'); + $table->decimal('shipping_cost', 10, 0)->nullable()->after('vehicle_tonnage'); + $table->string('vehicle_no', 20)->nullable()->after('shipping_cost'); + $table->string('driver_name', 50)->nullable()->after('vehicle_no'); + $table->string('driver_contact', 50)->nullable()->after('driver_name'); + $table->datetime('expected_arrival')->nullable()->after('driver_contact'); + $table->datetime('confirmed_arrival')->nullable()->after('expected_arrival'); + }); + } +}; \ No newline at end of file diff --git a/database/migrations/2026_03_18_203210_change_shipments_delivery_method_to_varchar.php b/database/migrations/2026_03_18_203210_change_shipments_delivery_method_to_varchar.php new file mode 100644 index 00000000..4f3e0d3f --- /dev/null +++ b/database/migrations/2026_03_18_203210_change_shipments_delivery_method_to_varchar.php @@ -0,0 +1,24 @@ +