fix: 복구 - 계좌를 이름 대신 원본 ID 기준 매핑 + 잘못된 이체 스킵

- 같은 이름 계좌가 있어도 정확히 매핑(이름 충돌로 '출금=입금' 오류 해결)
- 이체인데 계좌 없거나 같으면 해당 항목만 건너뜀(전체 롤백 방지)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
ByungCheol
2026-06-28 09:03:11 +09:00
co-authored by Claude Opus 4.8
parent 3b46d2ba09
commit f130d53f62
2 changed files with 57 additions and 23 deletions
@@ -57,12 +57,22 @@ public class BackupService {
backupMapper.deleteTags(memberId);
backupMapper.deleteWallets(memberId);
// 2) 계좌 → 이름→새 ID
Map<String, Long> walletMap = new HashMap<>();
// 2) 계좌 → 원본 id(oldId) → 새 id (같은 이름 계좌가 있어도 정확)
Map<Long, Long> walletMap = new HashMap<>();
if (req.getWallets() != null) {
for (WalletRequest w : req.getWallets()) {
for (RestoreRequest.Wal w : req.getWallets()) {
if (w == null || w.getName() == null) continue;
walletMap.put(w.getName(), accountService.createWallet(w, memberId).getId());
WalletRequest wr = new WalletRequest();
wr.setType(w.getType());
wr.setName(w.getName());
wr.setIssuer(w.getIssuer());
wr.setAccountNumber(w.getAccountNumber());
wr.setCardType(w.getCardType());
wr.setOpeningBalance(w.getOpeningBalance());
wr.setOpeningDate(w.getOpeningDate());
wr.setCurrentValue(w.getCurrentValue());
Long newId = accountService.createWallet(wr, memberId).getId();
if (w.getOldId() != null) walletMap.put(w.getOldId(), newId);
}
}
@@ -101,14 +111,17 @@ public class BackupService {
if (req.getEntries() != null) {
for (RestoreRequest.Entry e : req.getEntries()) {
if (e.getEntryDate() == null || e.getType() == null) continue;
Long wid = walletMap.get(e.getWalletId());
Long twid = walletMap.get(e.getToWalletId());
if (badTransfer(e.getType(), wid, twid)) continue; // 이체 계좌가 없거나 같으면 건너뜀
AccountEntryRequest er = new AccountEntryRequest();
er.setEntryDate(e.getEntryDate());
er.setType(e.getType());
er.setCategory(e.getCategory());
er.setAmount(e.getAmount());
er.setMemo(e.getMemo());
er.setWalletId(walletMap.get(e.getWallet()));
er.setToWalletId(walletMap.get(e.getToWallet()));
er.setWalletId(wid);
er.setToWalletId(twid);
er.setInstallmentMonths(e.getInstallmentMonths());
if (e.getTags() != null) {
er.setTagIds(e.getTags().stream().map(tagMap::get).filter(Objects::nonNull).toList());
@@ -121,14 +134,17 @@ public class BackupService {
if (req.getRecurrings() != null) {
for (RestoreRequest.Recur r : req.getRecurrings()) {
if (r.getTitle() == null) continue;
Long wid = walletMap.get(r.getWalletId());
Long twid = walletMap.get(r.getToWalletId());
if (badTransfer(r.getType(), wid, twid)) continue;
RecurringRequest rr = new RecurringRequest();
rr.setTitle(r.getTitle());
rr.setType(r.getType());
rr.setAmount(r.getAmount());
rr.setCategory(r.getCategory());
rr.setMemo(r.getMemo());
rr.setWalletId(walletMap.get(r.getWallet()));
rr.setToWalletId(walletMap.get(r.getToWallet()));
rr.setWalletId(wid);
rr.setToWalletId(twid);
rr.setFrequency(r.getFrequency());
rr.setDayOfMonth(r.getDayOfMonth());
rr.setDayOfWeek(r.getDayOfWeek());
@@ -158,7 +174,7 @@ public class BackupService {
qr.setCategory(q.getCategory());
qr.setAmount(q.getAmount());
qr.setMemo(q.getMemo());
qr.setWalletId(walletMap.get(q.getWallet()));
qr.setWalletId(walletMap.get(q.getWalletId()));
quickEntryService.create(qr, memberId);
}
}
@@ -171,6 +187,11 @@ public class BackupService {
return type + "|" + name;
}
/** 이체인데 출금/입금 계좌가 없거나 같으면 복구에서 제외(검증 오류로 전체 롤백 방지) */
private static boolean badTransfer(String type, Long walletId, Long toWalletId) {
return "TRANSFER".equals(type) && (walletId == null || toWalletId == null || walletId.equals(toWalletId));
}
private boolean isEmpty(RestoreRequest r) {
return empty(r.getWallets()) && empty(r.getCategories()) && empty(r.getTags())
&& empty(r.getEntries()) && empty(r.getRecurrings()) && empty(r.getBudgets())