Changes in / [11:30241f3a03eb:12:73483c3145ff] in stamper


Ignore:
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • bin/stamps

    r3 r10  
    11#!/usr/bin/env python
    22
    3 import sys
     3import argparse
    44from stamper import Stamper
    5 
    6 
    7 def usage(name):
    8     msg = """
    9     Usage:
    10 
    11     To gather information of recorded times: %(name)s
    12 
    13     Recorded times for a given customer: %(name)s customer
    14 
    15     Detailed times for a given customer: %(name)s customer details
    16     """ % {'name': name}
    17     print(msg)
    185
    196
    207if __name__ == '__main__':
    218
     9    parser = argparse.ArgumentParser(
     10        description='stamps: show recorded times information')
     11    parser.add_argument('customer', action="store", nargs='?',
     12                        help='Show times only for this customer')
     13    parser.add_argument('filter', action="store", nargs='?',
     14                        help='Filter the times by date range')
     15    parser.add_argument('-v', '--verbose', action="store_true",
     16                        help='Include detailed times information')
     17
     18    args = parser.parse_args()
     19
    2220    s = Stamper()
    2321    s.load_stamps()
    24 
    25     if len(sys.argv) == 1:
    26         totals = s.totals()
    27         print('Total times for all customers:')
    28         for t in totals:
    29             print(' -> %(customer)s: %(total)s' % {'customer': t,
    30                                                    'total': totals[t]})
    31     elif len(sys.argv) == 2:
    32         if sys.argv[1] in s.customers():
    33             print('Total time for %(customer)s: %(total)s' % {
    34                 'customer': sys.argv[1],
    35                 'total': s.total_by_customer(sys.argv[1])
    36                 })
    37 
    38     elif len(sys.argv) == 3:
    39         if sys.argv[1] in s.customers():
    40             print('Detailed time for %(customer)s' % {
    41                 'customer': sys.argv[1],
    42                 })
    43             details, totals = s.details_by_customer(sys.argv[1])
    44             for day in details:
    45                 print('------ %(day)s ------' % {'day': day})
    46                 for line in details[day]:
    47                     print(line)
    48                 print(' Total: %(total)s' % {'total': totals[day]})
    49 
    50     else:
    51         usage(sys.argv[0])
    52         sys.exit(1)
     22    s.show_stamps(args.customer, args.filter, args.verbose)
  • stamper/stamper.py

    r0 r9  
    11
    22import json
     3import re
    34from datetime import datetime, timedelta
    45from os.path import expanduser, exists
     6
    57
    68STAMPS_FILE = expanduser('~/.workstamps.json')
     
    4951        return worktime.seconds
    5052
     53    def validate_filter(self, stamp_filter):
     54        """
     55        Validate a given filter. Filters can have the following notation:
     56
     57        - %Y-%m-%d--%Y-%m-%d: Times recorded between two dates
     58
     59        - -%Y-%m-%d: Times recorded before a given date
     60
     61        - +%Y-%m-%d: Times recorded after a given date
     62
     63        - N...N[d|w|m|y]: Times recorded N...N days/weeks/months/years ago
     64        """
     65        # First try the date filters, one by one
     66        matches = ['%Y-%m-%d', '-%Y-%m-%d', '+%Y-%m-%d']
     67        for match in matches:
     68            try:
     69                if '--' in stamp_filter:
     70                    filter_from, filter_to = stamp_filter.split('--')
     71                    filter_from = datetime.strptime(stamp_filter, match)
     72                    filter_to = datetime.strptime(stamp_filter, match)
     73                else:
     74                    valid_filter = datetime.strptime(stamp_filter, match)
     75            except ValueError:
     76                pass
     77            else:
     78                return stamp_filter
     79
     80        valid_filter = re.search(r'(\d+[dwmyDWMY]{1})', stamp_filter)
     81        if valid_filter:
     82            return stamp_filter
     83
     84        # Not a valid filter
     85        return None
     86
    5187    def customers(self):
    5288        customers = []
     
    5793        return customers
    5894
    59     def total_by_customer(self, customer):
    60         total = 0
     95    def totals(self, stamp_filter=None):
     96        totals = {}
    6197        for stamp in self.stamps:
    62             if stamp['customer'] == customer:
    63                 total += self.worktime(stamp['start'], stamp['end'])
    64         total = timedelta(seconds=total)
    65         return str(total)
     98            customer = stamp['customer']
     99            if customer:
     100                # c will be None for "start" stamps, having no end time
     101                if customer not in totals:
     102                    totals[customer] = 0
     103                totals[customer] += self.worktime(stamp['start'], stamp['end'])
     104        return totals
    66105
    67     def totals(self):
     106    def details(self):
     107        details = {}
    68108        totals = {}
    69         for customer in self.customers():
    70             totals[customer] = self.total_by_customer(customer)
    71         return totals
     109        for stamp in self.stamps:
     110            if stamp['customer']:
     111                # avoid "start" stamps
     112                start_day = stamp['start'].split(' ')[0]
     113                if start_day not in details:
     114                    details[start_day] = []
     115                if start_day not in totals:
     116                    totals[start_day] = 0
     117                worktime = self.worktime(stamp['start'], stamp['end'])
     118                details[start_day].append(
     119                    ' -> %(worktime)s %(customer)s %(action)s' % {
     120                        'worktime': str(timedelta(seconds=worktime)),
     121                        'customer': stamp['customer'],
     122                        'action': stamp['action']
     123                    })
     124                totals[start_day] += worktime
     125        for day in totals:
     126            totals[day] = str(timedelta(seconds=totals[day]))
     127        return details, totals
    72128
    73129    def details_by_customer(self, customer):
     
    92148            totals[day] = str(timedelta(seconds=totals[day]))
    93149        return details, totals
     150
     151    def show_stamps(self, customer=None, stamp_filter=None, verbose=False):
     152        if stamp_filter:
     153            stamp_filter = self.validate_filter(stamp_filter)
     154
     155        totals = self.totals(stamp_filter)
     156
     157        if customer:
     158            total = timedelta(seconds=totals.get(customer, 0))
     159            print(' %(customer)s: %(total)s' % {'customer': customer,
     160                                                'total': total})
     161        else:
     162            for c in totals:
     163                total = timedelta(seconds=totals[c])
     164                print(' %(customer)s: %(total)s' % {'customer': c,
     165                                                    'total': total})
     166
     167        if verbose:
     168            if customer:
     169                details, totals = self.details_by_customer(customer)
     170            else:
     171                details, totals = self.details()
     172            for day in details:
     173                print('------ %(day)s ------' % {'day': day})
     174                for line in details[day]:
     175                    print(line)
     176                print(' Total: %(total)s' % {'total': totals[day]})
Note: See TracChangeset for help on using the changeset viewer.