diff --git a/src/components/accounting/DepositManagement/DepositDetailClientV2.tsx b/src/components/accounting/DepositManagement/DepositDetailClientV2.tsx index 0de82619..1f044239 100644 --- a/src/components/accounting/DepositManagement/DepositDetailClientV2.tsx +++ b/src/components/accounting/DepositManagement/DepositDetailClientV2.tsx @@ -12,8 +12,8 @@ import { createDeposit, updateDeposit, deleteDeposit, - getVendors, + getBankAccounts, } from './actions'; import { useDevFill, generateDepositData } from '@/components/dev'; @@ -35,11 +35,15 @@ export default function DepositDetailClientV2({ // ===== DevFill: 자동 입력 기능 ===== useDevFill('deposit', useCallback(async () => { if (initialMode === 'create') { - // 거래처 목록 가져오기 - const vendorResult = await getVendors(); + // 거래처 및 계좌 목록 가져오기 + const [vendorResult, bankAccountResult] = await Promise.all([ + getVendors(), + getBankAccounts(), + ]); const vendors = vendorResult.success ? vendorResult.data : undefined; + const bankAccounts = bankAccountResult.success ? bankAccountResult.data : undefined; - const mockData = generateDepositData({ vendors }); + const mockData = generateDepositData({ vendors, bankAccounts }); setDeposit(mockData as unknown as DepositRecord); toast.success('입금 데이터가 자동 입력되었습니다.'); } diff --git a/src/components/accounting/DepositManagement/actions.ts b/src/components/accounting/DepositManagement/actions.ts index 5683e1c9..f302413f 100644 --- a/src/components/accounting/DepositManagement/actions.ts +++ b/src/components/accounting/DepositManagement/actions.ts @@ -41,7 +41,10 @@ function transformApiToFrontend(apiData: DepositApiData): DepositRecord { depositAmount: typeof apiData.amount === 'string' ? parseFloat(apiData.amount) : (apiData.amount ?? 0), - accountName: apiData.bank_account?.account_name || '', + bankAccountId: apiData.bank_account_id ? String(apiData.bank_account_id) : '', + accountName: apiData.bank_account + ? `${apiData.bank_account.bank_name} ${apiData.bank_account.account_name}` + : '', depositorName: apiData.client_name || apiData.client?.name || '', note: apiData.description || '', depositType: (apiData.account_code || 'unset') as DepositType, @@ -61,9 +64,18 @@ function transformFrontendToApi(data: Partial): Record { + const url = `${process.env.NEXT_PUBLIC_API_URL}/api/v1/bank-accounts?per_page=100`; + const { response, error } = await serverFetch(url, { method: 'GET' }); + + if (error) { + return { success: false, data: [], error: error.message }; + } + + if (!response?.ok) { + return { success: false, data: [], error: `API 오류: ${response?.status}` }; + } + + const result = await response.json(); + + if (!result.success) { + return { success: false, data: [], error: result.message }; + } + + const accounts = result.data?.data || result.data || []; + + return { + success: true, + data: accounts.map((a: { id: number; account_name: string; bank_name: string }) => ({ + id: String(a.id), + name: `${a.bank_name} ${a.account_name}`, + })), + }; +} diff --git a/src/components/accounting/DepositManagement/depositDetailConfig.ts b/src/components/accounting/DepositManagement/depositDetailConfig.ts index 089deb83..da83c53d 100644 --- a/src/components/accounting/DepositManagement/depositDetailConfig.ts +++ b/src/components/accounting/DepositManagement/depositDetailConfig.ts @@ -2,7 +2,7 @@ import { Banknote } from 'lucide-react'; import type { DetailConfig, FieldDefinition } from '@/components/templates/IntegratedDetailTemplate/types'; import type { DepositRecord } from './types'; import { DEPOSIT_TYPE_SELECTOR_OPTIONS } from './types'; -import { getVendors } from './actions'; +import { getVendors, getBankAccounts } from './actions'; // ===== 필드 정의 ===== const fields: FieldDefinition[] = [ @@ -16,10 +16,20 @@ const fields: FieldDefinition[] = [ }, // 입금계좌 { - key: 'accountName', + key: 'bankAccountId', label: '입금계좌', - type: 'text', - placeholder: '입금계좌를 입력해주세요', + type: 'select', + placeholder: '선택', + fetchOptions: async () => { + const result = await getBankAccounts(); + if (result.success) { + return result.data.map((a) => ({ + value: a.id, + label: a.name, + })); + } + return []; + }, disabled: (mode) => mode === 'view', }, // 입금자명 @@ -105,7 +115,7 @@ export const depositDetailConfig: DetailConfig = { const record = data as unknown as DepositRecord; return { depositDate: record.depositDate || '', - accountName: record.accountName || '', + bankAccountId: record.bankAccountId || '', depositorName: record.depositorName || '', depositAmount: record.depositAmount || 0, note: record.note || '', @@ -116,7 +126,7 @@ export const depositDetailConfig: DetailConfig = { transformSubmitData: (formData: Record): Partial => { return { depositDate: formData.depositDate as string, - accountName: formData.accountName as string, + bankAccountId: formData.bankAccountId as string, depositorName: formData.depositorName as string, depositAmount: formData.depositAmount ? Number(formData.depositAmount) : 0, note: formData.note as string, diff --git a/src/components/accounting/DepositManagement/types.ts b/src/components/accounting/DepositManagement/types.ts index 5951902b..dd36bd13 100644 --- a/src/components/accounting/DepositManagement/types.ts +++ b/src/components/accounting/DepositManagement/types.ts @@ -117,6 +117,7 @@ export interface DepositRecord { id: string; depositDate: string; // 입금일 depositAmount: number; // 입금액 + bankAccountId?: string; // 입금계좌 ID accountName: string; // 입금계좌명 depositorName: string; // 입금자명 note: string; // 적요 diff --git a/src/components/accounting/WithdrawalManagement/WithdrawalDetailClientV2.tsx b/src/components/accounting/WithdrawalManagement/WithdrawalDetailClientV2.tsx index 97b21cc7..b68002f1 100644 --- a/src/components/accounting/WithdrawalManagement/WithdrawalDetailClientV2.tsx +++ b/src/components/accounting/WithdrawalManagement/WithdrawalDetailClientV2.tsx @@ -13,6 +13,7 @@ import { updateWithdrawal, deleteWithdrawal, getVendors, + getBankAccounts, } from './actions'; import { useDevFill, generateWithdrawalData } from '@/components/dev'; @@ -34,11 +35,15 @@ export default function WithdrawalDetailClientV2({ // ===== DevFill: 자동 입력 기능 ===== useDevFill('withdrawal', useCallback(async () => { if (initialMode === 'create') { - // 거래처 목록 가져오기 - const vendorResult = await getVendors(); + // 거래처 및 계좌 목록 가져오기 + const [vendorResult, bankAccountResult] = await Promise.all([ + getVendors(), + getBankAccounts(), + ]); const vendors = vendorResult.success ? vendorResult.data : undefined; + const bankAccounts = bankAccountResult.success ? bankAccountResult.data : undefined; - const mockData = generateWithdrawalData({ vendors }); + const mockData = generateWithdrawalData({ vendors, bankAccounts }); setWithdrawal(mockData as unknown as WithdrawalRecord); toast.success('출금 데이터가 자동 입력되었습니다.'); } diff --git a/src/components/accounting/WithdrawalManagement/actions.ts b/src/components/accounting/WithdrawalManagement/actions.ts index a5c25b37..aad53208 100644 --- a/src/components/accounting/WithdrawalManagement/actions.ts +++ b/src/components/accounting/WithdrawalManagement/actions.ts @@ -45,7 +45,10 @@ function transformApiToFrontend(apiData: WithdrawalApiData): WithdrawalRecord { withdrawalAmount: typeof apiData.amount === 'string' ? parseFloat(apiData.amount) : (apiData.amount ?? 0), - accountName: apiData.bank_account?.account_name || '', + bankAccountId: apiData.bank_account_id ? String(apiData.bank_account_id) : '', + accountName: apiData.bank_account + ? `${apiData.bank_account.bank_name} ${apiData.bank_account.account_name}` + : '', recipientName: apiData.merchant_name || apiData.client_name || apiData.client?.name || '', note: apiData.description || '', withdrawalType: (apiData.account_code || 'unset') as WithdrawalType, @@ -64,9 +67,18 @@ function transformFrontendToApi(data: Partial): Record { + const url = `${process.env.NEXT_PUBLIC_API_URL}/api/v1/bank-accounts?per_page=100`; + const { response, error } = await serverFetch(url, { method: 'GET' }); + + if (error) { + return { success: false, data: [], error: error.message }; + } + + if (!response?.ok) { + return { success: false, data: [], error: `API 오류: ${response?.status}` }; + } + + const result = await response.json(); + + if (!result.success) { + return { success: false, data: [], error: result.message }; + } + + const accounts = result.data?.data || result.data || []; + + return { + success: true, + data: accounts.map((a: { id: number; account_name: string; bank_name: string }) => ({ + id: String(a.id), + name: `${a.bank_name} ${a.account_name}`, + })), + }; +} diff --git a/src/components/accounting/WithdrawalManagement/types.ts b/src/components/accounting/WithdrawalManagement/types.ts index 619ef411..60c1b3c4 100644 --- a/src/components/accounting/WithdrawalManagement/types.ts +++ b/src/components/accounting/WithdrawalManagement/types.ts @@ -97,6 +97,7 @@ export interface WithdrawalRecord { id: string; withdrawalDate: string; // 출금일 withdrawalAmount: number; // 출금액 + bankAccountId?: string; // 출금계좌 ID accountName: string; // 출금계좌명 recipientName: string; // 수취인명 note: string; // 적요 diff --git a/src/components/accounting/WithdrawalManagement/withdrawalDetailConfig.ts b/src/components/accounting/WithdrawalManagement/withdrawalDetailConfig.ts index a93caee2..f7077833 100644 --- a/src/components/accounting/WithdrawalManagement/withdrawalDetailConfig.ts +++ b/src/components/accounting/WithdrawalManagement/withdrawalDetailConfig.ts @@ -2,7 +2,7 @@ import { Banknote } from 'lucide-react'; import type { DetailConfig, FieldDefinition } from '@/components/templates/IntegratedDetailTemplate/types'; import type { WithdrawalRecord } from './types'; import { WITHDRAWAL_TYPE_SELECTOR_OPTIONS } from './types'; -import { getVendors } from './actions'; +import { getVendors, getBankAccounts } from './actions'; // ===== 필드 정의 ===== const fields: FieldDefinition[] = [ @@ -16,10 +16,20 @@ const fields: FieldDefinition[] = [ }, // 출금계좌 { - key: 'accountName', + key: 'bankAccountId', label: '출금계좌', - type: 'text', - placeholder: '출금계좌를 입력해주세요', + type: 'select', + placeholder: '선택', + fetchOptions: async () => { + const result = await getBankAccounts(); + if (result.success) { + return result.data.map((a) => ({ + value: a.id, + label: a.name, + })); + } + return []; + }, disabled: (mode) => mode === 'view', }, // 수취인명 @@ -105,7 +115,7 @@ export const withdrawalDetailConfig: DetailConfig = { const record = data as unknown as WithdrawalRecord; return { withdrawalDate: record.withdrawalDate || '', - accountName: record.accountName || '', + bankAccountId: record.bankAccountId || '', recipientName: record.recipientName || '', withdrawalAmount: record.withdrawalAmount ? record.withdrawalAmount.toLocaleString() : '0', note: record.note || '', @@ -116,7 +126,7 @@ export const withdrawalDetailConfig: DetailConfig = { transformSubmitData: (formData: Record): Partial => { return { withdrawalDate: formData.withdrawalDate as string, - accountName: formData.accountName as string, + bankAccountId: formData.bankAccountId as string, recipientName: formData.recipientName as string, withdrawalAmount: typeof formData.withdrawalAmount === 'string' ? parseInt(formData.withdrawalAmount.replace(/,/g, ''), 10)