From c8beed57d9fb10c02b8951cd4267017984ca5beb Mon Sep 17 00:00:00 2001
From: dujinkim <dujin.kim@dtsolution.co.kr>
Date: Wed, 17 Sep 2025 10:41:29 +0000
Subject: (최겸) 구매 일반계약 프로젝트id추가, 선적지, 하역지 연동, numbering
 수정
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../detail/general-contract-basic-info.tsx         | 241 ++++++++++++++++-----
 1 file changed, 189 insertions(+), 52 deletions(-)

(limited to 'lib/general-contracts/detail/general-contract-basic-info.tsx')

diff --git a/lib/general-contracts/detail/general-contract-basic-info.tsx b/lib/general-contracts/detail/general-contract-basic-info.tsx
index ac1315bb..882ed8b2 100644
--- a/lib/general-contracts/detail/general-contract-basic-info.tsx
+++ b/lib/general-contracts/detail/general-contract-basic-info.tsx
@@ -14,6 +14,7 @@ import { toast } from 'sonner'
 import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
 import { GeneralContract } from '@/db/schema'
 import { ContractDocuments } from './general-contract-documents'
+import { getPaymentTermsForSelection, getIncotermsForSelection, getPlaceOfShippingForSelection, getPlaceOfDestinationForSelection } from '@/lib/procurement-select/service'
 
 interface ContractBasicInfoProps {
   contractId: number
@@ -27,6 +28,13 @@ export function ContractBasicInfo({ contractId }: ContractBasicInfoProps) {
   
   // 독립적인 상태 관리
   const [paymentDeliveryPercent, setPaymentDeliveryPercent] = useState('')
+
+  // Procurement 데이터 상태들
+  const [paymentTermsOptions, setPaymentTermsOptions] = useState<Array<{code: string, description: string}>>([])
+  const [incotermsOptions, setIncotermsOptions] = useState<Array<{code: string, description: string}>>([])
+  const [shippingPlaces, setShippingPlaces] = useState<Array<{code: string, description: string}>>([])
+  const [destinationPlaces, setDestinationPlaces] = useState<Array<{code: string, description: string}>>([])
+  const [procurementLoading, setProcurementLoading] = useState(false)
   
   const [formData, setFormData] = useState({
     specificationType: '',
@@ -169,6 +177,67 @@ export function ContractBasicInfo({ contractId }: ContractBasicInfoProps) {
       loadContract()
     }
   }, [contractId])
+
+  // Procurement 데이터 로드 함수들
+  const loadPaymentTerms = React.useCallback(async () => {
+    setProcurementLoading(true);
+    try {
+      const data = await getPaymentTermsForSelection();
+      setPaymentTermsOptions(data);
+    } catch (error) {
+      console.error("Failed to load payment terms:", error);
+      toast.error("결제조건 목록을 불러오는데 실패했습니다.");
+    } finally {
+      setProcurementLoading(false);
+    }
+  }, []);
+
+  const loadIncoterms = React.useCallback(async () => {
+    setProcurementLoading(true);
+    try {
+      const data = await getIncotermsForSelection();
+      setIncotermsOptions(data);
+    } catch (error) {
+      console.error("Failed to load incoterms:", error);
+      toast.error("운송조건 목록을 불러오는데 실패했습니다.");
+    } finally {
+      setProcurementLoading(false);
+    }
+  }, []);
+
+  const loadShippingPlaces = React.useCallback(async () => {
+    setProcurementLoading(true);
+    try {
+      const data = await getPlaceOfShippingForSelection();
+      setShippingPlaces(data);
+    } catch (error) {
+      console.error("Failed to load shipping places:", error);
+      toast.error("선적지 목록을 불러오는데 실패했습니다.");
+    } finally {
+      setProcurementLoading(false);
+    }
+  }, []);
+
+  const loadDestinationPlaces = React.useCallback(async () => {
+    setProcurementLoading(true);
+    try {
+      const data = await getPlaceOfDestinationForSelection();
+      setDestinationPlaces(data);
+    } catch (error) {
+      console.error("Failed to load destination places:", error);
+      toast.error("하역지 목록을 불러오는데 실패했습니다.");
+    } finally {
+      setProcurementLoading(false);
+    }
+  }, []);
+
+  // 컴포넌트 마운트 시 procurement 데이터 로드
+  React.useEffect(() => {
+    loadPaymentTerms();
+    loadIncoterms();
+    loadShippingPlaces();
+    loadDestinationPlaces();
+  }, [loadPaymentTerms, loadIncoterms, loadShippingPlaces, loadDestinationPlaces]);
   const handleSaveContractInfo = async () => {
     if (!userId) {
       toast.error('사용자 정보를 찾을 수 없습니다.')
@@ -518,15 +587,16 @@ export function ContractBasicInfo({ contractId }: ContractBasicInfoProps) {
                     <Label htmlFor="apBond" className="text-sm">AP Bond & Performance Bond</Label>
                     <Input
                       type="number"
+                      min="0"
                       placeholder="%"
                       className="w-16"
                       value={formData.paymentBeforeDelivery.apBondPercent || ''}
-                      onChange={(e) => setFormData(prev => ({ 
-                        ...prev, 
-                        paymentBeforeDelivery: { 
-                          ...prev.paymentBeforeDelivery, 
-                          apBondPercent: e.target.value 
-                        } 
+                      onChange={(e) => setFormData(prev => ({
+                        ...prev,
+                        paymentBeforeDelivery: {
+                          ...prev.paymentBeforeDelivery,
+                          apBondPercent: e.target.value
+                        }
                       }))}
                       disabled={!formData.paymentBeforeDelivery.apBond}
                     />
@@ -548,15 +618,16 @@ export function ContractBasicInfo({ contractId }: ContractBasicInfoProps) {
                     <Label htmlFor="drawingSubmission" className="text-sm">도면제출</Label>
                     <Input
                       type="number"
+                      min="0"
                       placeholder="%"
                       className="w-16"
                       value={formData.paymentBeforeDelivery.drawingSubmissionPercent || ''}
-                      onChange={(e) => setFormData(prev => ({ 
-                        ...prev, 
-                        paymentBeforeDelivery: { 
-                          ...prev.paymentBeforeDelivery, 
-                          drawingSubmissionPercent: e.target.value 
-                        } 
+                      onChange={(e) => setFormData(prev => ({
+                        ...prev,
+                        paymentBeforeDelivery: {
+                          ...prev.paymentBeforeDelivery,
+                          drawingSubmissionPercent: e.target.value
+                        }
                       }))}
                       disabled={!formData.paymentBeforeDelivery.drawingSubmission}
                     />
@@ -578,15 +649,16 @@ export function ContractBasicInfo({ contractId }: ContractBasicInfoProps) {
                     <Label htmlFor="materialPurchase" className="text-sm">소재구매 문서</Label>
                     <Input
                       type="number"
+                      min="0"
                       placeholder="%"
                       className="w-16"
                       value={formData.paymentBeforeDelivery.materialPurchasePercent || ''}
-                      onChange={(e) => setFormData(prev => ({ 
-                        ...prev, 
-                        paymentBeforeDelivery: { 
-                          ...prev.paymentBeforeDelivery, 
-                          materialPurchasePercent: e.target.value 
-                        } 
+                      onChange={(e) => setFormData(prev => ({
+                        ...prev,
+                        paymentBeforeDelivery: {
+                          ...prev.paymentBeforeDelivery,
+                          materialPurchasePercent: e.target.value
+                        }
                       }))}
                       disabled={!formData.paymentBeforeDelivery.materialPurchase}
                     />
@@ -618,6 +690,7 @@ export function ContractBasicInfo({ contractId }: ContractBasicInfoProps) {
                       <div className="flex items-center gap-2 mt-2">
                         <Input
                           type="number"
+                          min="0"
                           value={paymentDeliveryPercent}
                           onChange={(e) => setPaymentDeliveryPercent(e.target.value)}
                           placeholder="퍼센트"
@@ -654,15 +727,16 @@ export function ContractBasicInfo({ contractId }: ContractBasicInfoProps) {
                     <Label htmlFor="commissioning" className="text-sm">Commissioning 완료</Label>
                     <Input
                       type="number"
+                      min="0"
                       placeholder="%"
                       className="w-16"
                       value={formData.paymentAfterDelivery.commissioningPercent || ''}
-                      onChange={(e) => setFormData(prev => ({ 
-                        ...prev, 
-                        paymentAfterDelivery: { 
-                          ...prev.paymentAfterDelivery, 
-                          commissioningPercent: e.target.value 
-                        } 
+                      onChange={(e) => setFormData(prev => ({
+                        ...prev,
+                        paymentAfterDelivery: {
+                          ...prev.paymentAfterDelivery,
+                          commissioningPercent: e.target.value
+                        }
                       }))}
                       disabled={!formData.paymentAfterDelivery.commissioning}
                     />
@@ -684,15 +758,16 @@ export function ContractBasicInfo({ contractId }: ContractBasicInfoProps) {
                     <Label htmlFor="finalDocument" className="text-sm">최종문서 승인</Label>
                     <Input
                       type="number"
+                      min="0"
                       placeholder="%"
                       className="w-16"
                       value={formData.paymentAfterDelivery.finalDocumentPercent || ''}
-                      onChange={(e) => setFormData(prev => ({ 
-                        ...prev, 
-                        paymentAfterDelivery: { 
-                          ...prev.paymentAfterDelivery, 
-                          finalDocumentPercent: e.target.value 
-                        } 
+                      onChange={(e) => setFormData(prev => ({
+                        ...prev,
+                        paymentAfterDelivery: {
+                          ...prev.paymentAfterDelivery,
+                          finalDocumentPercent: e.target.value
+                        }
                       }))}
                       disabled={!formData.paymentAfterDelivery.finalDocument}
                     />
@@ -736,13 +811,27 @@ export function ContractBasicInfo({ contractId }: ContractBasicInfoProps) {
                 <div className="space-y-3">
                   <div className="space-y-2">
                     <Label htmlFor="paymentTerm">지불조건 <span className="text-red-600">*</span></Label>
-                    <Input
-                      type="text"
+                    <Select
                       value={formData.paymentTerm}
-                      onChange={(e) => setFormData(prev => ({ ...prev, paymentTerm: e.target.value }))}
-                      placeholder="지불조건을 입력하세요"
-                      className={errors.paymentTerm ? 'border-red-500' : ''}
-                    />
+                      onValueChange={(value) => setFormData(prev => ({ ...prev, paymentTerm: value }))}
+                    >
+                      <SelectTrigger className={errors.paymentTerm ? 'border-red-500' : ''}>
+                        <SelectValue placeholder="지불조건을 선택하세요" />
+                      </SelectTrigger>
+                      <SelectContent>
+                        {paymentTermsOptions.length > 0 ? (
+                          paymentTermsOptions.map((option) => (
+                            <SelectItem key={option.code} value={option.code}>
+                              {option.code} {option.description && `(${option.description})`}
+                            </SelectItem>
+                          ))
+                        ) : (
+                          <SelectItem value="loading" disabled>
+                            데이터를 불러오는 중...
+                          </SelectItem>
+                        )}
+                      </SelectContent>
+                    </Select>
                     {errors.paymentTerm && (
                       <p className="text-sm text-red-600">지불조건은 필수값입니다.</p>
                     )}
@@ -781,12 +870,13 @@ export function ContractBasicInfo({ contractId }: ContractBasicInfoProps) {
                     <Label htmlFor="liquidatedDamages" className="text-sm">지체상금</Label>
                     <Input
                       type="number"
+                      min="0"
                       placeholder="%"
                       className="w-16"
                       value={formData.liquidatedDamagesPercent || ''}
-                      onChange={(e) => setFormData(prev => ({ 
-                        ...prev, 
-                        liquidatedDamagesPercent: e.target.value 
+                      onChange={(e) => setFormData(prev => ({
+                        ...prev,
+                        liquidatedDamagesPercent: e.target.value
                       }))}
                       disabled={!formData.liquidatedDamages}
                     />
@@ -823,12 +913,27 @@ export function ContractBasicInfo({ contractId }: ContractBasicInfoProps) {
                   <div className="space-y-3">
                     <div className="space-y-2">
                       <Label htmlFor="deliveryTerm">인도조건</Label>
-                      <Input
-                        type="text"
+                      <Select
                         value={formData.deliveryTerm}
-                        onChange={(e) => setFormData(prev => ({ ...prev, deliveryTerm: e.target.value }))}
-                        placeholder="인도조건을 입력하세요"
-                      />
+                        onValueChange={(value) => setFormData(prev => ({ ...prev, deliveryTerm: value }))}
+                      >
+                        <SelectTrigger>
+                          <SelectValue placeholder="인도조건을 선택하세요" />
+                        </SelectTrigger>
+                        <SelectContent>
+                          {incotermsOptions.length > 0 ? (
+                            incotermsOptions.map((option) => (
+                              <SelectItem key={option.code} value={option.code}>
+                                {option.code} {option.description && `(${option.description})`}
+                              </SelectItem>
+                            ))
+                          ) : (
+                            <SelectItem value="loading" disabled>
+                              데이터를 불러오는 중...
+                            </SelectItem>
+                          )}
+                        </SelectContent>
+                      </Select>
                     </div>
                   </div>
                 </div>
@@ -838,11 +943,27 @@ export function ContractBasicInfo({ contractId }: ContractBasicInfoProps) {
                   <div className="space-y-3">
                     <div className="space-y-2">
                       <Label htmlFor="shippingLocation">선적지</Label>
-                      <Input
+                      <Select
                         value={formData.shippingLocation}
-                        onChange={(e) => setFormData(prev => ({ ...prev, shippingLocation: e.target.value }))}
-                        placeholder="선적지를 입력하세요"
-                      />
+                        onValueChange={(value) => setFormData(prev => ({ ...prev, shippingLocation: value }))}
+                      >
+                        <SelectTrigger>
+                          <SelectValue placeholder="선적지를 선택하세요" />
+                        </SelectTrigger>
+                        <SelectContent>
+                          {shippingPlaces.length > 0 ? (
+                            shippingPlaces.map((place) => (
+                              <SelectItem key={place.code} value={place.code}>
+                                {place.code} {place.description && `(${place.description})`}
+                              </SelectItem>
+                            ))
+                          ) : (
+                            <SelectItem value="loading" disabled>
+                              데이터를 불러오는 중...
+                            </SelectItem>
+                          )}
+                        </SelectContent>
+                      </Select>
                     </div>
                   </div>
                 </div>
@@ -852,11 +973,27 @@ export function ContractBasicInfo({ contractId }: ContractBasicInfoProps) {
                   <div className="space-y-3">
                     <div className="space-y-2">
                       <Label htmlFor="dischargeLocation">하역지</Label>
-                      <Input
+                      <Select
                         value={formData.dischargeLocation}
-                        onChange={(e) => setFormData(prev => ({ ...prev, dischargeLocation: e.target.value }))}
-                        placeholder="하역지를 입력하세요"
-                      />
+                        onValueChange={(value) => setFormData(prev => ({ ...prev, dischargeLocation: value }))}
+                      >
+                        <SelectTrigger>
+                          <SelectValue placeholder="하역지를 선택하세요" />
+                        </SelectTrigger>
+                        <SelectContent>
+                          {destinationPlaces.length > 0 ? (
+                            destinationPlaces.map((place) => (
+                              <SelectItem key={place.code} value={place.code}>
+                                {place.code} {place.description && `(${place.description})`}
+                              </SelectItem>
+                            ))
+                          ) : (
+                            <SelectItem value="loading" disabled>
+                              데이터를 불러오는 중...
+                            </SelectItem>
+                          )}
+                        </SelectContent>
+                      </Select>
                     </div>
                   </div>
                 </div>
-- 
cgit v1.2.3

