diff --git a/app/Http/Controllers/Barobill/EcardController.php b/app/Http/Controllers/Barobill/EcardController.php
index f8eb6f9b..419239cb 100644
--- a/app/Http/Controllers/Barobill/EcardController.php
+++ b/app/Http/Controllers/Barobill/EcardController.php
@@ -1865,6 +1865,8 @@ public function storeJournal(Request $request): JsonResponse
'lines.*.account_name' => 'required|string|max:100',
'lines.*.debit_amount' => 'required|integer|min:0',
'lines.*.credit_amount' => 'required|integer|min:0',
+ 'lines.*.trading_partner_id' => 'nullable|integer',
+ 'lines.*.trading_partner_name' => 'nullable|string|max:100',
'lines.*.description' => 'nullable|string|max:300',
]);
@@ -1926,6 +1928,8 @@ public function storeJournal(Request $request): JsonResponse
'account_name' => $line['account_name'],
'debit_amount' => $line['debit_amount'],
'credit_amount' => $line['credit_amount'],
+ 'trading_partner_id' => $line['trading_partner_id'] ?? null,
+ 'trading_partner_name' => $line['trading_partner_name'] ?? null,
'description' => $line['description'] ?? null,
]);
}
@@ -2003,6 +2007,8 @@ public function getJournal(Request $request): JsonResponse
'account_name' => $line->account_name,
'debit_amount' => $line->debit_amount,
'credit_amount' => $line->credit_amount,
+ 'trading_partner_id' => $line->trading_partner_id,
+ 'trading_partner_name' => $line->trading_partner_name,
'description' => $line->description,
]),
],
diff --git a/resources/views/barobill/ecard/index.blade.php b/resources/views/barobill/ecard/index.blade.php
index f2fd5833..127a7af0 100644
--- a/resources/views/barobill/ecard/index.blade.php
+++ b/resources/views/barobill/ecard/index.blade.php
@@ -556,6 +556,96 @@ className="flex-1 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 t
);
};
+ // ============================================
+ // TradingPartnerSelect - 거래처 드롭다운
+ // ============================================
+ const TradingPartnerSelect = ({ value, valueName, onChange }) => {
+ const [isOpen, setIsOpen] = useState(false);
+ const [search, setSearch] = useState('');
+ const [partners, setPartners] = useState([]);
+ const [loading, setLoading] = useState(false);
+ const [highlightIndex, setHighlightIndex] = useState(-1);
+ const containerRef = useRef(null);
+ const listRef = useRef(null);
+
+ const displayText = valueName || '';
+
+ // 검색어 변경 시 API 조회
+ useEffect(() => {
+ if (!isOpen) return;
+ setLoading(true);
+ const url = search
+ ? `/finance/journal-entries/trading-partners?search=${encodeURIComponent(search)}`
+ : '/finance/journal-entries/trading-partners';
+ fetch(url)
+ .then(res => res.json())
+ .then(data => { if (data.success) setPartners(data.data || []); })
+ .catch(() => {})
+ .finally(() => setLoading(false));
+ }, [isOpen, search]);
+
+ useEffect(() => { setHighlightIndex(-1); }, [search]);
+ useEffect(() => {
+ const handleClickOutside = (e) => {
+ if (containerRef.current && !containerRef.current.contains(e.target)) {
+ setIsOpen(false); setSearch(''); setHighlightIndex(-1);
+ }
+ };
+ document.addEventListener('mousedown', handleClickOutside);
+ return () => document.removeEventListener('mousedown', handleClickOutside);
+ }, []);
+
+ const handleSelect = (partner) => {
+ onChange(partner.id, partner.name);
+ setIsOpen(false); setSearch(''); setHighlightIndex(-1);
+ };
+ const handleClear = (e) => { e.stopPropagation(); onChange(null, ''); setSearch(''); };
+
+ const handleKeyDown = (e) => {
+ const maxIdx = partners.length - 1;
+ if (e.key === 'ArrowDown') { e.preventDefault(); setHighlightIndex(prev => prev < maxIdx ? prev + 1 : 0); }
+ else if (e.key === 'ArrowUp') { e.preventDefault(); setHighlightIndex(prev => prev > 0 ? prev - 1 : maxIdx); }
+ else if (e.key === 'Enter' && partners.length > 0) { e.preventDefault(); handleSelect(partners[highlightIndex >= 0 ? highlightIndex : 0]); }
+ else if (e.key === 'Escape') { setIsOpen(false); setSearch(''); setHighlightIndex(-1); }
+ };
+
+ return (
+
+
setIsOpen(!isOpen)}
+ className={`w-full px-3 py-1.5 text-sm border rounded-lg cursor-pointer flex items-center justify-between gap-1 ${isOpen ? 'border-purple-500 ring-1 ring-purple-500' : 'border-stone-200'} bg-white`}>
+
{displayText || '거래처 선택'}
+
+
+ {isOpen && (
+
+
+ setSearch(e.target.value)} onKeyDown={handleKeyDown}
+ placeholder="거래처명 또는 사업자번호 검색..." className="w-full px-2.5 py-1.5 text-sm border border-stone-200 rounded-lg focus:ring-1 focus:ring-purple-500 outline-none" autoFocus />
+
+
+ {loading ? (
+
검색 중...
+ ) : partners.length === 0 ? (
+
검색 결과 없음
+ ) : partners.map((p, index) => (
+
handleSelect(p)}
+ className={`px-3 py-1.5 text-sm cursor-pointer ${index === highlightIndex ? 'bg-purple-600 text-white font-semibold' : value === p.id ? 'bg-purple-100 text-purple-700' : 'text-stone-700 hover:bg-purple-50'}`}>
+ {p.name}
+ {p.biz_no && ({p.biz_no})}
+
+ ))}
+
+
+ )}
+
+ );
+ };
+
// ============================================
// CardJournalModal - 복식부기 분개 모달
// ============================================
@@ -580,14 +670,14 @@ className="flex-1 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 t
if (isDeductible) {
return [
- { dc_type: 'debit', account_code: expenseCode, account_name: expenseName, debit_amount: supplyAmount, credit_amount: 0, description: '' },
- { dc_type: 'debit', account_code: '135', account_name: '부가세대급금', debit_amount: taxAmount, credit_amount: 0, description: '' },
- { dc_type: 'credit', account_code: '205', account_name: '미지급비용', debit_amount: 0, credit_amount: totalAmount, description: '' },
+ { dc_type: 'debit', account_code: expenseCode, account_name: expenseName, debit_amount: supplyAmount, credit_amount: 0, trading_partner_id: null, trading_partner_name: '', description: '' },
+ { dc_type: 'debit', account_code: '135', account_name: '부가세대급금', debit_amount: taxAmount, credit_amount: 0, trading_partner_id: null, trading_partner_name: '', description: '' },
+ { dc_type: 'credit', account_code: '205', account_name: '미지급비용', debit_amount: 0, credit_amount: totalAmount, trading_partner_id: null, trading_partner_name: '', description: '' },
];
} else {
return [
- { dc_type: 'debit', account_code: expenseCode, account_name: expenseName, debit_amount: totalAmount, credit_amount: 0, description: '' },
- { dc_type: 'credit', account_code: '205', account_name: '미지급비용', debit_amount: 0, credit_amount: totalAmount, description: '' },
+ { dc_type: 'debit', account_code: expenseCode, account_name: expenseName, debit_amount: totalAmount, credit_amount: 0, trading_partner_id: null, trading_partner_name: '', description: '' },
+ { dc_type: 'credit', account_code: '205', account_name: '미지급비용', debit_amount: 0, credit_amount: totalAmount, trading_partner_id: null, trading_partner_name: '', description: '' },
];
}
};
@@ -610,6 +700,8 @@ className="flex-1 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 t
account_name: l.account_name,
debit_amount: l.debit_amount,
credit_amount: l.credit_amount,
+ trading_partner_id: l.trading_partner_id || null,
+ trading_partner_name: l.trading_partner_name || '',
description: l.description || '',
})));
setIsEditMode(true);
@@ -627,6 +719,8 @@ className="flex-1 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 t
account_name: l.account_name,
debit_amount: l.debit_amount,
credit_amount: l.credit_amount,
+ trading_partner_id: l.trading_partner_id || null,
+ trading_partner_name: l.trading_partner_name || '',
description: l.description || '',
})));
setIsEditMode(true);
@@ -651,7 +745,7 @@ className="flex-1 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 t
};
const addLine = () => {
- setLines(prev => [...prev, { dc_type: 'debit', account_code: '', account_name: '', debit_amount: 0, credit_amount: 0, description: '' }]);
+ setLines(prev => [...prev, { dc_type: 'debit', account_code: '', account_name: '', debit_amount: 0, credit_amount: 0, trading_partner_id: null, trading_partner_name: '', description: '' }]);
};
const removeLine = (idx) => {
@@ -746,8 +840,9 @@ className="flex-1 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 t
| 차/대 |
계정과목 |
- 차변금액 |
- 대변금액 |
+ 거래처 |
+ 차변금액 |
+ 대변금액 |
|
@@ -773,6 +868,15 @@ className={`px-2 py-0.5 rounded text-xs font-medium cursor-pointer hover:opacity
accountCodes={accountCodes}
/>
+
+ {
+ setLines(prev => prev.map((l, i) => i === idx ? { ...l, trading_partner_id: id, trading_partner_name: name } : l));
+ }}
+ />
+ |
합계 |
+ 합계 |
{formatCurrency(totalDebit)} |
{formatCurrency(totalCredit)} |
|