def share_expense_with_group_members(sw: Splitwise, desc, cost, group_id, date): grp = sw.getGroup(group_id) current_user = sw.getCurrentUser() other_members = [m for m in grp.getMembers() if m.id != current_user.id] _debug(current_user) _debug(other_members) cost_per_user = round(cost / len(grp.members), 2) expense = Expense() expense.cost = f"{cost}" expense.description = f"{desc}" expense.group_id = f"{group_id}" expense.setDate(date.strftime("%Y/%m/%d")) users = [] for om in other_members: user = ExpenseUser() user.setId(om.id) user.setPaidShare(f"0") user.setOwedShare(f"{cost_per_user}") users.append(user) user = ExpenseUser() user.setId(current_user.id) user.setPaidShare(f"{cost}") user.setOwedShare(f"{cost - len(users) * cost_per_user}") users.append(user) expense.users = users sw.createExpense(expense)
class GetCategoriesTestCase(unittest.TestCase): def setUp(self): self.sObj = Splitwise('consumerkey', 'consumersecret') def test_getGroup_default_group_success(self, mockMakeRequest): mockMakeRequest.return_value = '{"group":{"id":0,"name":"Non-group expenses","created_at":"2012-08-21T16:11:14Z","updated_at":"2020-06-23T09:42:10Z","members":[{"id":79774,"first_name":"Naman","last_name":"Aggarwal","picture":{"small":"https://splitwise.s3.amazonaws.com/uploads/user/avatar/79774/small_mypic.jpg","medium":"https://splitwise.s3.amazonaws.com/uploads/user/avatar/79774/medium_mypic.jpg","large":"https://splitwise.s3.amazonaws.com/uploads/user/avatar/79774/large_mypic.jpg"},"custom_picture":true,"email":"*****@*****.**","registration_status":"confirmed","balance":[{"amount":"115000.0","currency_code":"INR"},{"amount":"2162.82","currency_code":"SGD"}]}],"simplify_by_default":false,"original_debts":[{"to":79774,"from":18145926,"amount":"115000.0","currency_code":"INR"},{"to":79774,"from":784241,"amount":"2162.82","currency_code":"SGD"}],"simplified_debts":[{"to":79774,"from":18145926,"amount":"115000.0","currency_code":"INR"},{"to":79774,"from":784241,"amount":"2162.82","currency_code":"SGD"}],"avatar":{"original":null,"xxlarge":"https://s3.amazonaws.com/splitwise/uploads/group/default_avatars/avatar-nongroup-1000px.png","xlarge":"https://s3.amazonaws.com/splitwise/uploads/group/default_avatars/avatar-nongroup-500px.png","large":"https://s3.amazonaws.com/splitwise/uploads/group/default_avatars/avatar-nongroup-200px.png","medium":"https://s3.amazonaws.com/splitwise/uploads/group/default_avatars/avatar-nongroup-100px.png","small":"https://s3.amazonaws.com/splitwise/uploads/group/default_avatars/avatar-nongroup-50px.png"},"custom_avatar":false,"cover_photo":{"xxlarge":"https://s3.amazonaws.com/splitwise/uploads/group/default_cover_photos/coverphoto-nongroup-1000px.png","xlarge":"https://s3.amazonaws.com/splitwise/uploads/group/default_cover_photos/coverphoto-nongroup-500px.png"}}}' # noqa: E501 group = self.sObj.getGroup() mockMakeRequest.assert_called_with( "https://secure.splitwise.com/api/v3.0/get_group/0") self.assertEqual(group.getId(), 0) self.assertEqual(group.getName(), "Non-group expenses") self.assertEqual(group.getUpdatedAt(), "2020-06-23T09:42:10Z") self.assertEqual(len(group.getMembers()), 1) self.assertEqual(group.getMembers()[0].getId(), 79774) self.assertEqual(group.getMembers()[0].getFirstName(), "Naman") self.assertEqual(group.getMembers()[0].getLastName(), "Aggarwal") self.assertEqual( group.getMembers()[0].getPicture().getSmall(), "https://splitwise.s3.amazonaws.com/uploads/user/avatar/79774/small_mypic.jpg" ) self.assertEqual( group.getMembers()[0].getPicture().getMedium(), "https://splitwise.s3.amazonaws.com/uploads/user/avatar/79774/medium_mypic.jpg" ) self.assertEqual( group.getMembers()[0].getPicture().getLarge(), "https://splitwise.s3.amazonaws.com/uploads/user/avatar/79774/large_mypic.jpg" ) self.assertEqual(group.getMembers()[0].getEmail(), "*****@*****.**") self.assertEqual(group.getMembers()[0].getRegistrationStatus(), "confirmed") self.assertEqual(len(group.getMembers()[0].getBalances()), 2) self.assertEqual(group.getMembers()[0].getBalances()[0].getAmount(), "115000.0") self.assertEqual( group.getMembers()[0].getBalances()[0].getCurrencyCode(), "INR") self.assertEqual(group.getMembers()[0].getBalances()[1].getAmount(), "2162.82") self.assertEqual( group.getMembers()[0].getBalances()[1].getCurrencyCode(), "SGD") self.assertEqual(len(group.getOriginalDebts()), 2) self.assertEqual(group.getOriginalDebts()[0].getToUser(), 79774) self.assertEqual(group.getOriginalDebts()[0].getFromUser(), 18145926) self.assertEqual(group.getOriginalDebts()[0].getAmount(), "115000.0") self.assertEqual(group.getOriginalDebts()[0].getCurrencyCode(), "INR") self.assertEqual(group.getOriginalDebts()[1].getToUser(), 79774) self.assertEqual(group.getOriginalDebts()[1].getFromUser(), 784241) self.assertEqual(group.getOriginalDebts()[1].getAmount(), "2162.82") self.assertEqual(group.getOriginalDebts()[1].getCurrencyCode(), "SGD") self.assertEqual(len(group.getSimplifiedDebts()), 2) self.assertEqual(group.getSimplifiedDebts()[0].getToUser(), 79774) self.assertEqual(group.getSimplifiedDebts()[0].getFromUser(), 18145926) self.assertEqual(group.getSimplifiedDebts()[0].getAmount(), "115000.0") self.assertEqual(group.getSimplifiedDebts()[0].getCurrencyCode(), "INR") self.assertEqual(group.getSimplifiedDebts()[1].getToUser(), 79774) self.assertEqual(group.getSimplifiedDebts()[1].getFromUser(), 784241) self.assertEqual(group.getSimplifiedDebts()[1].getAmount(), "2162.82") self.assertEqual(group.getSimplifiedDebts()[1].getCurrencyCode(), "SGD") # self.assertEqual(group.getAvatar().getOriginal(), None) # self.assertEqual(group.getAvatar().getXxlarge(), # "https://s3.amazonaws.com/splitwise/uploads/group/default_avatars/avatar-nongroup-1000px.png") # self.assertEqual(group.getAvatar().getXlarge(), # "https://s3.amazonaws.com/splitwise/uploads/group/default_avatars/avatar-nongroup-500px.png") # self.assertEqual(group.getAvatar().getLarge(), # "https://s3.amazonaws.com/splitwise/uploads/group/default_avatars/avatar-nongroup-200px.png") # self.assertEqual(group.getAvatar().getMedium(), # "https://s3.amazonaws.com/splitwise/uploads/group/default_avatars/avatar-nongroup-100px.png") # self.assertEqual(group.getAvatar().getSmall(), # "https://s3.amazonaws.com/splitwise/uploads/group/default_avatars/avatar-nongroup-50px.png") # self.assertEqual(group.getCoverPhoto().getXxlarge(), # "https://s3.amazonaws.com/splitwise/uploads/group/default_cover_photos/coverphoto-nongroup-1000px.png") # self.assertEqual(group.getCoverPhoto().getXlarge(), # "https://s3.amazonaws.com/splitwise/uploads/group/default_cover_photos/coverphoto-nongroup-500px.png") def test_getGroup_success(self, mockMakeRequest): mockMakeRequest.return_value = '{"group":{"id":10843533,"name":"Flatmates Again","created_at":"2019-01-01T06:01:57Z","updated_at":"2020-06-23T09:33:38Z","members":[{"id":79774,"first_name":"Naman","last_name":"Aggarwal","picture":{"small":"https://splitwise.s3.amazonaws.com/uploads/user/avatar/79774/small_mypic.jpg","medium":"https://splitwise.s3.amazonaws.com/uploads/user/avatar/79774/medium_mypic.jpg","large":"https://splitwise.s3.amazonaws.com/uploads/user/avatar/79774/large_mypic.jpg"},"custom_picture":true,"email":"*****@*****.**","registration_status":"confirmed","balance":[{"currency_code":"SGD","amount":"-14.2"}]},{"id":281236,"first_name":"Siddharth","last_name":"Goel","picture":{"small":"https://splitwise.s3.amazonaws.com/uploads/user/avatar/281236/small_f5fccc37-0a88-4519-9398-59c8c19b92aa.jpeg","medium":"https://splitwise.s3.amazonaws.com/uploads/user/avatar/281236/medium_f5fccc37-0a88-4519-9398-59c8c19b92aa.jpeg","large":"https://splitwise.s3.amazonaws.com/uploads/user/avatar/281236/large_f5fccc37-0a88-4519-9398-59c8c19b92aa.jpeg"},"custom_picture":true,"email":"*****@*****.**","registration_status":"confirmed","balance":[{"currency_code":"SGD","amount":"975.05"}]},{"id":643871,"first_name":"Shantanu","last_name":"Alshi","picture":{"small":"https://s3.amazonaws.com/splitwise/uploads/user/default_avatars/avatar-blue19-50px.png","medium":"https://s3.amazonaws.com/splitwise/uploads/user/default_avatars/avatar-blue19-100px.png","large":"https://s3.amazonaws.com/splitwise/uploads/user/default_avatars/avatar-blue19-200px.png"},"custom_picture":false,"email":"*****@*****.**","registration_status":"confirmed","balance":[{"currency_code":"SGD","amount":"-960.85"}]},{"id":784241,"first_name":"ruks","last_name":null,"picture":{"small":"https://s3.amazonaws.com/splitwise/uploads/user/default_avatars/avatar-ruby47-50px.png","medium":"https://s3.amazonaws.com/splitwise/uploads/user/default_avatars/avatar-ruby47-100px.png","large":"https://s3.amazonaws.com/splitwise/uploads/user/default_avatars/avatar-ruby47-200px.png"},"custom_picture":false,"email":"*****@*****.**","registration_status":"confirmed","balance":[{"currency_code":"SGD","amount":"0.0"}]}],"simplify_by_default":true,"original_debts":[{"from":281236,"to":79774,"amount":"2307.23","currency_code":"SGD"},{"currency_code":"SGD","from":79774,"to":643871,"amount":"2311.77"},{"currency_code":"SGD","from":79774,"to":784241,"amount":"9.66"},{"from":643871,"to":281236,"amount":"2520.67","currency_code":"SGD"},{"from":784241,"to":281236,"amount":"761.61","currency_code":"SGD"},{"currency_code":"SGD","from":643871,"to":784241,"amount":"751.95"}],"simplified_debts":[{"from":79774,"to":281236,"amount":"14.2","currency_code":"SGD"},{"from":643871,"to":281236,"amount":"960.85","currency_code":"SGD"}],"whiteboard":null,"group_type":"apartment","invite_link":"https://www.splitwise.com/join/d7bsHriQF5A+1pjy","avatar":{"original":"https://splitwise.s3.amazonaws.com/uploads/group/avatar/10843533/a3734b4d-817e-42f4-9763-8001b12e33b8.jpeg","xxlarge":"https://splitwise.s3.amazonaws.com/uploads/group/avatar/10843533/xxlarge_a3734b4d-817e-42f4-9763-8001b12e33b8.jpeg","xlarge":"https://splitwise.s3.amazonaws.com/uploads/group/avatar/10843533/xlarge_a3734b4d-817e-42f4-9763-8001b12e33b8.jpeg","large":"https://splitwise.s3.amazonaws.com/uploads/group/avatar/10843533/large_a3734b4d-817e-42f4-9763-8001b12e33b8.jpeg","medium":"https://splitwise.s3.amazonaws.com/uploads/group/avatar/10843533/medium_a3734b4d-817e-42f4-9763-8001b12e33b8.jpeg","small":"https://splitwise.s3.amazonaws.com/uploads/group/avatar/10843533/small_a3734b4d-817e-42f4-9763-8001b12e33b8.jpeg"},"custom_avatar":true,"cover_photo":{"xxlarge":"https://splitwise.s3.amazonaws.com/uploads/group/avatar/10843533/xxlarge_a3734b4d-817e-42f4-9763-8001b12e33b8.jpeg","xlarge":"https://splitwise.s3.amazonaws.com/uploads/group/avatar/10843533/xlarge_a3734b4d-817e-42f4-9763-8001b12e33b8.jpeg"}}}' # noqa: E501 group = self.sObj.getGroup(10843533) mockMakeRequest.assert_called_with( "https://secure.splitwise.com/api/v3.0/get_group/10843533") self.assertEqual(group.getId(), 10843533) self.assertEqual(group.getName(), "Flatmates Again") # self.assertEqual(group.getCreatedAt(), "2019-01-01T06:01:57Z") self.assertEqual(group.getUpdatedAt(), "2020-06-23T09:33:38Z") self.assertEqual(len(group.getMembers()), 4) self.assertEqual(group.getMembers()[0].getId(), 79774) self.assertEqual(group.getMembers()[0].getFirstName(), "Naman") self.assertEqual(group.getMembers()[0].getLastName(), "Aggarwal") self.assertEqual( group.getMembers()[0].getPicture().getSmall(), "https://splitwise.s3.amazonaws.com/uploads/user/avatar/79774/small_mypic.jpg" ) self.assertEqual( group.getMembers()[0].getPicture().getMedium(), "https://splitwise.s3.amazonaws.com/uploads/user/avatar/79774/medium_mypic.jpg" ) self.assertEqual( group.getMembers()[0].getPicture().getLarge(), "https://splitwise.s3.amazonaws.com/uploads/user/avatar/79774/large_mypic.jpg" ) self.assertEqual(group.getMembers()[0].getEmail(), "*****@*****.**") self.assertEqual(group.getMembers()[0].getRegistrationStatus(), "confirmed") self.assertEqual(len(group.getMembers()[0].getBalances()), 1) self.assertEqual( group.getMembers()[0].getBalances()[0].getCurrencyCode(), "SGD") self.assertEqual(group.getMembers()[0].getBalances()[0].getAmount(), "-14.2") self.assertEqual(group.getMembers()[1].getId(), 281236) self.assertEqual(group.getMembers()[1].getFirstName(), "Siddharth") self.assertEqual(group.getMembers()[1].getLastName(), "Goel") self.assertEqual( group.getMembers()[1].getPicture().getSmall(), "https://splitwise.s3.amazonaws.com/uploads/user/avatar/281236/small_f5fccc37-0a88-4519-9398-59c8c19b92aa.jpeg" ) self.assertEqual( group.getMembers()[1].getPicture().getMedium(), "https://splitwise.s3.amazonaws.com/uploads/user/avatar/281236/medium_f5fccc37-0a88-4519-9398-59c8c19b92aa.jpeg" ) self.assertEqual( group.getMembers()[1].getPicture().getLarge(), "https://splitwise.s3.amazonaws.com/uploads/user/avatar/281236/large_f5fccc37-0a88-4519-9398-59c8c19b92aa.jpeg" ) self.assertEqual(group.getMembers()[1].getEmail(), "*****@*****.**") self.assertEqual(group.getMembers()[1].getRegistrationStatus(), "confirmed") self.assertEqual(len(group.getMembers()[1].getBalances()), 1) self.assertEqual( group.getMembers()[1].getBalances()[0].getCurrencyCode(), "SGD") self.assertEqual(group.getMembers()[1].getBalances()[0].getAmount(), "975.05") self.assertEqual(group.getMembers()[2].getId(), 643871) self.assertEqual(group.getMembers()[2].getFirstName(), "Shantanu") self.assertEqual(group.getMembers()[2].getLastName(), "Alshi") self.assertEqual( group.getMembers()[2].getPicture().getSmall(), "https://s3.amazonaws.com/splitwise/uploads/user/default_avatars/avatar-blue19-50px.png" ) self.assertEqual( group.getMembers()[2].getPicture().getMedium(), "https://s3.amazonaws.com/splitwise/uploads/user/default_avatars/avatar-blue19-100px.png" ) self.assertEqual( group.getMembers()[2].getPicture().getLarge(), "https://s3.amazonaws.com/splitwise/uploads/user/default_avatars/avatar-blue19-200px.png" ) self.assertEqual(group.getMembers()[2].getEmail(), "*****@*****.**") self.assertEqual(group.getMembers()[2].getRegistrationStatus(), "confirmed") self.assertEqual(len(group.getMembers()[2].getBalances()), 1) self.assertEqual( group.getMembers()[2].getBalances()[0].getCurrencyCode(), "SGD") self.assertEqual(group.getMembers()[2].getBalances()[0].getAmount(), "-960.85") self.assertEqual(group.getMembers()[3].getId(), 784241) self.assertEqual(group.getMembers()[3].getFirstName(), "ruks") self.assertEqual(group.getMembers()[3].getLastName(), None) self.assertEqual( group.getMembers()[3].getPicture().getSmall(), "https://s3.amazonaws.com/splitwise/uploads/user/default_avatars/avatar-ruby47-50px.png" ) self.assertEqual( group.getMembers()[3].getPicture().getMedium(), "https://s3.amazonaws.com/splitwise/uploads/user/default_avatars/avatar-ruby47-100px.png" ) self.assertEqual( group.getMembers()[3].getPicture().getLarge(), "https://s3.amazonaws.com/splitwise/uploads/user/default_avatars/avatar-ruby47-200px.png" ) def test_getGroup_exception(self, mockMakeRequest): mockMakeRequest.side_effect = Exception( "Invalid response %s. Please check your consumer key and secret." % 404) with self.assertRaises(Exception): self.sObj.getGroup(123) mockMakeRequest.assert_called_with( "https://secure.splitwise.com/api/v3.0/get_group/123")
class SplitwiseInterface: def __init__(self): self.consumer_key = getConsumerKey() self.consumer_secret = getConsumerSecret() self.oauth_verifier = None self.oauth_token = None self.access_token = getAccessToken() self.login_secret = None self.url = None self.sObj = Splitwise(self.consumer_key, self.consumer_secret) self.sObj.setAccessToken(self.access_token) def accessCheck(self) -> None: """ Checks for access token. Starts login process if not """ if self.access_token: return self.access_token = self.login() def login(self) -> None: """ Logs into Splitwise. Requires manually entering the token and verifier """ sObj = Splitwise(self.consumer_key, self.consumer_secret) self.url, self.login_secret = sObj.getAuthorizeURL() print(self.url) self.oauth_token = input('token: ') self.oauth_verifier = input('verifier: ') def authorize(self) -> None: """ Authorizes app to Splitwise """ if not self.login_secret: #TODO trigger error self.login() sObj = Splitwise(self.consumer_key, self.consumer_secret) self.access_token = sObj.getAccessToken(self.oauth_token, self.login_secret, self.oauth_verifier) def friends(self) -> List['Friend']: """ Returns list of Friend objects for the current user """ return self.sObj.getFriends() def getCurrentUser(self) -> 'CurrentUser': """ Returns CurrentUser object for the current user """ return self.sObj.getCurrentUser() def getGroup(self, group_id: int) -> 'Group': """ Returns Group object for the given group_id """ return self.sObj.getGroup(group_id) def getGroupMemberIDs(self, group: 'Group') -> Dict[str, int]: """ Returns a dict of group members {name:id} from a given Group object """ member_object_list = group.getMembers() member_dict = {} for member in member_object_list: member_dict[member.getFirstName()] = member.getId() return member_dict def addExpense(self, cost: float, description: str, group_id: int, payer: str) -> None: """ Adds expense to Splitwise group. If expenses don't evenly get distributed, it will randomly assign pennies to even things off """ expense = Expense() expense.setCost(str(cost)) expense.setDescription(description) expense.setGroupId(group_id) group = self.sObj.getGroup(group_id) member_dict = self.getGroupMemberIDs(group) member_count = len(member_dict) per_person_cost = round(cost / member_count, 2) expense_members = [] print(per_person_cost * member_count, cost) for member in member_dict: expense_user = ExpenseUser() expense_user.setId(member_dict[member]) expense_user.setFirstName(member) expense_user.setOwedShare(str(per_person_cost)) if member == payer: expense_user.setPaidShare(cost) else: expense_user.setPaidShare('0.00') expense_members.append(expense_user) if cost < per_person_cost * member_count: remainder = (per_person_cost * float(member_count)) - cost shuffle(expense_members) i = 0 while remainder > 0.00: owed = float(expense_members[i].getOwedShare()) owed -= 0.01 expense_members[i].setOwedShare(str(owed)) remainder -= 0.01 if i == member_count - 1: i = 0 else: i += 1 elif cost > per_person_cost * member_count: remainder = round(cost - (per_person_cost * float(member_count)), 2) print(remainder) shuffle(expense_members) i = 0 while remainder > 0.00: owed = float(expense_members[i].getOwedShare()) owed += 0.01 expense_members[i].setOwedShare(str(owed)) remainder -= 0.01 if i == member_count - 1: i = 0 else: i += 1 expense.setUsers(expense_members) expenses = self.sObj.createExpense(expense) print('Successfully added to Splitwise. Expense ID:', expenses.getId())
import json from splitwise import Splitwise import config import utils from excel import generate_expenses_xlsx import yacht_expense_details s = Splitwise(config.consumer_key, config.consumer_secret, api_key=config.API_key) utils.create_folder(config.json_filename) expenses = s.getExpenses(group_id=config.group_id, limit=config.expenses_list_limit) group = s.getGroup(id=config.group_id) members_json = group.__dict__['members'] members_array = json.loads( json.dumps(members_json, default=lambda o: o.__dict__, ensure_ascii=False)) def expenses_to_json(expenses): expenses_array = [] for expense in expenses: comments = s.getComments(expense.id) js = json.loads( json.dumps(expense.__dict__, default=lambda o: o.__dict__, ensure_ascii=False)) js['comments'] = json.loads( json.dumps(comments, default=lambda o: o.__dict__, ensure_ascii=False))