diff options
Diffstat (limited to 'lib/vendor-document-list')
5 files changed, 310 insertions, 227 deletions
diff --git a/lib/vendor-document-list/plant/document-stage-dialogs.tsx b/lib/vendor-document-list/plant/document-stage-dialogs.tsx index f49d7d47..4c1861b9 100644 --- a/lib/vendor-document-list/plant/document-stage-dialogs.tsx +++ b/lib/vendor-document-list/plant/document-stage-dialogs.tsx @@ -64,6 +64,7 @@ import { cn, formatDate } from "@/lib/utils" import ExcelJS from 'exceljs' import { Progress } from "@/components/ui/progress" import { Alert, AlertDescription } from "@/components/ui/alert" +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" const getStatusVariant = (status: string) => { switch (status) { @@ -97,69 +98,116 @@ interface AddDocumentDialogProps { projectType: "ship" | "plant" } + export function AddDocumentDialog({ open, onOpenChange, contractId, projectType }: AddDocumentDialogProps) { - const [isLoading, setIsLoading] = React.useState(false) + const [isLoadingInitialData, setIsLoadingInitialData] = React.useState(false) + const [isSubmitting, setIsSubmitting] = React.useState(false) const [documentNumberTypes, setDocumentNumberTypes] = React.useState<any[]>([]) const [documentClasses, setDocumentClasses] = React.useState<any[]>([]) const [selectedTypeConfigs, setSelectedTypeConfigs] = React.useState<any[]>([]) const [comboBoxOptions, setComboBoxOptions] = React.useState<Record<number, any[]>>({}) const [documentClassOptions, setDocumentClassOptions] = React.useState<any[]>([]) - const [isLoadingInitialData, setIsLoadingInitialData] = React.useState(false) - const [isSubmitting, setIsSubmitting] = React.useState(false) + + // SHI와 CPY 타입 체크 + const [shiType, setShiType] = React.useState<any>(null) + const [cpyType, setCpyType] = React.useState<any>(null) + const [activeTab, setActiveTab] = React.useState<"SHI" | "CPY">("SHI") + const [dataLoaded, setDataLoaded] = React.useState(false) + console.log(dataLoaded,"dataLoaded") const [formData, setFormData] = React.useState({ documentNumberTypeId: "", documentClassId: "", title: "", - vendorDocNumber: "", fieldValues: {} as Record<string, string>, - planDates: {} as Record<number, string> // optionId -> planDate + planDates: {} as Record<number, string> }) // Load initial data - React.useEffect(() => { - if (open) { - resetForm() // 폼 리셋 추가 - loadInitialData() - } - }, [open]) +// Dialog가 닫힐 때 상태 초기화를 확실히 하기 +React.useEffect(() => { + if (!open) { + // Dialog가 닫힐 때만 초기화 + resetForm() + } else if (!dataLoaded) { + // Dialog가 열리고 데이터가 로드되지 않았을 때만 + loadInitialData() + } +}, [open]) + const loadInitialData = async () => { - setIsLoadingInitialData(true) // isLoading 대신 + setIsLoadingInitialData(true) + let foundShiType = null; + let foundCpyType = null; + try { const [typesResult, classesResult] = await Promise.all([ getDocumentNumberTypes(contractId), getDocumentClasses(contractId) ]) - if (typesResult.success) { + console.log(typesResult,"typesResult") + + if (typesResult.success && typesResult.data) { setDocumentNumberTypes(typesResult.data) + + // 로컬 변수에 먼저 저장 + foundShiType = typesResult.data.find((type: any) => + type.name?.toUpperCase().trim() === "SHI" + ) + foundCpyType = typesResult.data.find((type: any) => + type.name?.toUpperCase().trim() === "CPY" + ) + + setShiType(foundShiType || null) + setCpyType(foundCpyType || null) + + // 로컬 변수 사용 + if (foundShiType) { + await handleTabChange("SHI", String(foundShiType.id)) + } else if (foundCpyType) { + setActiveTab("CPY") + await handleTabChange("CPY", String(foundCpyType.id)) + } } + if (classesResult.success) { setDocumentClasses(classesResult.data) } + + setDataLoaded(true) } catch (error) { + console.error("Error loading data:", error) toast.error("Error loading data.") } finally { + // 로컬 변수를 체크 + if (!foundShiType && !foundCpyType) { + console.error("No types found after loading") + } setIsLoadingInitialData(false) } } - // Handle document type change - const handleDocumentTypeChange = async (documentNumberTypeId: string) => { - setFormData({ - ...formData, - documentNumberTypeId, - fieldValues: {} - }) - + // 탭 변경 처리 + const handleTabChange = async (tab: "SHI" | "CPY", typeId?: string) => { + setActiveTab(tab) + + const documentNumberTypeId = typeId || (tab === "SHI" ? shiType?.id : cpyType?.id) + if (documentNumberTypeId) { + setFormData(prev => ({ + ...prev, + documentNumberTypeId: String(documentNumberTypeId), + fieldValues: {} + })) + const configsResult = await getDocumentNumberTypeConfigs(Number(documentNumberTypeId)) if (configsResult.success) { setSelectedTypeConfigs(configsResult.data) @@ -238,22 +286,21 @@ export function AddDocumentDialog({ selectedTypeConfigs.forEach((config, index) => { const fieldKey = `field_${config.sdq}` const value = formData.fieldValues[fieldKey] || "[value]" - preview += value - if (index < selectedTypeConfigs.length - 1) { - preview += "-" + + if (index > 0 && config.delimiter) { + preview += config.delimiter } + preview += value }) return preview } // Check if form is valid for submission const isFormValid = () => { - // Check basic required fields if (!formData.documentNumberTypeId || !formData.documentClassId || !formData.title.trim()) { return false } - // Check if all required document number components are filled const requiredConfigs = selectedTypeConfigs.filter(config => config.required) for (const config of requiredConfigs) { const fieldKey = `field_${config.sdq}` @@ -263,7 +310,6 @@ export function AddDocumentDialog({ } } - // Check if document number can be generated const docNumber = generatePreviewDocNumber() if (!docNumber || docNumber === "" || docNumber.includes("[value]")) { return false @@ -278,24 +324,27 @@ export function AddDocumentDialog({ return } - const docNumber = generatePreviewDocNumber() - if (!docNumber) { + const generatedDocNumber = generatePreviewDocNumber() + if (!generatedDocNumber) { toast.error("Cannot generate document number.") return } - setIsSubmitting(true) // isLoading 대신 + setIsSubmitting(true) try { - const result = await createDocument({ + // CPY 탭에서는 생성된 문서번호를 vendorDocNumber로 저장 + const submitData = { contractId, documentNumberTypeId: Number(formData.documentNumberTypeId), documentClassId: Number(formData.documentClassId), title: formData.title, - docNumber: docNumber, // 미리 생성된 문서번호 전송 + docNumber: activeTab === "SHI" ? generatedDocNumber : "", // SHI는 docNumber로 + vendorDocNumber: activeTab === "CPY" ? generatedDocNumber : "", // CPY는 vendorDocNumber로 fieldValues: formData.fieldValues, planDates: formData.planDates, - vendorDocNumber: formData.vendorDocNumber, - }) + } + + const result = await createDocument(submitData) if (result.success) { toast.success("Document added successfully.") @@ -307,7 +356,7 @@ export function AddDocumentDialog({ } catch (error) { toast.error("Error adding document.") } finally { - setIsSubmitting(false) // isLoading 대신 + setIsSubmitting(false) } } @@ -316,16 +365,165 @@ export function AddDocumentDialog({ documentNumberTypeId: "", documentClassId: "", title: "", - vendorDocNumber: "", fieldValues: {}, planDates: {} }) setSelectedTypeConfigs([]) setComboBoxOptions({}) setDocumentClassOptions([]) + setActiveTab("SHI") + setDataLoaded(false) } - const isPlantProject = projectType === "plant" + // 공통 폼 컴포넌트 + const DocumentForm = () => ( + <div className="grid gap-4"> + {/* Dynamic Fields */} + {selectedTypeConfigs.length > 0 && ( + <div className="border rounded-lg p-4 bg-blue-50/30 dark:bg-blue-950/30"> + <Label className="text-sm font-medium text-blue-800 dark:text-blue-200 mb-3 block"> + Document Number Components + </Label> + <div className="grid gap-3"> + {selectedTypeConfigs.map((config) => ( + <div key={config.id} className="grid gap-2"> + <Label className="text-sm"> + {config.codeGroup?.description || config.description} + {config.required && <span className="text-red-500 ml-1">*</span>} + {config.remark && ( + <span className="text-xs text-gray-500 dark:text-gray-400 ml-2">({config.remark})</span> + )} + </Label> + + {config.codeGroup?.controlType === 'combobox' ? ( + <Select + value={formData.fieldValues[`field_${config.sdq}`] || ""} + onValueChange={(value) => handleFieldValueChange(`field_${config.sdq}`, value)} + > + <SelectTrigger> + <SelectValue placeholder="Select option" /> + </SelectTrigger> + <SelectContent> + {(comboBoxOptions[config.codeGroupId!] || []).map((option) => ( + <SelectItem key={option.id} value={option.code}> + {option.code} - {option.description} + </SelectItem> + ))} + </SelectContent> + </Select> + ) : config.documentClass ? ( + <div className="p-2 bg-gray-100 dark:bg-gray-800 rounded text-sm"> + {config.documentClass.code} - {config.documentClass.description} + </div> + ) : ( + <Input + value={formData.fieldValues[`field_${config.sdq}`] || ""} + onChange={(e) => handleFieldValueChange(`field_${config.sdq}`, e.target.value)} + placeholder="Enter value" + /> + )} + </div> + ))} + </div> + + {/* Document Number Preview */} + <div className="mt-3 p-2 bg-white dark:bg-gray-900 border rounded"> + <Label className="text-xs text-gray-600 dark:text-gray-400"> + {activeTab === "SHI" ? "Document Number" : "Vendor Document Number"} Preview: + </Label> + <div className="font-mono text-sm font-medium text-blue-600 dark:text-blue-400"> + {generatePreviewDocNumber()} + </div> + </div> + </div> + )} + + {/* Document Class Selection */} + <div className="grid gap-2"> + <Label htmlFor="documentClassId"> + Document Class <span className="text-red-500">*</span> + </Label> + <Select + value={formData.documentClassId} + onValueChange={handleDocumentClassChange} + > + <SelectTrigger> + <SelectValue placeholder="Select document class" /> + </SelectTrigger> + <SelectContent> + {documentClasses.map((cls) => ( + <SelectItem key={cls.id} value={String(cls.id)}> + {cls.value} + </SelectItem> + ))} + </SelectContent> + </Select> + {formData.documentClassId && ( + <p className="text-xs text-gray-600 dark:text-gray-400"> + Options from the selected class will be automatically created as stages. + </p> + )} + </div> + + {/* Document Class Options with Plan Dates */} + {documentClassOptions.length > 0 && ( + <div className="border rounded-lg p-4 bg-green-50/30 dark:bg-green-950/30"> + <Label className="text-sm font-medium text-green-800 dark:text-green-200 mb-3 block"> + Document Class Stages with Plan Dates + </Label> + <div className="grid gap-3"> + {documentClassOptions.map((option) => ( + <div key={option.id} className="grid grid-cols-2 gap-3 items-center"> + <div> + <Label className="text-sm font-medium"> + {option.optionValue} + </Label> + {option.optionCode && ( + <p className="text-xs text-gray-500 dark:text-gray-400">Code: {option.optionCode}</p> + )} + </div> + <div className="grid gap-1"> + <Label className="text-xs text-gray-600 dark:text-gray-400">Plan Date</Label> + <Input + type="date" + value={formData.planDates[option.id] || ""} + onChange={(e) => handlePlanDateChange(option.id, e.target.value)} + className="text-sm" + /> + </div> + </div> + ))} + </div> + </div> + )} + + {/* Document Title */} + <div className="grid gap-2"> + <Label htmlFor="title"> + Document Title <span className="text-red-500">*</span> + </Label> + <Input + id="title" + value={formData.title} + onChange={(e) => setFormData({ ...formData, title: e.target.value })} + placeholder="Enter document title" + /> + </div> + </div> + ) + + // 로딩 중이거나 데이터 체크 중일 때 표시 + if (isLoadingInitialData) { + return ( + <Dialog open={open} onOpenChange={onOpenChange}> + <DialogContent className="sm:max-w-[700px] h-[80vh] flex flex-col"> + <div className="flex items-center justify-center py-8 flex-1"> + <Loader2 className="h-8 w-8 animate-spin" /> + </div> + </DialogContent> + </Dialog> + ) + } return ( <Dialog open={open} onOpenChange={onOpenChange}> @@ -337,195 +535,77 @@ export function AddDocumentDialog({ </DialogDescription> </DialogHeader> - {isLoading ? ( - <div className="flex items-center justify-center py-8 flex-1"> - <Loader2 className="h-8 w-8 animate-spin" /> + {!shiType && !cpyType ? ( + <div className="flex-1 flex items-center justify-center"> + <Alert className="max-w-md"> + <AlertTriangle className="h-4 w-4" /> + <AlertDescription> + 필수 Document Number Type (SHI, CPY)이 설정되지 않았습니다. + 먼저 Number Types 관리에서 설정해주세요. + </AlertDescription> + </Alert> </div> ) : ( - <div className="flex-1 overflow-y-auto pr-2"> - <div className="grid gap-4 py-4"> - {/* Document Number Type Selection */} - <div className="grid gap-2"> - <Label htmlFor="documentNumberTypeId"> - Document Number Type <span className="text-red-500">*</span> - </Label> - <Select - value={formData.documentNumberTypeId} - onValueChange={handleDocumentTypeChange} - > - <SelectTrigger> - <SelectValue placeholder="Select document number type" /> - </SelectTrigger> - <SelectContent> - {documentNumberTypes.map((type) => ( - <SelectItem key={type.id} value={String(type.id)}> - {type.name} - </SelectItem> - ))} - </SelectContent> - </Select> - </div> - - {/* Dynamic Fields */} - {selectedTypeConfigs.length > 0 && ( - <div className="border rounded-lg p-4 bg-blue-50/30 dark:bg-blue-950/30"> - <Label className="text-sm font-medium text-blue-800 dark:text-blue-200 mb-3 block"> - Document Number Components - </Label> - <div className="grid gap-3"> - {selectedTypeConfigs.map((config) => ( - <div key={config.id} className="grid gap-2"> - <Label className="text-sm"> - {config.codeGroup?.description || config.description} - {config.required && <span className="text-red-500 ml-1">*</span>} - {config.remark && ( - <span className="text-xs text-gray-500 dark:text-gray-400 ml-2">({config.remark})</span> - )} - </Label> - - {config.codeGroup?.controlType === 'combobox' ? ( - <Select - value={formData.fieldValues[`field_${config.sdq}`] || ""} - onValueChange={(value) => handleFieldValueChange(`field_${config.sdq}`, value)} - > - <SelectTrigger> - <SelectValue placeholder="Select option" /> - </SelectTrigger> - <SelectContent> - {(comboBoxOptions[config.codeGroupId!] || []).map((option) => ( - <SelectItem key={option.id} value={option.code}> - {option.code} - {option.description} - </SelectItem> - ))} - </SelectContent> - </Select> - ) : config.documentClass ? ( - <div className="p-2 bg-gray-100 dark:bg-gray-800 rounded text-sm"> - {config.documentClass.code} - {config.documentClass.description} - </div> - ) : ( - <Input - value={formData.fieldValues[`field_${config.sdq}`] || ""} - onChange={(e) => handleFieldValueChange(`field_${config.sdq}`, e.target.value)} - placeholder="Enter value" - /> - )} - </div> - ))} - </div> - - {/* Document Number Preview */} - <div className="mt-3 p-2 bg-white dark:bg-gray-900 border rounded"> - <Label className="text-xs text-gray-600 dark:text-gray-400">Document Number Preview:</Label> - <div className="font-mono text-sm font-medium text-blue-600 dark:text-blue-400"> - {generatePreviewDocNumber()} - </div> - </div> - </div> - )} - - {/* Document Class Selection */} - <div className="grid gap-2"> - <Label htmlFor="documentClassId"> - Document Class <span className="text-red-500">*</span> - </Label> - <Select - value={formData.documentClassId} - onValueChange={handleDocumentClassChange} - > - <SelectTrigger> - <SelectValue placeholder="Select document class" /> - </SelectTrigger> - <SelectContent> - {documentClasses.map((cls) => ( - <SelectItem key={cls.id} value={String(cls.id)}> - {cls.value} - </SelectItem> - ))} - </SelectContent> - </Select> - {formData.documentClassId && ( - <p className="text-xs text-gray-600 dark:text-gray-400"> - Options from the selected class will be automatically created as stages. - </p> - )} - </div> - - {/* Document Class Options with Plan Dates */} - {documentClassOptions.length > 0 && ( - <div className="border rounded-lg p-4 bg-green-50/30 dark:bg-green-950/30"> - <Label className="text-sm font-medium text-green-800 dark:text-green-200 mb-3 block"> - Document Class Stages with Plan Dates - </Label> - <div className="grid gap-3"> - {documentClassOptions.map((option) => ( - <div key={option.id} className="grid grid-cols-2 gap-3 items-center"> - <div> - <Label className="text-sm font-medium"> - {option.optionValue} - </Label> - {option.optionCode && ( - <p className="text-xs text-gray-500 dark:text-gray-400">Code: {option.optionCode}</p> - )} - </div> - <div className="grid gap-1"> - <Label className="text-xs text-gray-600 dark:text-gray-400">Plan Date</Label> - <Input - type="date" - value={formData.planDates[option.id] || ""} - onChange={(e) => handlePlanDateChange(option.id, e.target.value)} - className="text-sm" - /> - </div> - </div> - ))} - </div> - </div> - )} - - {/* Document Title */} - <div className="grid gap-2"> - <Label htmlFor="title"> - Document Title <span className="text-red-500">*</span> - </Label> - <Input - id="title" - value={formData.title} - onChange={(e) => setFormData({ ...formData, title: e.target.value })} - placeholder="Enter document title" - /> + <> + <Tabs value={activeTab} onValueChange={(v) => handleTabChange(v as "SHI" | "CPY")} className="flex-1 flex flex-col"> + <TabsList className="grid w-full grid-cols-2"> + <TabsTrigger value="SHI" disabled={!shiType}> + SHI (삼성중공업 도서번호) + {!shiType && <AlertTriangle className="ml-2 h-3 w-3" />} + </TabsTrigger> + <TabsTrigger value="CPY" disabled={!cpyType}> + CPY (프로젝트 문서번호) + {!cpyType && <AlertTriangle className="ml-2 h-3 w-3" />} + </TabsTrigger> + </TabsList> + + <div className="flex-1 overflow-y-auto pr-2 mt-4"> + <TabsContent value="SHI" className="mt-0"> + {shiType ? ( + <DocumentForm /> + ) : ( + <Alert> + <AlertTriangle className="h-4 w-4" /> + <AlertDescription> + SHI Document Number Type이 설정되지 않았습니다. + </AlertDescription> + </Alert> + )} + </TabsContent> + + <TabsContent value="CPY" className="mt-0"> + {cpyType ? ( + <DocumentForm /> + ) : ( + <Alert> + <AlertTriangle className="h-4 w-4" /> + <AlertDescription> + CPY Document Number Type이 설정되지 않았습니다. + </AlertDescription> + </Alert> + )} + </TabsContent> </div> + </Tabs> - {/* Additional Information */} - {isPlantProject && ( - <div className="grid gap-2"> - <Label htmlFor="vendorDocNumber">Vendor Document Number</Label> - <Input - id="vendorDocNumber" - value={formData.vendorDocNumber} - onChange={(e) => setFormData({ ...formData, vendorDocNumber: e.target.value })} - placeholder="Vendor provided document number" - /> - </div> - )} - </div> - </div> + <DialogFooter className="flex-shrink-0"> + <Button variant="outline" onClick={() => onOpenChange(false)} disabled={isSubmitting}> + Cancel + </Button> + <Button + onClick={handleSubmit} + disabled={isSubmitting || !isFormValid() || (!shiType && !cpyType)} + > + {isSubmitting ? <Loader2 className="h-4 w-4 animate-spin mr-2" /> : null} + Add Document + </Button> + </DialogFooter> + </> )} - - <DialogFooter className="flex-shrink-0"> - <Button variant="outline" onClick={() => onOpenChange(false)} disabled={isSubmitting}> - Cancel - </Button> - <Button onClick={handleSubmit} disabled={isSubmitting || !isFormValid()}> - {isSubmitting ? <Loader2 className="h-4 w-4 animate-spin mr-2" /> : null} - Add Document - </Button> - </DialogFooter> </DialogContent> </Dialog> ) } - // ============================================================================= // Edit Document Dialog (with improved stage plan date editing) // ============================================================================= @@ -1236,7 +1316,7 @@ export function ExcelImportDialog({ <li>Document Name* (문서명)</li> <li>Document Class* (문서클래스 - 드롭다운 선택)</li> {projectType === "plant" && ( - <li>Vendor Doc No. (벤더문서번호)</li> + <li>Project Doc No. (벤더문서번호)</li> )} </ul> <p className="mt-2"><strong>Stage Plan Dates 시트 (선택사항):</strong></p> @@ -1513,7 +1593,7 @@ async function createImportTemplate(projectType: "ship" | "plant", contractId: n "Document Number*", "Document Name*", "Document Class*", - ...(projectType === "plant" ? ["Vendor Doc No."] : []), + ...(projectType === "plant" ? ["Project Doc No."] : []), "Notes", ]; const documentHeaderRow = documentsSheet.addRow(documentHeaders); @@ -1596,7 +1676,7 @@ async function createImportTemplate(projectType: "ship" | "plant", contractId: n [" - Document Number*: 고유한 문서 번호를 입력하세요"], [" - Document Name*: 문서명을 입력하세요"], [" - Document Class*: 드롭다운에서 문서 클래스를 선택하세요"], - [" - Vendor Doc No.: 벤더 문서 번호"], + [" - Project Doc No.: 벤더 문서 번호"], [" - Notes: 참고사항"], [""], ["2. Stage Plan Dates 시트 (선택사항)"], diff --git a/lib/vendor-document-list/plant/document-stage-toolbar.tsx b/lib/vendor-document-list/plant/document-stage-toolbar.tsx index 601a9152..ccb9e15c 100644 --- a/lib/vendor-document-list/plant/document-stage-toolbar.tsx +++ b/lib/vendor-document-list/plant/document-stage-toolbar.tsx @@ -18,7 +18,7 @@ import { sendDocumentsToSHI } from "./document-stages-service" import { useDocumentPolling } from "@/hooks/use-document-polling" import { cn } from "@/lib/utils" import { MultiUploadDialog } from "./upload/components/multi-upload-dialog" -// import { useRouter } from "next/navigation" +import { useRouter } from "next/navigation" // 서버 액션 import (필요한 경우) // import { importDocumentsExcel } from "./document-stages-service" diff --git a/lib/vendor-document-list/plant/document-stages-columns.tsx b/lib/vendor-document-list/plant/document-stages-columns.tsx index 2f8fd482..0b85c3f8 100644 --- a/lib/vendor-document-list/plant/document-stages-columns.tsx +++ b/lib/vendor-document-list/plant/document-stages-columns.tsx @@ -298,7 +298,7 @@ export function getDocumentStagesColumns({ { accessorKey: "vendorDocNumber", header: ({ column }) => ( - <DataTableColumnHeaderSimple column={column} title="Vendor Doc No." /> + <DataTableColumnHeaderSimple column={column} title="Project Doc No." /> ), cell: ({ row }) => { const doc = row.original @@ -311,7 +311,7 @@ export function getDocumentStagesColumns({ size: 120, enableResizing: true, meta: { - excelHeader: "Vendor Doc No." + excelHeader: "Project Doc No." }, }, ) diff --git a/lib/vendor-document-list/plant/document-stages-service.ts b/lib/vendor-document-list/plant/document-stages-service.ts index 30a235c3..2c65b4e6 100644 --- a/lib/vendor-document-list/plant/document-stages-service.ts +++ b/lib/vendor-document-list/plant/document-stages-service.ts @@ -689,6 +689,8 @@ export async function getDocumentNumberTypes(contractId: number) { } } + console.log(project,"project") + const types = await db .select() .from(documentNumberTypes) @@ -711,6 +713,7 @@ export async function getDocumentNumberTypeConfigs(documentNumberTypeId: number) id: documentNumberTypeConfigs.id, sdq: documentNumberTypeConfigs.sdq, description: documentNumberTypeConfigs.description, + delimiter: documentNumberTypeConfigs.delimiter, remark: documentNumberTypeConfigs.remark, codeGroupId: documentNumberTypeConfigs.codeGroupId, // documentClassId: documentNumberTypeConfigs.documentClassId, diff --git a/lib/vendor-document-list/plant/shi-buyer-system-api.ts b/lib/vendor-document-list/plant/shi-buyer-system-api.ts index 1f15efa6..582490af 100644 --- a/lib/vendor-document-list/plant/shi-buyer-system-api.ts +++ b/lib/vendor-document-list/plant/shi-buyer-system-api.ts @@ -162,10 +162,9 @@ export class ShiBuyerSystemAPI { vendorName: sql<string>`(SELECT vendor_name FROM vendors WHERE id = ${stageDocuments.vendorId})`, stages: sql<any[]>` COALESCE( - (SELECT json_agg(row_to_json(s.*)) + (SELECT json_agg(row_to_json(s.*) ORDER BY s.stage_order) FROM stage_issue_stages s - WHERE s.document_id = ${stageDocuments.id} - ORDER BY s.stage_order), + WHERE s.document_id = ${stageDocuments.id}), '[]'::json ) ` @@ -178,7 +177,8 @@ export class ShiBuyerSystemAPI { ne(stageDocuments.buyerSystemStatus, "승인(DC)") ) ) - + + return result } |
