Skip to content

Commit e980f09

Browse files
committed
in the process of refactoring. almost there.
1 parent 9b0e246 commit e980f09

1 file changed

Lines changed: 175 additions & 138 deletions

File tree

src/groupsplit.py

Lines changed: 175 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import pickle
77
import pprint
88
import urllib
9+
import optparse
910
import requests
1011
import subprocess
1112
import webbrowser
@@ -14,165 +15,201 @@
1415
from pprint import pprint
1516
from datetime import datetime
1617

17-
def get_client_auth():
18-
if os.path.isfile("consumer_oauth.json"):
19-
with open("consumer_oauth.json", 'rb') as oauth_file:
20-
consumer = json.load(oauth_file)
21-
ckey = consumer['consumer_key']
22-
csecret = consumer['consumer_secret']
23-
else:
24-
with open("consumer_oauth.json", 'wb') as oauth_file:
25-
json.dump({'consumer_key':'YOUR KEY HERE',
26-
'consumer_secret':'YOUR SECRET HERE'}, oauth_file)
27-
exit("go to https://secure.splitwise.com/oauth_clients to obtain your keys."+
28-
"place them in consumer_oauth.json")
29-
return ckey, csecret
30-
31-
def get_client():
32-
ckey, csecret = get_client_auth()
33-
client = oauthlib.oauth1.Client(ckey, client_secret=csecret)
34-
uri, headers, body = client.sign("https://secure.splitwise.com/api/v3.0/get_request_token",
35-
http_method='POST')
36-
r = requests.post(uri, headers=headers, data=body)
37-
resp = r.text.split('&')
38-
oauth_token = resp[0].split('=')[1]
39-
oauth_secret = resp[1].split('=')[1]
40-
uri = "https://secure.splitwise.com/authorize?oauth_token=%s" % oauth_token
41-
42-
webbrowser.open_new(uri)
43-
44-
proc = subprocess.Popen(['python', 'server.py'], stdout=subprocess.PIPE, shell=True)
45-
stdout, stderr = proc.communicate()
46-
if stderr:
47-
exit(stderr)
48-
client = oauthlib.oauth1.Client(ckey, client_secret=csecret,
49-
resource_owner_key=oauth_token,
50-
resource_owner_secret=oauth_secret,
51-
verifier=stdout.strip())
52-
53-
uri, headers, body = client.sign("https://secure.splitwise.com/api/v3.0/get_access_token",
54-
http_method='POST')
55-
resp = requests.post(uri, headers=headers, data=body)
56-
tokens = resp.text.split('&')
57-
oauth_token = tokens[0].split('=')[1]
58-
oauth_secret = tokens[1].split('=')[1]
59-
client = oauthlib.oauth1.Client(ckey, client_secret=csecret,
60-
resource_owner_key=oauth_token,
61-
resource_owner_secret=oauth_secret,
62-
verifier=stdout.strip())
63-
with open('oauth_client.pkl', 'wb') as pkl:
64-
pickle.dump(client, pkl)
65-
return client
66-
6718
def split(total, num_people):
6819
base = total * 100 // num_people / 100
6920
extra = total - num_people * base
7021
assert base * num_people + extra == total, "InternalError:" + \
7122
" something doesnt add up here: %d * %d + %d != %d" %(base, num_people, extra, total)
7223
return base, extra
7324

74-
def api_call(url, http_method, client):
75-
uri, headers, body = client.sign(url, http_method=http_method)
76-
resp = requests.request(http_method, uri, headers=headers, data=body)
77-
return resp.json()
78-
79-
def main():
80-
if os.path.isfile("oauth_client.pkl"):
81-
with open('oauth_client.pkl', 'rb') as oauth_pkl:
82-
client = pickle.load(oauth_pkl)
83-
else:
84-
client = get_client()
85-
86-
resp = api_call("https://secure.splitwise.com/api/v3.0/get_current_user", 'GET', client)
87-
my_id = resp['user']['id']
88-
89-
resp = api_call("https://secure.splitwise.com/api/v3.0/get_groups", 'GET', client)
90-
num_found = 0
91-
gid = ''
92-
members = {}
93-
94-
for group in resp['groups']:
95-
if group['name'].lower() == sys.argv[2].lower():
96-
gid = group['id']
97-
members = [m['id'] for m in group['members'] if m['id'] != my_id]
98-
num_found += 1
99-
100-
if num_found > 1:
101-
exit("More than 1 group found")
102-
elif num_found < 1:
103-
exit("No matching group")
104-
elif len(members) < 1:
105-
exit("No members in group")
106-
107-
with open(sys.argv[1], 'rb') as csvfile:
108-
reader = csv.reader(csvfile)
109-
rows = [x for x in reader]
110-
111-
112-
if os.path.isfile("csv_settings.pkl"):
113-
with open('csv_settings.pkl', 'rb') as f:
114-
date_col, amount_col, desc_col, has_title_row, local_currency, remember = pickle.load(f)
115-
116-
else:
117-
print "These are the first two rows of your csv"
118-
print '\n'.join([str(t) for t in rows[0:2]])
119-
print 'Colnum numbers start at 0'
120-
date_col = input("Which column has the date?")
121-
amount_col = input("Which column has the amount?")
122-
desc_col = input("Which column has the description?")
123-
has_title_row = raw_input("Does first row have titles? [Y/n]").lower() != 'n'
124-
local_currency = raw_input("What currency were these transactions made in?")
125-
test = Money("1.00", local_currency) #pylint: disable=W0612
126-
remember = raw_input("Remember these settings? [Y/n]").lower() != 'n'
127-
128-
if remember:
129-
with open("csv_settings.pkl", "wb") as pkl:
130-
csv_settings = (date_col, amount_col, desc_col, has_title_row, local_currency, remember)
131-
pickle.dump(csv_settings, pkl)
132-
133-
if has_title_row:
134-
rows = rows[1:]
135-
transactions = [{"date": datetime.strftime(datetime.strptime(r[date_col], "%m/%d/%y"), "%Y-%m-%dT%H:%M:%SZ"),
136-
"amount": -1 * Money(r[amount_col], local_currency),
137-
"desc": re.sub('\s+',' ', r[desc_col])}
138-
for r in rows if float(r[amount_col]) < 0]
139-
splits = []
140-
for t in transactions:
141-
if raw_input("%s at %s $%s. Split? [y/N]" % (t['date'], t['desc'], t['amount'])).lower() == 'y':
142-
splits.append(t)
143-
25+
class Splitwise:
26+
def __init__(self):
27+
if os.path.isfile("oauth_client.pkl"):
28+
with open('oauth_client.pkl', 'rb') as oauth_pkl:
29+
self.client = pickle.load(oauth_pkl)
30+
else:
31+
self.get_client()
32+
33+
def get_client_auth(self):
34+
if os.path.isfile("consumer_oauth.json"):
35+
with open("consumer_oauth.json", 'rb') as oauth_file:
36+
consumer = json.load(oauth_file)
37+
ckey = consumer['consumer_key']
38+
csecret = consumer['consumer_secret']
39+
else:
40+
with open("consumer_oauth.json", 'wb') as oauth_file:
41+
json.dump({'consumer_key':'YOUR KEY HERE',
42+
'consumer_secret':'YOUR SECRET HERE'}, oauth_file)
43+
exit("go to https://secure.splitwise.com/oauth_clients to obtain your keys."+
44+
"place them in consumer_oauth.json")
45+
self.ckey = ckey
46+
self.csecret = csecret
47+
48+
def get_client(self):
49+
self.get_client_auth()
50+
client = oauthlib.oauth1.Client(self.ckey, client_secret=self.csecret)
51+
uri, headers, body = client.sign("https://secure.splitwise.com/api/v3.0/get_request_token",
52+
http_method='POST')
53+
r = requests.post(uri, headers=headers, data=body)
54+
resp = r.text.split('&')
55+
oauth_token = resp[0].split('=')[1]
56+
oauth_secret = resp[1].split('=')[1]
57+
uri = "https://secure.splitwise.com/authorize?oauth_token=%s" % oauth_token
58+
59+
webbrowser.open_new(uri)
60+
61+
proc = subprocess.Popen(['python', 'server.py'], stdout=subprocess.PIPE)
62+
stdout, stderr = proc.communicate()
63+
if stderr:
64+
exit(stderr)
65+
client = oauthlib.oauth1.Client(self.ckey, client_secret=self.csecret,
66+
resource_owner_key=oauth_token,
67+
resource_owner_secret=oauth_secret,
68+
verifier=stdout.strip())
69+
70+
uri, headers, body = client.sign("https://secure.splitwise.com/api/v3.0/get_access_token",
71+
http_method='POST')
72+
resp = requests.post(uri, headers=headers, data=body)
73+
tokens = resp.text.split('&')
74+
oauth_token = tokens[0].split('=')[1]
75+
oauth_secret = tokens[1].split('=')[1]
76+
client = oauthlib.oauth1.Client(self.ckey, client_secret=self.csecret,
77+
resource_owner_key=oauth_token,
78+
resource_owner_secret=oauth_secret,
79+
verifier=stdout.strip())
80+
with open('oauth_client.pkl', 'wb') as pkl:
81+
pickle.dump(client, pkl)
82+
self.client = client
83+
84+
def api_call(self, url, http_method):
85+
uri, headers, body = self.client.sign(url, http_method=http_method)
86+
resp = requests.request(http_method, uri, headers=headers, data=body)
87+
return resp.json()
88+
89+
def get_id(self):
90+
if not hasattr(self, "my_id"):
91+
resp = self.api_call("https://secure.splitwise.com/api/v3.0/get_current_user", 'GET')
92+
self.my_id = resp['user']['id']
93+
return self.my_id
94+
95+
def get_groups(self):
96+
resp = self.api_call("https://secure.splitwise.com/api/v3.0/get_groups", 'GET')
97+
return resp['groups']
98+
99+
def post_expense(self, uri):
100+
resp = self.api_call(uri, 'POST')
101+
if resp["errors"]:
102+
print "URI:"
103+
print uri
104+
pprint(resp)
105+
else:
106+
sys.stdout.write(".")
107+
sys.stdout.flush()
144108

145-
print "Uploading %d splits" % len(splits)
146-
one_cent = Money("0.01", local_currency)
147-
for s in splits:
148-
num_people = len(members) + 1
109+
class SplitGenerator():
110+
def __init__(self, options, args, api):
111+
self.api = api
112+
csv_file = args[0]
113+
group_name = args[1]
114+
with open(csv_file, 'rb') as csvfile:
115+
reader = csv.reader(csvfile)
116+
self.rows = [x for x in reader]
117+
118+
119+
if os.path.isfile("csv_settings.pkl"):
120+
with open('csv_settings.pkl', 'rb') as f:
121+
self = pickle.load(f)
122+
123+
else:
124+
print "These are the first two rows of your csv"
125+
print '\n'.join([str(t) for t in self.rows[0:2]])
126+
print 'Colnum numbers start at 0'
127+
self.date_col = input("Which column has the date?")
128+
self.amount_col = input("Which column has the amount?")
129+
self.desc_col = input("Which column has the description?")
130+
self.has_title_row = raw_input("Does first row have titles? [Y/n]").lower() != 'n'
131+
self.local_currency = raw_input("What currency were these transactions made in?").upper()
132+
self.test = Money("1.00", self.local_currency) #pylint: disable=W0612
133+
self.remember = raw_input("Remember these settings? [Y/n]").lower() != 'n'
134+
135+
if self.remember:
136+
with open("csv_settings.pkl", "wb") as pkl:
137+
pickle.dump(self, pkl)
138+
139+
if self.has_title_row:
140+
self.rows = self.rows[1:]
141+
142+
self.make_transactions()
143+
self.get_group(group_name)
144+
self.splits = []
145+
self.ask_for_splits()
146+
147+
def make_transactions(self):
148+
self.transactions = [{"date": datetime.strftime(datetime.strptime(r[self.date_col], "%m/%d/%y"), "%Y-%m-%dT%H:%M:%SZ"),
149+
"amount": -1 * Money(r[self.amount_col], self.local_currency),
150+
"desc": re.sub('\s+',' ', r[self.desc_col])}
151+
for r in self.rows if float(r[self.amount_col]) < 0]
152+
153+
def get_group(self, name):
154+
num_found = 0
155+
gid = ''
156+
members = {}
157+
groups = self.api.get_groups()
158+
for group in groups:
159+
if group['name'].lower() == name.lower():
160+
gid = group['id']
161+
members = [m['id'] for m in group['members'] if m['id'] != self.api.get_id()]
162+
num_found += 1
163+
164+
if num_found > 1:
165+
exit("More than 1 group found")
166+
elif num_found < 1:
167+
exit("No matching group")
168+
elif len(members) < 1:
169+
exit("No members in group")
170+
171+
self.members = members
172+
self.gid = gid
173+
174+
def ask_for_splits(self):
175+
for t in self.transactions:
176+
if raw_input("%s at %s $%s. Split? [y/N]" % (t['date'], t['desc'], t['amount'])).lower() == 'y':
177+
self.splits.append(t)
178+
179+
def __getitem__(self, index):
180+
s = self.splits[index]
181+
one_cent = Money("0.01", self.local_currency)
182+
num_people = len(self.members) + 1
149183
base, extra = split(s['amount'], num_people)
150184
params = {
151185
"payment": 'false',
152186
"cost": s["amount"].amount,
153187
"description": s["desc"],
154188
"date": s["date"],
155-
"group_id": gid,
156-
"currency_code": local_currency,
157-
"users__0__user_id": my_id,
189+
"group_id": self.gid,
190+
"currency_code": self.local_currency,
191+
"users__0__user_id": self.api.get_id(),
158192
"users__0__paid_share": s["amount"].amount,
159193
"users__0__owed_share": base.amount,
160194
}
161-
for i in range(len(members)):
162-
params['users__%s__user_id' % (i+1)] = members[i]
195+
for i in range(len(self.members)):
196+
params['users__%s__user_id' % (i+1)] = sef.members[i]
163197
params['users__%s__paid_share' % (i+1)] = 0
164198
params['users__%s__owed_share' % (i+1)] = (base + one_cent).amount if extra else base.amount
165199
extra -= one_cent
166200
paramsStr = urllib.urlencode(params)
167-
uri = "https://secure.splitwise.com/api/v3.0/create_expense?%s" % (paramsStr)
168-
resp = api_call(uri, 'POST', client)
169-
if resp["errors"]:
170-
print "URI:"
171-
print uri
172-
pprint(resp)
173-
else:
174-
sys.stdout.write(".")
175-
sys.stdout.flush()
201+
return "https://secure.splitwise.com/api/v3.0/create_expense?%s" % (paramsStr)
202+
203+
204+
def main():
205+
parser = optparse.OptionParser()
206+
parser.add_option('-v', '--verbose', default=False, dest='verbose')
207+
options, args = parser.parse_args()
208+
splitwise = Splitwise()
209+
split_gen = SplitGenerator(options, args, splitwise)
210+
print "Uploading splits"
211+
for uri in split_gen:
212+
splitwise.post_expense(uri)
176213
sys.stdout.write("\n")
177214
sys.stdout.flush()
178215

0 commit comments

Comments
 (0)