view contrib/zeiterfassung @ 100:8f433e3c2f21

Allow to pass entries to the DeleteEntryState By default DeleteEntryState uses the selected entries if no entry is passes to the constructor. This allows to reuse the state class for single entry deletion
author Björn Ricks <bjoern.ricks@intevation.de>
date Mon, 12 Sep 2011 14:05:34 +0200
parents 4b58763e75c1
children e7548b8c6dcc
line wrap: on
line source
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# zeiterfassung
# -------------
# (c) 2008 by Sascha L. Teichmann <sascha.teichmann@intevation.de>
#
# Simple script which generates lines for zeiterfassung.txt files.
#
# This is Free Software licensed under the terms of GPLv3 or later.
# For details see LICENSE coming with the source of 'getan'.
#
import os
import os.path
import sys
import getopt
import re
import codecs

from pysqlite2 import dbapi2 as db

from datetime import date

DEFAULT_DATABASE = "time.db"

TYPE_OF_ENTRY = "?"

WORKPACKAGE = re.compile("^\[(\w*)(\s|\])")

USAGE = '''usage: %s <options>
    with <options>
    [--user=|-u <user>]        : Name of user,          default: $USER
    [--database=|-d <database>]: getan database,        default: time.db
    [--project=|-p <key>]      : Key of output project, default: all
    [--encoding=|-e encoding]  : encoding of output,    default: none
    [--week=]|-w <week>]       : week of year
    [--year=]|-y <year>]       : year
    [--list|-l]                : list all projects
    [--help|-h]                : This text
    [--emtpy|-m]               : show empty projects'''

LIST_PROJECTS = '''
SELECT key, description, active FROM projects
'''

PROJECT_ID_BY_KEY = '''
SELECT id, description FROM projects where key = :key
'''

ALL_PROJECT_IDS = '''
SELECT id, key, description FROM projects
'''

WEEK_ENTRIES = '''
SELECT 
    date(start_time) AS t, 
    sum(strftime('%s', stop_time) - strftime('%s', start_time)), 
    'no description' AS description
FROM entries 
WHERE 
    project_id = :project_id AND 
    (strftime('%Y', start_time) ) = :year AND
    (description IS NULL or length(description) = 0) -- trim() function is missing
    AND (strftime('%W', start_time) = :week OR strftime('%W', stop_time) = :week)
GROUP BY round(julianday(start_time))
UNION
SELECT date(start_time) AS s, strftime('%s', stop_time) - strftime('%s', start_time), description
FROM entries 
WHERE 
    project_id = :project_id AND 
    (strftime('%Y', start_time) ) = :year AND
    description IS NOT NULL AND length(description) > 0
    AND (strftime('%W', start_time) = :week OR strftime('%W', stop_time) = :week)
ORDER BY t
'''

ENTRIES = '''
SELECT 
    date(start_time), 
    sum(strftime('%s', stop_time) - strftime('%s', start_time)), 
    'no description' AS description
FROM entries 
WHERE 
    project_id = :project_id AND 
    (description IS NULL or length(description) = 0) -- trim() function is missing
GROUP BY round(julianday(start_time))
UNION
SELECT date(start_time), strftime('%s', stop_time) - strftime('%s', start_time), description
FROM entries 
WHERE 
    project_id = :project_id AND 
    description IS NOT NULL AND length(description) > 0
'''

ENTRIES_YEAR = '''
SELECT 
    date(start_time), 
    sum(strftime('%s', stop_time) - strftime('%s', start_time)), 
    'no description' AS description
FROM entries 
WHERE 
    project_id = :project_id AND 
    (description IS NULL or length(description) = 0) -- trim() function is missing
GROUP BY round(julianday(start_time))
UNION
SELECT date(start_time), strftime('%s', stop_time) - strftime('%s', start_time), description
FROM entries 
WHERE 
    project_id = :project_id AND 
    (strftime('%Y', start_time) ) = :year AND
    description IS NOT NULL AND length(description) > 0
'''

def human_time(s):
    h = s / 3600
    m = (s % 3600) / 60
    if (s % 60) >= 30:
        m += 1
        if m == 60:
            m = 0
            h += 1
    return "%2d:%02d" % (h, m)

class TermError(Exception):

    def __init__(self, msg):
        Exception.__init__(self)
        self.msg = msg

    def __str__(self):
        return repr(self.msg)

def tolerantClose(c):
    if c:
        try: c.close()
        except: pass

def usage(exit_code = 0):
    print USAGE % sys.argv[0]
    sys.exit(exit_code)

def main():

    database      = DEFAULT_DATABASE
    user          = None
    list_projects = False
    project       = None
    encoding      = None
    week          = None
    year          = None
    empty_proj    = False

    opts, args = getopt.getopt(
        sys.argv[1:],
        'd:u:p:e:hl:w:y:m',
        ['database=', 'user=', 'project=', 'encoding=', 'help', 'list', 'week=', 'year=', 'empty'])

    for opt, val in opts:
        if opt in ("--database", "-d"):
            database = val
        elif opt in ("--user", "-u"):
            user = val
        elif opt in ("--project", "-p"):
            project = val
        elif opt in ("--encoding", "-e"):
            encoding = val
        elif opt in ("--help", "-h"):
            usage()
        elif opt in ("--list", "-l"):
            list_projects = True
        elif opt in ("--week", "-w"):
            week = val
        elif opt in ("--year", "-y"):
            year = val
        elif opt in ("--empty", "-m"):
            empty_proj = True

    if not user:
        user = os.getenv("USER")

    proj_year = year
    if not proj_year:
        proj_year = date.today().strftime("%Y")

    if encoding:
        Writer = codecs.getwriter(encoding)
        sys.stdout = Writer(sys.stdout)

    if not os.path.isfile(database):
        print >> sys.stderr, "'%s' does not exist or is not a file." % database
        sys.exit(1)

    con, cur = None, None
    try:
        try:
            con = db.connect(database)
            if encoding:
                con.text_factory = lambda s: s.decode(encoding)
            cur = con.cursor()

            if list_projects:
                cur.execute(LIST_PROJECTS)
                while True:
                    row = cur.fetchone()
                    if not row: break
                    print "%s %s %s" % (row[0], row[2] and "*" or "-", row[1])
            else:
                if project:
                    cur.execute(PROJECT_ID_BY_KEY, { 'key': project })
                    row = cur.fetchone()
                    if row is None:
                        raise TermError("There is no project with key '%s'" % project)
                    project_ids = [[row[0], project, row[1]]]
                else:
                    cur.execute(ALL_PROJECT_IDS);
                    project_ids = cur.fetchall()

                total = 0
                for project_id, project, proj_desc in project_ids:
                    if not week is None:
                        cur.execute(WEEK_ENTRIES, {'project_id': project_id, 'week': week, 'year' : proj_year})
                    elif not year:
                        cur.execute(ENTRIES, {'project_id': project_id})
                    else:
                        cur.execute(ENTRIES_YEAR, {'project_id': project_id, 'year':proj_year})
                    total_proj = 0
                    row = cur.fetchone()
                    if row or empty_proj:
                        print "# project: %s (%s)" % (project, proj_desc)
                    while row:
                        d = date(*map(int, row[0].split('-'))) 
                        t = max(60, row[1])
                        c = row[2]
                        total_proj += t
                        workpackage = "----"
                        if c:
                            m = WORKPACKAGE.match(c)
                            if m:
                                workpackage = m.group(1)
                                c = c[m.end():].strip()
                            c = c.replace('\x1b', '')
                        print "%s %sh %s %-3s [%s] %s" % (
                            d.strftime("%d.%m.%Y"),
                            human_time(t),
                            TYPE_OF_ENTRY,
                            user,
                            workpackage,
                            c)
                        row = cur.fetchone()
                    total += total_proj
                    if empty_proj or total_proj > 0:
                        print "# total: %sh\n\n" % human_time(total_proj)
                print "# total all projects: %sh\n\n" % human_time(total)
        finally:
            tolerantClose(cur)
            tolerantClose(con)

    except TermError, e:
        print >> sys.stderr, "error: %s" % e.msg

if __name__ == '__main__':
    main()

# vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8:
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)