feat: span task pertama dihitung dari jam 08:00

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
sas.fajri
2026-05-28 10:26:44 +07:00
parent d8a0370775
commit 65470b4f6b

View File

@@ -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)"
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)")