source: stamper/stamper/stamper.py@ 7:7f7b4ef7c0c1

Last change on this file since 7:7f7b4ef7c0c1 was 7:7f7b4ef7c0c1, checked in by Borja Lopez <borja@…>, 10 years ago

Added method to parse a string and tell if it is a valid date-based
filter.

File size: 4.1 KB
Line 
1
2import json
3import re
4from datetime import datetime, timedelta
5from os.path import expanduser, exists
6
7
8STAMPS_FILE = expanduser('~/.workstamps.json')
9DATE_FORMAT = '%Y-%m-%d %H:%M:%S'
10
11
12class Stamper(object):
13
14 def __init__(self, stamps_file=STAMPS_FILE):
15 self.stamps_file = STAMPS_FILE
16 self.ensure_stamps_file()
17 self.stamps = []
18
19 def ensure_stamps_file(self):
20 if not exists(self.stamps_file):
21 with open(self.stamps_file, 'w') as stamps_file:
22 stamps_file.write('')
23
24 def load_stamps(self):
25 with open(self.stamps_file, 'r') as stamps_file:
26 try:
27 self.stamps = json.load(stamps_file)
28 except ValueError:
29 self.stamps = []
30
31 def save_stamps(self):
32 with open(self.stamps_file, 'w') as stamps_file:
33 json.dump(self.stamps, stamps_file, indent=4)
34
35 def stamp(self, start, end, customer, action):
36 self.stamps.append({
37 'start': start,
38 'end': end,
39 'customer': customer,
40 'action': action,
41 })
42
43 def last_stamp(self):
44 if not self.stamps:
45 return None
46 return self.stamps[-1]
47
48 def worktime(self, start, end):
49 worktime = (datetime.strptime(end, DATE_FORMAT) -
50 datetime.strptime(start, DATE_FORMAT))
51 return worktime.seconds
52
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
87 def customers(self):
88 customers = []
89 for stamp in self.stamps:
90 if stamp['customer'] not in customers:
91 customers.append(stamp['customer'])
92 customers.remove(None)
93 return customers
94
95 def total_by_customer(self, customer):
96 total = 0
97 for stamp in self.stamps:
98 if stamp['customer'] == customer:
99 total += self.worktime(stamp['start'], stamp['end'])
100 total = timedelta(seconds=total)
101 return str(total)
102
103 def totals(self):
104 totals = {}
105 for customer in self.customers():
106 totals[customer] = self.total_by_customer(customer)
107 return totals
108
109 def details_by_customer(self, customer):
110 details = {}
111 totals = {}
112 for stamp in self.stamps:
113 if stamp['customer'] == customer:
114 start_day = stamp['start'].split(' ')[0]
115 if start_day not in details:
116 details[start_day] = []
117 if start_day not in totals:
118 totals[start_day] = 0
119 worktime = self.worktime(stamp['start'], stamp['end'])
120 details[start_day].append(
121 ' -> %(worktime)s %(customer)s %(action)s' % {
122 'worktime': str(timedelta(seconds=worktime)),
123 'customer': stamp['customer'],
124 'action': stamp['action']
125 })
126 totals[start_day] += worktime
127 for day in totals:
128 totals[day] = str(timedelta(seconds=totals[day]))
129 return details, totals
Note: See TracBrowser for help on using the repository browser.