feat(budget): 1회성 예산 API 추가

- 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
co-authored by Claude Sonnet 4.6
parent 24858f23e8
commit a0509099f7
10 changed files with 320 additions and 2 deletions
@@ -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>