- weeklyWalletFlow(월요일 기준 주별 순현금흐름) + netWorthTrendWeekly(기본 13주) - 컨트롤러에 unit=WEEK&weeks=N 지원(기존 월별은 그대로) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -167,11 +167,16 @@ public class AccountController {
|
||||
return accountService.categoryStats(current.getId(), type, year, month);
|
||||
}
|
||||
|
||||
/** 월별 순자산 추이 */
|
||||
/** 순자산 추이 (unit=WEEK 면 주별, weeks 개수 / 그 외 월별, months 개수) */
|
||||
@GetMapping("/networth/trend")
|
||||
public List<NetWorthPoint> netWorthTrend(
|
||||
@RequestParam(required = false) Integer months,
|
||||
@RequestParam(required = false) Integer weeks,
|
||||
@RequestParam(defaultValue = "MONTH") String unit,
|
||||
@RequestAttribute(AuthInterceptor.CURRENT_MEMBER) SessionUser current) {
|
||||
if ("WEEK".equalsIgnoreCase(unit)) {
|
||||
return accountService.netWorthTrendWeekly(current.getId(), weeks);
|
||||
}
|
||||
return accountService.netWorthTrend(current.getId(), months);
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,9 @@ public interface AccountEntryMapper {
|
||||
/** 월별 순현금흐름(수입−지출, 계좌 지정분) — {ym, net} 행 반환 (순자산 추이용) */
|
||||
List<Map<String, Object>> monthlyWalletFlow(@Param("memberId") Long memberId);
|
||||
|
||||
/** 주별 순현금흐름(수입−지출, 계좌 지정분) — {wk(=주 월요일 yyyy-MM-dd), net} (주간 순자산 추이용) */
|
||||
List<Map<String, Object>> weeklyWalletFlow(@Param("memberId") Long memberId);
|
||||
|
||||
/** 기간 버킷(일/주/월/년)별 수입·지출 — {bucket, income, expense} (이체 제외) */
|
||||
List<Map<String, Object>> statsByPeriod(@Param("memberId") Long memberId,
|
||||
@Param("unit") String unit,
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.YearMonth;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -128,6 +129,66 @@ public class AccountService {
|
||||
return result;
|
||||
}
|
||||
|
||||
/** 주별 순자산 추이 (월요일 기준 버킷). 기본 13주(최근 약 3개월). */
|
||||
public List<NetWorthPoint> netWorthTrendWeekly(Long memberId, Integer weeks) {
|
||||
int n = (weeks == null || weeks <= 0 || weeks > 53) ? 13 : weeks;
|
||||
LocalDate today = LocalDate.now();
|
||||
LocalDate currentMon = today.minusDays(today.getDayOfWeek().getValue() - 1L); // 이번 주 월요일
|
||||
LocalDate startMon = currentMon.minusWeeks(n - 1L);
|
||||
|
||||
Map<String, Long> flow = new HashMap<>();
|
||||
for (Map<String, Object> row : mapper.weeklyWalletFlow(memberId)) {
|
||||
Object net = row.get("net");
|
||||
flow.put((String) row.get("wk"), net == null ? 0L : ((Number) net).longValue());
|
||||
}
|
||||
|
||||
// 개시잔액: 개시주가 시작주 이전(또는 미상)이면 기준선, 범위 내면 해당 주 버킷
|
||||
List<Wallet> ws = walletMapper.findByMember(memberId);
|
||||
Map<String, Long> openingByWeek = new HashMap<>();
|
||||
long baseline = 0;
|
||||
for (Wallet w : ws) {
|
||||
long ob = w.getOpeningBalance() == null ? 0L : w.getOpeningBalance();
|
||||
if (ob == 0) {
|
||||
continue;
|
||||
}
|
||||
LocalDate od = w.getOpeningDate();
|
||||
LocalDate om = od == null ? null : od.minusDays(od.getDayOfWeek().getValue() - 1L);
|
||||
if (om == null || om.isBefore(startMon)) {
|
||||
baseline += ob;
|
||||
} else if (!om.isAfter(currentMon)) {
|
||||
openingByWeek.merge(om.toString(), ob, Long::sum);
|
||||
}
|
||||
}
|
||||
String startKey = startMon.toString();
|
||||
for (Map.Entry<String, Long> e : flow.entrySet()) {
|
||||
if (e.getKey().compareTo(startKey) < 0) {
|
||||
baseline += e.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
List<NetWorthPoint> result = new ArrayList<>();
|
||||
long running = baseline;
|
||||
for (LocalDate m = startMon; !m.isAfter(currentMon); m = m.plusWeeks(1)) {
|
||||
String key = m.toString();
|
||||
running += flow.getOrDefault(key, 0L);
|
||||
running += openingByWeek.getOrDefault(key, 0L);
|
||||
result.add(NetWorthPoint.builder().month(key).netWorth(running).build());
|
||||
}
|
||||
|
||||
// 투자 손익(실현+평가)은 과거 주별 이력이 없으므로 마지막 점에만 가산 (월간과 동일)
|
||||
if (!result.isEmpty()) {
|
||||
long investAdjust = 0;
|
||||
for (InvestService.WalletInvest wi : investService.valuationByWallet(memberId).values()) {
|
||||
investAdjust += wi.cashDelta + wi.stockEval;
|
||||
}
|
||||
if (investAdjust != 0) {
|
||||
NetWorthPoint last = result.get(result.size() - 1);
|
||||
last.setNetWorth(last.getNetWorth() + investAdjust);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** 기간 버킷(일/주/월/년)별 수입·지출 통계 */
|
||||
public List<PeriodStat> stats(Long memberId, String unit, Integer year, Integer month) {
|
||||
String u = switch (unit == null ? "" : unit.toUpperCase()) {
|
||||
|
||||
Reference in New Issue
Block a user