class GetCurrentUserTestCase(unittest.TestCase): def setUp(self): self.sObj = Splitwise('consumerkey', 'consumersecret') def test_getCurrentUser_success(self, mockMakeRequest): mockMakeRequest.return_value = '{"user":{"id":12345,"first_name":"Naman","last_name":"Aggarwal","picture":{"small":"https://splitwise.s3.amazonaws.com/uploads/user/avatar/12345/small_mypic.jpg","medium":"https://splitwise.s3.amazonaws.com/uploads/user/avatar/12345/medium_mypic.jpg","large":"https://splitwise.s3.amazonaws.com/uploads/user/avatar/12345/large_mypic.jpg"},"custom_picture":true,"email":"*****@*****.**","registration_status":"confirmed","force_refresh_at":"2017-03-18T11:41:36Z","locale":"en","country_code":"IN","date_format":"MM/DD/YYYY","default_currency":"SGD","default_group_id":null,"notifications_read":"2020-06-10T14:12:01Z","notifications_count":8,"notifications":{"added_as_friend":true,"added_to_group":true,"expense_added":false,"expense_updated":false,"bills":true,"payments":true,"monthly_summary":true,"announcements":true}}}' # noqa: E501 user = self.sObj.getCurrentUser() mockMakeRequest.assert_called_with( "https://secure.splitwise.com/api/v3.0/get_current_user") self.assertEqual(user.getId(), 12345) self.assertEqual(user.getFirstName(), "Naman") self.assertEqual(user.getLastName(), "Aggarwal") self.assertEqual(user.getEmail(), "*****@*****.**") self.assertEqual( user.getPicture().getSmall(), "https://splitwise.s3.amazonaws.com/uploads/user/avatar/12345/small_mypic.jpg" ) self.assertEqual( user.getPicture().getMedium(), "https://splitwise.s3.amazonaws.com/uploads/user/avatar/12345/medium_mypic.jpg" ) self.assertEqual( user.getPicture().getLarge(), "https://splitwise.s3.amazonaws.com/uploads/user/avatar/12345/large_mypic.jpg" ) self.assertEqual(user.getRegistrationStatus(), "confirmed") def test_getCurrentUser_exception(self, mockMakeRequest): mockMakeRequest.side_effect = Exception( "Invalid response %s. Please check your consumer key and secret." % 404) with self.assertRaises(Exception): self.sObj.getCurrentUser() mockMakeRequest.assert_called_with( "https://secure.splitwise.com/api/v3.0/get_current_user")
def authorize(): if 'secret' not in session: return redirect(url_for("home")) oauth_token = request.args.get('oauth_token') oauth_verifier = request.args.get('oauth_verifier') sObj = Splitwise(consumer_key, secret_key) access_token = sObj.getAccessToken(oauth_token,session['secret'],oauth_verifier) session['access_token'] = access_token sObj.setAccessToken(session['access_token']) createGroup([[sObj.getCurrentUser().getFirstName(),sObj.getCurrentUser().getLastName(), sObj.getCurrentUser().getEmail()]], "The Room") return redirect(url_for("home"))
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)
def transaction(Description, Group, Payer, Price, Contributors): # price, date, description, group ID or this particular groups name, members sObj = Splitwise(consumer_key, secret_key) sObj.setAccessToken(session['access_token']) user = sObj.getCurrentUser() groups = sObj.getGroups() group_dict = {group.getName(): group for group in groups} importedData = {'Date': datetime.datetime.now(), 'Description': Description, 'Group': Group, 'Payer': Payer, 'Debit': Price} expense = Expense() price = float(importedData['Debit'] or 0) expense.setCost(price) expense.setDate(importedData['Date']) expense.setDescription(importedData['Description']) expense.setGroupId(group_dict[importedData['Group']].getId()) members = group_dict[importedData['Group']].getMembers() users = [] contributors = Contributors for member in members: if member.getFirstName() in contributors: user = ExpenseUser() user.setId(member.getId()) if member.getFirstName() == importedData['Payer']: user.setPaidShare(price) else: user.setPaidShare(0) users.append(user) paid = 0 share = round(price/len(users), 2) for user in users: user.setOwedShare(share) paid = paid + share diff = price - paid if diff != 0: user = random.choice(users) user.setOwedShare(share + diff) expense.setUsers(users) expense = sObj.createExpense(expense)
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())
class SplitwiseImporter: def __init__(self, Secrets): self.ynab_budget_id = Secrets.getSecret( 'splitwise.ynab_budget_id').strip() self.ynab_splitwise_account_id = Secrets.getSecret( 'splitwise.ynab_splitwise_account_id').strip() self.splitwise_group_names = Secrets.getSecret( 'splitwise.splitwise_group_names') self.dated_after = Secrets.getSecret( 'splitwise.import_dated_after') or None consumer_key = Secrets.getSecret('splitwise.consumer_key').strip() consumer_secret = Secrets.getSecret( 'splitwise.consumer_secret').strip() oauth_token = Secrets.getSecret('splitwise.oauth_token').strip() oauth_token_secret = Secrets.getSecret( 'splitwise.oauth_token_secret').strip() self.logger = logging.getLogger('splitwise') self.splitwise = Splitwise(consumer_key, consumer_secret) access_token = { 'oauth_token': oauth_token, 'oauth_token_secret': oauth_token_secret } self.splitwise.setAccessToken(access_token) self.currentUserId = self.splitwise.getCurrentUser().getId() self.spltiwise_group_double_map = {} groups = self.splitwise.getGroups() for g in groups: self.spltiwise_group_double_map[g.getId()] = g.getName() self.spltiwise_group_double_map[g.getName()] = g.getId() self.ynab_token = Secrets.getSecret("ynab_token").strip() self.ynabClient = YNAB(self.ynab_token) def generate_ynab_transaction(self, e): user = None for u in e.getUsers(): if u.getId() == self.currentUserId: user = u if not user: return {} memo_parts = [e.getDescription()] if e.getGroupId(): memo_parts.append( "splitwise-" + slugify(self.spltiwise_group_double_map[e.getGroupId()])) return TransactionRequest( self.ynab_splitwise_account_id, e.getDate(), int(float(user.getNetBalance()) * 1000), payee_name=(e.getDescription() if float(user.getNetBalance()) < 0 else "Splitwise Contribution"), memo=" ,".join(memo_parts), cleared="cleared", approved=False, import_id=e.getId()) def run(self): # expenses = self.splitwise.getExpenses(group_id=self.splitwise_group_id) transactions = [] if not len(self.splitwise_group_names): # None will get all groups self.splitwise_group_names = [None] for g in self.splitwise_group_names: # change group name to id if g: g = self.spltiwise_group_double_map[g] expenses = self.splitwise.getExpenses(dated_after=self.dated_after, group_id=g, limit=0) delta = 0 for e in expenses: if e.getDeletedAt(): continue transaction = self.generate_ynab_transaction(e) if transaction == {}: # self.logger.info("Got empty transaction for " + # e.getDescription()) continue transactions.append(transaction) delta += float(transaction.amount) if len(transactions): try: self.ynabClient.transactions.create_transactions( self.ynab_budget_id, transactions) self.logger.info("splitwise done") except Exception as e: self.logger.error( "Exception when calling ynab->create_transactions: %s\n" % e)