feat: [shipment] MES 데이터 정합성 개선 — can_ship 검증, ShipmentItem FK, 재고차감 비활성화
- ShipmentService::updateStatus()에 can_ship 검증 추가 (ready/shipping/completed 전환 시) - shipment_items에 order_item_id, work_order_item_id 컬럼+인덱스 추가 (마이그레이션) - ShipmentItem 모델에 orderItem(), workOrderItem() 관계 추가 - createShipmentFromOrder()에서 order_item_id, work_order_item_id 자동 매핑 - decreaseStockForShipment() 호출 비활성화 (수주생산=재고 미경유, 선생산=자재 투입 시 차감)
This commit is contained in:
@@ -309,6 +309,13 @@ public function updateStatus(int $id, string $status, ?array $additionalData = n
|
||||
|
||||
$shipment = Shipment::where('tenant_id', $tenantId)->findOrFail($id);
|
||||
|
||||
// 출하 가능 여부 검증 (scheduled → ready 이상 전환 시)
|
||||
if (in_array($status, ['ready', 'shipping', 'completed']) && ! $shipment->can_ship) {
|
||||
throw new \Symfony\Component\HttpKernel\Exception\BadRequestHttpException(
|
||||
__('error.shipment.cannot_ship')
|
||||
);
|
||||
}
|
||||
|
||||
$updateData = [
|
||||
'status' => $status,
|
||||
'updated_by' => $userId,
|
||||
@@ -344,10 +351,8 @@ public function updateStatus(int $id, string $status, ?array $additionalData = n
|
||||
$previousStatus = $shipment->status;
|
||||
$shipment->update($updateData);
|
||||
|
||||
// 🆕 출하완료 시 재고 차감 (FIFO)
|
||||
if ($status === 'completed' && $previousStatus !== 'completed') {
|
||||
$this->decreaseStockForShipment($shipment);
|
||||
}
|
||||
// 재고 차감 비활성화: 수주생산은 재고 미경유, 선생산 완성품은 자재 투입 시 차감됨
|
||||
// TODO: 선생산 로직 검증 후 재검토 (decreaseStockForShipment)
|
||||
|
||||
// 연결된 수주(Order) 상태 동기화
|
||||
$this->syncOrderStatus($shipment, $tenantId);
|
||||
@@ -357,10 +362,21 @@ public function updateStatus(int $id, string $status, ?array $additionalData = n
|
||||
|
||||
/**
|
||||
* 출하 완료 시 재고 차감
|
||||
*
|
||||
* 수주 연결 출하(order_id 있음)는 재고를 거치지 않으므로 차감 skip.
|
||||
* 재고 출고(order_id 없음)만 재고 차감 수행.
|
||||
*
|
||||
* @return array 실패 내역 (빈 배열이면 전체 성공)
|
||||
*/
|
||||
private function decreaseStockForShipment(Shipment $shipment): void
|
||||
private function decreaseStockForShipment(Shipment $shipment): array
|
||||
{
|
||||
// 수주 연결 출하는 재고 입고 없이 바로 출하하므로 차감하지 않음
|
||||
if ($shipment->order_id) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$stockService = app(StockService::class);
|
||||
$failures = [];
|
||||
|
||||
// 출하 품목 조회
|
||||
$items = $shipment->items;
|
||||
@@ -389,15 +405,23 @@ private function decreaseStockForShipment(Shipment $shipment): void
|
||||
stockLotId: $item->stock_lot_id
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
// 재고 부족 등의 에러는 로그만 기록하고 계속 진행
|
||||
\Illuminate\Support\Facades\Log::warning('Failed to decrease stock for shipment item', [
|
||||
'shipment_id' => $shipment->id,
|
||||
'item_code' => $item->item_code,
|
||||
'quantity' => $item->quantity,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
|
||||
$failures[] = [
|
||||
'item_code' => $item->item_code,
|
||||
'item_name' => $item->item_name,
|
||||
'quantity' => $item->quantity,
|
||||
'reason' => $e->getMessage(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $failures;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user