diff options
Diffstat (limited to 'lib/vendor-regular-registrations')
| -rw-r--r-- | lib/vendor-regular-registrations/safety-qualification-update-sheet.tsx | 143 | ||||
| -rw-r--r-- | lib/vendor-regular-registrations/service.ts | 62 | ||||
| -rw-r--r-- | lib/vendor-regular-registrations/table/major-items-update-dialog.tsx (renamed from lib/vendor-regular-registrations/major-items-update-sheet.tsx) | 38 | ||||
| -rw-r--r-- | lib/vendor-regular-registrations/table/safety-qualification-update-dialog.tsx (renamed from lib/vendor-regular-registrations/table/safety-qualification-update-sheet.tsx) | 36 | ||||
| -rw-r--r-- | lib/vendor-regular-registrations/table/vendor-regular-registrations-table-columns.tsx | 22 |
5 files changed, 102 insertions, 199 deletions
diff --git a/lib/vendor-regular-registrations/safety-qualification-update-sheet.tsx b/lib/vendor-regular-registrations/safety-qualification-update-sheet.tsx deleted file mode 100644 index a93fbf22..00000000 --- a/lib/vendor-regular-registrations/safety-qualification-update-sheet.tsx +++ /dev/null @@ -1,143 +0,0 @@ -"use client" - -import * as React from "react" -import { useForm } from "react-hook-form" -import { zodResolver } from "@hookform/resolvers/zod" -import { z } from "zod" -import { toast } from "sonner" - -import { - Sheet, - SheetContent, - SheetDescription, - SheetHeader, - SheetTitle, -} from "@/components/ui/sheet" -import { - Form, - FormControl, - FormField, - FormItem, - FormLabel, - FormMessage, -} from "@/components/ui/form" -import { Button } from "@/components/ui/button" -import { Textarea } from "@/components/ui/textarea" -import { updateSafetyQualification } from "./service" - -const formSchema = z.object({ - safetyQualificationContent: z.string().min(1, "안전적격성 평가 내용을 입력해주세요."), -}) - -interface SafetyQualificationUpdateSheetProps { - open: boolean - onOpenChange: (open: boolean) => void - registrationId?: number - vendorName?: string - currentContent?: string | null - onSuccess?: () => void -} - -export function SafetyQualificationUpdateSheet({ - open, - onOpenChange, - registrationId, - vendorName, - currentContent, - onSuccess, -}: SafetyQualificationUpdateSheetProps) { - const [isLoading, setIsLoading] = React.useState(false) - - const form = useForm<z.infer<typeof formSchema>>({ - resolver: zodResolver(formSchema), - defaultValues: { - safetyQualificationContent: currentContent || "", - }, - }) - - // 폼 값 초기화 - React.useEffect(() => { - if (open) { - form.reset({ - safetyQualificationContent: currentContent || "", - }) - } - }, [open, currentContent, form]) - - async function onSubmit(values: z.infer<typeof formSchema>) { - if (!registrationId) { - toast.error("등록 ID가 없습니다.") - return - } - - setIsLoading(true) - try { - const result = await updateSafetyQualification( - registrationId, - values.safetyQualificationContent - ) - - if (result.success) { - toast.success("안전적격성 평가가 등록되었습니다.") - onOpenChange(false) - onSuccess?.() - } else { - toast.error(result.error || "안전적격성 평가 등록에 실패했습니다.") - } - } catch (error) { - console.error("안전적격성 평가 등록 오류:", error) - toast.error("안전적격성 평가 등록 중 오류가 발생했습니다.") - } finally { - setIsLoading(false) - } - } - - return ( - <Sheet open={open} onOpenChange={onOpenChange}> - <SheetContent className="w-[400px] sm:w-[540px]"> - <SheetHeader> - <SheetTitle>안전적격성 평가 입력</SheetTitle> - <SheetDescription> - {vendorName && `${vendorName}의 `}안전적격성 평가 내용을 입력해주세요. - </SheetDescription> - </SheetHeader> - - <Form {...form}> - <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6 mt-6"> - <FormField - control={form.control} - name="safetyQualificationContent" - render={({ field }) => ( - <FormItem> - <FormLabel>안전적격성 평가 내용</FormLabel> - <FormControl> - <Textarea - placeholder="안전적격성 평가 결과 및 내용을 입력해주세요..." - className="min-h-[200px]" - {...field} - /> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - - <div className="flex justify-end space-x-2"> - <Button - type="button" - variant="outline" - onClick={() => onOpenChange(false)} - disabled={isLoading} - > - 취소 - </Button> - <Button type="submit" disabled={isLoading}> - {isLoading ? "저장 중..." : "저장"} - </Button> - </div> - </form> - </Form> - </SheetContent> - </Sheet> - ) -} diff --git a/lib/vendor-regular-registrations/service.ts b/lib/vendor-regular-registrations/service.ts index 51f4e82b..d64c7b8b 100644 --- a/lib/vendor-regular-registrations/service.ts +++ b/lib/vendor-regular-registrations/service.ts @@ -25,7 +25,46 @@ import { basicContractTemplates
} from "@/db/schema";
import db from "@/db/db";
-import { inArray, eq, desc } from "drizzle-orm";
+import { inArray, eq, desc, and, lt } from "drizzle-orm";
+
+// 3개월 이상 정규등록검토 상태인 등록을 장기미등록으로 변경
+async function updatePendingApprovals() {
+ try {
+ const threeMonthsAgo = new Date();
+ threeMonthsAgo.setMonth(threeMonthsAgo.getMonth() - 3);
+
+ // 3개월 이상 정규등록검토 상태인 등록들을 조회
+ const outdatedRegistrations = await db
+ .select()
+ .from(vendorRegularRegistrations)
+ .where(
+ and(
+ eq(vendorRegularRegistrations.status, "in_review"),
+ lt(vendorRegularRegistrations.updatedAt, threeMonthsAgo)
+ )
+ );
+
+ // 장기미등록으로 상태 변경
+ if (outdatedRegistrations.length > 0) {
+ await db
+ .update(vendorRegularRegistrations)
+ .set({
+ status: "pending_approval",
+ updatedAt: new Date(),
+ })
+ .where(
+ and(
+ eq(vendorRegularRegistrations.status, "in_review"),
+ lt(vendorRegularRegistrations.updatedAt, threeMonthsAgo)
+ )
+ );
+
+ console.log(`${outdatedRegistrations.length}개의 등록이 장기미등록으로 변경되었습니다.`);
+ }
+ } catch (error) {
+ console.error("장기미등록 상태 업데이트 오류:", error);
+ }
+}
// 캐싱과 에러 핸들링이 포함된 조회 함수
export async function fetchVendorRegularRegistrations(input?: {
@@ -37,6 +76,9 @@ export async function fetchVendorRegularRegistrations(input?: { return unstable_cache(
async () => {
try {
+ // 장기미등록 상태 업데이트 실행
+ await updatePendingApprovals();
+
const registrations = await getVendorRegularRegistrations();
let filteredData = registrations;
@@ -113,6 +155,7 @@ export async function createVendorRegistration(data: { const registration = await createVendorRegularRegistration({
...data,
+ status: data.status || "under_review", // 기본 상태를 '검토중'으로 설정
majorItems: majorItemsJson,
});
@@ -438,7 +481,7 @@ export async function skipLegalReview(vendorIds: number[], skipReason: string) { // 새로 생성
const newRegistration = await createVendorRegularRegistration({
vendorId: vendorId,
- status: "cp_finished", // CP완료로 변경
+ status: "under_review", // 검토중으로 변경
remarks: `GTC Skip: ${skipReason}`,
});
registrationId = newRegistration.id;
@@ -451,7 +494,6 @@ export async function skipLegalReview(vendorIds: number[], skipReason: string) { : `GTC Skip: ${skipReason}`;
await updateVendorRegularRegistration(registrationId, {
- status: "cp_finished", // CP완료로 변경
gtcSkipped: true, // GTC Skip 여부 설정
remarks: newRemarks,
});
@@ -630,7 +672,7 @@ export async function fetchVendorRegistrationStatus(vendorId: number) { }
}
- // 정규업체 등록 정보
+ // 정규업체 등록 정보 (없을 수도 있음 - 기존 정규업체이거나 아직 등록 진행 안함)
const registration = await db
.select({
id: vendorRegularRegistrations.id,
@@ -653,6 +695,15 @@ export async function fetchVendorRegistrationStatus(vendorId: number) { .where(eq(vendorRegularRegistrations.vendorId, vendorId))
.limit(1)
+ // 정규업체 등록 정보가 없는 경우 (정상적인 상황)
+ if (!registration[0]) {
+ return {
+ success: false,
+ error: "정규업체 등록 진행 정보가 없습니다.", // 에러가 아닌 정보성 메시지
+ noRegistration: true // 등록 정보가 없음을 명시적으로 표시
+ }
+ }
+
// 벤더 첨부파일 조회
const vendorFiles = await db
.select()
@@ -783,7 +834,8 @@ export async function fetchVendorRegistrationStatus(vendorId: number) { missingDocuments,
businessContacts,
missingContactTypes,
- additionalInfo: additionalInfoCompleted, // boolean 값으로 변경
+ additionalInfo: additionalInfo[0] || null, // 실제 추가정보 데이터 반환
+ additionalInfoCompleted, // 완료 여부는 별도 필드로 추가
pqSubmission: pqSubmission[0] || null,
auditPassed: investigationFiles.length > 0,
basicContracts: vendorContracts, // 기본계약 정보 추가
diff --git a/lib/vendor-regular-registrations/major-items-update-sheet.tsx b/lib/vendor-regular-registrations/table/major-items-update-dialog.tsx index ba125bbe..26741a1b 100644 --- a/lib/vendor-regular-registrations/major-items-update-sheet.tsx +++ b/lib/vendor-regular-registrations/table/major-items-update-dialog.tsx @@ -6,18 +6,18 @@ import { toast } from "sonner" import { X, Plus, Search } from "lucide-react" import { - Sheet, - SheetContent, - SheetDescription, - SheetHeader, - SheetTitle, -} from "@/components/ui/sheet" + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog" import { Button } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { Badge } from "@/components/ui/badge" import { Label } from "@/components/ui/label" import { searchItemsForPQ } from "@/lib/items/service" -import { updateMajorItems } from "./service" +import { updateMajorItems } from "../service" // PQ 대상 품목 타입 정의 interface PQItem { @@ -25,7 +25,7 @@ interface PQItem { itemName: string } -interface MajorItemsUpdateSheetProps { +interface MajorItemsUpdateDialogProps { open: boolean onOpenChange: (open: boolean) => void registrationId?: number @@ -34,14 +34,14 @@ interface MajorItemsUpdateSheetProps { onSuccess?: () => void } -export function MajorItemsUpdateSheet({ +export function MajorItemsUpdateDialog({ open, onOpenChange, registrationId, vendorName, currentItems, onSuccess, -}: MajorItemsUpdateSheetProps) { +}: MajorItemsUpdateDialogProps) { const [isLoading, setIsLoading] = useState(false) const [selectedItems, setSelectedItems] = useState<PQItem[]>([]) @@ -144,14 +144,14 @@ export function MajorItemsUpdateSheet({ } return ( - <Sheet open={open} onOpenChange={onOpenChange}> - <SheetContent className="w-[400px] sm:w-[540px]"> - <SheetHeader> - <SheetTitle>주요품목 등록</SheetTitle> - <SheetDescription> + <Dialog open={open} onOpenChange={onOpenChange}> + <DialogContent className="w-[400px] sm:w-[540px] max-h-[90vh] overflow-y-auto"> + <DialogHeader> + <DialogTitle>주요품목 등록</DialogTitle> + <DialogDescription> {vendorName && `${vendorName}의 `}주요품목을 등록해주세요. - </SheetDescription> - </SheetHeader> + </DialogDescription> + </DialogHeader> <div className="space-y-6 mt-6"> {/* 선택된 아이템들 표시 */} @@ -239,7 +239,7 @@ export function MajorItemsUpdateSheet({ {isLoading ? "저장 중..." : "저장"} </Button> </div> - </SheetContent> - </Sheet> + </DialogContent> + </Dialog> ) } diff --git a/lib/vendor-regular-registrations/table/safety-qualification-update-sheet.tsx b/lib/vendor-regular-registrations/table/safety-qualification-update-dialog.tsx index c2aeba70..80084732 100644 --- a/lib/vendor-regular-registrations/table/safety-qualification-update-sheet.tsx +++ b/lib/vendor-regular-registrations/table/safety-qualification-update-dialog.tsx @@ -7,12 +7,12 @@ import { z } from "zod" import { toast } from "sonner" import { - Sheet, - SheetContent, - SheetDescription, - SheetHeader, - SheetTitle, -} from "@/components/ui/sheet" + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog" import { Form, FormControl, @@ -29,7 +29,7 @@ const formSchema = z.object({ safetyQualificationContent: z.string().min(1, "안전적격성 평가 내용을 입력해주세요."), }) -interface SafetyQualificationUpdateSheetProps { +interface SafetyQualificationUpdateDialogProps { open: boolean onOpenChange: (open: boolean) => void registrationId?: number @@ -38,14 +38,14 @@ interface SafetyQualificationUpdateSheetProps { onSuccess?: () => void } -export function SafetyQualificationUpdateSheet({ +export function SafetyQualificationUpdateDialog({ open, onOpenChange, registrationId, vendorName, currentContent, onSuccess, -}: SafetyQualificationUpdateSheetProps) { +}: SafetyQualificationUpdateDialogProps) { const [isLoading, setIsLoading] = React.useState(false) const form = useForm<z.infer<typeof formSchema>>({ @@ -93,14 +93,14 @@ export function SafetyQualificationUpdateSheet({ } return ( - <Sheet open={open} onOpenChange={onOpenChange}> - <SheetContent className="w-[400px] sm:w-[540px]"> - <SheetHeader> - <SheetTitle>안전적격성 평가 입력</SheetTitle> - <SheetDescription> + <Dialog open={open} onOpenChange={onOpenChange}> + <DialogContent className="w-[400px] sm:w-[540px] max-h-[90vh] overflow-y-auto"> + <DialogHeader> + <DialogTitle>안전적격성 평가 입력</DialogTitle> + <DialogDescription> {vendorName && `${vendorName}의 `}안전적격성 평가 내용을 입력해주세요. - </SheetDescription> - </SheetHeader> + </DialogDescription> + </DialogHeader> <Form {...form}> <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6 mt-6"> @@ -137,7 +137,7 @@ export function SafetyQualificationUpdateSheet({ </div> </form> </Form> - </SheetContent> - </Sheet> + </DialogContent> + </Dialog> ) } diff --git a/lib/vendor-regular-registrations/table/vendor-regular-registrations-table-columns.tsx b/lib/vendor-regular-registrations/table/vendor-regular-registrations-table-columns.tsx index 765b0279..7446716b 100644 --- a/lib/vendor-regular-registrations/table/vendor-regular-registrations-table-columns.tsx +++ b/lib/vendor-regular-registrations/table/vendor-regular-registrations-table-columns.tsx @@ -13,29 +13,23 @@ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigge import { Eye, FileText, Ellipsis, Shield, Package } from "lucide-react"
import { toast } from "sonner"
import { useState } from "react"
-import { SafetyQualificationUpdateSheet } from "./safety-qualification-update-sheet"
-import { MajorItemsUpdateSheet } from "../major-items-update-sheet"
+import { SafetyQualificationUpdateDialog } from "./safety-qualification-update-dialog"
+import { MajorItemsUpdateDialog } from "./major-items-update-dialog"
const statusLabels = {
- audit_pass: "실사통과",
- cp_submitted: "CP등록",
- cp_review: "CP검토",
- cp_finished: "CP완료",
+ under_review: "검토중",
approval_ready: "조건충족",
- registration_requested: "등록요청됨",
in_review: "정규등록검토",
+ completed: "등록완료",
pending_approval: "장기미등록",
}
const statusColors = {
- audit_pass: "bg-blue-100 text-blue-800",
- cp_submitted: "bg-green-100 text-green-800",
- cp_review: "bg-yellow-100 text-yellow-800",
- cp_finished: "bg-purple-100 text-purple-800",
+ under_review: "bg-blue-100 text-blue-800",
approval_ready: "bg-emerald-100 text-emerald-800",
- registration_requested: "bg-indigo-100 text-indigo-800",
in_review: "bg-orange-100 text-orange-800",
+ completed: "bg-green-100 text-green-800",
pending_approval: "bg-red-100 text-red-800",
}
@@ -295,7 +289,7 @@ export function getColumns(): ColumnDef<VendorRegularRegistration>[] { </DropdownMenuContent>
</DropdownMenu>
- <SafetyQualificationUpdateSheet
+ <SafetyQualificationUpdateDialog
open={safetyQualificationSheetOpen}
onOpenChange={setSafetyQualificationSheetOpen}
registrationId={registration.id}
@@ -306,7 +300,7 @@ export function getColumns(): ColumnDef<VendorRegularRegistration>[] { window.location.reload()
}}
/>
- <MajorItemsUpdateSheet
+ <MajorItemsUpdateDialog
open={majorItemsSheetOpen}
onOpenChange={setMajorItemsSheetOpen}
registrationId={registration.id}
|
