Beispiel #1
0
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
Beispiel #2
0
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()
Beispiel #3
0
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')
Beispiel #4
0
    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()
Beispiel #5
0
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'
Beispiel #6
0
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'
Beispiel #7
0
def get_response():
    client = Client(client_id='test_id', secret='test_secret', access_token='usertoken')
    client.config({'url':'https://tartan.plaid.com'})
    account_type = 'ins_100088'
    user = '******'
    pwd = 'plaid_good'
    response = client.connect(account_type, {
        'username': user,
        'password': pwd
    })
    response = client.connect_step(account_type, 'tomato')
    return response.json() # This is a dict
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 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
Beispiel #10
0
 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()
Beispiel #11
0
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'
Beispiel #12
0
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'
Beispiel #13
0
def test_ResourceNotFound_connect():
    client = Client('test_id', 'test_secret')
    with pytest.raises(ResourceNotFoundError):
        client.connect('pnc', no_mfa_credentials)
Beispiel #14
0
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'
Beispiel #15
0
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'
Beispiel #16
0
def test_ResourceNotFound_connect():
    client = Client('test_id', 'test_secret')
    with pytest.raises(ResourceNotFoundError):
      client.connect('pnc', no_mfa_credentials)
Beispiel #17
0
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
    def initial_login(self, account_type, username, password, email):
        client = Client(client_id=self.client_id, secret=self.secret)
        connect = client.connect(account_type=account_type, username=username, password=password, email=email)

        json_response = json.loads(connect.content)
        return json_response
Beispiel #19
0

def answer_selections(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)


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
Beispiel #20
0
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:
Beispiel #21
0
from plaid import Client
from plaid import errors as plaid_errors
from plaid.utils import json

id_plaid = '584f8ac239361943b6a40c2f'
id_secret = '2eb94d1cfb298020b6d4c1e396eb75'
bank_user = '******'
bank_pass = '******'

client = Client(client_id=id_plaid, secret=id_secret)
account_type = 'bofa'

try:
    response = client.connect(account_type, {
        'username': bank_user,
        'password': bank_pass
    })
except plaid_errors.PlaidError, e:
    pass
else:
    if response.status_code == 200:
        # User connected
        data = resposnse.json()
    elif response.stat_code == 201:
        # MFA required
        try:
            mfa_response = answer_mfa(response.json())
        except plaid_errors.PlaidError, e:
            pass
        else:
            None