diff --git a/src/main/java/com/sb/web/account/controller/AccountController.java b/src/main/java/com/sb/web/account/controller/AccountController.java index 779fe95..ac58ae4 100644 --- a/src/main/java/com/sb/web/account/controller/AccountController.java +++ b/src/main/java/com/sb/web/account/controller/AccountController.java @@ -56,7 +56,9 @@ public class AccountController { public ResponseEntity createWallet( @Valid @RequestBody WalletRequest req, @RequestAttribute(AuthInterceptor.CURRENT_MEMBER) SessionUser current) { - return ResponseEntity.status(HttpStatus.CREATED).body(accountService.createWallet(req, current.getId())); + boolean premium = "ADMIN".equals(current.getRole()) || "PREMIUM".equals(current.getPlan()); + return ResponseEntity.status(HttpStatus.CREATED) + .body(accountService.createWallet(req, current.getId(), premium)); } @PutMapping("/wallets/{id}") diff --git a/src/main/java/com/sb/web/account/mapper/WalletMapper.java b/src/main/java/com/sb/web/account/mapper/WalletMapper.java index ba12c0a..42bdd79 100644 --- a/src/main/java/com/sb/web/account/mapper/WalletMapper.java +++ b/src/main/java/com/sb/web/account/mapper/WalletMapper.java @@ -31,4 +31,7 @@ public interface WalletMapper { /** 해당 타입의 현재 최대 sort_order (신규 계좌를 맨 뒤에 배치) */ Integer maxSortOrder(@Param("memberId") Long memberId, @Param("type") String type); + + /** 해당 타입의 계좌 개수 (무료 회원 종류별 등록 한도 판정용) */ + int countByType(@Param("memberId") Long memberId, @Param("type") String type); } diff --git a/src/main/java/com/sb/web/account/service/AccountService.java b/src/main/java/com/sb/web/account/service/AccountService.java index 1e9107a..0b55296 100644 --- a/src/main/java/com/sb/web/account/service/AccountService.java +++ b/src/main/java/com/sb/web/account/service/AccountService.java @@ -556,8 +556,27 @@ public class AccountService { .build(); } + // 무료 회원 계좌 등록 한도: 종류(은행·현금·카드·대출·증권·마이너스)별 기본 2개. + // 포인트 상점(추후)에서 영구 보너스 슬롯을 구매하면 종류별 최대 5개까지 확장 가능. + public static final int FREE_WALLET_BASE_LIMIT = 2; + public static final int FREE_WALLET_MAX_LIMIT = 5; + + /** 무료 회원의 해당 타입 등록 한도 = 기본 2 + 구매한 영구 보너스 슬롯(추후 상점), 최대 5. */ + private int freeWalletLimit(Long memberId, String type) { + int bonus = 0; // TODO: 포인트 상점 구현 시 회원×종류별 구매 슬롯 수를 조회해 더함 + return Math.min(FREE_WALLET_BASE_LIMIT + bonus, FREE_WALLET_MAX_LIMIT); + } + @Transactional - public WalletResponse createWallet(WalletRequest req, Long memberId) { + public WalletResponse createWallet(WalletRequest req, Long memberId, boolean premium) { + // 유료(또는 관리자)는 무제한. 무료는 종류별 한도 검증. + if (!premium) { + int limit = freeWalletLimit(memberId, req.getType()); + if (walletMapper.countByType(memberId, req.getType()) >= limit) { + throw new ApiException(HttpStatus.BAD_REQUEST, + "무료 회원은 종류별 계좌를 " + limit + "개까지 등록할 수 있어요. 유료로 업그레이드하면 무제한이에요."); + } + } Wallet wallet = toWallet(req); wallet.setMemberId(memberId); Integer max = walletMapper.maxSortOrder(memberId, req.getType()); 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 94974f8..f32e929 100644 --- a/src/main/java/com/sb/web/account/service/BackupService.java +++ b/src/main/java/com/sb/web/account/service/BackupService.java @@ -71,7 +71,8 @@ public class BackupService { wr.setOpeningBalance(w.getOpeningBalance()); wr.setOpeningDate(w.getOpeningDate()); wr.setCurrentValue(w.getCurrentValue()); - Long newId = accountService.createWallet(wr, memberId).getId(); + // 복원은 사용자 본인 데이터 복구이므로 무료 한도(종류별 2개)를 적용하지 않는다. + Long newId = accountService.createWallet(wr, memberId, true).getId(); if (w.getOldId() != null) walletMap.put(w.getOldId(), newId); } } diff --git a/src/main/resources/mapper/WalletMapper.xml b/src/main/resources/mapper/WalletMapper.xml index a8454de..fae50b2 100644 --- a/src/main/resources/mapper/WalletMapper.xml +++ b/src/main/resources/mapper/WalletMapper.xml @@ -97,4 +97,8 @@ SELECT MAX(sort_order) FROM wallet WHERE member_id = #{memberId} AND type = #{type} + +