diff --git a/hamstertools/__init__.py b/hamstertools/__init__.py index 183809a..309bd9e 100755 --- a/hamstertools/__init__.py +++ b/hamstertools/__init__.py @@ -1,10 +1,13 @@ #!/usr/bin/env python3.7 -import sqlite3 import click +import csv +from datetime import datetime from pathlib import Path +import sqlite3 -HAMSTER_FILE = Path.home() / '.local/share/hamster-applet/hamster.db' +HAMSTER_DIR = Path.home() / '.local/share/hamster-applet' +HAMSTER_FILE = HAMSTER_DIR / 'hamster.db' conn = sqlite3.connect(HAMSTER_FILE) c = conn.cursor() @@ -37,7 +40,7 @@ def get_categories(ids=None, search=None): return results -def get_activities(ids=None, search=None): +def get_activities(ids=None, search=None, category_search=None): sql = ''' SELECT activities.id, activities.name, categories.name, categories.id @@ -61,6 +64,11 @@ def get_activities(ids=None, search=None): search = '%{0}%'.format(search) args.append(search) + if category_search is not None: + sql = sql + " WHERE categories.name LIKE ?" + category_search = '%{0}%'.format(category_search) + args.append(category_search) + results = c.execute(sql, args) results = c.fetchall() @@ -320,6 +328,144 @@ def find_duplicates(): click.secho('@{0[0]}: {0[1]} » @{0[2]}: {0[3]} ({0[4]})'.format(r), fg='blue') +@cli.group() +def export(): + pass + + +@export.command() +@click.option('--mapping', help='Mapping file (default ~/.local/share/hamster/mapping.kimai.csv)') +@click.option('--output', help='Output file (default kimai.csv)') +@click.option('--category-search', help='Category search string') +def kimai(mapping=None, output=None, category_search=None): + if mapping is None: + mapping = HAMSTER_DIR / 'mapping.kimai.csv' + if output is None: + output = 'kimai.csv' + + try: + mapping_file = open(mapping) + mapping_reader = csv.reader(mapping_file) + except FileNotFoundError: + click.confirm( + 'Mapping file {} not found, create it?:'.format(mapping), + abort=True + ) + mapping_file = open(mapping, 'w') + mapping_writer = csv.writer(mapping_file) + + mapping_writer.writerow([ + 'FROM category', + 'FROM activity', + 'TO Customer', + 'TO Project', + 'TO Activity' + ]) + + results = get_activities(category_search=category_search) + + for r in results: + mapping_writer.writerow([ + r[2], r[1] + ]) + + mapping_file.close() + return + + next(mapping_reader) + + mapping = { + '{0}:{1}'.format(row[0], row[1]): [row[2], row[3], row[4]] + for row in mapping_reader + } + + mapping_file.close() + + output_file = open(output, 'w') + output_writer = csv.writer(output_file) + + args = [] + + sql = ''' + SELECT + facts.id, facts.start_time, facts.end_time, facts.description, + activities.id, activities.name, + categories.name, categories.id + FROM + facts + LEFT JOIN + activities ON facts.activity_id = activities.id + LEFT JOIN + categories ON activities.category_id = categories.id ''' + + if category_search is not None: + sql = sql + " WHERE categories.name LIKE ?" + category_search = '%{0}%'.format(category_search) + args.append(category_search) + + results = c.execute(sql, args) + results = c.fetchall() + + output_writer.writerow([ + "Date", + "From", + "To", + "Duration", + "Rate", + "User", + "Customer", + "Project", + "Activity", + "Description", + "Exported", + "Tags", + "Hourly rate", + "Fixed rate" + ]) + + for fact in results: + k = '{0}:{1}'.format(fact[6], fact[5]) + try: + mapping_ = mapping[k] + except KeyError: + click.secho("Can't find mapping for '{0}', skipping".format(k), fg='yellow') + continue + + if fact[1] is None or fact[2] is None: + click.secho("Missing duration data '{0}-{1}', skipping".format( + fact[1], + fact[2] + ), fg='yellow') + continue + + date_start, date_end = ( + datetime.strptime(fact[2].split('.')[0], '%Y-%m-%d %H:%M:%S'), + datetime.strptime(fact[1].split('.')[0], '%Y-%m-%d %H:%M:%S') + ) + duration = ( + date_start - date_end + ).seconds + + output_writer.writerow([ + date_start.strftime('%Y-%m-%d'), + date_start.strftime('%H:%M'), + '', # To (time) + duration, + '', # Rate + '3wordchant', + mapping_[0], + mapping_[1], + mapping_[2], + fact[3] or '', + '0', # Exported + '', # Tags + '', # Hourly rate + '', # Fixed rate + ]) + + output_file.close() + + @cli.command() def hamster(): click.echo('🐹')