# 출금 가능 잔액 — 원장 기반 전환 지침서

> **2026-04-02** | 영향 범위: `partner-api` 모듈

## 배경

파트너 콘솔 출금 화면에서 "출금 가능" 잔액이 `wallet_balances`(MASTER 온체인 잔액)를 조회하지만,
실제 출금 검증(`SettlementService.freeze()`)은 `ledger_entries`(원장)를 사용합니다.

이 불일치로 인해 UI에는 잔액이 표시되지만 출금 요청 시 "잔액이 부족합니다" 에러가 발생합니다.

**open-api(위젯)**은 이미 `SettlementService.getLedgerBalance()`를 사용 중이므로,
partner-api도 동일한 방식으로 통일합니다.

## 변경 대상

### 1. `PartnerWithdrawalService.java` — 의존성 추가 + 메서드 변경

**파일:** `partner-api/src/main/java/com/cryptoments/partnerapi/service/PartnerWithdrawalService.java`

#### 1-1. 의존성 추가

```java
// import 추가
import com.cryptoments.common.entity.PartnerChainConfig;
import com.cryptoments.common.repository.PartnerChainConfigRepository;
import com.cryptoments.common.repository.BlockchainNetworkRepository;
import com.cryptoments.common.repository.CurrencyRepository;
import com.cryptoments.core.settlement.SettlementService;

// 필드 추가
private final SettlementService settlementService;
private final PartnerChainConfigRepository partnerChainConfigRepository;
private final CurrencyRepository currencyRepository;
private final BlockchainNetworkRepository blockchainNetworkRepository;
```

생성자에 위 4개 필드를 추가합니다.

#### 1-2. `getAvailableBalance()` 메서드 교체

**변경 전:**
```java
/**
 * 출금 가능 잔액 조회 (MASTER 잔액 - 미실현 수수료).
 */
public WithdrawalAvailableBalanceResponse getAvailableBalance(Long partnerId) {
    var currencies = partnerWithdrawalMapper.findAvailableBalances(partnerId);
    return WithdrawalAvailableBalanceResponse.builder()
            .currencies(currencies)
            .build();
}
```

**변경 후:**
```java
/**
 * 출금 가능 잔액 조회 (ledger_entries 기반 — freeze() 검증과 동일 소스).
 */
public WithdrawalAvailableBalanceResponse getAvailableBalance(Long partnerId) {
    List<PartnerChainConfig> configs = partnerChainConfigRepository.findByPartnerId(partnerId);

    List<WithdrawalAvailableBalanceResponse.CurrencyBalance> currencies = configs.stream()
            .filter(PartnerChainConfig::getIsActive)
            .map(config -> {
                BigDecimal ledgerBalance = settlementService
                        .getLedgerBalance(partnerId, config.getCurrencyId(), config.getNetworkId());

                var currency = currencyRepository.findOne(config.getCurrencyId());
                var network = blockchainNetworkRepository.findOne(config.getNetworkId());

                return WithdrawalAvailableBalanceResponse.CurrencyBalance.builder()
                        .currencyId(config.getCurrencyId())
                        .currencyCode(currency != null ? currency.getSymbol() : "UNKNOWN")
                        .networkId(config.getNetworkId())
                        .networkName(network != null ? network.getName() : "UNKNOWN")
                        .availableBalance(ledgerBalance)
                        .build();
            })
            .filter(b -> b.getAvailableBalance().compareTo(BigDecimal.ZERO) > 0)
            .toList();

    return WithdrawalAvailableBalanceResponse.builder()
            .currencies(currencies)
            .build();
}
```

### 2. `WithdrawalAvailableBalanceResponse.java` — JavaDoc 수정

**파일:** `partner-api/.../dto/response/WithdrawalAvailableBalanceResponse.java`

```java
/**
 * 출금 가능 잔액 응답 (ledger_entries 원장 기반).
 */
// CurrencyBalance 내부:
/** 출금 가능 잔액 (원장 기반 — CREDIT + ADJUSTMENT - DEBIT - FEE) */
private BigDecimal availableBalance;
```

### 3. `PartnerWithdrawalMapper.java` — `findAvailableBalances()` 제거 (선택)

`getAvailableBalance()`에서 더 이상 호출하지 않으므로, 해당 메서드를 삭제하거나
`@Deprecated` 처리합니다. 다른 곳에서 참조하지 않는지 확인 후 제거합니다.

## 검증

변경 후 다음을 확인합니다:

1. **파트너 콘솔** — 출금 요청 화면에서 "출금 가능" 금액이 실제 출금 가능한 금액과 일치
2. **위젯** — 기존과 동일하게 동작 (이미 ledger 기반)
3. **출금 요청** — UI 표시 금액 이내에서 출금 시 "잔액 부족" 에러 없음

## 참고: DB 보정 (완료)

v1→v2 마이그레이션 시 누락된 원장 잔액은 운영 DB에 ADJUSTMENT 레코드로 보정 완료:

```sql
-- 16건의 ADJUSTMENT 삽입 완료 (2026-04-02)
SELECT * FROM ledger_entries WHERE reference_type = 'MIGRATION';
```
