/** * 공통 Zod 검증 스키마 * * 품목명, 품목유형, 날짜, 숫자, BOM 등 여러 스키마에서 공유하는 기본 블록 */ import { z } from 'zod'; // ===== 내부 전용 스키마 ===== /** * 품목 코드 검증 * 형식: {업체코드}-{품목유형}-{일련번호} * 예: KD-FG-001 * * 현재 사용하지 않음 (품목 코드 자동 생성) */ export const _itemCodeSchema = z.string() .min(1, '품목 코드를 입력해주세요') .regex( /^[A-Z0-9]+-[A-Z]{2}-\d+$/, '품목 코드 형식이 올바르지 않습니다 (예: KD-FG-001)' ); // ===== 공통 필드 스키마 ===== /** * 품목명 검증 */ export const itemNameSchema = z.preprocess( (val) => val === undefined || val === null ? "" : val, z.string().min(1, '품목명을 입력해주세요').max(200, '품목명은 200자 이내로 입력해주세요') ); /** * 품목 유형 검증 */ export const itemTypeSchema = z.enum(['FG', 'PT', 'SM', 'RM', 'CS'], { message: '품목 유형을 선택해주세요', }); /** * 단위 검증 * * 현재 사용하지 않음 (materialUnitSchema로 대체) */ export const _unitSchema = z.string() .min(1, '단위를 입력해주세요') .max(20, '단위는 20자 이내로 입력해주세요'); /** * 양수 검증 (가격, 수량 등) * undefined나 빈 문자열은 검증하지 않음 */ export const positiveNumberSchema = z.union([ z.number().positive('0보다 큰 값을 입력해주세요'), z.string().transform((val) => parseFloat(val)).pipe(z.number().positive('0보다 큰 값을 입력해주세요')), z.undefined(), z.null(), z.literal('') ]).optional(); /** * 날짜 검증 (YYYY-MM-DD) * 빈 문자열이나 undefined는 검증하지 않음 */ export const dateSchema = z.preprocess( (val) => { if (val === undefined || val === null || val === '') return undefined; return val; }, z.string() .regex(/^\d{4}-\d{2}-\d{2}$/, '날짜 형식이 올바르지 않습니다 (YYYY-MM-DD)') .optional() ); // ===== BOM 라인 스키마 ===== /** * 절곡품 전개도 상세 스키마 */ export const bendingDetailSchema = z.object({ id: z.string(), no: z.number().int().positive(), input: z.number(), elongation: z.number().default(-1), calculated: z.number(), sum: z.number(), shaded: z.boolean().default(false), aAngle: z.number().optional(), }); /** * BOM 라인 스키마 */ export const bomLineSchema = z.object({ id: z.string(), childItemCode: z.string().min(1, '하위 품목 코드를 입력해주세요'), childItemName: z.string().min(1, '하위 품목명을 입력해주세요'), quantity: z.number().positive('수량은 0보다 커야 합니다'), unit: z.string().min(1, '단위를 입력해주세요'), unitPrice: positiveNumberSchema, quantityFormula: z.string().optional(), note: z.string().max(500).optional(), // 절곡품 관련 isBending: z.boolean().optional(), bendingDiagram: z.string().url().optional(), bendingDetails: z.array(bendingDetailSchema).optional(), });