|
|
|
@ -3,12 +3,11 @@ import getpass |
|
|
|
|
import logging |
|
|
|
|
import pickle |
|
|
|
|
import sys |
|
|
|
|
from typing import Union |
|
|
|
|
|
|
|
|
|
import requests as requests |
|
|
|
|
|
|
|
|
|
from timebot.constants import COMING_ENTRY_CODE_ID, LEAVING_ENTRY_CODE_ID, BREAK_START_ENTRY_CODE_ID, \ |
|
|
|
|
BREAK_END_ENTRY_CODE_ID, SIMPLE_DATE_FORMAT, SIMPLE_TIME_FORMAT, SIMPLE_DATETIME_FORMAT, \ |
|
|
|
|
USER_AGENT |
|
|
|
|
from timebot.constants import PunchCodes, DateFormats, USER_AGENT |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
package_logger = logging.getLogger(__name__) |
|
|
|
@ -21,20 +20,21 @@ class TimeParseError(Exception): |
|
|
|
|
def parse_user_time_input(stamp: str) -> datetime.datetime: |
|
|
|
|
errors = [] |
|
|
|
|
try: |
|
|
|
|
package_logger.debug(f"trying to parse date with format \"{SIMPLE_DATETIME_FORMAT}\"") |
|
|
|
|
return datetime.datetime.strptime(stamp, SIMPLE_DATETIME_FORMAT) |
|
|
|
|
package_logger.debug(f"trying to parse date with format \"{DateFormats.SIMPLE_DATETIME.value}\"") |
|
|
|
|
return datetime.datetime.strptime(stamp, DateFormats.SIMPLE_DATETIME.value) |
|
|
|
|
except ValueError as e: |
|
|
|
|
errors.append(e) |
|
|
|
|
try: |
|
|
|
|
package_logger.debug(f"trying to parse date with format \"{SIMPLE_TIME_FORMAT}\"") |
|
|
|
|
t = datetime.datetime.strptime(stamp, SIMPLE_TIME_FORMAT) |
|
|
|
|
package_logger.debug(f"trying to parse date with format \"{DateFormats.SIMPLE_TIME}\"") |
|
|
|
|
t = datetime.datetime.strptime(stamp, DateFormats.SIMPLE_TIME.value) |
|
|
|
|
dt = datetime.datetime.now() |
|
|
|
|
dt = dt.replace(hour=0, minute=0, second=0, microsecond=0) |
|
|
|
|
dt += datetime.timedelta(hours=t.hour, minutes=t.minute) |
|
|
|
|
return dt |
|
|
|
|
except ValueError as e: |
|
|
|
|
errors.append(e) |
|
|
|
|
package_logger.error(f"could not parse date with format \"{SIMPLE_DATETIME_FORMAT}\" or \"{SIMPLE_TIME_FORMAT}\"") |
|
|
|
|
package_logger.error(f"could not parse date with format \"{DateFormats.SIMPLE_DATETIME.value}\" or" |
|
|
|
|
f" \"{DateFormats.SIMPLE_TIME.value}\"") |
|
|
|
|
raise TimeParseError(errors) |
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -179,8 +179,8 @@ class MobatimeApi: |
|
|
|
|
:param str note: free text note added to the Mobatime entry |
|
|
|
|
:return: requests response object |
|
|
|
|
""" |
|
|
|
|
punch_date = punch_datetime.strftime(SIMPLE_DATE_FORMAT) |
|
|
|
|
punch_time = punch_datetime.strftime(SIMPLE_TIME_FORMAT) |
|
|
|
|
punch_date = punch_datetime.strftime(DateFormats.SIMPLE_DATE.value) |
|
|
|
|
punch_time = punch_datetime.strftime(DateFormats.SIMPLE_TIME.value) |
|
|
|
|
entry_data = { |
|
|
|
|
"periode0Date": punch_date, |
|
|
|
|
"periode0Time": punch_time, |
|
|
|
@ -193,7 +193,7 @@ class MobatimeApi: |
|
|
|
|
request = self.session.post(self.baseurl + "Entry/SaveEntry", data=entry_data) |
|
|
|
|
return request |
|
|
|
|
|
|
|
|
|
def get_entries(self, entries: int = 10, |
|
|
|
|
def get_entries(self, entries: Union[str, None] = 10, |
|
|
|
|
start_date: datetime.datetime = None, |
|
|
|
|
end_date: datetime.datetime = None) -> list: |
|
|
|
|
""" |
|
|
|
@ -217,12 +217,12 @@ class MobatimeApi: |
|
|
|
|
filters["filter"]["filters"].append({ |
|
|
|
|
"field": "startDate", |
|
|
|
|
"operator": "gte", |
|
|
|
|
"value": start_date.strftime(SIMPLE_DATETIME_FORMAT), |
|
|
|
|
"value": start_date.strftime(DateFormats.SIMPLE_DATETIME.value), |
|
|
|
|
}) |
|
|
|
|
filters["filter"]["filters"].append({ |
|
|
|
|
"field": "endDate", |
|
|
|
|
"operator": "lte", |
|
|
|
|
"value": end_date.strftime(SIMPLE_DATETIME_FORMAT), |
|
|
|
|
"value": end_date.strftime(DateFormats.SIMPLE_DATETIME.value), |
|
|
|
|
}) |
|
|
|
|
request = self.session.post(self.baseurl + "Entry/GetEntries", json=filters) |
|
|
|
|
request.raise_for_status() |
|
|
|
@ -269,30 +269,30 @@ class TimeBot: |
|
|
|
|
:param datetime.datetime punch_datetime: datetime object |
|
|
|
|
:raises: on status code != 2xx |
|
|
|
|
""" |
|
|
|
|
self.mobatime_api.save_entry(punch_datetime, COMING_ENTRY_CODE_ID, note="da").raise_for_status() |
|
|
|
|
self.mobatime_api.save_entry(punch_datetime, PunchCodes.COMING.value, note="da").raise_for_status() |
|
|
|
|
|
|
|
|
|
def punch_out(self, punch_datetime: datetime.datetime): |
|
|
|
|
""" |
|
|
|
|
:param datetime.datetime punch_datetime: datetime object |
|
|
|
|
:raises: on status code != 2xx |
|
|
|
|
""" |
|
|
|
|
self.mobatime_api.save_entry(punch_datetime, LEAVING_ENTRY_CODE_ID, note="weg").raise_for_status() |
|
|
|
|
self.mobatime_api.save_entry(punch_datetime, PunchCodes.LEAVING.value, note="weg").raise_for_status() |
|
|
|
|
|
|
|
|
|
def break_start(self, punch_datetime: datetime.datetime): |
|
|
|
|
""" |
|
|
|
|
:param datetime.datetime punch_datetime: datetime object |
|
|
|
|
:raises: on status code != 2xx |
|
|
|
|
""" |
|
|
|
|
self.mobatime_api.save_entry(punch_datetime, BREAK_START_ENTRY_CODE_ID, note="pause").raise_for_status() |
|
|
|
|
self.mobatime_api.save_entry(punch_datetime, PunchCodes.BREAK_START.value, note="pause").raise_for_status() |
|
|
|
|
|
|
|
|
|
def break_end(self, punch_datetime: datetime.datetime): |
|
|
|
|
""" |
|
|
|
|
:param datetime.datetime punch_datetime: datetime object |
|
|
|
|
:raises: on status code != 2xx |
|
|
|
|
""" |
|
|
|
|
self.mobatime_api.save_entry(punch_datetime, BREAK_END_ENTRY_CODE_ID, note="pause ende").raise_for_status() |
|
|
|
|
self.mobatime_api.save_entry(punch_datetime, PunchCodes.BREAK_END.value, note="pause ende").raise_for_status() |
|
|
|
|
|
|
|
|
|
def smart_punch(self, punch_datetime): |
|
|
|
|
def smart_punch(self, punch_datetime) -> None: |
|
|
|
|
last_punch = self.mobatime_api.get_entries( |
|
|
|
|
1, |
|
|
|
|
start_date=punch_datetime.replace(hour=0, minute=0, second=0, microsecond=0), |
|
|
|
@ -302,16 +302,16 @@ class TimeBot: |
|
|
|
|
if not last_punch or last_punch[0]["entryNumber"] is None: |
|
|
|
|
self.logger.debug("could not detect any time entry for today... punching in") |
|
|
|
|
method = "punch_in" |
|
|
|
|
elif last_punch[0]["entryNumber"] == COMING_ENTRY_CODE_ID: |
|
|
|
|
elif last_punch[0]["entryNumber"] == PunchCodes.COMING: |
|
|
|
|
self.logger.debug("your last entry was `punch_in`... starting break") |
|
|
|
|
method = "break_start" |
|
|
|
|
elif last_punch[0]["entryNumber"] == BREAK_START_ENTRY_CODE_ID: |
|
|
|
|
elif last_punch[0]["entryNumber"] == PunchCodes.BREAK_START: |
|
|
|
|
self.logger.debug("your last entry was `break_start`... ending break") |
|
|
|
|
method = "break_end" |
|
|
|
|
elif last_punch[0]["entryNumber"] == BREAK_END_ENTRY_CODE_ID: |
|
|
|
|
elif last_punch[0]["entryNumber"] == PunchCodes.BREAK_END: |
|
|
|
|
self.logger.debug("your last entry was `break_end`... punching out") |
|
|
|
|
method = "punch_out" |
|
|
|
|
elif last_punch[0]["entryNumber"] == LEAVING_ENTRY_CODE_ID: |
|
|
|
|
elif last_punch[0]["entryNumber"] == PunchCodes.LEAVING: |
|
|
|
|
self.logger.error("your last entry was `punch_out`... punching in again with this command is not supported") |
|
|
|
|
sys.exit(1) |
|
|
|
|
if method is None: |
|
|
|
@ -320,12 +320,12 @@ class TimeBot: |
|
|
|
|
exit(1) |
|
|
|
|
self.logger.info("running `{}` with date `{}` and time `{}`".format( |
|
|
|
|
method, |
|
|
|
|
punch_datetime.strftime(SIMPLE_DATE_FORMAT), |
|
|
|
|
punch_datetime.strftime(SIMPLE_TIME_FORMAT), |
|
|
|
|
punch_datetime.strftime(DateFormats.SIMPLE_DATE), |
|
|
|
|
punch_datetime.strftime(DateFormats.SIMPLE_TIME), |
|
|
|
|
)) |
|
|
|
|
getattr(self, method)(punch_datetime) |
|
|
|
|
|
|
|
|
|
def status(self): |
|
|
|
|
def status(self) -> str: |
|
|
|
|
tracking_data = self.mobatime_api.get_tracking_data() |
|
|
|
|
account_info = self.mobatime_api.get_account_information() |
|
|
|
|
ret = "Tracking Info:\n" |
|
|
|
@ -336,3 +336,13 @@ class TimeBot: |
|
|
|
|
for i in account_info: |
|
|
|
|
ret += f" {i['accountName']}: {i['value']}\n" |
|
|
|
|
return ret |
|
|
|
|
|
|
|
|
|
def get_hours_present(self) -> datetime.timedelta: |
|
|
|
|
now = datetime.datetime.now() |
|
|
|
|
punches = self.mobatime_api.get_entries( |
|
|
|
|
None, |
|
|
|
|
start_date=now.replace(hour=0, minute=0, second=0, microsecond=0), |
|
|
|
|
end_date=now.replace(hour=0, minute=0, second=0, microsecond=0), |
|
|
|
|
) |
|
|
|
|
time_delta = now - datetime.datetime.strptime(punches[0]["dateTime"], DateFormats.FULL_DATETIME.value) |
|
|
|
|
return time_delta |
|
|
|
|