diff --git a/app/Http/Controllers/Finance/CorporateCardController.php b/app/Http/Controllers/Finance/CorporateCardController.php index 36c6856e..ff6f493b 100644 --- a/app/Http/Controllers/Finance/CorporateCardController.php +++ b/app/Http/Controllers/Finance/CorporateCardController.php @@ -255,34 +255,40 @@ public function summary(): JsonResponse 'cardUsages' => $usageResult['perCard'], 'prepaidAmount' => (int) $prepayment->amount, 'prepaidMemo' => $prepayment->memo ?? '', + 'prepaidItems' => $prepayment->items ?? [], ], ]); } /** - * 선불결제 금액 수정 + * 결제 내역 수정 */ public function updatePrepayment(Request $request): JsonResponse { $request->validate([ - 'amount' => 'required|integer|min:0', - 'memo' => 'nullable|string|max:200', + 'items' => 'present|array', + 'items.*.date' => 'required|date', + 'items.*.amount' => 'required|integer|min:0', + 'items.*.description' => 'nullable|string|max:200', ]); $tenantId = session('selected_tenant_id', 1); $yearMonth = Carbon::now()->format('Y-m'); + $items = collect($request->input('items', []))->filter(fn($item) => ($item['amount'] ?? 0) > 0)->values()->toArray(); + $amount = collect($items)->sum('amount'); + $prepayment = CorporateCardPrepayment::updateOrCreate( ['tenant_id' => $tenantId, 'year_month' => $yearMonth], - ['amount' => $request->input('amount'), 'memo' => $request->input('memo')] + ['amount' => $amount, 'items' => $items, 'memo' => null] ); return response()->json([ 'success' => true, - 'message' => '선불결제 금액이 저장되었습니다.', + 'message' => '결제 내역이 저장되었습니다.', 'data' => [ 'amount' => (int) $prepayment->amount, - 'memo' => $prepayment->memo ?? '', + 'items' => $prepayment->items ?? [], ], ]); } diff --git a/app/Models/Finance/CorporateCardPrepayment.php b/app/Models/Finance/CorporateCardPrepayment.php index 147eb3c0..123afb8b 100644 --- a/app/Models/Finance/CorporateCardPrepayment.php +++ b/app/Models/Finance/CorporateCardPrepayment.php @@ -8,7 +8,11 @@ class CorporateCardPrepayment extends Model { protected $table = 'corporate_card_prepayments'; - protected $fillable = ['tenant_id', 'year_month', 'amount', 'memo']; + protected $fillable = ['tenant_id', 'year_month', 'amount', 'memo', 'items']; + + protected $casts = [ + 'items' => 'array', + ]; public function scopeForTenant($query, int $tenantId) { diff --git a/resources/views/finance/corporate-cards.blade.php b/resources/views/finance/corporate-cards.blade.php index eab4f414..7b85d9d3 100644 --- a/resources/views/finance/corporate-cards.blade.php +++ b/resources/views/finance/corporate-cards.blade.php @@ -63,7 +63,9 @@ function CorporateCardsManagement() { // 요약 데이터 const [summaryData, setSummaryData] = useState(null); const [showPrepaymentModal, setShowPrepaymentModal] = useState(false); - const [prepaymentForm, setPrepaymentForm] = useState({ amount: '', memo: '' }); + const [prepaymentItems, setPrepaymentItems] = useState([ + { date: new Date().toISOString().slice(0, 10), amount: '', description: '' } + ]); // CSRF 토큰 const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content'); @@ -112,43 +114,85 @@ function CorporateCardsManagement() { } }; - // 선불결제 저장 + // 결제 항목 추가 + const addPrepaymentItem = () => { + setPrepaymentItems(prev => [...prev, { + date: new Date().toISOString().slice(0, 10), + amount: '', + description: '' + }]); + }; + + // 결제 항목 삭제 + const removePrepaymentItem = (index) => { + if (prepaymentItems.length <= 1) return; + setPrepaymentItems(prev => prev.filter((_, i) => i !== index)); + }; + + // 결제 항목 수정 + const updatePrepaymentItem = (index, field, value) => { + setPrepaymentItems(prev => prev.map((item, i) => + i === index ? { ...item, [field]: value } : item + )); + }; + + // 결제 합계 계산 + const prepaymentTotal = prepaymentItems.reduce( + (sum, item) => sum + (parseInt(parseInputCurrency(item.amount)) || 0), 0 + ); + + // 결제 내역 저장 const handleSavePrepayment = async () => { try { + const items = prepaymentItems + .filter(item => item.amount && parseInt(parseInputCurrency(item.amount)) > 0) + .map(item => ({ + date: item.date, + amount: parseInt(parseInputCurrency(item.amount)), + description: item.description, + })); + const response = await fetch('/finance/corporate-cards/prepayment', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': csrfToken, }, - body: JSON.stringify({ - amount: parseInt(parseInputCurrency(prepaymentForm.amount)) || 0, - memo: prepaymentForm.memo, - }), + body: JSON.stringify({ items }), }); const result = await response.json(); if (result.success) { setSummaryData(prev => ({ ...prev, prepaidAmount: result.data.amount, - prepaidMemo: result.data.memo, + prepaidItems: result.data.items, })); setShowPrepaymentModal(false); } else { alert(result.message || '저장에 실패했습니다.'); } } catch (error) { - console.error('선불결제 저장 실패:', error); + console.error('결제 내역 저장 실패:', error); alert('저장 중 오류가 발생했습니다.'); } }; - // 선불결제 수정 모달 열기 + // 결제 내역 수정 모달 열기 const openPrepaymentModal = () => { - setPrepaymentForm({ - amount: summaryData?.prepaidAmount ? String(summaryData.prepaidAmount) : '', - memo: summaryData?.prepaidMemo || '', - }); + const items = summaryData?.prepaidItems; + if (items && items.length > 0) { + setPrepaymentItems(items.map(item => ({ + date: item.date, + amount: String(item.amount), + description: item.description || '', + }))); + } else { + setPrepaymentItems([{ + date: new Date().toISOString().slice(0, 10), + amount: '', + description: '' + }]); + } setShowPrepaymentModal(true); }; @@ -491,10 +535,10 @@ className="p-1.5 bg-amber-500 hover:bg-amber-600 text-white rounded transition-c : '-'}

- {/* 5. 선불결제 */} + {/* 5. 결제 */}
- 선불결제 + 결제
{/* 6. 잔여 한도 */} @@ -518,7 +562,7 @@ className="text-xs px-1.5 py-0.5 bg-amber-100 hover:bg-amber-200 text-amber-700

{formatCurrency(totalLimit - (summaryData?.billingUsage || 0) + (summaryData?.prepaidAmount || 0))}원

-

한도-사용+선결제

+

한도-사용+결제

@@ -878,12 +922,12 @@ className="flex-1 px-4 py-2 bg-violet-600 hover:bg-violet-700 text-white rounded )} - {/* 선불결제 수정 모달 */} + {/* 결제 내역 수정 모달 */} {showPrepaymentModal && (
-
+
-

선불결제 금액 수정

+

결제 내역 수정

-
-
- - setPrepaymentForm(prev => ({ ...prev, amount: parseInputCurrency(e.target.value) }))} - placeholder="0" - className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-amber-500 text-right text-lg font-bold" - /> -
-
- - setPrepaymentForm(prev => ({ ...prev, memo: e.target.value }))} - placeholder="예: 2월 선결제" - maxLength={200} - className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-amber-500" - /> -
+ + {/* 항목 헤더 */} +
+
날짜
+
금액
+
내용
+
-
+ + {/* 항목 리스트 */} +
+ {prepaymentItems.map((item, index) => ( +
+
+ updatePrepaymentItem(index, 'date', e.target.value)} + className="w-full px-2 py-1.5 border border-gray-300 rounded-lg focus:ring-2 focus:ring-amber-500 text-sm" + /> +
+
+ updatePrepaymentItem(index, 'amount', parseInputCurrency(e.target.value))} + placeholder="0" + className="w-full px-2 py-1.5 border border-gray-300 rounded-lg focus:ring-2 focus:ring-amber-500 text-sm text-right" + /> +
+
+