#!/usr/local/Cellar/python3/3.4.3/Frameworks/Python.framework/Versions/3.4/bin/python3.4 # -*- coding: utf-8 -*- __author__ = 'admin' api_url = "http://basicdata.ru/api/json/calend/" from functools import lru_cache import calendar import datetime import urllib.request import json def flatten(a): if isinstance(a, list): for b in a: for x in flatten(b): yield x else: yield a # Генерирует расписание на заданный год по умолчанию # Все дни с понедельника по пятницу отмечаются рабочими # Все субботы и воскресенья - выходными def generate_default_calendar(year): return group_by_month( map(lambda x: (x[0], x[1] < 6), map(lambda x: (x[0], x[1] + 1), filter(lambda x: x[0] > 0, flatten(calendar.Calendar.yeardays2calendar(calendar.Calendar(), year)) ) ) ) ) # Разделяет дни на группы по месяцам def group_by_month_inner(items): month = [] for day, flag in items: if month and month[-1][0] > day: # new month starting yield month month = [] month.append((day, flag)) if month: yield month def group_by_month(items): return list(group_by_month_inner(items)) # Загружает дни-исключения @lru_cache(maxsize=None) def load_exceptions(apiurl, year): return json.loads(urllib.request.urlopen(apiurl).read().decode('utf8'))["data"][str(year)] # Меняет значения структуры по умолчанию для дней-исключений def apply_exceptions(months, exc): i = 0 for m in months: newm = [] i += 1 for d in m: if str(i) in exc and str(d[0]) in exc[str(i)]: d = (d[0], exc[str(i)][str(d[0])]["isWorking"] != 2) newm.append(d) yield newm # Удаляет все выходные, конвертирует кортежи в простые дни месяца def filter_holidays(months): for m in months: yield list( map( lambda x: x[0], filter( lambda x: x[1], m ) ) ) # Получает все рабочие дни за определенные месяц/год в виде массива. Если указать месяц, вернет только его def get_workdays(year=None, month=None): if year is None and month is None: year = datetime.datetime.now().year month = datetime.datetime.now().month if month is None: return list(filter_holidays(apply_exceptions(generate_default_calendar(year), load_exceptions(api_url, year)))) else: return get_workdays(year)[month - 1] # Считает кол-в рабочих дней в году/месяце @lru_cache(maxsize=None) def count_workdays(year=None, month=None): if month is None and year is None: return len(get_workdays()) elif month is not None: return len(get_workdays(year, month)) else: return sum(list(map(lambda x: len(x), get_workdays(year))), 0) @lru_cache(maxsize=None) def _get_expected_hours(year, month, day): return len(list(filter(lambda x: x < day, get_workdays()))) * 8 # Возвращает сколько часов ты уже должен был отработать def get_expected_hours(): return _get_expected_hours(datetime.datetime.now().year, datetime.datetime.now().month, datetime.datetime.now().day) # Считает заработанные деньги исходя из зарплаты и кол-ва отработанны часов @lru_cache(maxsize=None) def earned(salary, hours): return hours / (count_workdays(datetime.datetime.now().year, datetime.datetime.now().month) * 8) * salary def print_earned_with_stats(hours, salary=None): if salary is None: salary = 50000 real = earned(salary, hours) expected = earned(salary, get_expected_hours()) print("Earned: ", real, " Expected: ", expected) if real > expected: print("Well done, you've already earned extra ", real - expected, " money -", hours - get_expected_hours(), " extra hours worked") elif real < expected: print("You should work extra ", get_expected_hours() - hours, " hours to catch schedule") else: print("Going on schedule!") if __name__ == '__main__': import sys _salary = None _hours = None if len(sys.argv) > 1: _hours = int(sys.argv[1]) if len(sys.argv) > 2: _salary = int(sys.argv[2]) if _hours is None: _hours = 8 print_earned_with_stats(_hours, _salary)