v2.4.0: Phase 2 — meal time, past records, goals, CSV import, crash report

- Meal time dialog (right-click lunch/dinner button to enter actual times)
- Calendar right-click context: add/edit/delete past records
- Monthly goal settings + progress widget (overtime cap, avg daily)
- CSV import (our standard format) with conflict policy
- Global crash handler with Gitea Issues auto-report

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
KINDNICK
2026-04-30 18:38:38 +09:00
co-authored by Claude Opus 4.7
parent d3a4efc173
commit 9ebf4ad961
14 changed files with 1059 additions and 7 deletions
+58 -5
View File
@@ -652,6 +652,9 @@ class Database:
'discord_notif_clock_in': 'true',
'discord_notif_clock_out': 'true',
'discord_notif_health': 'true',
# v2.4.0
'goal_overtime_max_monthly': '0', # 0=비활성, >0=분 단위 상한
'goal_avg_hours_daily': '0', # 0=비활성
}
conn = self.get_connection()
@@ -1265,21 +1268,71 @@ class Database:
# ===== 외출 관련 메서드 =====
def add_break_record(self, work_record_id: int, date: str, break_out: str, reason: str = None) -> int:
"""외출 기록 추가"""
def add_break_record(self, work_record_id: int, date: str, break_out: str,
reason: str = None, break_type: str = 'break') -> int:
"""외출 기록 추가. break_type: 'break'(외출) / 'lunch' / 'dinner'."""
conn = self.get_connection()
cursor = conn.cursor()
cursor.execute('''
INSERT INTO break_records (work_record_id, date, break_out, reason)
VALUES (?, ?, ?, ?)
''', (work_record_id, date, break_out, reason))
INSERT INTO break_records (work_record_id, date, break_out, reason, break_type)
VALUES (?, ?, ?, ?, ?)
''', (work_record_id, date, break_out, reason, break_type))
record_id = cursor.lastrowid
conn.commit()
conn.close()
return record_id
def add_meal_record(self, date: str, start_time: str, end_time: str,
meal_type: str = 'lunch') -> int:
"""식사 시간 기록 (시작·종료 둘 다 알 때).
Args:
date: 'YYYY-MM-DD'
start_time, end_time: 'HH:MM:SS'
meal_type: 'lunch' or 'dinner'
Returns:
새 break_record id
"""
from datetime import datetime as _dt
# 분 계산
start_dt = _dt.strptime(start_time, '%H:%M:%S')
end_dt = _dt.strptime(end_time, '%H:%M:%S')
if end_dt < start_dt:
from datetime import timedelta as _td
end_dt += _td(days=1)
total_min = int((end_dt - start_dt).total_seconds() / 60)
rec = self.get_today_record() if date == _dt.now().date().isoformat() else None
wid = rec['id'] if rec else None
conn = self.get_connection()
cursor = conn.cursor()
cursor.execute('''
INSERT INTO break_records (work_record_id, date, break_out, break_in,
total_minutes, break_type)
VALUES (?, ?, ?, ?, ?, ?)
''', (wid, date, start_time, end_time, total_min, meal_type))
rid = cursor.lastrowid
conn.commit()
conn.close()
return rid
def get_meal_minutes_today(self, meal_type: str = 'lunch') -> int:
"""오늘의 식사 시간 합계 (분). 수동 입력된 경우만."""
from datetime import date as _date
today = _date.today().isoformat()
conn = self.get_connection()
cursor = conn.cursor()
cursor.execute('''
SELECT COALESCE(SUM(total_minutes), 0) FROM break_records
WHERE date = ? AND break_type = ? AND total_minutes IS NOT NULL
''', (today, meal_type))
result = cursor.fetchone()[0] or 0
conn.close()
return int(result)
def update_break_return(self, break_id: int, break_in: str):
"""외출 복귀 시간 업데이트"""
conn = self.get_connection()
+8
View File
@@ -44,6 +44,10 @@ DB_PATH_OVERRIDE = 'db_path_override'
# 백업
LAST_BACKUP_DATE = 'last_backup_date'
# Crash Report (Gitea Issues 통합 — 옵션)
GITEA_FEEDBACK_TOKEN = 'gitea_feedback_token' # PAT (저장소 issue 쓰기 권한)
GITEA_FEEDBACK_ENABLED = 'gitea_feedback_enabled'
# === v2.3.0 신규 ===
# 온보딩
ONBOARDING_COMPLETED = 'onboarding_completed'
@@ -57,6 +61,10 @@ OVERTIME_RATE = 'overtime_rate' # 1.5
HEALTH_BREAK_ENABLED = 'health_break_enabled'
HEALTH_BREAK_HOURS = 'health_break_hours' # 기본 4
# 목표
GOAL_OVERTIME_MAX_MONTHLY = 'goal_overtime_max_monthly' # 월 연장근무 상한 (분)
GOAL_AVG_HOURS_DAILY = 'goal_avg_hours_daily' # 일평균 목표 (시간, float)
# Discord 웹훅
DISCORD_WEBHOOK_URL = 'discord_webhook_url'
DISCORD_NOTIF_CLOCK_IN = 'discord_notif_clock_in'
+1 -1
View File
@@ -4,4 +4,4 @@
릴리스 시 이 값을 올린 후 git tag → push.
CHANGELOG.md의 최상단 항목과 일치시킬 것.
"""
__version__ = '2.3.3'
__version__ = '2.4.0'