diff --git a/src/main/java/com/sb/web/account/dto/RestoreRequest.java b/src/main/java/com/sb/web/account/dto/RestoreRequest.java index 8ab5225..9c4c38f 100644 --- a/src/main/java/com/sb/web/account/dto/RestoreRequest.java +++ b/src/main/java/com/sb/web/account/dto/RestoreRequest.java @@ -7,18 +7,31 @@ import java.util.List; /** * 데이터 복구(가져오기) 요청 — 엑셀 백업을 파싱한 결과. - * 참조는 이름 기준(계좌명·분류 대분류명·태그명). 서버에서 새 ID 로 재매핑한다. + * 계좌는 원본 ID(oldId) 기준으로 매핑(같은 이름 계좌가 있어도 정확). 분류·태그는 이름 기준(유니크). */ @Data public class RestoreRequest { - private List wallets; // 계좌 (이름 참조 없음 → 요청 DTO 재사용) - private List categories; // 분류 (parent = 대분류명) - private List tags; // 태그명 - private List entries; // 내역 - private List recurrings; // 고정지출 - private List budgets; // 예산 (분류명 참조) - private List quickEntries; // 자주 쓰는 내역 + private List wallets; + private List categories; + private List tags; + private List entries; + private List recurrings; + private List budgets; + private List quickEntries; + + @Data + public static class Wal { + private Long oldId; // 원본 계좌 id (매핑 키) + private String type; + private String name; + private String issuer; + private String accountNumber; + private String cardType; + private Long openingBalance; + private LocalDate openingDate; + private Long currentValue; + } @Data public static class Cat { @@ -34,10 +47,10 @@ public class RestoreRequest { private String category; private Long amount; private String memo; - private String wallet; // 계좌명 - private String toWallet; // 입금 계좌명(이체) + private Long walletId; // 원본 계좌 id + private Long toWalletId; // 원본 입금 계좌 id(이체) private Integer installmentMonths; - private List tags; // 태그명 + private List tags; // 태그명 } @Data @@ -47,8 +60,8 @@ public class RestoreRequest { private Long amount; private String category; private String memo; - private String wallet; - private String toWallet; + private Long walletId; + private Long toWalletId; private String frequency; private Integer dayOfMonth; private Integer dayOfWeek; @@ -65,6 +78,6 @@ public class RestoreRequest { private String category; private Long amount; private String memo; - private String wallet; + private Long walletId; } } diff --git a/src/main/java/com/sb/web/account/service/BackupService.java b/src/main/java/com/sb/web/account/service/BackupService.java index b6b5e0e..7bfaf00 100644 --- a/src/main/java/com/sb/web/account/service/BackupService.java +++ b/src/main/java/com/sb/web/account/service/BackupService.java @@ -57,12 +57,22 @@ public class BackupService { backupMapper.deleteTags(memberId); backupMapper.deleteWallets(memberId); - // 2) 계좌 → 이름→새 ID - Map walletMap = new HashMap<>(); + // 2) 계좌 → 원본 id(oldId) → 새 id (같은 이름 계좌가 있어도 정확) + Map 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())