You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

72 lines
2.7 KiB
Python

# backend/app/connectors/finance/normalize.py — provider → finance_tx 정규화 + upsert
import uuid
from sqlmodel import Session, select
from ...models import ExternalLink, FinanceTx
from ..base import NormalizedRecord, RawRecord
# 가맹점/내용 키워드 → life-data.js 카테고리 6종
_CATS = [
("식비", ["식당", "김밥", "백반", "마트", "푸드", "배달", "음식", "고기"]),
("카페·간식", ["카페", "커피", "스타벅스", "베이커리", "디저트", "투썸", "이디야"]),
("교통", ["택시", "버스", "지하철", "주유", "기차", "ktx", "교통", "카카오t"]),
("쇼핑", ["쿠팡", "올리브영", "백화점", "쇼핑", "무신사", "29cm", "패션"]),
("구독", ["넷플릭스", "유튜브", "스포티파이", "구독", "멤버십", "프라임"]),
("문화·여가", ["영화", "cgv", "공연", "전시", "서점", "교보", "여가", "헬스"]),
]
def categorize(merchant: str) -> str:
low = (merchant or "").lower()
for cat, kws in _CATS:
if any(kw in low for kw in kws):
return cat
return "기타"
def normalize_tx(account, raw: RawRecord) -> NormalizedRecord:
p = raw.payload
merchant = str(p.get("merchant", p.get("내용", p.get("가맹점", "")))).strip()
raw_amt = p.get("amount", p.get("금액", 0))
try:
amount = int(str(raw_amt).replace(",", "").replace("원", "").strip() or 0)
except ValueError:
amount = 0
category = p.get("category") or p.get("분류") or categorize(merchant)
fields = {
"account_id": account.id,
"date": str(p.get("date", p.get("거래일", p.get("날짜", "")))).strip(),
"merchant": merchant,
"amount": amount,
"category": category,
"account_label": account.name,
}
return NormalizedRecord(
entity_type="finance_tx",
external_id=raw.external_id,
fields=fields,
etag=raw.etag,
external_updated_at=raw.external_updated_at,
)
def upsert_tx(session: Session, norm: NormalizedRecord) -> tuple[str, bool]:
link = session.exec(
select(ExternalLink).where(
ExternalLink.external_id == norm.external_id,
ExternalLink.entity_type == "finance_tx",
)
).first()
if link:
tx = session.get(FinanceTx, link.entity_id)
if tx:
for k, v in norm.fields.items():
if v is not None and hasattr(tx, k):
setattr(tx, k, v)
session.add(tx)
return tx.id, False
tid = "ftx-" + uuid.uuid4().hex[:8]
session.add(FinanceTx(id=tid, **{k: v for k, v in norm.fields.items() if v is not None}))
return tid, True