From c8beed57d9fb10c02b8951cd4267017984ca5beb Mon Sep 17 00:00:00 2001 From: dujinkim 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 --- .../general-contract-approval-request-dialog.tsx | 2 +- .../detail/general-contract-basic-info.tsx | 241 ++++++++++++++++----- 2 files changed, 190 insertions(+), 53 deletions(-) (limited to 'lib/general-contracts/detail') diff --git a/lib/general-contracts/detail/general-contract-approval-request-dialog.tsx b/lib/general-contracts/detail/general-contract-approval-request-dialog.tsx index e4aa022a..f05fe9ef 100644 --- a/lib/general-contracts/detail/general-contract-approval-request-dialog.tsx +++ b/lib/general-contracts/detail/general-contract-approval-request-dialog.tsx @@ -863,7 +863,7 @@ export function ContractApprovalRequestDialog({ 선적지: {String(contractSummary?.basicInfo?.shippingLocation || '')}
- 도착지: {String(contractSummary?.basicInfo?.dischargeLocation || '')} + 하역지: {String(contractSummary?.basicInfo?.dischargeLocation || '')}
계약납기: {String(contractSummary?.basicInfo?.contractDeliveryDate || '')} 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>([]) + const [incotermsOptions, setIncotermsOptions] = useState>([]) + const [shippingPlaces, setShippingPlaces] = useState>([]) + const [destinationPlaces, setDestinationPlaces] = useState>([]) + 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) { 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) { 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) { 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) {
setPaymentDeliveryPercent(e.target.value)} placeholder="퍼센트" @@ -654,15 +727,16 @@ export function ContractBasicInfo({ contractId }: ContractBasicInfoProps) { 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) { 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) {
- setFormData(prev => ({ ...prev, paymentTerm: e.target.value }))} - placeholder="지불조건을 입력하세요" - className={errors.paymentTerm ? 'border-red-500' : ''} - /> + onValueChange={(value) => setFormData(prev => ({ ...prev, paymentTerm: value }))} + > + + + + + {paymentTermsOptions.length > 0 ? ( + paymentTermsOptions.map((option) => ( + + {option.code} {option.description && `(${option.description})`} + + )) + ) : ( + + 데이터를 불러오는 중... + + )} + + {errors.paymentTerm && (

지불조건은 필수값입니다.

)} @@ -781,12 +870,13 @@ export function ContractBasicInfo({ contractId }: ContractBasicInfoProps) { 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) {
- setFormData(prev => ({ ...prev, deliveryTerm: e.target.value }))} - placeholder="인도조건을 입력하세요" - /> + onValueChange={(value) => setFormData(prev => ({ ...prev, deliveryTerm: value }))} + > + + + + + {incotermsOptions.length > 0 ? ( + incotermsOptions.map((option) => ( + + {option.code} {option.description && `(${option.description})`} + + )) + ) : ( + + 데이터를 불러오는 중... + + )} + +
@@ -838,11 +943,27 @@ export function ContractBasicInfo({ contractId }: ContractBasicInfoProps) {
- setFormData(prev => ({ ...prev, shippingLocation: e.target.value }))} - placeholder="선적지를 입력하세요" - /> + onValueChange={(value) => setFormData(prev => ({ ...prev, shippingLocation: value }))} + > + + + + + {shippingPlaces.length > 0 ? ( + shippingPlaces.map((place) => ( + + {place.code} {place.description && `(${place.description})`} + + )) + ) : ( + + 데이터를 불러오는 중... + + )} + +
@@ -852,11 +973,27 @@ export function ContractBasicInfo({ contractId }: ContractBasicInfoProps) {
- setFormData(prev => ({ ...prev, dischargeLocation: e.target.value }))} - placeholder="하역지를 입력하세요" - /> + onValueChange={(value) => setFormData(prev => ({ ...prev, dischargeLocation: value }))} + > + + + + + {destinationPlaces.length > 0 ? ( + destinationPlaces.map((place) => ( + + {place.code} {place.description && `(${place.description})`} + + )) + ) : ( + + 데이터를 불러오는 중... + + )} + +
-- cgit v1.2.3