Beispiel #1
0
class PlaidApi:
    """
    Documentation for Plaid API:
    https://plaid.github.io/plaid-python/index.html
    https://github.com/plaid/plaid-python
    """

    def __init__(self):
        env = settings.PLAID_ENV
        if env not in ['production', 'development', 'sandbox']:
            raise ValueError('Incorrect value for PLAID_ENV in settings.')

        self.client = Client(
            client_id=settings.PLAID_CLIENT_ID,
            secret=settings.PLAID_SECRET,
            public_key=settings.PLAID_PUBLIC_KEY,
            environment=env)

    @catch_exception
    def create_item(
            self, username, password, institution_plaid_id,
            initial_products=None):
        """
        Used for tests in sandbox environment.
        In development and production mode Items created
        by Plaid Link via frontend.
        """
        if initial_products is None:
            initial_products = ['transactions', 'auth']
        api_data = self.client.Item.create(
            credentials=dict(username=username, password=password),
            institution_id=institution_plaid_id,
            initial_products=initial_products,
            webhook='https://example.com/webhook')
        d = api_data['item']
        d['access_token'] = api_data['access_token']
        return d

    def get_item(self, access_token):
        api_data = self.client.Item.get(access_token)
        d = api_data['item']
        d['request_id'] = api_data['request_id']
        d['access_token'] = access_token
        return d

    def delete_item(self, access_token):
        self.client.Item.delete(access_token)

    def get_categories(self):
        return self.client.Categories.get()

    def get_institutions(self, count, offset=0):
        """
        Example response:
        {
            'total': 9147,
            'request_id': 'U7KD1',
            'institutions': [
                {
                    'has_mfa': True,
                    'name': 'Bank of America',
                    'credentials': [
                        {
                            'type': 'text',
                            'label': 'Online ID',
                            'name': 'username'
                        },
                        {
                            'type': 'password',
                            'label': 'Password',
                            'name': 'password'
                        }
                    ],
                    'products': ['auth', 'balance'],
                    'institution_id': 'ins_1',
                    'mfa': ['questions(3)']
                },
                ...
            ]
        }
        """
        return self.client.Institutions.get(count, offset)

    def get_institution(self, plaid_id):
        d = self.client.Institutions.get_by_id(plaid_id)
        return d['institution']

    def get_accounts(self, access_token):
        """
        Returns accounts for particular item.
        """
        return self.client.Accounts.get(access_token)

    def get_accounts_info(self, access_token):
        """
        Returns extended accounts with account's numbers.
        """
        return self.client.Auth.get(access_token)

    def get_balances(self, access_token):
        """
        Returns accounts with balances.
        """
        return self.client.Accounts.balance.get(access_token)

    def create_public_token(self, access_token):
        """
        Returns public_token (string).
        """
        d = self.client.Item.public_token.create(access_token)
        return d['public_token']

    def create_dwolla_processor_token(self, access_token, account_id):
        """
        Create processor token
        """
        url = settings.DWOLLA_PROCESSOR_TOKEN_CREATE
        dwolla_token = self.client.post(url,
                                        {"client_id": settings.PLAID_CLIENT_ID,
                                         "secret": settings.PLAID_SECRET,
                                         "access_token": access_token,
                                         "account_id": account_id})
        processor_token = dwolla_token['processor_token']

        return processor_token

    def exchange_public_token(self, user, public_token):
        """
        Frontend Link returns public_token.
        We need to exchange it for access token.
        Returns access_token (string).
        """
        exchange_token_response = self.client.Item.public_token.exchange(
            public_token
        )

        return exchange_token_response['access_token']

    def rotate_access_token(self, access_token):
        """
        Updates access token.
        Returns access_token (string).
        """
        d = self.client.Item.access_token.invalidate(access_token)
        return d['new_access_token']

    def get_stripe_token(self, access_token, account_id):
        d = self.client.Processor.stripeBankAccountTokenCreate(
            access_token, account_id)
        return d['stripe_bank_account_token']

    def update_webhook(self, access_token, webhook):
        self.client.update(access_token, webhook)

    def get_identity(self, access_token):
        """
        Requires additional permissions.
        In Sandbox raises error.
        """
        return self.client.Identity.get(access_token)

    def get_income(self, access_token):
        """
        Requires additional permissions.
        In Sandbox raises error.
        """
        return self.client.Income.get(access_token)

    def get_credit_details(self, access_token):
        """
        Requires additional permissions.
        In Sandbox raises error.
        """
        return self.client.CreditDetails.get(access_token)

    def reset_login(self, access_token):
        """
        Sandbox only.
        Put an item into an ITEM_LOGIN_REQUIRED error state.
        """
        self.client.Sandbox.item.reset_login(access_token)

    def get_transactions(self, access_token, start_date=None, end_date=None):
        """
        If start_date is None: set 2 weeks ago.
        If end_date is None: set today.

        "start_date" and "end_date" can be passed as
        Date or DateTime objects.

        If transactions are not ready yet, raises ItemError.
        """
        if start_date is None:
            start_date = datetime.date.today() - datetime.timedelta(days=14)

        if end_date is None:
            end_date = datetime.date.today()

        start_date = start_date.strftime('%Y-%m-%d')
        end_date = end_date.strftime('%Y-%m-%d')

        while True:
            try:
                d = self.client.Transactions.get(
                    access_token, start_date=start_date, end_date=end_date)
                break
            except PlaidError as e:
                if e.code == 'PRODUCT_NOT_READY':
                    print('Transactions not ready')
                    time.sleep(20)
                    continue
                raise Exception(e)
        transactions = d['transactions']

        while len(transactions) < d['total_transactions']:
            d = self.client.Transactions.get(
                access_token,
                start_date=start_date,
                end_date=end_date,
                offset=len(transactions)
            )
            transactions.extend(d['transactions'])
        return transactions