Compare commits

..

No commits in common. "main" and "v2.13.0" have entirely different histories.

5 changed files with 25 additions and 73 deletions

View File

@ -4,21 +4,6 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
## [2.13.1] — 2026-09-01
### Fixed
- **일일보고에서 시간 단위 연차가 "0시간"으로 표시되던 문제** — 30분 연차(0.0625일)가
`int(days * 8)` 절삭으로 0시간이 되어 보고서를 받는 담당자가 사용 내역을 알 수 없었다.
분 단위까지 표시하도록 수정 (`30분`, `1시간 30분`, `1일 4시간`).
- **단축근무 사용자의 연차 시간 환산 오류** — 보고서만 1일=8시간으로 하드코딩되어 있어
7h30m 근무자의 반차가 4시간으로 표시됐다. DB 정본(`days * work_minutes`)과 동일한
기준으로 통일 — 이제 3시간 45분.
### Added
- `utils.time_format.format_leave_amount(days, work_minutes)` — 연차 일수를
(일수, 나머지 분)으로 분해하는 공용 헬퍼 + 자체 검사(`python utils/time_format.py`).
- i18n 키 `report.leave_used_days_time` (`{days}일 {time}` / `{days}d {time}`).
## [2.13.0] — 2026-08-12 ## [2.13.0] — 2026-08-12
### Fixed — 익일(자정 넘김) 퇴근 ### Fixed — 익일(자정 넘김) 퇴근

View File

@ -450,7 +450,6 @@ _DICT = {
'report.leave_used': '🌴 연차 사용: {value}', 'report.leave_used': '🌴 연차 사용: {value}',
'report.leave_used_days_hours': '{days}{hours}시간', 'report.leave_used_days_hours': '{days}{hours}시간',
'report.leave_used_days': '{days}', 'report.leave_used_days': '{days}',
'report.leave_used_days_time': '{days}{time}',
'report.leave_used_hours': '{hours}시간', 'report.leave_used_hours': '{hours}시간',
'report.leave_detail': ' - {type}: {time}{memo}', 'report.leave_detail': ' - {type}: {time}{memo}',
'report.title': '📋 일일 근무 보고서 - {date}', 'report.title': '📋 일일 근무 보고서 - {date}',
@ -1614,7 +1613,6 @@ _DICT = {
'report.leave_used': '🌴 Leave used: {value}', 'report.leave_used': '🌴 Leave used: {value}',
'report.leave_used_days_hours': '{days}d {hours}h', 'report.leave_used_days_hours': '{days}d {hours}h',
'report.leave_used_days': '{days}d', 'report.leave_used_days': '{days}d',
'report.leave_used_days_time': '{days}d {time}',
'report.leave_used_hours': '{hours}h', 'report.leave_used_hours': '{hours}h',
'report.leave_detail': ' - {type}: {time}{memo}', 'report.leave_detail': ' - {type}: {time}{memo}',
'report.title': '📋 Daily Work Report - {date}', 'report.title': '📋 Daily Work Report - {date}',

View File

@ -4,4 +4,4 @@
릴리스 값을 올린 git tag push. 릴리스 값을 올린 git tag push.
CHANGELOG.md의 최상단 항목과 일치시킬 . CHANGELOG.md의 최상단 항목과 일치시킬 .
""" """
__version__ = '2.13.1' __version__ = '2.13.0'

View File

@ -34,7 +34,7 @@ from ui.settings_view import SettingsView
from ui.break_view import BreakView from ui.break_view import BreakView
from core.notifier import Notifier from core.notifier import Notifier
from utils.system_tray import SystemTrayIcon from utils.system_tray import SystemTrayIcon
from utils.time_format import format_hours_minutes, format_leave_amount from utils.time_format import format_hours_minutes
from ui.styles import get_theme, ThemeColors, apply_dark_titlebar from ui.styles import get_theme, ThemeColors, apply_dark_titlebar
from utils.debug_log import dlog from utils.debug_log import dlog
@ -2265,21 +2265,6 @@ class MainWindow(QMainWindow):
if self.is_clocked_in and self.clock_in_time: if self.is_clocked_in and self.clock_in_time:
self.update_display() self.update_display()
def _format_leave_used(self, days: float) -> str:
"""연차 사용량을 '30분' / '3시간 45분' / '1일 4시간' 형태로.
기존에는 `int(days * 8)` 시간만 뽑아 30 연차(0.0625) "0시간"으로
표시됐다. 환산 기준도 DB 정본(`days * work_minutes`) 맞춰 단축근무
사용자의 반차가 4시간으로 뻥튀기되지 않게 한다.
"""
d, rem = format_leave_amount(days, self.db.get_work_minutes())
if d and rem:
return tr('report.leave_used_days_time', days=d,
time=format_hours_minutes(rem, omit_zero_minutes=True))
if d:
return tr('report.leave_used_days', days=d)
return format_hours_minutes(rem, omit_zero_minutes=True)
def _append_meal_section(self, report_lines, today: str, label: str, def _append_meal_section(self, report_lines, today: str, label: str,
flag: bool, records: list, default_min: int) -> None: flag: bool, records: list, default_min: int) -> None:
"""일일 보고서의 점심/저녁 섹션 출력. """일일 보고서의 점심/저녁 섹션 출력.
@ -2473,7 +2458,16 @@ class MainWindow(QMainWindow):
if filtered_leave_records: if filtered_leave_records:
total_leave_days = sum(r['days'] for r in filtered_leave_records) total_leave_days = sum(r['days'] for r in filtered_leave_records)
value = self._format_leave_used(total_leave_days) if total_leave_days >= 1:
days = int(total_leave_days)
hours = int((total_leave_days - days) * 8)
if hours > 0:
value = tr('report.leave_used_days_hours', days=days, hours=hours)
else:
value = tr('report.leave_used_days', days=days)
else:
hours = int(total_leave_days * 8)
value = tr('report.leave_used_hours', hours=hours)
report_lines.append(tr('report.leave_used', value=value)) report_lines.append(tr('report.leave_used', value=value))
for lr in filtered_leave_records: for lr in filtered_leave_records:
@ -2489,7 +2483,19 @@ class MainWindow(QMainWindow):
'반반차': tr('leave.type.quarter') '반반차': tr('leave.type.quarter')
}.get(lr.get('leave_type', ''), lr.get('leave_type', tr('leave.type.annual'))) }.get(lr.get('leave_type', ''), lr.get('leave_type', tr('leave.type.annual')))
time_str = self._format_leave_used(lr['days']) days_used = lr['days']
# 일수를 시간으로 표시
if days_used >= 1:
d = int(days_used)
h = int((days_used - d) * 8)
if h > 0:
time_str = tr('report.leave_used_days_hours', days=d, hours=h)
else:
time_str = tr('report.leave_used_days', days=d)
else:
h = int(days_used * 8)
time_str = tr('report.leave_used_hours', hours=h)
memo = f" - {lr['memo']}" if lr.get('memo') else "" memo = f" - {lr['memo']}" if lr.get('memo') else ""
report_lines.append(f" - {leave_type_name}: {time_str}{memo}") report_lines.append(f" - {leave_type_name}: {time_str}{memo}")

View File

@ -31,40 +31,3 @@ def format_hours_minutes(total_minutes: int, *, omit_zero_minutes: bool = False)
if m == 0: if m == 0:
return f"{h}시간" return f"{h}시간"
return f"{h}시간 {m}" return f"{h}시간 {m}"
def format_leave_amount(days: float, work_minutes: int) -> tuple:
"""연차 일수를 (완전한 일수, 나머지 분)으로 분해.
`int(days * 8)` 시간만 뽑던 표시가 30 연차(0.0625) "0시간"으로
삼켜버리던 문제를 막는다. 환산 기준은 DB 정본과 동일한 work_minutes
(`Database.get_leave_minutes_for` `days * get_work_minutes()` 쓴다)
단축근무 7h30m 사용자의 반차는 4시간이 아니라 3시간 45분이다.
Args:
days: 연차 일수 (1.0 / 0.5 / 0.25 / 0.0625 )
work_minutes: 1 근무 (기본 480)
Returns:
(일수, 나머지 ) : 480 기준 1.5 (1, 240), 0.0625 (0, 30)
"""
unit = int(work_minutes) if work_minutes and work_minutes > 0 else 480
total_minutes = int(round(float(days) * unit))
return divmod(total_minutes, unit)
if __name__ == '__main__':
# 표준 8시간(480분) 기준
assert format_leave_amount(0.0625, 480) == (0, 30), '30분 연차'
assert format_leave_amount(0.125, 480) == (0, 60), '1시간 연차'
assert format_leave_amount(0.25, 480) == (0, 120), '반반차'
assert format_leave_amount(0.5, 480) == (0, 240), '반차'
assert format_leave_amount(1.0, 480) == (1, 0), '종일'
assert format_leave_amount(1.5, 480) == (1, 240), '1.5일'
# 단축근무 7h30m(450분) — 반차는 3시간 45분
assert format_leave_amount(0.5, 450) == (0, 225), '단축근무 반차'
assert format_leave_amount(1.0, 450) == (1, 0), '단축근무 종일'
# work_minutes 이상값은 480으로 폴백
assert format_leave_amount(0.5, 0) == (0, 240), '0 폴백'
assert format_hours_minutes(30, omit_zero_minutes=True) == '30분'
print('format_leave_amount 자체 검사 통과')