summaryrefslogtreecommitdiff
path: root/lib/b-rfq/validations.ts
diff options
context:
space:
mode:
Diffstat (limited to 'lib/b-rfq/validations.ts')
-rw-r--r--lib/b-rfq/validations.ts447
1 files changed, 0 insertions, 447 deletions
diff --git a/lib/b-rfq/validations.ts b/lib/b-rfq/validations.ts
deleted file mode 100644
index bee10a11..00000000
--- a/lib/b-rfq/validations.ts
+++ /dev/null
@@ -1,447 +0,0 @@
-import { createSearchParamsCache,
- parseAsArrayOf,
- parseAsInteger,
- parseAsString,
- parseAsStringEnum,parseAsBoolean
- } from "nuqs/server"
- import * as z from "zod"
-
-import { getFiltersStateParser, getSortingStateParser } from "@/lib/parsers"
-import { FinalRfqDetailView, VendorAttachmentResponse } from "@/db/schema";
-
-export const searchParamsRFQDashboardCache = createSearchParamsCache({
- // 공통 플래그
- flags: parseAsArrayOf(z.enum(["advancedTable", "floatingBar"])).withDefault([]),
-
- // 페이징
- page: parseAsInteger.withDefault(1),
- perPage: parseAsInteger.withDefault(10),
-
- // 정렬 - rfqDashboardView 기반
- sort: getSortingStateParser<{
- rfqId: number;
- rfqCode: string;
- description: string;
- status: string;
- dueDate: Date;
- projectCode: string;
- projectName: string;
- packageNo: string;
- packageName: string;
- picName: string;
- totalAttachments: number;
- initialVendorCount: number;
- finalVendorCount: number;
- initialResponseRate: number;
- finalResponseRate: number;
- overallProgress: number;
- daysToDeadline: number;
- createdAt: Date;
- }>().withDefault([
- { id: "createdAt", desc: true },
- ]),
-
- // 고급 필터
- filters: getFiltersStateParser().withDefault([]),
- joinOperator: parseAsStringEnum(["and", "or"]).withDefault("and"),
-
- // 기본 필터
- rfqBasicFilters: getFiltersStateParser().withDefault([]),
- rfqBasicJoinOperator: parseAsStringEnum(["and", "or"]).withDefault("and"),
- basicFilters: getFiltersStateParser().withDefault([]),
- basicJoinOperator: parseAsStringEnum(["and", "or"]).withDefault("and"),
-
- // 검색 키워드
- search: parseAsString.withDefault(""),
-
- // RFQ 특화 필터
- rfqCode: parseAsString.withDefault(""),
- projectName: parseAsString.withDefault(""),
- projectCode: parseAsString.withDefault(""),
- picName: parseAsString.withDefault(""),
- packageNo: parseAsString.withDefault(""),
- status: parseAsStringEnum([
- "DRAFT",
- "Doc. Received",
- "PIC Assigned",
- "Doc. Confirmed",
- "Init. RFQ Sent",
- "Init. RFQ Answered",
- "TBE started",
- "TBE finished",
- "Final RFQ Sent",
- "Quotation Received",
- "Vendor Selected"
- ]),
- dueDateFrom: parseAsString.withDefault(""),
- dueDateTo: parseAsString.withDefault(""),
- progressMin: parseAsInteger.withDefault(0),
- progressMax: parseAsInteger.withDefault(100),
- });
-
- export type GetRFQDashboardSchema = Awaited<ReturnType<typeof searchParamsRFQDashboardCache.parse>>
-
-
- export const createRfqServerSchema = z.object({
- projectId: z.number().min(1, "프로젝트를 선택해주세요"), // 필수로 변경
- dueDate: z.date(), // Date 객체로 직접 받기
- picCode: z.string().min(1, "구매 담당자 코드를 입력해주세요"),
- picName: z.string().optional(),
- engPicName: z.string().optional(),
- packageNo: z.string().min(1, "패키지 번호를 입력해주세요"),
- packageName: z.string().min(1, "패키지명을 입력해주세요"),
- remark: z.string().optional(),
- projectCompany: z.string().optional(),
- projectFlag: z.string().optional(),
- projectSite: z.string().optional(),
- createdBy: z.number(),
- updatedBy: z.number(),
- })
-
- export type CreateRfqInput = z.infer<typeof createRfqServerSchema>
-
-
-
- export type RfqAttachment = {
- id: number
- attachmentType: string
- serialNo: string
- rfqId: number
- fileName: string
- originalFileName: string
- filePath: string
- fileSize: number | null
- fileType: string | null
- description: string | null
- createdBy: number
- createdAt: Date
- createdByName?: string
- responseStats?: {
- totalVendors: number
- respondedCount: number
- pendingCount: number
- waivedCount: number
- responseRate: number
- }
- }
-
- // RFQ Attachments용 검색 파라미터 캐시
- export const searchParamsRfqAttachmentsCache = createSearchParamsCache({
- flags: parseAsArrayOf(z.enum(["advancedTable", "floatingBar"])).withDefault([]),
- page: parseAsInteger.withDefault(1),
- perPage: parseAsInteger.withDefault(10),
- sort: getSortingStateParser<RfqAttachment>().withDefault([
- { id: "createdAt", desc: true },
- ]),
- // 기본 필터
- attachmentType: parseAsArrayOf(z.string()).withDefault([]),
- fileType: parseAsArrayOf(z.string()).withDefault([]),
- search: parseAsString.withDefault(""),
- // advanced filter
- filters: getFiltersStateParser().withDefault([]),
- joinOperator: parseAsStringEnum(["and", "or"]).withDefault("and"),
- })
-
- // 스키마 타입들
- export type GetRfqAttachmentsSchema = Awaited<ReturnType<typeof searchParamsRfqAttachmentsCache.parse>>
-
-
- // 첨부파일 레코드 타입
-export const attachmentRecordSchema = z.object({
- rfqId: z.number().positive(),
- attachmentType: z.enum(["구매", "설계"]),
- // serialNo: z.string().min(1),
- description: z.string().optional(),
- fileName: z.string(),
- originalFileName: z.string(),
- filePath: z.string(),
- fileSize: z.number(),
- fileType: z.string(),
-})
-
-export type AttachmentRecord = z.infer<typeof attachmentRecordSchema>
-
-export const deleteAttachmentsSchema = z.object({
- ids: z.array(z.number()).min(1, "삭제할 첨부파일을 선택해주세요."),
-})
-
-export type DeleteAttachmentsInput = z.infer<typeof deleteAttachmentsSchema>
-
-
-//Inital RFQ
-export const searchParamsInitialRfqDetailCache = createSearchParamsCache({
- // 공통 플래그
- flags: parseAsArrayOf(z.enum(["advancedTable", "floatingBar"])).withDefault([]),
-
- // 페이징
- page: parseAsInteger.withDefault(1),
- perPage: parseAsInteger.withDefault(10),
-
- // 정렬 - initialRfqDetailView 기반
- sort: getSortingStateParser<{
- rfqId: number;
- rfqCode: string;
- rfqStatus: string;
- initialRfqId: number;
- initialRfqStatus: string;
- vendorId: number;
- vendorCode: string;
- vendorName: string;
- vendorCountry: string;
- vendorBusinessSize: string;
- dueDate: Date;
- validDate: Date;
- incotermsCode: string;
- incotermsDescription: string;
- shortList: boolean;
- returnYn: boolean;
- cpRequestYn: boolean;
- prjectGtcYn: boolean;
- returnRevision: number;
- gtc: string;
- gtcValidDate: string;
- classification: string;
- sparepart: string;
- createdAt: Date;
- updatedAt: Date;
- }>().withDefault([
- { id: "createdAt", desc: true },
- ]),
-
- // 고급 필터
- filters: getFiltersStateParser().withDefault([]),
- joinOperator: parseAsStringEnum(["and", "or"]).withDefault("and"),
-
- // 기본 필터
- basicFilters: getFiltersStateParser().withDefault([]),
- basicJoinOperator: parseAsStringEnum(["and", "or"]).withDefault("and"),
-
- // 검색 키워드
- search: parseAsString.withDefault(""),
-
- // Initial RFQ Detail 특화 필터
- rfqCode: parseAsString.withDefault(""),
- rfqStatus: parseAsStringEnum([
- "DRAFT",
- "Doc. Received",
- "PIC Assigned",
- "Doc. Confirmed",
- "Init. RFQ Sent",
- "Init. RFQ Answered",
- "TBE started",
- "TBE finished",
- "Final RFQ Sent",
- "Quotation Received",
- "Vendor Selected"
- ]),
- initialRfqStatus: parseAsStringEnum([
- "PENDING",
- "SENT",
- "RESPONDED",
- "EXPIRED",
- "CANCELLED"
- ]),
- vendorName: parseAsString.withDefault(""),
- vendorCode: parseAsString.withDefault(""),
- vendorCountry: parseAsString.withDefault(""),
- vendorBusinessSize: parseAsStringEnum([
- "LARGE",
- "MEDIUM",
- "SMALL",
- "STARTUP"
- ]),
- incotermsCode: parseAsString.withDefault(""),
- dueDateFrom: parseAsString.withDefault(""),
- dueDateTo: parseAsString.withDefault(""),
- validDateFrom: parseAsString.withDefault(""),
- validDateTo: parseAsString.withDefault(""),
- shortList: parseAsStringEnum(["true", "false"]),
- returnYn: parseAsStringEnum(["true", "false"]),
- cpRequestYn: parseAsStringEnum(["true", "false"]),
- prjectGtcYn: parseAsStringEnum(["true", "false"]),
- classification: parseAsString.withDefault(""),
- sparepart: parseAsString.withDefault(""),
-});
-
-export type GetInitialRfqDetailSchema = Awaited<ReturnType<typeof searchParamsInitialRfqDetailCache.parse>>;
-
-
-
-export const updateInitialRfqSchema = z.object({
- initialRfqStatus: z.enum(["DRAFT", "Init. RFQ Sent", "S/L Decline", "Init. RFQ Answered"]),
- dueDate: z.date({
- required_error: "마감일을 선택해주세요.",
- }),
- validDate: z.date().optional(),
- gtc: z.string().optional(),
- gtcValidDate: z.string().optional(),
- incotermsCode: z.string().max(20, "Incoterms 코드는 20자 이하여야 합니다.").optional(),
- classification: z.string().max(255, "분류는 255자 이하여야 합니다.").optional(),
- sparepart: z.string().max(255, "예비부품은 255자 이하여야 합니다.").optional(),
- shortList: z.boolean().default(false),
- returnYn: z.boolean().default(false),
- cpRequestYn: z.boolean().default(false),
- prjectGtcYn: z.boolean().default(false),
- rfqRevision: z.number().int().min(0, "RFQ 리비전은 0 이상이어야 합니다.").default(0),
-})
-
-export const removeInitialRfqsSchema = z.object({
- ids: z.array(z.number()).min(1, "최소 하나의 항목을 선택해주세요."),
-})
-
-export type UpdateInitialRfqSchema = z.infer<typeof updateInitialRfqSchema>
-export type RemoveInitialRfqsSchema = z.infer<typeof removeInitialRfqsSchema>
-
-// 벌크 이메일 발송 스키마
-export const bulkEmailSchema = z.object({
- initialRfqIds: z.array(z.number()).min(1, "최소 하나의 초기 RFQ를 선택해주세요."),
- language: z.enum(["en", "ko"]).default("en"),
-})
-
-export type BulkEmailInput = z.infer<typeof bulkEmailSchema>
-
-// 검색 파라미터 캐시 설정
-
-export type ResponseStatus = "NOT_RESPONDED" | "RESPONDED" | "REVISION_REQUESTED" | "WAIVED";
-export type RfqType = "INITIAL" | "FINAL";
-
-
-export type VendorRfqResponseColumns = {
- id: string;
- vendorId: number;
- rfqRecordId: number;
- rfqType: RfqType;
- overallStatus: ResponseStatus;
- totalAttachments: number;
- respondedCount: number;
- pendingCount: number;
- responseRate: number;
- completionRate: number;
- requestedAt: Date;
- lastRespondedAt: Date | null;
-};
-
-// 검색 파라미터 캐시 설정
-export const searchParamsVendorResponseCache = createSearchParamsCache({
- flags: parseAsArrayOf(z.enum(["advancedTable", "floatingBar"])).withDefault([]),
- page: parseAsInteger.withDefault(1),
- perPage: parseAsInteger.withDefault(10),
- sort: getSortingStateParser<VendorRfqResponseColumns>().withDefault([
- { id: "requestedAt", desc: true },
- ]),
-
- // 고급 필터
- filters: getFiltersStateParser().withDefault([]),
- joinOperator: parseAsStringEnum(["and", "or"]).withDefault("and"),
-
- // 기본 필터
- basicFilters: getFiltersStateParser().withDefault([]),
- basicJoinOperator: parseAsStringEnum(["and", "or"]).withDefault("and"),
-
- // 검색 및 필터
- search: parseAsString.withDefault(""),
- rfqType: parseAsStringEnum(["INITIAL", "FINAL", "ALL"]).withDefault("ALL"),
- responseStatus: parseAsStringEnum(["NOT_RESPONDED", "RESPONDED", "REVISION_REQUESTED", "WAIVED", "ALL"]).withDefault("ALL"),
-
- // 날짜 범위
- from: parseAsString.withDefault(""),
- to: parseAsString.withDefault(""),
-});
-
-export type GetVendorResponsesSchema = Awaited<ReturnType<typeof searchParamsVendorResponseCache.parse>>;
-
-// vendorId + rfqRecordId로 그룹핑된 응답 요약 타입
-export type VendorRfqResponseSummary = {
- id: string; // vendorId + rfqRecordId + rfqType 조합으로 생성된 고유 ID
- vendorId: number;
- rfqRecordId: number;
- rfqType: RfqType;
-
- // RFQ 정보
- rfq: {
- id: number;
- rfqCode: string | null;
- description: string | null;
- status: string;
- dueDate: Date;
- } | null;
-
- // 벤더 정보
- vendor: {
- id: number;
- vendorCode: string;
- vendorName: string;
- country: string | null;
- businessSize: string | null;
- } | null;
-
- // 응답 통계
- totalAttachments: number;
- respondedCount: number;
- pendingCount: number;
- revisionRequestedCount: number;
- waivedCount: number;
- responseRate: number;
- completionRate: number;
- overallStatus: ResponseStatus; // 전체적인 상태
-
- // 날짜 정보
- requestedAt: Date;
- lastRespondedAt: Date | null;
-
- // 기타
- hasComments: boolean;
-};
-
-
-// 수정 요청 스키마
-export const requestRevisionSchema = z.object({
- responseId: z.number().positive(),
- revisionReason: z.string().min(10, "수정 요청 사유를 최소 10자 이상 입력해주세요").max(500),
-});
-
-// 수정 요청 결과 타입
-export type RequestRevisionResult = {
- success: boolean;
- message: string;
- error?: string;
-};
-
-export const shortListConfirmSchema = z.object({
- rfqId: z.number(),
- selectedVendorIds: z.array(z.number()).min(1),
- rejectedVendorIds: z.array(z.number()),
-})
-
-export type ShortListConfirmInput = z.infer<typeof shortListConfirmSchema>
-
-
-export const searchParamsFinalRfqDetailCache = createSearchParamsCache({
- // 공통 플래그
- flags: parseAsArrayOf(z.enum(["advancedTable", "floatingBar"])).withDefault([]),
-
- // 페이징
- page: parseAsInteger.withDefault(1),
- perPage: parseAsInteger.withDefault(10),
-
- // 정렬 - initialRfqDetailView 기반
- sort: getSortingStateParser<FinalRfqDetailView>().withDefault([
- { id: "createdAt", desc: true },
- ]),
-
- // 고급 필터
- filters: getFiltersStateParser().withDefault([]),
- joinOperator: parseAsStringEnum(["and", "or"]).withDefault("and"),
-
- // 기본 필터
- basicFilters: getFiltersStateParser().withDefault([]),
- basicJoinOperator: parseAsStringEnum(["and", "or"]).withDefault("and"),
-
- // 검색 키워드
- search: parseAsString.withDefault(""),
-
-
-});
-
-export type GetFinalRfqDetailSchema = Awaited<ReturnType<typeof searchParamsFinalRfqDetailCache.parse>>;
-