CSV取込機能を実装し、Expenseモデルと関連するStore・ExpenseCategoryモデルを追加。CSVパーサーを作成し、出光CSVに対応。明細編集画面のAJAX保存機能を実装し、取込結果を表示する機能を追加。作業ログをdiary.mdに追記。
This commit is contained in:
67
expenses/csv_parsers/idemitsu.py
Normal file
67
expenses/csv_parsers/idemitsu.py
Normal file
@@ -0,0 +1,67 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import csv
|
||||
import hashlib
|
||||
from datetime import datetime
|
||||
from typing import Iterable
|
||||
|
||||
from .base import CSVParserBase, ExpenseRow
|
||||
|
||||
|
||||
class IdemitsuParser(CSVParserBase):
|
||||
source = 'idemitsu'
|
||||
|
||||
def detect(self, header_line: str) -> bool:
|
||||
return '出光' in header_line or 'apollostation' in header_line
|
||||
|
||||
def parse(self, lines: Iterable[str]) -> list[ExpenseRow]:
|
||||
rows: list[ExpenseRow] = []
|
||||
reader = csv.reader(lines)
|
||||
last_row_index: int | None = None
|
||||
for columns in reader:
|
||||
if not columns:
|
||||
continue
|
||||
head = columns[0].strip()
|
||||
if head in ('カード名称', 'お支払日', '今回ご請求額'):
|
||||
continue
|
||||
if head == '利用日':
|
||||
continue
|
||||
if not head:
|
||||
if last_row_index is not None:
|
||||
extra_desc = columns[1].strip() if len(columns) > 1 else ''
|
||||
extra_note = columns[6].strip() if len(columns) > 6 else ''
|
||||
if extra_desc:
|
||||
rows[last_row_index].description += f' {extra_desc}'
|
||||
if extra_note:
|
||||
if rows[last_row_index].note:
|
||||
rows[last_row_index].note += f' {extra_note}'
|
||||
else:
|
||||
rows[last_row_index].note = extra_note
|
||||
continue
|
||||
if len(columns) < 6:
|
||||
continue
|
||||
try:
|
||||
use_date = datetime.strptime(head, '%Y/%m/%d').date()
|
||||
except ValueError:
|
||||
continue
|
||||
description = columns[1].strip()
|
||||
amount_text = columns[5].replace(',', '').strip()
|
||||
note = columns[6].strip() if len(columns) > 6 else ''
|
||||
try:
|
||||
amount = int(amount_text)
|
||||
except ValueError:
|
||||
continue
|
||||
raw = f"{use_date.isoformat()}|{description}|{amount}|{note}|{self.source}"
|
||||
source_hash = hashlib.sha256(raw.encode('utf-8')).hexdigest()
|
||||
rows.append(
|
||||
ExpenseRow(
|
||||
use_date=use_date,
|
||||
description=description,
|
||||
amount=amount,
|
||||
note=note,
|
||||
source=self.source,
|
||||
source_hash=source_hash,
|
||||
)
|
||||
)
|
||||
last_row_index = len(rows) - 1
|
||||
return rows
|
||||
Reference in New Issue
Block a user