Beispiel #1
0
def create_access_token(django_user, public_token):
    client = PlaidClient(client_id=client_id, secret=secret)
    resp = client.exchange_token(public_token)
    if resp.status_code != 200:
        logger.error(
            "Unable to exchange public token for access token for user {0}".
            format(django_user))
        return None

    # else "client.access_token" should now be populated with
    # a valid access_token for making authenticated requests

    # Get the plaid user for this django user; make one if nec.
    if not getattr(django_user, 'plaid_user', False):
        plaid_user = PlaidUser(user=django_user)
        plaid_user.save()

    plaid_user = django_user.plaid_user
    plaid_user.access_token = client.access_token
    plaid_user.save()
    return True
Beispiel #2
0
def test_exchange():
    client = Client('test_id', 'test_secret')
    response = client.exchange_token('test,chase,connected')
    assert response.status_code == 200
    assert to_json(response)['access_token'] == 'test_chase'
    assert client.access_token == 'test_chase'
Beispiel #3
0
def test_exchange():
    client = Client('test_id', 'test_secret')
    response = client.exchange_token('test,chase,connected')
    assert response.status_code == 200
    assert to_json(response)['access_token'] == 'test_chase'
    assert client.access_token == 'test_chase'
Beispiel #4
0
class PlaidClient:
    """
    A wrapper class around the Plaid API client.
    """

    def __init__(self, access_token=None):
        """
        Initializes an instance.

        NOTE: we don't use the Lazy pattern here because the Plaid Client caches access tokens between method calls.
        """

        self._client = Client(
            client_id=current_app.config['PLAID_CLIENT_ID'],
            secret=current_app.config['PLAID_SECRET'],
            access_token=access_token
        )

        self._client.config({
            'url': current_app.config['PLAID_URL']
        })

    def get_transactions(
        self,
        start: datetime.datetime=datetime.datetime.utcnow() - datetime.timedelta(days=30),
        end: datetime.datetime=datetime.datetime.utcnow(),
        pending=False,
        account_id=None
    ):
        """
        Retrieves transactions from the institution specified by the stored access token.

        Args:
            start: The start date for the transaction history set. Default one month before today.
            end: The end date for the transaction history set. Default today.
            pending: Whether or not to fetch pending transactions.
            account_id: If not None, will fetch transactions only from this account id.

        Returns:
            TODO, a dictionary for now.

        Raises:
            TODO
        """

        options = {
            'pending': pending,
            'gte': start.isoformat(),
            'end': end.isoformat(),
            'account': account_id
        }

        response = self._client.connect_get(options)
        return self._process_transactions(response)

    def delete_user(self):
        """
        Deletes the user associated with this client from Plaid's cache. They will have to log in again next time.
        """

        response = self._client.connect_delete()
        if not response.ok:
            raise exceptions.BadRequest('TODO: SOMETHING F****D UP')

    def exchange_token(self, public_token):
        """
        Exchanges the public_token returned by the Plaid Link module for a complete Plaid access token.
        """

        response = self._client.exchange_token(public_token)

        if not response.ok:
            raise exceptions.BadRequest('TODO: SOMETHING F****D UP')

        return response.json()['access_token']

    def _process_transactions(self, response):
        """
        Processes a response with data containing transactions from Plaid to be in a specific format.

        Args:
            response: A response from plaid.Client.

        Returns:
            TODO

        Raises:
            TODO
        """

        if not response.ok:
            raise exceptions.BadRequest('TODO: SOMETHING F****D UP')

        response_json = response.json()

        transactions = [
            {
                '_id': transaction['_id'],
                '_account': transaction['_account'],
                'date': self._process_transaction_date(transaction['date']),
                'amount': transaction['amount'],
                'name': self._process_transaction_name(transaction['name']),
                'pending': transaction['pending']
            }
            for transaction
            in response_json['transactions']
        ]

        return transactions

    @staticmethod
    def _process_transaction_name(name):
        """
        Prettify the names of transactions.

        TODO: Should we do this at all, or send whatever we get from Plaid?
        """
        return titlecase(name)

    @staticmethod
    def _process_transaction_date(date):
        """Converts `date` from YYYY-MM-DD to epoch time."""
        return datetime.datetime.strptime(date, '%Y-%m-%d')
Beispiel #5
0
class PlaidAPI():
    client_id = '554e702a0effc0670b8c9454'
    public_key = '341f751f231458d8f651e072dd3184'
    secret = '09a1032a267857c25718ff0fdc102b'
    env = 'tartan'
    if (False):
        client_id = 'test_id'
        secret = 'test_secret'

    def exchangeLinkTokenForAccount(self, user, public_token):
        Client.config({
            'url': 'https://tartan.plaid.com'
        })
        print('creating client')
        self.client = Client(client_id=PlaidAPI.client_id,
                             secret=PlaidAPI.secret)
        print('getting response')
        response = self.client.exchange_token(public_token)
        print('response')
        print(response)
        access_token = self.client.access_token
        print("Access token {0}".format(access_token))

        ##create account and store in db
        plaiduser = PlaidUserToken()  # is there a good constructor syntax?
        plaiduser.user = user
        plaiduser.access_token = access_token
        plaiduser.status = 'new'
        plaiduser.status_text = "Created {0}".format(timezone.now())
        plaiduser.save()
        print('saved')
        return plaiduser

    def getTransactions(self, usertoken):
        # retrive transactions from a plaid usertoken
        # @todo:  need to specifiy retrieval since day X ago
        self.client = Client(client_id=PlaidAPI.client_id,
                             secret=PlaidAPI.secret,
                             access_token=usertoken.access_token)
        response = self.client.connect_get()
        print('parsing response')
        json_data = json.loads(response.content.decode('utf-8'))

        ##load in the accounts
        json_accounts = json_data['accounts']
        for a in json_accounts:
            account = PlaidAccount.objects.filter(_id=a['_id'].encode('utf-8'))
            if account:
                account=account.get()
                created='updated'
            else:
                account = PlaidAccount()
                created='created'

            account.usertoken = usertoken
            account._id = a['_id'].encode('utf-8')
            account._item = a['_item'].encode('utf-8')
            account._user = a['_user'].encode('utf-8')
            account.name = a['meta']['name'].encode('utf-8')
            account.type = a['type']
            account.institution_type = a['institution_type'].encode('utf-8')
            account.save()


            #tmp_id = unicodedata.normalize('NFKD', account._id).encode('ascii','ignore')
            #tmp_name = line = unicodedata.normalize('NFKD', account.name).encode('ascii','ignore')
            print("{0} account: {1} id: {2}".format(created,account.name, account._id) )

        ##Load in the accounts
        json_transactions = json_data['transactions']
        new_transaction_list=[]
        for t in json_transactions:
            transaction = PlaidTransaction.objects.filter(_id=t['_id'].encode('utf-8'))
            if transaction:
                transaction=transaction.get()
                created='updated'
            else:
                transaction = PlaidTransaction()
                created='created'
                transaction.state=PlaidTransaction.STATE_NEW
                new_transaction_list.append(transaction)

            transaction.usertoken = usertoken
            transaction._id = t['_id'].encode('utf-8')
            transaction._account = t['_account'].encode('utf-8')
            transaction.account=PlaidAccount.objects.filter(_id=t['_account'].encode('utf-8')).get()
            transaction.amount = t['amount']
            transaction.name = t['name'].encode('utf-8')
            transaction.date = t['date']
            transaction.type = t['type']
            if 'category' in t:
                transaction.category = t['category']
            if 'meta' in t:
                transaction.meta = t['meta']
                transaction.meta_score = t['score']

            transaction.save()
            print("{0} tx: {1} {2} ".format(created,transaction.date,transaction.name) )

        # update the user token

        usertoken.status_text = "Synced on {0}. Retrieved {1} accounts and {2} transactions ({3} new)".format(timezone.now(),len(json_accounts),len(json_transactions),len(new_transaction_list))
        usertoken.last_sync = timezone.now()
        usertoken.save()
        return new_transaction_list