Ejemplo n.º 1
0
def day(date):
    start_dt = ui.parse_date(date, context="day")
    end_dt = start_dt.clone().ceil("day")

    ranges = database.active_ranges(start_dt, end_dt)
    edits = database.edits(start_dt)
    current_range = database.current_range() if not state.is_away() else None

    # tally minutes
    minutes = 0
    for dtr in ranges:
        minutes += dtr.minutes
    for edit in edits:
        minutes += edit.minutes

    # header
    print("%s %s %s" % (
        coloured("yellow", ui.format_minutes(minutes)),
        coloured("yellow", start_dt.format("ddd Do MMM")),
        ui.format_minutes_relative(cfg.work_week * 60 / 5, minutes),
    ))

    # active ranges
    previous_end_dt = None
    for dtr in ranges:
        # ignore zero-minute ranges
        if not dtr.minutes:
            continue

        current = (current_range and dtr.start_dt == current_range.start_dt
                   and dtr.end_dt == current_range.end_dt)

        gap = None
        if previous_end_dt:
            delta = dtr.start_dt - previous_end_dt
            gap = ui.format_minutes(delta.total_seconds() / 60)
        previous_end_dt = dtr.end_dt

        print("%5s %s%s%s %s%s" % (
            coloured("dark-grey", gap) if gap else "",
            dtr.start_dt.format("HH:mm"),
            coloured("dark-grey", "-"),
            dtr.end_dt.format("HH:mm"),
            coloured("green", ui.format_minutes(dtr.minutes)),
            " %s" % ui.CHAR_CURRENT if current else "",
        ))

    # edits
    for edit in edits:
        print("%s %s" %
              (ui.format_minutes_relative(0, edit.minutes), edit.reason))
Ejemplo n.º 2
0
def month(start, end):
    start = (
        arrow.now(tz=cfg.time_zone).format("YYYY-01-01")
        if start is None
        else _as_month(start)
    )
    start_dt = ui.parse_date(start, context="month").floor("month")

    end = start_dt.format("YYYY-12-31") if end is None else _as_month(end)
    end_dt = ui.parse_date(end, context="month").ceil("month")

    today = arrow.now(tz=cfg.time_zone).ceil("day")
    if end_dt > today:
        end_dt = today

    days = {}
    dt = start_dt
    while dt < end_dt:
        days[dt.format("YYYYMMDD")] = dict(dt=dt.clone(), minutes=0)
        dt = dt.shift(days=1)

    minutes = 0
    for dtr in database.active_ranges(start_dt, end_dt):
        days[dtr.start_dt.format("YYYYMMDD")]["minutes"] += dtr.minutes
        minutes += dtr.minutes

    for ymd in sorted(days.keys()):
        for edit in database.edits(days[ymd]["dt"]):
            days[ymd]["minutes"] += edit.minutes
            minutes += edit.minutes

    # group into months
    months = {}
    total = 0
    for ymd in sorted(days.keys()):
        dt = days[ymd]["dt"]
        ym = dt.format("YYYYMM")
        months.setdefault(ym, dict(name=dt.format("YYYY MMM"), minutes=0))
        months[ym]["minutes"] += days[ymd]["minutes"]
        total += days[ymd]["minutes"]

    hour_width = len(ui.format_minutes(total))

    # header
    print(
        coloured("yellow", "%{}s TOTAL".format(hour_width) % ui.format_minutes(total))
    )

    # report
    for m in sorted(months.keys()):
        print(
            "%{}s %s".format(hour_width)
            % (ui.format_minutes(months[m]["minutes"]), months[m]["name"])
        )
Ejemplo n.º 3
0
def input_ex(prompt, *, required=False, default=None, validator=None, options=None):
    if validator:
        assert callable(validator)

    if options:
        assert not validator

        def _check_options(value):
            value = value.lower()
            if value not in options:
                raise ValueError("")
            return value

        validator = _check_options

    if default:
        prompt = "%s (%s)" % (prompt, default)
    prompt = "%s: " % prompt

    try:
        while True:
            res = input(coloured("green", prompt)).strip()

            if res == "":
                if required:
                    continue
                if default:
                    res = default

            if validator:
                try:
                    res = validator(res)
                except ValueError as e:
                    if str(e):
                        logger.error(e)
                    continue

            return res
    except KeyboardInterrupt:
        print("")
        sys.exit(1)
Ejemplo n.º 4
0
def week(date, status):
    start_dt = ui.parse_date(date, context="week")

    # start_dt needs to be a monday
    if start_dt.weekday() != 0:
        start_dt = start_dt.shift(days=-7).shift(weekday=0)

    end_dt = start_dt.shift(days=7).shift(minutes=-1)

    # count days worked
    days = {}
    dt = start_dt.clone()
    while dt < end_dt:
        days[dt.format("YYYYMMDD")] = dict(dt=dt.clone(), minutes=0, edited=False)
        dt = dt.shift(days=1)

    # tally minutes
    total_minutes = 0
    for dtr in database.active_ranges(start_dt, end_dt):
        days[dtr.start_dt.format("YYYYMMDD")]["minutes"] += dtr.minutes
        total_minutes += dtr.minutes

    # process edits
    for ymd in sorted(days.keys()):
        for edit in database.edits(days[ymd]["dt"]):
            days[ymd]["minutes"] += edit.minutes
            days[ymd]["edited"] = True
            total_minutes += edit.minutes

    # header
    print(
        "%s %s %s %s - %s"
        % (
            coloured("yellow", ui.format_minutes(total_minutes)),
            coloured("yellow", "%-9s" % "WEEK"),
            ui.format_minutes_relative(cfg.work_week * 60, total_minutes),
            coloured("yellow", start_dt.format("Do MMM")),
            coloured("yellow", end_dt.format("Do MMM")),
        )
    )

    hours_per_day = (cfg.work_week * 60) / 5
    today = arrow.now(tz=cfg.time_zone).ceil("day")
    today_ymd = today.format("YYYYMMDD")
    is_away = state.is_away()
    for ymd in sorted(days.keys()):
        dt = days[ymd]["dt"]
        minutes = days[ymd]["minutes"]
        edited = days[ymd]["edited"]
        current = not is_away and ymd == today_ymd

        # don't report on the weekend unless there were hours logged
        if dt.weekday() > 4 and minutes == 0:
            continue

        # only report future dates if there's edits
        if dt > today and not edited:
            continue

        print(
            "%s %s %s%s%s"
            % (
                ui.format_minutes(minutes),
                "%-9s" % dt.format("dddd"),
                ui.format_minutes_relative(hours_per_day, minutes),
                " %s" % ui.CHAR_EDITED if edited else "",
                " %s" % ui.CHAR_CURRENT if current else "",
            )
        )

    if status:
        invoke(["status", "--no-daemon"])
Ejemplo n.º 5
0
def format_minutes_relative(target, minutes):
    if minutes == target:
        return coloured("green", "⦗ %s⦘" % format_minutes(0))
    if minutes < target:
        return coloured("red", "⦗-%s⦘" % format_minutes(target - minutes))
    return coloured("green", "⦗+%s⦘" % format_minutes(minutes - target))
Ejemplo n.º 6
0
 def format(self, record):
     result = super().format(record)
     if record.levelname in self.log_colours:
         result = coloured(self.log_colours[record.levelname], result)
     return result