feat(budget): 1회성 예산 API 추가
Deploy / deploy (push) Failing after 11m13s

- BudgetOnetime 도메인/DTO/Mapper/Service 신규
- BudgetController: GET/POST/PUT/DELETE /api/account/budgets/onetime 엔드포인트 추가
- account.sql: budget_onetime 테이블 CREATE TABLE IF NOT EXISTS 추가
- WalletRequest: MINUS 유형 허용 추가
- CategoryService: importDefaults, validateParent, ensureCategory 추가

※ 최초 배포 시 서버 .env에 SQL_INIT_MODE=always 추가 후 재시작 필요 (budget_onetime 테이블 생성)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
ByungCheol
2026-07-05 16:15:15 +09:00
parent 24858f23e8
commit a0509099f7
10 changed files with 320 additions and 2 deletions
+15
View File
@@ -197,6 +197,21 @@ CREATE TABLE IF NOT EXISTS budget_income (
PRIMARY KEY (member_id, `year`, `month`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- 1회성 예산 (기간·제목별 단발 예산)
CREATE TABLE IF NOT EXISTS budget_onetime (
id BIGINT NOT NULL AUTO_INCREMENT,
member_id BIGINT NOT NULL COMMENT '소유자 member.id',
title VARCHAR(100) NOT NULL COMMENT '제목 (예: 7월 여행)',
category VARCHAR(50) NULL COMMENT '카테고리 (NULL=전체 지출)',
amount BIGINT NOT NULL COMMENT '총 예산',
start_date DATE NOT NULL COMMENT '기간 시작일',
end_date DATE NOT NULL COMMENT '기간 종료일',
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY idx_bot_member_date (member_id, start_date, end_date)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- 투자 보유 종목 (INVEST 지갑별 · 사용자별)
CREATE TABLE IF NOT EXISTS invest_holding (
id BIGINT NOT NULL AUTO_INCREMENT,
@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.sb.web.account.mapper.BudgetOnetimeMapper">
<resultMap id="rm" type="com.sb.web.account.domain.BudgetOnetime">
<id property="id" column="id"/>
<result property="memberId" column="member_id"/>
<result property="title" column="title"/>
<result property="category" column="category"/>
<result property="amount" column="amount"/>
<result property="startDate" column="start_date"/>
<result property="endDate" column="end_date"/>
<result property="createdAt" column="created_at"/>
<result property="updatedAt" column="updated_at"/>
</resultMap>
<select id="findByMember" resultMap="rm">
SELECT id, member_id, title, category, amount, start_date, end_date, created_at, updated_at
FROM budget_onetime
WHERE member_id = #{memberId}
ORDER BY start_date DESC
</select>
<select id="findByIdAndMember" resultMap="rm">
SELECT id, member_id, title, category, amount, start_date, end_date, created_at, updated_at
FROM budget_onetime
WHERE id = #{id} AND member_id = #{memberId}
</select>
<!-- 기간 내 지출 합산 (category=null 이면 전체, 값 있으면 해당 카테고리만) -->
<select id="sumExpenseInRange" resultType="long">
SELECT COALESCE(SUM(amount), 0)
FROM account_entry
WHERE member_id = #{memberId}
AND type = 'EXPENSE'
AND entry_date BETWEEN #{startDate} AND #{endDate}
<if test="category != null and category != ''">
AND category = #{category}
</if>
</select>
<insert id="insert" parameterType="com.sb.web.account.domain.BudgetOnetime"
useGeneratedKeys="true" keyProperty="id">
INSERT INTO budget_onetime (member_id, title, category, amount, start_date, end_date, created_at, updated_at)
VALUES (#{memberId}, #{title}, #{category}, #{amount}, #{startDate}, #{endDate}, NOW(), NOW())
</insert>
<update id="update" parameterType="com.sb.web.account.domain.BudgetOnetime">
UPDATE budget_onetime
SET title = #{title}, category = #{category}, amount = #{amount},
start_date = #{startDate}, end_date = #{endDate}, updated_at = NOW()
WHERE id = #{id} AND member_id = #{memberId}
</update>
<delete id="delete">
DELETE FROM budget_onetime WHERE id = #{id} AND member_id = #{memberId}
</delete>
</mapper>