def test_institution(): client = Client('test_id', 'test_secret') response = client.institution( to_json(client.institutions())[0]['id'] ) assert response.status_code == 200
def connect(plaid_credentials, bank, bank_credentials): client = Client(client_id=plaid_credentials.client_id, secret=plaid_credentials.secret) try: response = client.connect(bank, { 'username': bank_credentials.username, 'password': bank_credentials.password }) data = json.loads(response.content) if response.status_code == 200: print data if "access_token" in data: client_access_token = data["access_token"] client = Client(client_id=plaid_credentials.client_id, secret=plaid_credentials.secret, access_token=client_access_token) response = client.connect_get() data = json.loads(response.content) with open("tx.json", "w") as f: f.write(json.dumps(data)) else: print "Something went horribly wrong..." print data except plaid_errors.UnauthorizedError as e: # handle this print e
class Plaid: def __init__(self, clientId, clientSecret, accessToken=None): self.client = Client(client_id=clientId, secret=clientSecret, access_token=accessToken) def connect(self, accountType, username, password, email): connect = self.client.connect(account_type=accountType, username=username, password=password, email=email) if connect.ok: json_response = json.loads(connect.content) return json_response; def answerMFA(self, accountType, mfaAnswer): step = self.client.step(account_type=accountType, mfa=mfaAnswer) if step.ok: transactions = json.loads(step.content) return transactions def getTransactions(self, options=None): transactions = self.client.transactions(options) if transactions.ok: transactions = json.loads(transactions.content) return transactions def delete(self): self.client.delete_user()
def tool_bank(): user = g.user client = Client(client_id='test_id', secret='test_secret') connect = client.connect(account_type='wells', username='******', password='******', email='*****@*****.**') if connect.ok: step = client.step(account_type='wells', mfa='tomato') if step.ok: data = json.loads(step.content) transactions = data['transactions'] spent = { 'school': 0, 'essentials': 0, 'snacks': 0, 'gas': 0, 'clothing': 0, 'recreation': 0 } for t in transactions: if t['type']['primary'] in ['place', 'digital']: name = t['name'].lower() amount = t['amount'] category = analyze_name(name) spent[category] += amount pie = '[' for cat, val in spent.iteritems(): pie += '["%s",%d],' % (cat, val) pie = pie[:-1] pie += ']' return render_template('tool/bank.html', pie=pie) return render_template_string('Error')
def import_into_database(self, user, sub_account, access_token): # data = PlaidData.getData('wells', "joefarned3", "angela0816", '*****@*****.**') client = Client(client_id=self.client_id, secret=self.secret) client.set_access_token(access_token) connect = client.transactions() data = json.loads(connect.content) c = MongoClient() db = c['pava'] accounts = db['accounts'] transactions = db['transactions'] for account in data['accounts']: account['_user_id'] = user.id account['_user_account'] = sub_account.id if not accounts.find({'_id': account['_id']}).count(): print accounts.insert(account) else: accounts.update({'_id': account['_id']}, account) for transaction in data['transactions']: transaction['_user_id'] = user.id if not transactions.find({'_id': transaction['_id']}).count(): print transactions.insert(transaction) return data
def test_ResourceNotFound_categories_with_suppressed_error(): Client.config({'suppress_http_errors': True}) client = Client('test_id', 'test_secret') response = client.category('pnc') assert response.status_code == 404 assert ( to_json(response)['message'] == 'unable to find category' )
def test_connect_mfa_list(): client = Client('test_id', 'test_secret') # These credentials erroneously still force mfa in the sandbox # Should disambiguate by disallowing institution on API level # for this particular calling response = client.connect('chase', no_mfa_credentials) assert response.status_code == 201 assert to_json(response)['type'] == 'list'
def test_connect_step_device_phone(): client = Client('test_id', 'test_secret', access_token='test_chase') response = client.connect_step('chase', None, options={ 'send_method': {'type': 'phone'} }) assert response.status_code == 201 assert to_json(response)['type'] == 'device' assert to_json(response)['mfa']['message'] == 'Code sent to xxx-xxx-5309'
def _get_plaid_client(passphrase, access_token = None): f = open('plaid.gpg', 'r') plaid_config_data_gpg = f.read() f.close() crypter_util = crypt.Crypt() plaid_config_data = crypter_util.decrypt(plaid_config_data_gpg, passphrase) plaid_config = json.loads(plaid_config_data) Client.config({ 'url': plaid_config['plaidendpoint'] }) return Client(client_id=plaid_config['client'], secret=plaid_config['secret'], access_token=access_token)
def test_connect(): with patch('requests.post') as mock_requests_post: mock_response = Mock() mock_response.content = '{}' mock_requests_post.return_value = mock_response client = Client('myclientid', 'mysecret') account_type = 'bofa' username = '******' password = '******' email = '*****@*****.**' response = client.connect(account_type, username, password, email) assert mock_response == response
class PlaidData: client_id = '54137790d8675800005de8d2' secret = 'SKTzUuKXq2ZcxviiwW0fiJ' def __init__(self, username, password): self.client = Client(client_id=self.client_id, secret=self.secret) self.connect = self.client.connect(account_type='wells', username=username, password=password, email='*****@*****.**') def getJSONResponse(self): json_response = json.loads(self.connect.content) import pprint pprint.pprint(json_response) message = "Your last transaction was @ " + json_response['transactions'][0]['name'] Messaging.sendMessage(message, "+16508620978")
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 test_institution_search_without_product(): client = Client('test_id', 'test_secret') response = client.institution_search('wells') assert response.status_code == 200
def test_institution_search_with_bad_product(): client = Client('test_id', 'test_secret') response = client.institution_search('wells fargo', 'bad') assert response.status_code == 200 assert len(to_json(response)) == 0
def test_institutions(): client = Client('test_id', 'test_secret') response = client.institutions() assert response.status_code == 200
def test_get_connect(): client = Client('test_id', 'test_secret', access_token='test_bofa') response = client.connect_get() assert response.status_code == 200
def test_unauthorizedError_bad_username(): client = Client('test_idz', 'test_secret') with pytest.raises(UnauthorizedError): client.balance()
def test_auth_mfa(): client = Client('test_id', 'test_secret') response = client.auth('pnc', no_mfa_credentials) assert response.status_code == 201 assert to_json(response)['type'] == 'questions'
def test_ResourceNotFound_connect(): client = Client('test_id', 'test_secret') with pytest.raises(ResourceNotFoundError): client.connect('pnc', no_mfa_credentials)
def test_connect_mfa_question(): client = Client('test_id', 'test_secret') response = client.connect('bofa', no_mfa_credentials) assert response.status_code == 201 assert to_json(response)['type'] == 'questions'
def test_connect_no_mfa(): client = Client('test_id', 'test_secret') response = client.connect('amex', no_mfa_credentials) assert response.status_code == 200 assert to_json(response)['access_token'] == 'test_amex'
def test_auth_step(): client = Client('test_id', 'test_secret', access_token='test_pnc') response = client.auth_step('pnc', 'tomato') assert response.status_code == 200 assert to_json(response)['access_token'] == 'test_pnc'
def test_ResourceNotFound_categories_with_suppressed_error(): Client.config({'suppress_http_errors': True}) client = Client('test_id', 'test_secret') response = client.category('pnc') assert response.status_code == 404 assert (to_json(response)['message'] == 'unable to find category')
def test_ResourceNotFound_categories(): client = Client('test_id', 'test_secret') with pytest.raises(ResourceNotFoundError): client.category('pnc')
def test_institution_search_requires_q_or_id(): client = Client('test_id', 'test_secret') with pytest.raises(AssertionError): client.institution_search(p='auth')
def test_auth_delete(): client = Client('test_id', 'test_secret', access_token='test_chase') response = client.auth_delete() assert response.status_code == 200 assert to_json(response)['message'] == 'Successfully removed from system'
def test_connect_step_question(): client = Client('test_id', 'test_secret', access_token='test_bofa') response = client.connect_step('bofa', 'tomato') assert response.status_code == 200 assert to_json(response)['access_token'] == 'test_bofa'
def test_unauthorizedError_bad_password(): client = Client('test_id', 'test_secretz') with pytest.raises(UnauthorizedError): client.balance()
def test_connect_step_question_loop(): client = Client('test_id', 'test_secret', access_token='test_bofa') response = client.connect_step('bofa', 'again') assert response.status_code == 201 assert to_json(response)['type'] == 'questions'
import time import pandas as pd import numpy as np from plaid import Client from datetime import datetime from google.oauth2 import service_account from googleapiclient.http import MediaFileUpload from googleapiclient.discovery import build DEFAULT_INSTITUTION_ID = 'ins_1' # Set Plaid API access data and get Client object client = Client( client_id='5ece97fc33df8d00137c4a43', secret='c70bb94dccf11c154b80ed8a1c0213', public_key='f571792e76a5251f1892b3e5b1bc04', environment='sandbox' ) # For upload files to google GOOGLE_SCOPES = ['https://www.googleapis.com/auth/drive'] GOOGLE_SERVICE_ACCOUNT_FILE = '../quickstart/python/Quickstart.json' google_credentials = service_account.Credentials.from_service_account_file( GOOGLE_SERVICE_ACCOUNT_FILE, scopes=GOOGLE_SCOPES ) service = build('drive', 'v3', credentials=google_credentials) def google_upload(filepath, name): folder_id = '1DzhQWufGGqHKcGyZSKkxAa3nvofPPzRF4tInLDW_xyI' name = name file_path = filepath
def test_balance(): client = Client('test_id', 'test_secret', access_token='test_bofa') response = client.balance() assert response.status_code == 200
from plaid import Client from backend.link_token import LinkToken from general_falcon_webserver import WebApp client = Client(client_id='5e2e3527dd6924001167e8e8', secret='0b89f518880456b6f60020f481b3d7', environment='sandbox') app = WebApp() app.add_route('link', LinkToken(client)) app.launch_webserver()
def make_client(client_id, secret, public_key, env="development"): return Client(client_id=client_id, secret=secret, public_key=public_key, environment=env)
from celery import shared_task from plaid import Client from .models import Tokens plaid_client_id = "5da9e9d3470e370016651aa3" plaid_secret = "1026c23bcd23fccd4f9dabb1f9f172" client = Client(client_id=plaid_client_id, secret=plaid_secret, environment='sandbox') @shared_task def add(x, y): print('sum: ', x + y) return x + y @shared_task def saveTask(user, access_token): item_response = client.Item.get(access_token) institution_response = client.Institutions.get_by_id( item_response['item']['institution_id'], 'US') item_id = item_response['item_id'] webhook = item_response['webhook'] token = Tokens.objects.create(user=user, access_tkn=access_token, item_id=item_id, webhook=webhook)
def test_institution_search_with_multi_tokens(): client = Client('test_id', 'test_secret') response = client.institution_search('wells fargo', 'auth') assert response.status_code == 200 assert to_json(response)[0]['name'] == 'Wells Fargo'
def __init__(self): self.client = Client(client_id=settings.PLAID_CLIENT_ID, secret=settings.PLAID_SECRET, public_key=settings.PLAID_PUBLIC_KEY, environment=settings.PLAID_ENV)
from django.conf import settings from plaid import Client plaid_client = Client( client_id=settings.PLAID_CLIENT_ID, secret=settings.PLAID_SECRET, public_key=settings.PLAID_PUBLIC_KEY, environment=settings.PLAID_ENVIRONMENT, )
def test_institution_search_with_bad_id(): client = Client('test_id', 'test_secret') response = client.institution_search(institution_id='bad') assert response.status_code == 200 assert len(to_json(response)) == 0
import time import pandas as pd import numpy as np from plaid import Client from datetime import datetime from google.oauth2 import service_account from googleapiclient.http import MediaFileUpload from googleapiclient.discovery import build DEFAULT_INSTITUTION_ID = 'ins_1' # Set Plaid API access data and get Client object client = Client(client_id='5ecba3951aa68500131ccd7a', secret='4b79ae100459ab86833f5aedb9caf7', public_key='19586b0d0ac976669c9f0abf56ddf7', environment='sandbox') # For upload files to google GOOGLE_SCOPES = ['https://www.googleapis.com/auth/drive'] GOOGLE_SERVICE_ACCOUNT_FILE = '../service_account.json' google_credentials = service_account.Credentials.from_service_account_file( GOOGLE_SERVICE_ACCOUNT_FILE, scopes=GOOGLE_SCOPES) service = build('drive', 'v3', credentials=google_credentials) def google_upload(filepath, name): folder_id = '1UscZpDhizXJsJQoHUy6JjRS4o-DhBOtH' name = name file_path = filepath file_metadata = { 'name': name, 'mimeType': 'application/vnd.google-apps.spreadsheet',
def test_UnauthorizedError_bad_token(): client = Client('test_id', 'test_secret', 'test_zoba') with pytest.raises(UnauthorizedError): client.balance()
class PlaidAccess(): def __init__(self, client_id=None, secret=None, account_id=None, access_token=None): if client_id and secret: self.client_id = client_id self.secret = secret else: self.client_id, self.secret = cm.get_plaid_config() self.client = Client(client_id=self.client_id, secret=self.secret) # if access_token: self.acceess_token = access_token # if account_id: self.account_id = account_id def get_transactions(self, access_token, account_id, start_date=None, end_date=None): """Get transaction for a given account for the given dates""" self.client.access_token = access_token options = {} options["account"] = account_id # options["pending"] = True #get all transaction up to and including today options['lte'] = datetime.date.today().strftime('%Y-%m-%d') self.connect_response = self.client.connect_get(options).json() return self.connect_response['transactions'] def add_account(self, nickname): try: self._get_available_institutions() except Exception as e: raise Exception( "There was a problem obtaining a list of institutions. Try again later." ) from e selected_institution = self._get_institution() if selected_institution is None: print("Quitting, no account added", file=sys.stdout) sys.exit(0) self.active_institution = self.available_institutions[ selected_institution][1] self.account_type = self.active_institution["type"] un, pwd, pin = self._get_needed_creds() # self.client.client_id = "test_id" # self.client.secret = "test_secret" # un = "plaid_test" # pwd = "plaid_good" login = {'username': un, 'password': pwd} if pin: login['pin'] = pin try: self.connect_response = self.client.connect( self.account_type, login) except plaid_errors.PlaidError as e: print(e.message) return else: cont = True try: while not self._check_status(): cont = self._process_mfa(self.connect_response.json()) if not cont: break except plaid_errors.PlaidError as e: print( "The following error has occurred, no account added:\n{}". format(e.message), file=sys.stderr) sys.exit(1) else: if not cont: print("Quitting, no account added", file=sys.stderr) sys.exit(1) accts = self.connect_response.json()['accounts'] if not self._present_accounts(accts): print("Quitting, no account added", file=sys.stderr) sys.exit(1) self._save_account_section(nickname) def _save_account_section(self, nickname): acct_section = OrderedDict() acct_section[nickname] = OrderedDict() section = acct_section[nickname] section['access_token'] = self.client.access_token section['account'] = self.selected_account['_id'] a = prompt( "What account is used for posting transactions [{}]: ".format( cm.CONFIG_DEFAULTS.posting_account)) if a: section['posting_account'] = a else: section['posting_account'] = cm.CONFIG_DEFAULTS.posting_account a = prompt( "What currency does this account use for posting transactions [{}]: " .format(cm.CONFIG_DEFAULTS.currency)) if a: section['currency'] = a else: section['currency'] = cm.CONFIG_DEFAULTS.currency a = self._present_file_options(nickname, 'mapping', cm.FILE_DEFAULTS.mapping_file) if a: section['mapping_file'] = a a = self._present_file_options(nickname, 'journal', cm.FILE_DEFAULTS.journal_file) if a: section['journal_file'] = a a = self._present_file_options(nickname, 'accounts', cm.FILE_DEFAULTS.accounts_file) if a: section['accounts_file'] = a a = self._present_file_options(nickname, 'template', cm.FILE_DEFAULTS.template_file) if a: section['template_file'] = a cm.write_section(acct_section) def _present_file_options(self, nickname, file_type, default_file): a = prompt( "Create a separate {} file configuration setting for this account [Y/n]: " .format(file_type), validator=YesNoValidator()).lower() if not bool(a) or a.startswith("y"): cont = True while cont: path = prompt( "Enter the path for the {} file used for this account [{}]: " .format(file_type, default_file), completer=PATH_COMPLETER) if path: path = os.path.expanduser(path) file_exists = os.path.isfile(path) if not file_exists: create = prompt( "{} does not exist. Do you want to create it? [Y/n]: " .format(path), validator=YesNoValidator()).lower() if not bool(create) or create.startswith("y"): if not os.path.exists(path): cm._create_directory_tree(path) cm._create_directory_tree(path) cm.touch(path) cont = False else: cont = True else: cont = False else: #use default create = prompt( "{} does not exist. Do you want to create it? [Y/n]: ". format(default_file), validator=YesNoValidator()).lower() if not bool(create) or create.startswith("y"): if not os.path.exists(default_file): cm._create_directory_tree(default_file) cm.touch(default_file) path = default_file cont = False else: cont = True if cont: print("Invalid path {}. Please enter a valid path.".format( path)) else: cont = False if not path: path = cm.get_custom_file_path(nickname, file_type, create_file=True) return path elif a.startswith("n"): return None def _process_mfa(self, data): type = data['type'] mfa = data['mfa'] if type == 'questions': return self._present_question([q['question'] for q in mfa]) elif type == 'list': return self._present_list(mfa) elif type == 'selection': return self._present_selection(mfa) else: raise Exception("Unknown mfa type from Plaid") def _present_question(self, question): clear_screen() print(question[0]) answer = prompt("Answer: ", validator=NullValidator( message="You must enter your answer", allow_quit=True)) if answer.lower() == "q": return False #we have abandoned ship self.connect_response = self.client.connect_step( self.account_type, answer) return True def _present_accounts(self, data): clear_screen() accounts = list(enumerate(data, start=1)) message = ["Which account do you want to add:\n"] for i, d in accounts: a = {} a['choice'] = str(i) a['name'] = d['meta']['name'] a['type'] = d['subtype'] if 'subtype' in d else d['type'] message.append("{choice:<2}. {name:<40} {type}\n".format(**a)) message.append("\nEnter your selection: ") answer = prompt( "".join(message), validator=NumberValidator( message="Enter the NUMBER of the account you want to add", allow_quit=True, max_number=len(accounts))) if answer.lower() == "q": return False #we have abandoned ship self.selected_account = accounts[int(answer) - 1][1] return True def _present_list(self, data): clear_screen() devices = list(enumerate(data, start=1)) message = ["Where do you want to send the verification code:\n"] for i, d in devices: message.append("{:<4}{}\n".format(i, d["mask"])) message.append("\nEnter your selection: ") answer = prompt( "".join(message), validator=NumberValidator( message= "Enter the NUMBER where you want to send verification code", allow_quit=True, max_number=len(devices))) if answer.lower() == "q": return False #we have abandoned ship dev = devices[int(answer) - 1][1] print("Code will be sent to: {}".format(dev["mask"])) self.connect_response = self.client.connect_step( self.account_type, None, options={'send_method': { 'type': dev['type'] }}) code = prompt("Enter the code you received: ", validator=NumberValidator()) self.connect_response = self.client.connect_step( self.account_type, code) return True def _present_selection(self, data): """ Could not test: needs implementation """ clear_screen() raise NotImplementedError( "MFA selections are not yet implemented, sorry.") def _get_needed_creds(self): credentials = self.active_institution["credentials"] clear_screen() print("Enter the required credentials for {}\n".format( self.active_institution["name"])) user_prompt = "Username ({}): ".format(credentials["username"]) pass_prompt = "Password ({}): ".format(credentials["password"]) pin = None username = prompt( user_prompt, validator=NullValidator(message="Please enter your username")) password = prompt( pass_prompt, is_password=True, validator=NullValidator(message="You must enter your password")) if "pin" in credentials: pin = prompt( "PIN: ", validator=NumLengthValidator( message="Pin must be at least {} characters long")) if not bool(pin) or pin.lower() == "q": pin = None #make sure we have something return username, password, pin def _get_available_institutions(self): # limit to just those institutions that have connect abilities, # as that is the service we will be using to get transactions institutions = self.client.institutions().json() self.available_institutions = list( enumerate([i for i in institutions if 'connect' in i['products']], start=1)) def _get_institution(self): accounts = [] total_institutions = len(self.available_institutions) for account in self.available_institutions: num, info = account accounts.append("{num:<4}{inst}".format(num=num, inst=info['name'])) institution_prompt = textwrap.dedent( """What bank is this account going to be for? \n{}\n\nEnter Number [q to quit]:""" .format('\n'.join(accounts))) clear_screen() res = prompt(institution_prompt, validator=NumberValidator( message="You must enter the chosen number", allow_quit=True, max_number=total_institutions)) if res.isdigit(): choice = int(res) - 1 elif res.lower() == "q": choice = None return choice def _check_status(self): status = self.connect_response.status_code if status == 200: # good, user connected return True elif status == 201: # MFA required return False else: return False
class Meta: order_by = ('username', ) # the user model specifies its fields (or columns) declaratively, like django """class Credentials(BaseModel): name = CharField(unique=True) id = CharField() secret = CharField() class Meta: order_by = ('name',)""" database.create_table(User, safe=True) Client.config({'url': 'https://tartan.plaid.com'}) #ident = Person.get(Person.name == 'Grandma L.') #print(ident) id = "57b4e70c66710877408d0855" # obtain id and secret from db, same for all queries secret = "d416705651d48d87e080e966c80421" """ident = Credentials(name = 'main', id = id, secret = secret) ident.save() ident = Credentials.get(Credentials.name == 'main') print(ident)""" client = Client(client_id=id, secret=secret) account_type = 'chase' def answer_mfa(data, client): if data['type'] == 'questions': # Ask your user for the answer to the question[s].
def test_institution(): client = Client('test_id', 'test_secret') response = client.institution(to_json(client.institutions())[0]['id']) assert response.status_code == 200
def test_connect_update(): client = Client('test_id', 'test_secret', access_token='test_amex') response = client.connect_update(no_mfa_credentials) assert response.status_code == 200
def test_auth_update(): client = Client('test_id', 'test_secret', access_token='test_amex') response = client.auth_update(no_mfa_credentials) assert response.status_code == 200
def test_connect_step_update(): client = Client('test_id', 'test_secret', access_token='test_bofa') response = client.connect_update_step('bofa', 'tomato') assert response.status_code == 200
def test_upgrade(): client = Client('test_id', 'test_secret', access_token='test_bofa') response = client.upgrade('info') assert response.status_code == 200 assert 'info' in to_json(response).keys()
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'
def test_connect_delete(): client = Client('test_id', 'test_secret', access_token='test_chase') response = client.connect_delete() assert response.status_code == 200 assert to_json(response)['message'] == 'Successfully removed from system'