summaryrefslogtreecommitdiff
path: root/lib/vendor-investigation/validations.ts
blob: 19412539d4c1152b069d5c6d4b715c4b7bdeaa42 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import {
    createSearchParamsCache,
    parseAsArrayOf,
    parseAsInteger,
    parseAsString,
    parseAsStringEnum,
} from "nuqs/server"
import * as z from "zod"
import { getFiltersStateParser, getSortingStateParser } from "@/lib/parsers"
import { vendorInvestigationsView } from "@/db/schema"

export const searchParamsInvestigationCache = createSearchParamsCache({
    // Common flags
    flags: parseAsArrayOf(z.enum(["advancedTable", "floatingBar"])).withDefault([]),

    // Paging
    page: parseAsInteger.withDefault(1),
    perPage: parseAsInteger.withDefault(10),

    // Sorting - adjusting for vendorInvestigationsView
    sort: getSortingStateParser<typeof vendorInvestigationsView.$inferSelect>().withDefault([
        { id: "createdAt", desc: true },
    ]),

    // Advanced filter
    filters: getFiltersStateParser().withDefault([]),
    joinOperator: parseAsStringEnum(["and", "or"]).withDefault("and"),

    // Global search
    search: parseAsString.withDefault(""),

    // -----------------------------------------------------------------
    // Fields specific to vendor investigations
    // -----------------------------------------------------------------

    // investigationStatus: PLANNED, IN_PROGRESS, COMPLETED, CANCELED, RESULT_SENT
    investigationStatus: parseAsStringEnum(["PLANNED", "IN_PROGRESS", "COMPLETED", "CANCELED", "RESULT_SENT"]),

    // In case you also want to filter by vendorName, vendorCode, etc.
    vendorName: parseAsString.withDefault(""),
    vendorCode: parseAsString.withDefault(""),

    // If you need to filter by vendor status (e.g., PQ_SUBMITTED, ACTIVE, etc.),
    // you can include it here too. Example:
    // vendorStatus: parseAsStringEnum([
    //   "PENDING_REVIEW",
    //   "IN_REVIEW",
    //   "REJECTED",
    //   "IN_PQ",
    //   "PQ_SUBMITTED",
    //   "PQ_FAILED",
    //   "PQ_APPROVED",
    //   "APPROVED",
    //   "ACTIVE",
    //   "INACTIVE",
    //   "BLACKLISTED",
    // ]).optional(),
})

// Finally, export the type you can use in your server action:
export type GetVendorsInvestigationSchema = Awaited<ReturnType<typeof searchParamsInvestigationCache.parse>>

// 실사 진행 관리용 스키마
export const updateVendorInvestigationProgressSchema = z.object({
  investigationId: z.number({
    required_error: "Investigation ID is required",
  }),
  investigationAddress: z.string().optional(),
  investigationMethod: z.enum(["PURCHASE_SELF_EVAL", "DOCUMENT_EVAL", "PRODUCT_INSPECTION", "SITE_VISIT_EVAL"]).optional(),
  
  // 날짜 필드들
  forecastedAt: z.union([
    z.date(),
    z.string().transform((str) => str ? new Date(str) : undefined)
  ]).optional(),
  
  confirmedAt: z.union([
    z.date(),
    z.string().transform((str) => str ? new Date(str) : undefined)
  ]).optional(),
})

export type UpdateVendorInvestigationProgressSchema = z.infer<typeof updateVendorInvestigationProgressSchema>

// 실사 결과 입력용 스키마
export const updateVendorInvestigationResultSchema = z.object({
  investigationId: z.number({
    required_error: "Investigation ID is required",
  }),
  
  // 날짜 필드들
  completedAt: z.union([
    z.date(),
    z.string().transform((str) => str ? new Date(str) : undefined)
  ]).optional(),
  
  evaluationScore: z.number()
    .int("평가 점수는 정수여야 합니다.")
    .min(0, "평가 점수는 0점 이상이어야 합니다.")
    .max(100, "평가 점수는 100점 이하여야 합니다.")
    .optional(),
  evaluationResult: z.enum(["APPROVED", "SUPPLEMENT", "SUPPLEMENT_REINSPECT", "SUPPLEMENT_DOCUMENT", "REJECTED", "RESULT_SENT"]).optional(),
  investigationNotes: z.string().max(1000, "QM 의견은 1000자 이내로 입력해주세요.").optional(),
  attachments: z.any().optional(), // File 업로드를 위한 필드
})

export type UpdateVendorInvestigationResultSchema = z.infer<typeof updateVendorInvestigationResultSchema>

// 기존 호환성을 위한 통합 스키마
export const updateVendorInvestigationSchema = z.object({
  investigationId: z.number({
    required_error: "Investigation ID is required",
  }),
  investigationStatus: z.enum(["PLANNED", "IN_PROGRESS", "COMPLETED", "CANCELED", "SUPPLEMENT_REQUIRED", "RESULT_SENT"], {
    required_error: "실사 상태를 선택해주세요.",
  }),
  investigationAddress: z.string().optional(),
  investigationMethod: z.enum(["PURCHASE_SELF_EVAL", "DOCUMENT_EVAL", "PRODUCT_INSPECTION", "SITE_VISIT_EVAL"]).optional(),
  
  // 날짜 필드들
  forecastedAt: z.union([
    z.date(),
    z.string().transform((str) => str ? new Date(str) : undefined)
  ]).optional(),
  
  requestedAt: z.union([
    z.date(),
    z.string().transform((str) => str ? new Date(str) : undefined)
  ]).optional(),
  
  confirmedAt: z.union([
    z.date(),
    z.string().transform((str) => str ? new Date(str) : undefined)
  ]).optional(),
  
  completedAt: z.union([
    z.date(),
    z.string().transform((str) => str ? new Date(str) : undefined)
  ]).optional(),
  
  evaluationScore: z.number()
    .int("평가 점수는 정수여야 합니다.")
    .min(0, "평가 점수는 0점 이상이어야 합니다.")
    .max(100, "평가 점수는 100점 이하여야 합니다.")
    .optional(),
  evaluationResult: z.enum(["APPROVED", "SUPPLEMENT", "SUPPLEMENT_REINSPECT", "SUPPLEMENT_DOCUMENT", "REJECTED", "RESULT_SENT"]).optional(),
  investigationNotes: z.string().max(1000, "QM 의견은 1000자 이내로 입력해주세요.").optional(),
  attachments: z.any().optional(), // File 업로드를 위한 필드
})

export type UpdateVendorInvestigationSchema = z.infer<typeof updateVendorInvestigationSchema>