fix: [stock] 재고생산 삭제 허용 (IN_PROGRESS + 작업지시 함께 정리)
- STOCK 타입: IN_PROGRESS 상태에서도 삭제 허용 (IN_PRODUCTION부터 불가) - STOCK 타입: 작업지시(workOrders)가 있어도 삭제 허용 - cleanupStockWorkOrders(): 작업지시 soft delete + 재고예약 해제 - destroy(), bulkDestroy() 양쪽 적용 - 일반 수주(ORDER)는 기존 규칙 유지
This commit is contained in:
@@ -426,21 +426,38 @@ public function destroy(int $id)
|
||||
throw new NotFoundHttpException(__('error.not_found'));
|
||||
}
|
||||
|
||||
// 진행 중이거나 완료된 수주는 삭제 불가
|
||||
if (in_array($order->status_code, [
|
||||
Order::STATUS_IN_PROGRESS,
|
||||
Order::STATUS_IN_PRODUCTION,
|
||||
Order::STATUS_PRODUCED,
|
||||
Order::STATUS_SHIPPING,
|
||||
Order::STATUS_SHIPPED,
|
||||
Order::STATUS_COMPLETED,
|
||||
])) {
|
||||
throw new BadRequestHttpException(__('error.order.cannot_delete_in_progress'));
|
||||
$isStock = $order->order_type_code === Order::TYPE_STOCK;
|
||||
|
||||
// 재고생산(STOCK): 실제 생산 시작(IN_PRODUCTION) 전까지 삭제 허용
|
||||
// 일반 수주: 기존 규칙 유지
|
||||
if ($isStock) {
|
||||
if (in_array($order->status_code, [
|
||||
Order::STATUS_IN_PRODUCTION,
|
||||
Order::STATUS_PRODUCED,
|
||||
Order::STATUS_SHIPPING,
|
||||
Order::STATUS_SHIPPED,
|
||||
Order::STATUS_COMPLETED,
|
||||
])) {
|
||||
throw new BadRequestHttpException(__('error.order.cannot_delete_in_progress'));
|
||||
}
|
||||
} else {
|
||||
if (in_array($order->status_code, [
|
||||
Order::STATUS_IN_PROGRESS,
|
||||
Order::STATUS_IN_PRODUCTION,
|
||||
Order::STATUS_PRODUCED,
|
||||
Order::STATUS_SHIPPING,
|
||||
Order::STATUS_SHIPPED,
|
||||
Order::STATUS_COMPLETED,
|
||||
])) {
|
||||
throw new BadRequestHttpException(__('error.order.cannot_delete_in_progress'));
|
||||
}
|
||||
}
|
||||
|
||||
// 작업지시가 존재하면 삭제 불가
|
||||
if ($order->workOrders()->exists()) {
|
||||
throw new BadRequestHttpException(__('error.order.cannot_delete_has_work_orders'));
|
||||
// 재고생산(STOCK): 작업지시가 있어도 삭제 허용 (함께 정리)
|
||||
if (! $isStock) {
|
||||
if ($order->workOrders()->exists()) {
|
||||
throw new BadRequestHttpException(__('error.order.cannot_delete_has_work_orders'));
|
||||
}
|
||||
}
|
||||
|
||||
// 출하 정보가 존재하면 삭제 불가
|
||||
@@ -448,7 +465,12 @@ public function destroy(int $id)
|
||||
throw new BadRequestHttpException(__('error.order.cannot_delete_has_shipments'));
|
||||
}
|
||||
|
||||
return DB::transaction(function () use ($order, $userId) {
|
||||
return DB::transaction(function () use ($order, $userId, $isStock) {
|
||||
// 재고생산(STOCK): 연관 작업지시 + 재고예약 정리
|
||||
if ($isStock && $order->workOrders()->exists()) {
|
||||
$this->cleanupStockWorkOrders($order, $userId);
|
||||
}
|
||||
|
||||
// 0. 연결된 견적의 수주 연결 해제 (order_id → null, status → finalized)
|
||||
if ($order->quote_id) {
|
||||
Quote::withoutGlobalScopes()
|
||||
@@ -511,18 +533,36 @@ public function bulkDestroy(array $ids, bool $force = false): array
|
||||
// force=true (개발환경 완전삭제): 모든 상태 허용, 연관 데이터 모두 삭제
|
||||
$this->forceDeleteWorkOrders($order, $tenantId);
|
||||
} else {
|
||||
// 일반 삭제: 상태/작업지시/출하 검증
|
||||
if (! in_array($order->status_code, [
|
||||
Order::STATUS_DRAFT,
|
||||
Order::STATUS_CONFIRMED,
|
||||
Order::STATUS_CANCELLED,
|
||||
])) {
|
||||
$skippedIds[] = $order->id;
|
||||
$isStock = $order->order_type_code === Order::TYPE_STOCK;
|
||||
|
||||
continue;
|
||||
// 재고생산(STOCK): IN_PROGRESS까지 삭제 허용 (IN_PRODUCTION부터 불가)
|
||||
// 일반 수주: DRAFT/CONFIRMED/CANCELLED만 삭제 허용
|
||||
if ($isStock) {
|
||||
if (in_array($order->status_code, [
|
||||
Order::STATUS_IN_PRODUCTION,
|
||||
Order::STATUS_PRODUCED,
|
||||
Order::STATUS_SHIPPING,
|
||||
Order::STATUS_SHIPPED,
|
||||
Order::STATUS_COMPLETED,
|
||||
])) {
|
||||
$skippedIds[] = $order->id;
|
||||
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (! in_array($order->status_code, [
|
||||
Order::STATUS_DRAFT,
|
||||
Order::STATUS_CONFIRMED,
|
||||
Order::STATUS_CANCELLED,
|
||||
])) {
|
||||
$skippedIds[] = $order->id;
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ($order->workOrders()->exists()) {
|
||||
// 재고생산(STOCK): 작업지시가 있어도 삭제 허용 (함께 정리)
|
||||
if (! $isStock && $order->workOrders()->exists()) {
|
||||
$skippedIds[] = $order->id;
|
||||
|
||||
continue;
|
||||
@@ -533,6 +573,11 @@ public function bulkDestroy(array $ids, bool $force = false): array
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// 재고생산(STOCK): 연관 작업지시 + 재고예약 정리
|
||||
if ($isStock && $order->workOrders()->exists()) {
|
||||
$this->cleanupStockWorkOrders($order, $userId);
|
||||
}
|
||||
}
|
||||
|
||||
// 견적 연결 해제
|
||||
@@ -583,6 +628,46 @@ public function bulkDestroy(array $ids, bool $force = false): array
|
||||
/**
|
||||
* 작업지시 및 연관 데이터 강제 삭제 (개발환경 완전삭제용)
|
||||
*/
|
||||
/**
|
||||
* 재고생산(STOCK) 삭제 시 연관 작업지시 + 재고예약 정리
|
||||
* IN_PROGRESS 상태(아직 자재투입 없음)의 작업지시만 soft delete 처리
|
||||
*/
|
||||
private function cleanupStockWorkOrders(Order $order, int $userId): void
|
||||
{
|
||||
$workOrders = $order->workOrders()->get();
|
||||
|
||||
foreach ($workOrders as $wo) {
|
||||
// 자재투입이 있는 작업지시는 정리 불가 (이미 생산 시작됨)
|
||||
if (WorkOrderMaterialInput::where('work_order_id', $wo->id)->exists()) {
|
||||
Log::warning('재고생산 삭제: 자재투입된 작업지시 건너뜀', [
|
||||
'order_id' => $order->id,
|
||||
'work_order_id' => $wo->id,
|
||||
]);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// 작업지시 품목 soft delete
|
||||
$wo->items()->update(['deleted_by' => $userId]);
|
||||
$wo->items()->delete();
|
||||
|
||||
// 작업지시 soft delete
|
||||
$wo->deleted_by = $userId;
|
||||
$wo->save();
|
||||
$wo->delete();
|
||||
}
|
||||
|
||||
// 재고예약 해제
|
||||
try {
|
||||
app(StockService::class)->releaseReservationForOrder($order->items, $order->id);
|
||||
} catch (\Exception $e) {
|
||||
Log::warning('재고생산 삭제: 재고예약 해제 실패', [
|
||||
'order_id' => $order->id,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
private function forceDeleteWorkOrders(Order $order, int $tenantId): void
|
||||
{
|
||||
$workOrderIds = WorkOrder::where('tenant_id', $tenantId)
|
||||
|
||||
Reference in New Issue
Block a user