fix:수동입력 잔액 자동계산을 거래일 기준으로 개선

- 거래일 기준으로 해당 계좌의 직전 거래 잔액을 찾아 기준잔액 설정
- 계좌/거래일/거래시간 변경 시에도 기준잔액 재계산
- 수정 모드에서 자기 자신 거래를 제외하고 직전 잔액 검색

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
김보곤
2026-02-06 11:17:06 +09:00
parent 8c84b75320
commit e8f3396e61

View File

@@ -799,23 +799,40 @@ className="px-4 py-2 bg-emerald-600 text-white rounded-lg hover:bg-emerald-700 t
const isEditMode = !!editData;
// 선택된 계좌의 최근 잔액 찾기
const findLatestBalance = (accountNum) => {
// 거래일 기준으로 해당 계좌의 직전 거래 잔액 찾기
const findBaseBalanceByDate = (accountNum, transDate, transTime) => {
if (!accountNum || !logs || logs.length === 0) return 0;
// logs는 날짜 내림차순 정렬이므로 첫 번째 매칭이 가장 최근
const accountLog = logs.find(l => l.bankAccountNum === accountNum);
return accountLog ? (accountLog.balance || 0) : 0;
const targetDt = (transDate || '') + (transTime || '000000');
// 같은 계좌의 거래만 필터 (수정 중인 건은 제외)
const accountLogs = logs.filter(l =>
l.bankAccountNum === accountNum &&
!(editData && l.isManual && l.dbId === editData.dbId)
);
if (accountLogs.length === 0) return 0;
// logs는 날짜 내림차순 정렬 → 입력일보다 이전인 첫 번째 거래의 잔액이 기준
for (const log of accountLogs) {
const logDt = (log.transDate || '') + (log.transTime || '');
if (logDt < targetDt) {
return log.balance || 0;
}
}
return 0;
};
// 기준잔액 재계산 (계좌, 날짜, 시간 변경 시)
const recalcBase = (accountNum, transDate, transTime) => {
const base = findBaseBalanceByDate(accountNum, transDate, transTime);
setBaseBalance(base);
return base;
};
useEffect(() => {
if (isOpen) {
if (editData) {
const isRegisteredAccount = accounts.some(a => a.bankAccountNum === editData.bankAccountNum);
// 수정 모드: 잔액 역산 (입금이면 잔액-입금, 출금이면 잔액+출금)
const prevBalance = editData.deposit > 0
? editData.balance - editData.deposit
: editData.balance + editData.withdraw;
setBaseBalance(prevBalance);
// 수정 모드: 거래 잔액을 찾아서 기준잔액으로 설정
const base = findBaseBalanceByDate(editData.bankAccountNum, editData.transDate, editData.transTime);
setBaseBalance(base);
setForm({
bank_account_num: editData.bankAccountNum || '',
bank_code: editData.bankCode || '',
@@ -895,25 +912,39 @@ className="px-4 py-2 bg-emerald-600 text-white rounded-lg hover:bg-emerald-700 t
const handleAccountSelect = (accNum) => {
if (accNum === '__manual__') {
setBaseBalance(0);
setForm(prev => ({ ...prev, bank_account_num: '', bank_code: '', bank_name: '', _manualAccount: true, balance: 0 }));
setForm(prev => {
const newBal = calcBalance(0, prev.trans_type, prev.amount);
return { ...prev, bank_account_num: '', bank_code: '', bank_name: '', _manualAccount: true, balance: newBal };
});
} else {
const acc = accounts.find(a => a.bankAccountNum === accNum);
if (acc) {
const latestBal = findLatestBalance(acc.bankAccountNum);
setBaseBalance(latestBal);
const newBalance = calcBalance(latestBal, form.trans_type, form.amount);
setForm(prev => ({
...prev,
bank_account_num: acc.bankAccountNum,
bank_code: acc.bankCode || '',
bank_name: acc.bankName || '',
_manualAccount: false,
balance: newBalance,
}));
setForm(prev => {
const base = recalcBase(acc.bankAccountNum, prev.trans_date, prev.trans_time);
const newBalance = calcBalance(base, prev.trans_type, prev.amount);
return {
...prev,
bank_account_num: acc.bankAccountNum,
bank_code: acc.bankCode || '',
bank_name: acc.bankName || '',
_manualAccount: false,
balance: newBalance,
};
});
}
}
};
// 거래일 변경 시 기준잔액 재계산
const handleDateChange = (field, value) => {
setForm(prev => {
const newForm = { ...prev, [field]: value };
const base = recalcBase(newForm.bank_account_num, newForm.trans_date, newForm.trans_time);
const newBalance = calcBalance(base, newForm.trans_type, newForm.amount);
return { ...newForm, balance: newBalance };
});
};
const formatAmount = (val) => {
const num = String(val).replace(/[^\d]/g, '');
return num ? Number(num).toLocaleString() : '';
@@ -993,7 +1024,7 @@ className="px-3 py-2 border border-stone-200 rounded-lg text-sm focus:ring-2 foc
<input
type="text"
value={form.trans_date || ''}
onChange={(e) => setForm(prev => ({ ...prev, trans_date: e.target.value.replace(/[^\d]/g, '').slice(0, 8) }))}
onChange={(e) => handleDateChange('trans_date', e.target.value.replace(/[^\d]/g, '').slice(0, 8))}
placeholder="YYYYMMDD"
maxLength={8}
className="w-full px-3 py-2 border border-stone-200 rounded-lg text-sm focus:ring-2 focus:ring-emerald-500 outline-none"
@@ -1004,7 +1035,7 @@ className="w-full px-3 py-2 border border-stone-200 rounded-lg text-sm focus:rin
<input
type="text"
value={form.trans_time || ''}
onChange={(e) => setForm(prev => ({ ...prev, trans_time: e.target.value.replace(/[^\d]/g, '').slice(0, 6) }))}
onChange={(e) => handleDateChange('trans_time', e.target.value.replace(/[^\d]/g, '').slice(0, 6))}
placeholder="HHMMSS"
maxLength={6}
className="w-full px-3 py-2 border border-stone-200 rounded-lg text-sm focus:ring-2 focus:ring-emerald-500 outline-none"