'use client'; import { useState, useCallback, useEffect } from 'react'; import { Dialog, DialogContent, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { DatePicker } from '@/components/ui/date-picker'; import { Label } from '@/components/ui/label'; import { QuantityInput } from '@/components/ui/quantity-input'; import { CurrencyInput } from '@/components/ui/currency-input'; import { Switch } from '@/components/ui/switch'; import { Badge } from '@/components/ui/badge'; import { getPresetStyle } from '@/lib/utils/status-config'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { formatNumber } from '@/lib/utils/amount'; import { FileText, Plus, X, ExternalLink } from 'lucide-react'; import type { PurchaseRecord, PurchaseItem, PurchaseType } from './types'; import { PURCHASE_TYPE_LABELS } from './types'; import { getBankAccounts, getVendors } from './actions'; interface PurchaseDetailModalProps { open: boolean; onOpenChange: (open: boolean) => void; data: PurchaseRecord; onSave: (data: PurchaseRecord) => void; } // 계좌/거래처 타입 interface BankAccount { id: string; bankName: string; accountName: string; accountNumber: string; } interface Vendor { id: string; name: string; } export function PurchaseDetailModal({ open, onOpenChange, data, onSave, }: PurchaseDetailModalProps) { // ===== 로컬 상태 ===== const [formData, setFormData] = useState(data); const [items, setItems] = useState(data.items); const [accounts, setAccounts] = useState([]); const [vendors, setVendors] = useState([]); // ===== API 데이터 로드 ===== useEffect(() => { if (open) { // 계좌 목록 로드 getBankAccounts().then((result) => { if (result.success) { setAccounts(result.data); } }); // 거래처 목록 로드 getVendors().then((result) => { if (result.success) { setVendors(result.data); } }); } }, [open]); // ===== 핸들러 ===== const handleFieldChange = useCallback((field: keyof PurchaseRecord, value: unknown) => { setFormData(prev => ({ ...prev, [field]: value })); }, []); const handleAccountChange = useCallback((accountId: string) => { const account = accounts.find(a => a.id === accountId); if (account) { setFormData(prev => ({ ...prev, withdrawalAccount: { bankName: account.bankName, accountNo: account.accountNumber, accountAlias: account.accountName, }, })); } }, [accounts]); const handleVendorChange = useCallback((vendorId: string) => { const vendor = vendors.find(v => v.id === vendorId); if (vendor) { setFormData(prev => ({ ...prev, vendorId: vendor.id, vendorName: vendor.name, })); } }, [vendors]); const handleItemChange = useCallback((itemId: string, field: keyof PurchaseItem, value: unknown) => { setItems(prev => prev.map(item => { if (item.id === itemId) { const updated = { ...item, [field]: value }; // 자동 계산: 공급가액 = 수량 * 단가 if (field === 'quantity' || field === 'unitPrice') { updated.supplyPrice = updated.quantity * updated.unitPrice; updated.vat = Math.floor(updated.supplyPrice * 0.1); } return updated; } return item; })); }, []); const handleAddItem = useCallback(() => { const newItem: PurchaseItem = { id: `item-new-${Date.now()}`, itemName: '', quantity: 1, unitPrice: 0, supplyPrice: 0, vat: 0, }; setItems(prev => [...prev, newItem]); }, []); const handleRemoveItem = useCallback((itemId: string) => { setItems(prev => prev.filter(item => item.id !== itemId)); }, []); const handleSave = useCallback(() => { const updatedData: PurchaseRecord = { ...formData, items, updatedAt: new Date().toISOString(), }; onSave(updatedData); }, [formData, items, onSave]); // ===== 합계 계산 ===== const totalSupplyPrice = items.reduce((sum, item) => sum + item.supplyPrice, 0); const totalVat = items.reduce((sum, item) => sum + item.vat, 0); const totalAmount = totalSupplyPrice + totalVat; return ( 매입 상세
{/* ===== 기본 정보 섹션 ===== */} 기본 정보 {/* 근거 문서 */} {data.sourceDocument && (
{data.sourceDocument.type === 'proposal' ? '품의서' : '지출결의서'} {data.sourceDocument.documentNo} 예상 비용: {formatNumber(data.sourceDocument.expectedCost)}원
)}
{/* 매입일자 */}
handleFieldChange('purchaseDate', date)} />
{/* 출금계좌 */}
{/* 거래처 */}
{/* 매입 유형 */}
{/* ===== 품목 정보 섹션 ===== */}
품목 정보
# 품목명 수량 단가 공급가액 부가세 적요 {items.map((item, index) => ( {index + 1} handleItemChange(item.id, 'itemName', e.target.value)} placeholder="품목명" className="h-8" /> handleItemChange(item.id, 'quantity', value ?? 0)} className="h-8 text-right" min={1} /> handleItemChange(item.id, 'unitPrice', value ?? 0)} className="h-8 text-right" /> {formatNumber(item.supplyPrice)} {formatNumber(item.vat)} handleItemChange(item.id, 'note', e.target.value)} placeholder="적요" className="h-8" /> ))} {/* 합계 행 */} 합계 {formatNumber(totalSupplyPrice)} {formatNumber(totalVat)} 총액: {formatNumber(totalAmount)}원
{/* ===== 세금계산서 섹션 ===== */} 세금계산서
{formData.taxInvoiceReceived ? '수취완료' : '미수취'}
handleFieldChange('taxInvoiceReceived', checked)} />
{/* ===== 액션 버튼 ===== */}
); }