'use server'; import { serverFetch } from '@/lib/api/fetch-wrapper'; import type { BankTransaction, TransactionKind } from './types'; // ===== API 응답 타입 ===== interface BankTransactionApiItem { id: number; type: 'deposit' | 'withdrawal'; transaction_date: string; bank_account_id: number; bank_name: string; account_name: string; note: string | null; vendor_id: number | null; vendor_name: string | null; depositor_name: string | null; deposit_amount: number | string; withdrawal_amount: number | string; balance: number | string; transaction_type: string | null; source_id: string; created_at: string; updated_at: string; } interface BankTransactionApiSummary { total_deposit: number; total_withdrawal: number; deposit_unset_count: number; withdrawal_unset_count: number; } interface BankAccountOption { id: number; label: string; } interface PaginationMeta { current_page: number; last_page: number; per_page: number; total: number; } // ===== API → Frontend 변환 ===== function transformItem(item: BankTransactionApiItem): BankTransaction { return { id: String(item.id), bankName: item.bank_name, accountName: item.account_name, transactionDate: item.transaction_date, type: item.type as TransactionKind, note: item.note || undefined, vendorId: item.vendor_id ? String(item.vendor_id) : undefined, vendorName: item.vendor_name || undefined, depositorName: item.depositor_name || undefined, depositAmount: typeof item.deposit_amount === 'string' ? parseFloat(item.deposit_amount) : item.deposit_amount, withdrawalAmount: typeof item.withdrawal_amount === 'string' ? parseFloat(item.withdrawal_amount) : item.withdrawal_amount, balance: typeof item.balance === 'string' ? parseFloat(item.balance) : item.balance, transactionType: item.transaction_type || undefined, sourceId: item.source_id, createdAt: item.created_at, updatedAt: item.updated_at, }; } // ===== 입출금 통합 목록 조회 ===== export async function getBankTransactionList(params?: { page?: number; perPage?: number; startDate?: string; endDate?: string; bankAccountId?: number; transactionType?: string; search?: string; sortBy?: string; sortDir?: 'asc' | 'desc'; }): Promise<{ success: boolean; data: BankTransaction[]; pagination: { currentPage: number; lastPage: number; perPage: number; total: number; }; error?: string; }> { try { const searchParams = new URLSearchParams(); if (params?.page) searchParams.set('page', String(params.page)); if (params?.perPage) searchParams.set('per_page', String(params.perPage)); if (params?.startDate) searchParams.set('start_date', params.startDate); if (params?.endDate) searchParams.set('end_date', params.endDate); if (params?.bankAccountId) searchParams.set('bank_account_id', String(params.bankAccountId)); if (params?.transactionType) searchParams.set('transaction_type', params.transactionType); if (params?.search) searchParams.set('search', params.search); if (params?.sortBy) searchParams.set('sort_by', params.sortBy); if (params?.sortDir) searchParams.set('sort_dir', params.sortDir); const queryString = searchParams.toString(); const url = `${process.env.NEXT_PUBLIC_API_URL}/api/v1/bank-transactions${queryString ? `?${queryString}` : ''}`; const { response, error } = await serverFetch(url, { method: 'GET' }); if (error) { return { success: false, data: [], pagination: { currentPage: 1, lastPage: 1, perPage: 20, total: 0 }, error: error.message, }; } if (!response?.ok) { console.warn('[BankTransactionActions] GET bank-transactions error:', response?.status); return { success: false, data: [], pagination: { currentPage: 1, lastPage: 1, perPage: 20, total: 0 }, error: `API 오류: ${response?.status}`, }; } const result = await response.json(); if (!result.success) { return { success: false, data: [], pagination: { currentPage: 1, lastPage: 1, perPage: 20, total: 0 }, error: result.message || '은행 거래 조회에 실패했습니다.', }; } const paginationData = result.data; const items = (paginationData?.data || []).map(transformItem); const meta: PaginationMeta = { current_page: paginationData?.current_page || 1, last_page: paginationData?.last_page || 1, per_page: paginationData?.per_page || 20, total: paginationData?.total || items.length, }; return { success: true, data: items, pagination: { currentPage: meta.current_page, lastPage: meta.last_page, perPage: meta.per_page, total: meta.total, }, }; } catch (error) { console.error('[BankTransactionActions] getBankTransactionList error:', error); return { success: false, data: [], pagination: { currentPage: 1, lastPage: 1, perPage: 20, total: 0 }, error: '서버 오류가 발생했습니다.', }; } } // ===== 입출금 요약 통계 ===== export async function getBankTransactionSummary(params?: { startDate?: string; endDate?: string; }): Promise<{ success: boolean; data?: { totalDeposit: number; totalWithdrawal: number; depositUnsetCount: number; withdrawalUnsetCount: number; }; error?: string; }> { try { const searchParams = new URLSearchParams(); if (params?.startDate) searchParams.set('start_date', params.startDate); if (params?.endDate) searchParams.set('end_date', params.endDate); const queryString = searchParams.toString(); const url = `${process.env.NEXT_PUBLIC_API_URL}/api/v1/bank-transactions/summary${queryString ? `?${queryString}` : ''}`; const { response, error } = await serverFetch(url, { method: 'GET' }); if (error) { return { success: false, error: error.message }; } if (!response?.ok) { console.warn('[BankTransactionActions] GET summary error:', response?.status); return { success: false, error: `API 오류: ${response?.status}`, }; } const result = await response.json(); if (!result.success) { return { success: false, error: result.message || '요약 조회에 실패했습니다.', }; } const apiSummary: BankTransactionApiSummary = result.data; return { success: true, data: { totalDeposit: apiSummary.total_deposit, totalWithdrawal: apiSummary.total_withdrawal, depositUnsetCount: apiSummary.deposit_unset_count, withdrawalUnsetCount: apiSummary.withdrawal_unset_count, }, }; } catch (error) { console.error('[BankTransactionActions] getBankTransactionSummary error:', error); return { success: false, error: '서버 오류가 발생했습니다.', }; } } // ===== 계좌 목록 조회 (필터용) ===== export async function getBankAccountOptions(): Promise<{ success: boolean; data: { id: number; label: string }[]; error?: string; }> { try { const url = `${process.env.NEXT_PUBLIC_API_URL}/api/v1/bank-transactions/accounts`; const { response, error } = await serverFetch(url, { method: 'GET' }); if (error) { return { success: false, data: [], error: error.message }; } if (!response?.ok) { console.warn('[BankTransactionActions] GET accounts error:', response?.status); return { success: false, data: [], error: `API 오류: ${response?.status}`, }; } const result = await response.json(); if (!result.success) { return { success: false, data: [], error: result.message || '계좌 목록 조회에 실패했습니다.', }; } return { success: true, data: result.data as BankAccountOption[], }; } catch (error) { console.error('[BankTransactionActions] getBankAccountOptions error:', error); return { success: false, data: [], error: '서버 오류가 발생했습니다.', }; } }