feat: [자재투입] 개발전용 입고 강제생성 버튼 추가 (입고+재고+수입검사 자동)
This commit is contained in:
@@ -34,7 +34,7 @@ import {
|
||||
} from '@/components/ui/table';
|
||||
import { toast } from 'sonner';
|
||||
import { isNextRedirectError } from '@/lib/utils/redirect-error';
|
||||
import { getMaterialsForWorkOrder, registerMaterialInput, getMaterialsForItem, registerMaterialInputForItem, searchStockByCode, type MaterialForInput, type MaterialForItemInput, type StockSearchResult } from './actions';
|
||||
import { getMaterialsForWorkOrder, registerMaterialInput, getMaterialsForItem, registerMaterialInputForItem, searchStockByCode, forceCreateReceiving, type MaterialForInput, type MaterialForItemInput, type StockSearchResult } from './actions';
|
||||
import type { WorkOrder } from '../ProductionDashboard/types';
|
||||
import type { MaterialInput } from './types';
|
||||
import { formatNumber } from '@/lib/utils/amount';
|
||||
@@ -103,6 +103,8 @@ export function MaterialInputModal({
|
||||
setIsSearching(false);
|
||||
}, []);
|
||||
|
||||
const [isForceCreating, setIsForceCreating] = useState(false);
|
||||
|
||||
// 목업 자재 데이터 (개발용)
|
||||
const MOCK_MATERIALS: MaterialForInput[] = Array.from({ length: 5 }, (_, i) => ({
|
||||
stockLotId: 100 + i,
|
||||
@@ -346,6 +348,20 @@ export function MaterialInputModal({
|
||||
}
|
||||
}, [order, workOrderItemId, workOrderItemIds]);
|
||||
|
||||
// [개발전용] 입고 강제생성 핸들러
|
||||
const handleForceReceiving = useCallback(async (itemId: number, itemCode: string) => {
|
||||
setIsForceCreating(true);
|
||||
const result = await forceCreateReceiving(itemId, 100);
|
||||
if (result.success && result.data) {
|
||||
toast.success(`${result.data.item_code} 입고 생성 완료 (LOT: ${result.data.lot_no}, ${result.data.qty}EA)`);
|
||||
handleStockSearch(itemCode);
|
||||
loadMaterials();
|
||||
} else {
|
||||
toast.error(result.error || '입고 생성 실패');
|
||||
}
|
||||
setIsForceCreating(false);
|
||||
}, [handleStockSearch, loadMaterials]);
|
||||
|
||||
// 모달이 열릴 때 데이터 로드 + 선택 초기화
|
||||
useEffect(() => {
|
||||
if (open && order) {
|
||||
@@ -823,6 +839,19 @@ export function MaterialInputModal({
|
||||
) : searchQuery && (
|
||||
<p className="text-[11px] text-red-500">검색 결과 없음 — 해당 품목의 입고 처리가 필요합니다</p>
|
||||
)}
|
||||
{/* [개발전용] 입고 강제생성 버튼 */}
|
||||
{group.lots[0]?.itemId && (
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className="w-full h-8 text-xs mt-1 border-orange-300 text-orange-600 hover:bg-orange-50"
|
||||
disabled={isForceCreating}
|
||||
onClick={() => handleForceReceiving(group.lots[0].itemId, group.materialCode || group.materialName)}
|
||||
>
|
||||
{isForceCreating ? <Loader2 className="h-3 w-3 animate-spin mr-1" /> : <Zap className="h-3 w-3 mr-1" />}
|
||||
[DEV] 입고자료 강제생성 ({group.materialCode || '품목'} × 100EA)
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -886,6 +886,22 @@ export interface StockSearchResult {
|
||||
lots: Array<{ lotNo: string; availableQty: number; fifoOrder: number }>;
|
||||
}
|
||||
|
||||
// ===== [개발전용] 입고 강제 생성 =====
|
||||
export async function forceCreateReceiving(
|
||||
itemId: number,
|
||||
qty: number = 100
|
||||
): Promise<{ success: boolean; data?: { receiving_number: string; lot_no: string; item_code: string; item_name: string; qty: number; available_qty: number }; error?: string }> {
|
||||
const result = await executeServerAction<{
|
||||
receiving_number: string; lot_no: string; item_code: string; item_name: string; qty: number; available_qty: number;
|
||||
}>({
|
||||
url: buildApiUrl('/api/v1/dev/force-receiving'),
|
||||
method: 'POST',
|
||||
body: { item_id: itemId, qty },
|
||||
errorMessage: '입고 강제 생성에 실패했습니다.',
|
||||
});
|
||||
return { success: result.success, data: result.data, error: result.error };
|
||||
}
|
||||
|
||||
export async function searchStockByCode(
|
||||
search: string
|
||||
): Promise<{ success: boolean; data: StockSearchResult[]; error?: string }> {
|
||||
|
||||
Reference in New Issue
Block a user