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:
2026-03-13 22:45:43 +09:00
parent 54686cfc8a
commit d7c096b615
4 changed files with 84 additions and 6 deletions

View File

@@ -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;
}
/**