feat: 카드 결제 알림 자동인식(미확인 내역) 백엔드
CI / build (push) Failing after 14m48s

- account_entry pending/notif_key 컬럼 추가(멱등 마이그레이션)
- CardNotificationParser: 카드사·금액·가맹점·승인/취소 파싱
- POST /entries/notification(미확인 지출 생성, 중복방지, 카드 자동매칭)
- POST /entries/{id}/confirm(확정), GET /entries/pending/count

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
ByungCheol
2026-06-03 18:51:30 +09:00
parent c1f97364aa
commit 8fec057752
10 changed files with 314 additions and 3 deletions
@@ -16,6 +16,8 @@
<result property="toWalletId" column="to_wallet_id"/>
<result property="toWalletName" column="to_wallet_name"/>
<result property="installmentMonths" column="installment_months"/>
<result property="pending" column="pending"/>
<result property="notifKey" column="notif_key"/>
<result property="createdAt" column="created_at"/>
<result property="updatedAt" column="updated_at"/>
</resultMap>
@@ -29,7 +31,7 @@
e.id, e.member_id, e.entry_date, e.type, e.category, e.amount, e.memo,
e.wallet_id, w.name AS wallet_name,
e.to_wallet_id, tw.name AS to_wallet_name,
e.installment_months,
e.installment_months, e.pending, e.notif_key,
e.created_at, e.updated_at
</sql>
<sql id="entryJoins">
@@ -127,9 +129,11 @@
<insert id="insert" parameterType="com.sb.web.account.domain.AccountEntry"
useGeneratedKeys="true" keyProperty="id">
INSERT INTO account_entry (member_id, entry_date, type, category, amount, memo,
wallet_id, to_wallet_id, installment_months, created_at, updated_at)
wallet_id, to_wallet_id, installment_months, pending, notif_key,
created_at, updated_at)
VALUES (#{memberId}, #{entryDate}, #{type}, #{category}, #{amount}, #{memo},
#{walletId}, #{toWalletId}, #{installmentMonths}, NOW(), NOW())
#{walletId}, #{toWalletId}, #{installmentMonths},
COALESCE(#{pending}, 0), #{notifKey}, NOW(), NOW())
</insert>
<update id="update" parameterType="com.sb.web.account.domain.AccountEntry">
@@ -144,6 +148,27 @@
DELETE FROM account_entry WHERE id = #{id} AND member_id = #{memberId}
</delete>
<!-- ===== 알림 자동인식(미확인) ===== -->
<select id="findByMemberAndNotifKey" resultMap="entryResultMap">
SELECT <include refid="entryCols"/>
<include refid="entryJoins"/>
WHERE e.member_id = #{memberId} AND e.notif_key = #{notifKey}
LIMIT 1
</select>
<select id="countPending" resultType="int">
SELECT COUNT(*) FROM account_entry WHERE member_id = #{memberId} AND pending = 1
</select>
<update id="confirm">
UPDATE account_entry
SET pending = 0,
<if test="category != null">category = #{category},</if>
<if test="walletId != null">wallet_id = #{walletId},</if>
updated_at = NOW()
WHERE id = #{id} AND member_id = #{memberId} AND pending = 1
</update>
<select id="findDistinctCategories" resultType="string">
SELECT DISTINCT category FROM account_entry
WHERE member_id = #{memberId} AND type = #{type}