feat: [생산/출하] 수주 단위 출하 자동생성 + 상태 흐름 개선

- 출하를 작업지시(WO) 단위 → 수주(Order) 단위로 변경
  - createShipmentFromOrder: 모든 메인 WO 품목을 통합하여 출하 1건 생성
  - 출하에 수주 정보 복사 안함 (order_info accessor로 조인 참조)
- syncOrderStatus에서 PRODUCED 전환 시 자동 출하 생성
  - ensureShipmentExists: 이미 PRODUCED인데 출하 없으면 재생성
- POST /shipments/from-order/{orderId} 수동 출하 생성 API 추가
  - createShipmentForOrder: 상태 검증 + 작업지시 조회 + 출하 생성
- Shipment order_info accessor 확장 (receiver, delivery_address_detail, delivery_method)
- ShipmentService index에 creator 관계 추가 (목록 작성자 표시)
- autoCompleteWorkOrderIfAllStepsDone: 전체 step 완료 시 WO 자동완료
- autoCompleteOrphanedSteps: 고아 step 자동보정
- syncOrderStatus: 공정 미지정 WO 바이패스
- ApiResponse::success 201 인자 오류 수정

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-12 01:32:22 +09:00
parent 12373edf8c
commit 479059747b
6 changed files with 298 additions and 21 deletions

View File

@@ -8,13 +8,15 @@
use App\Http\Requests\Shipment\ShipmentUpdateRequest;
use App\Http\Requests\Shipment\ShipmentUpdateStatusRequest;
use App\Services\ShipmentService;
use App\Services\WorkOrderService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class ShipmentController extends Controller
{
public function __construct(
private readonly ShipmentService $service
private readonly ShipmentService $service,
private readonly WorkOrderService $workOrderService
) {}
/**
@@ -83,7 +85,7 @@ public function store(ShipmentStoreRequest $request): JsonResponse
{
$shipment = $this->service->store($request->validated());
return ApiResponse::success($shipment, __('message.created'), 201);
return ApiResponse::success($shipment, __('message.created'), [], 201);
}
/**
@@ -132,6 +134,22 @@ public function destroy(int $id): JsonResponse
}
}
/**
* 수주 기반 출하 생성
*/
public function createFromOrder(int $orderId): JsonResponse
{
try {
$shipment = $this->workOrderService->createShipmentForOrder($orderId);
return ApiResponse::success($shipment, __('message.created'), [], 201);
} catch (\Symfony\Component\HttpKernel\Exception\BadRequestHttpException $e) {
return ApiResponse::error($e->getMessage(), 400);
} catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
return ApiResponse::error(__('error.order.not_found'), 404);
}
}
/**
* LOT 옵션 조회
*/