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
def requestTransactions(self): if "token" not in self.credentials["plaid"]: client = Client(client_id=self.credentials["plaid"]["client"], secret=self.credentials["plaid"]["secret"]) data = "" try: response = client.connect(self.bank, { 'username': self.login, 'password': self.password }) data = response.json() except plaid_errors.UnauthorizedError as e: print("AHHH") print(e.message) exit() token = data['access_token'] self.credentials["plaid"]["token"] = token client = Client(client_id=self.credentials["plaid"]["client"], secret=self.credentials["plaid"]["secret"], access_token=self.credentials["plaid"]["token"]) if self.debug == True: options = {'pending': True, 'gte': '2017/01/01'} else: options = {'pending': True, 'gte': self.gte} response = client.connect_get(opts=options) self.data = response.json()
def load_statements_line_from_plaid( self, id_plaid='584f8ac239361943b6a40c2f', id_secret='2eb94d1cfb298020b6d4c1e396eb75', access_token='test_bofa'): # get transactions _logger.warning('\n\n\n Respuesta1: \n \n\n\n') client = Client(client_id=id_plaid, secret=id_secret, access_token='test_bofa') #PARA DELIMITAR CON FECFA response = client.connect_get(opts={'gte':'2014-06-01'}).json() response = client.connect_get().json() accounts = client.auth_get().json() #transactions = response.json() _logger.info('\n\n\n transaccion: \n %s \n\n\n' % response['transactions'][0]) _logger.info('\n\n\n Numero de Cuenta: \n %s \n\n\n' % accounts['accounts'][2]['numbers']['account']) _logger.info('\n\n\n id de la cuenta: \n %s \n\n\n' % accounts['accounts'][2]['_id']) _logger.info('\n\n\n id de la Cuenta en la transaccion: \n %s \n\n\n' % response['transactions'][0]['_account']) _logger.info('\n\n\n Monto de la transaccion: \n %s \n\n\n' % response['transactions'][0]['amount']) _logger.info('\n\n\n fecha de la transaccion: \n %s \n\n\n' % response['transactions'][0]['date']) _logger.info( '\n\n\n nombre del partner que realiza transaccion: \n %s \n\n\n' % response['transactions'][0]['name']) #for account in accounts['accounts']: values = [] for resp in response['transactions']: values.append((0, 0, { 'name': resp['name'], 'ref': resp['_id'], 'amount': resp['amount'], 'date': resp['date'] })) #OBSOLETO #new_id = self.env['account.bank.statement'].create({'name':"Prueba5", 'journal_id':6, 'line_ids': [(0,0,{'name': 'pruebaline', 'ref': '00002-line', 'amount': 100})]}) #new_id = self.env['account.bank.statement'].create({'name':"Prueba5", 'journal_id':6, 'line_ids': [(0,0,{'name': response['transactions'][0]['name'], # 'ref': response['transactions'][0]['_id'], # 'amount': response['transactions'][0]['amount'], # 'date': response['transactions'][0]['date'] # })]}) # new_id = self.env['account.bank.statement'].create({ 'name': "Prueba5", 'journal_id': 6, 'line_ids': values }) return True
def get(self, user): userData = User.get(User.username == user) userData = model_to_dict(userData) access_token = userData['accessToken'] #print(access_token) client = Client(client_id=id, secret=secret, access_token=access_token) transactions = client.connect_get().json() return transactions
def fetch_transactions(token, start_date): client = Client(client_id=CLIENT_ID, secret=CLIENT_SECRET, access_token=token) response = client.connect_get(opts={'gte': start_date}) if response.status_code != 200: logger.error("Got status %d from server: %s", response.status_code, response.text) raise exceptions.ProviderFetchError() trans = response.json() df = pd.DataFrame(trans['transactions']) return df
def test_connection(self): client = Client( client_id='57f28ea8062e8c1d58ff9391', secret='580f72db7f49c97b4d279b504eda2d' ) try: response = client.connect(account_type, { 'username': '******', 'password': '******' }) self.assertEqual(response.json()['type'], 'questions') self.assertEqual(response.status_code, 201) response = client.connect_step(account_type, 'tomato') self.assertEqual(response.status_code, 200) response = client.connect_get() for account in response.json()["accounts"]: process_account_creation(account) for transaction in response.json()["transactions"]: process_transaction(transaction) print Account.objects.values_list('_id', 'pend_transfer') except plaid_errors.UnauthorizedError: traceback.print_exc()
def test_get_connect(): client = Client('test_id', 'test_secret', access_token='test_bofa') response = client.connect_get() assert response.status_code == 200
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
return client.connect_step(account_type, answer) try: response = client.connect(account_type, { 'username': username, 'password': password }) except plaid_errors.PlaidError, e: pass else: if response.status_code == 200: # User connected data = json.loads(response.content) elif response.status_code == 201: # MFA required try: mfa_response = answer_mfa(json.loads(response.content)) except plaid_errors.PlaidError, e: pass else: # check for 200 vs 201 responses # 201 indicates that additional MFA steps required phone_code = raw_input('Enter your ID code from your phone: ') connected = client.connect_step(account_type, phone_code) balances = client.balance().json() response = client.connect_get() transactions = json.loads(response.content)
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')
import os, json from plaid import Client from plaid import errors as plaid_errors plaid_client_id = os.getenv('plaid_client_id', '') plaid_secret = os.getenv('plaid_secret', '') plaid_access_token = os.getenv('plaid_access_token', '') Client.config({ 'url': 'https://api.plaid.com', 'suppress_http_errors': True, }) client = Client(client_id=plaid_client_id, secret=plaid_secret, access_token=plaid_access_token) response = client.balance() balance = json.loads(response.content) response = client.connect_get() transactions = json.loads(response.content) print balance
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
class plaid(): account_type = 'chase' name = '' password = '' client = Client(client_id='57cccae6cfbf49f67b01fd5a', secret='2c13981884395fc691fda11148ed67') plaid_results = '' def __init__(self): print "created plaid object" Client.config({'url': 'https://tartan.plaid.com'}) def answer_mfa(data): print "answer_mfa" if data['type'] == 'questions': # Ask your user for the answer to the question[s]. # Although questions is a list, there is only ever a # single element in this list, at present return answer_question([q['question'] for q in data['mfa']]) elif data['type'] == 'list': return answer_list(data['mfa']) elif data['type'] == 'selection': return answer_selections(data['mfa']) else: raise Exception('Unknown mfa type from Plaid') def answer_question(questions): print "answer_question" # We have magically inferred the answer # so we respond immediately # In the real world, we would present questions[0] # to our user and submit their response answer = 'dogs' return client.connect_step(account_type, answer) def answer_list(devices): print "answer_list" print devices[1] # You should specify the device to which the passcode is sent. # The available devices are present in the devices list dog = client.connect_step( 'chase', None, options={'send_method': { 'mask': 'xxx-xxx-9793' }}) answer = raw_input("Please enter something: ") cat = client.connect_step(account_type, answer) print cat print cat.content # print dog # print type(dog) # new =dog.content # print new # print type(new) # token=new.access_token # print token return dog def answer_selections(selections): print "answer_selections" # We have magically inferred the answers # so we respond immediately # In the real world, we would present the selection # questions and choices to our user and submit their responses # in a JSON-encoded array with answers provided # in the same order as the given questions answer = json.dumps(['Yes', 'No']) return client.connect_step(account_type, answer) def use_token(self, username): obj = SQLConnection() token = obj.get_plaid_token(username) self.client = Client(client_id='57cccae6cfbf49f67b01fd5a', secret='2c13981884395fc691fda11148ed67', access_token=token) response = self.client.connect_get(token) self.plaid_results = response.content return response.content def create_user_plaid(self, username, account_type, bank_username, bank_password): try: response = self.client.connect(account_type, { 'username': bank_username, 'password': bank_password }) d = json.loads(response.content) access_token = d["access_token"] print access_token except plaid_errors.PlaidError, e: print e else: