diff --git a/daily_timesheet.py b/daily_timesheet.py index d0b0a5a..1dafda8 100755 --- a/daily_timesheet.py +++ b/daily_timesheet.py @@ -182,14 +182,25 @@ def get_commits_today(repo_path: str, author: str, today: str) -> list[dict]: # ── Pro-rata ────────────────────────────────────────────────────────────────── SINGLE_COMMIT_MINUTES = 30 # bobot minimum untuk task dengan 1 commit +WORK_START_HOUR = 8 # jam mulai kerja -def span_minutes(timestamps: list[datetime]) -> int: - """Menit antara commit pertama dan terakhir. Minimum 30 menit.""" - if len(timestamps) <= 1: - return SINGLE_COMMIT_MINUTES +def span_minutes(timestamps: list[datetime], extend_to_work_start: bool = False) -> int: + """ + Menit dari start sampai commit terakhir. Minimum 30 menit. + Jika extend_to_work_start=True, start dihitung dari jam 08:00 + (berlaku untuk task yang punya commit paling awal di hari itu). + """ + first = min(timestamps) + last = max(timestamps) + + if extend_to_work_start: + start = first.replace(hour=WORK_START_HOUR, minute=0, second=0, microsecond=0) + else: + start = first + return max( - int((max(timestamps) - min(timestamps)).total_seconds() / 60), + int((last - start).total_seconds() / 60), SINGLE_COMMIT_MINUTES, ) @@ -295,25 +306,40 @@ def main(): # 3. Hitung pro-rata berdasarkan time span keys = list(groups.keys()) - spans = [span_minutes(groups[k]["timestamps"]) for k in keys] + + # Task yang punya commit paling awal di hari itu → spannya dihitung dari 08:00 + global_first_dt = min(min(groups[k]["timestamps"]) for k in keys) + first_task_key = next( + k for k in keys if global_first_dt in groups[k]["timestamps"] + ) + + spans = [ + span_minutes(groups[k]["timestamps"], extend_to_work_start=(k == first_task_key)) + for k in keys + ] hours = distribute_hours(spans, total=float(TOTAL_HOURS)) # 4. Tampilkan preview - print(f"\n{'─' * 75}") - print(f" {'PROJECT':<20} {'TASK':<10} {'WAKTU':<13} {'SPAN':>6} {'JAM':>5} DESKRIPSI") - print(f"{'─' * 75}") + print(f"\n{'─' * 78}") + print(f" {'PROJECT':<20} {'TASK':<10} {'WAKTU':<15} {'SPAN':>6} {'JAM':>5} DESKRIPSI") + print(f"{'─' * 78}") entries = [] for key, h, span in zip(keys, hours, spans): - g = groups[key] - ts = sorted(g["timestamps"]) - if len(ts) == 1: - waktu = ts[0].strftime("%H:%M") + " (1 commit)" + g = groups[key] + ts = sorted(g["timestamps"]) + is_first = (key == first_task_key) + + if is_first: + start_label = f"08:00→{ts[-1].strftime('%H:%M')}" + elif len(ts) == 1: + start_label = ts[0].strftime("%H:%M") + " (1x)" else: - waktu = f"{ts[0].strftime('%H:%M')}–{ts[-1].strftime('%H:%M')}" - span_label = f"{span}m" if span > SINGLE_COMMIT_MINUTES else "30m*" + start_label = f"{ts[0].strftime('%H:%M')}–{ts[-1].strftime('%H:%M')}" + + span_label = f"{span}m{'↑' if is_first else ''}" if span > SINGLE_COMMIT_MINUTES else "30m*" desc = "; ".join(dict.fromkeys(g["descriptions"])) - print(f" {g['project']:<20} {str(g['task_id']):<10} {waktu:<13} {span_label:>6} {h:>5.2f} {desc[:30]}") + print(f" {g['project']:<20} {str(g['task_id']):<10} {start_label:<15} {span_label:>6} {h:>5.2f} {desc[:28]}") entries.append({ "odoo": { "name": desc, @@ -327,10 +353,10 @@ def main(): "display": g, }) - print(f"{'─' * 75}") + print(f"{'─' * 78}") total_span = sum(spans) - print(f" {'TOTAL':<20} {'':<10} {'':<13} {total_span:>5}m {sum(hours):>5.2f}") - print(f" * single commit → minimum {SINGLE_COMMIT_MINUTES} menit") + print(f" {'TOTAL':<20} {'':<10} {'':<15} {total_span:>5}m {sum(hours):>5.2f}") + print(f" ↑ span dihitung dari 08:00 | * single commit → minimum {SINGLE_COMMIT_MINUTES} menit") if not_found: print(f"\n {len(not_found)} commit diabaikan (task tidak ditemukan di Odoo)")