Exemplo n.º 1
0
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")
Exemplo n.º 2
0
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"))
Exemplo n.º 3
0
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)
Exemplo n.º 4
0
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)
Exemplo n.º 5
0
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())
Exemplo n.º 6
0
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)