Пример #1
0
def register_client():
    """register new client with email/name + password, expected json body would have keys ["name", "email", "passcode"]

  """
    #TODO this can through exception, need to handle it
    req = request.get_json(force=True)
    #TODO i think the required is to authenticate by email/name
    name = req.get('name', None)
    passcode = req.get('passcode', None)
    email = req.get('email', None)
    cur_pref = req.get('cur_pref', EUR)
    if not req or name == None or email == None or passcode == None:
        logger.critical("url is incomplete")
        print('incomplete')
        abort(401, 'incomplete post payload')
    cred_id = get_credid(email)
    logger.info("registering trader for client: {}".format(name))
    bid = 0
    db.init()
    lock = 2
    try:
        db.lock_advisory(lock)
        email_exists = db.exists.account_byemail(email)
        if email_exists:
            print('email exists')
            abort(400)
            logger.debug("account {}/{} + {} already exists".\
                         format(name, email, passcode))
            raise Exception("account already exists!")
        if not db.exists.currency(cur_pref):
            currency = Currency(cur_pref)
            if not currency.valid():
                print('invalid currency')
                raise Exception("currency isn't supported!")
            db.inserts.add_currency(cur_pref, currency.rate)
        cur_pref_id = db.gets.get_currency_id(cur_pref)
        cid = db.inserts.add_client(req['name'], req['email'], cur_pref_id)
        logger.debug("client added")
        db.inserts.register(cid, passcode, cred_id)
        db.commit(lock)
    except psycopg2.DatabaseError as error:
        db.rollback(lock)
        emsg = "registering failed, error: ".format(str(error))
        logger.critical(emsg)
        abort(500, emsg)
    except:
        db.rollback(lock)
        emsg = "registering failed"
        logger.critical(emsg)
        abort(403, emsg)
    finally:
        db.close()
        res = {'cred_id': cred_id}
    return jsonify(res), 201
Пример #2
0
 def test_update_balance(self):
     exchange = Currency(EUR)
     rate = exchange.rate
     if not db.exists.currency(EUR):
         db.inserts.add_currency(EUR, rate)
     curr_id = db.gets.get_currency_id(EUR)
     passcode = get_rand_pass()
     email = get_email()
     credid = get_credid(email)
     balance = get_balance()
     email = get_email()
     name = get_name()
     db.inserts.add_client(name, email, curr_id)
     db.commit()
     cid = db.gets.get_client_id_byemail(email)
     db.inserts.register(cid, passcode, credid)
     db.commit()
     #add_bank_addount
     bid = db.inserts.add_bank_account(cid, balance, bank_name,
                                       branch_number, account_number,
                                       name_reference, curr_id)
     db.commit()
     db.updates.update_account(cid, 0)
     balance_cur = db.gets.get_balance_by_cid(cid)['balance']
     self.assertEqual(balance_cur, 0)
Пример #3
0
    def test_bid_cid_conversion(self):
        """ bid_cid conversion testing

        convert, and cross-reference from client id, to bank id
        """
        exchange = Currency(EUR)
        rate = exchange.rate
        if not db.exists.currency(EUR):
            db.inserts.add_currency(EUR, rate)
        curr_id = db.gets.get_currency_id(EUR)
        passcode = get_rand_pass()
        email = get_email()
        credid = get_credid(email)
        banalce = get_balance()
        email = get_email()
        name = get_name()
        db.inserts.add_client(name, email, curr_id)
        cid = db.gets.get_client_id_byemail(email)
        db.inserts.register(cid, passcode, credid)
        #add_bank_addount
        bid = db.inserts.add_bank_account(cid, balance, bank_name,
                                          branch_number, account_number,
                                          name_reference, curr_id)
        cid_eq = db.gets.get_client_id(bid)
        bid_eq = db.gets.get_banking_id(cid_eq)
        self.assertEqual(cid_eq, cid)
        self.assertEqual(bid_eq, bid)
Пример #4
0
def add_bank_account():
    """ register bank account for the authenticated client of the current session

  @param: the post body is expect to be json with keys ["bank_name", branch_number", "account_number", "name_reference"], a client can register more than one bank account for tahweela account.
  @return return bid (banking id), since multiple bank accounts are supported, bid need to be sent for each transaction so that, the transactions are done with it.
  """
    req = request.get_json(force=True)
    bank_name = req.get("bank_name", None)
    branch_number = req.get("branch_number", None)
    account_number = req.get("account_number", None)
    name_reference = req.get("name_reference", "")
    if not req or bank_name == None or branch_number == None or account_number == None:
        print('-1')
        emsg = "incomplete request"
        logger.critical(emsg)
        abort(401, emsg)
    db.init()
    ADD_BANK_ACCOUNT_LOCK = 7
    lock = ADD_BANK_ACCOUNT_LOCK
    try:
        db.lock_advisory(lock)
        cid = db.gets.credid2cid(session['credid'])
        logger.debug("client added")
        print('0')
        bank = PaymentGate(bank_name, branch_number, account_number,
                           name_reference)
        if not bank.authenticated():
            raise Exception('payment gate authentication failure!')
        print('1')
        balance_dt = bank.get_balance()
        balance = balance_dt['balance']
        print('2')
        base_currency = balance_dt['base']
        if not db.exists.currency(base_currency):
            currency = Currency(base_currency)
            db.inserts.add_currency(base_currency, currency.rate)
        print('3')
        base_currency_id = db.gets.get_currency_id(base_currency)
        db.inserts.add_bank_account(cid, balance, bank_name, branch_number,
                                    account_number, name_reference,
                                    base_currency_id)
        print('4')
        db.commit(lock)
    except psycopg2.DatabaseError as error:
        db.rollback(lock)
        emsg = "assigning bank account failed, error: " + str(error)
        logger.critical(emsg)
        abort(500, emsg)
    except:
        print('err2')
        db.rollback(lock)
        emsg = "adding bank account failed"
        logger.critical(emsg)
        abort(401)
    finally:
        db.close()
    return jsonify({'balance': balance, 'base': base_currency}), 201
Пример #5
0
 def test_currency(self):
     #db.init()
     #db.repeatable_read()
     #db.lock_advisory(lock)
     exchange = Currency(EUR)
     rate = exchange.rate
     if not db.exists.currency(EUR):
         db.inserts.add_currency(EUR, rate)
     self.assertEqual(rate, 1)
Пример #6
0
    def get_transactions_sum(self, \
                             trx_with_credid, \
                             st_dt=None, \
                             end_dt=None):
        """ get the transactions within the given period inclusively

        @param trx_with_credid: the credential id of the client of interest
        @param st_dt: the start datetime
        @param end_dt: the end datetime
        @return dataframe of the transactions
        """
        if end_dt==None:
            end_dt=dt.datetime.now().strftime(TIMESTAMP_FORMAT)

        stat = "SELECT (ledger.trx_cost, cur.currency_name) FROM ledger INNER JOIN currency AS cur ON (cur.id=ledger.trx_cur_id) WHERE (trx_dest={to_credid} OR trx_src={from_credid});".\
            format(to_credid=sql.Literal(trx_with_credid),\
                   from_credid=sql.Literal(trx_with_credid))

        if not st_dt==None:
            #note! FOR UPDATE is not allowed with aggregate functions
            stat=sql.SQL("SELECT (ledger.trx_cost, cur.currency_name) FROM ledger INNER JOIN currency AS cur ON (cur.id=ledger.trx_cur_id) WHERE (trx_dt>={st_dt} AND trx_dt<{end_dt} AND trx_dest={to_credid}) OR (trx_dt>={st_dt} AND trx_dt<{end_dt} AND trx_src={from_credid});").\
            format(st_dt=sql.Literal(st_dt),\
                   end_dt=sql.Literal(end_dt),\
                   to_credid=sql.Literal(trx_with_credid), \
                   from_credid=sql.Literal(trx_with_credid))
        self.db_log.debug(stat)
        #self.cur.execute(stat)
        #fet=self.cur.fetchone()[0]
        #if fet==None:
            #return 0
        #return fet
        trxs_df=pd.read_sql(stat, self.conn)
        #the transaction sum in euros
        sum=0
        for i in range(len(trxs_df)):
            row=eval(trxs_df.iloc[i][0])
            value=row[0]
            base=row[1]
            currency = Currency(EUR, base)
            ineuro_cost=currency.exchange(value)
            sum+=float(ineuro_cost)
        return sum
Пример #7
0
 def test_client_exists(self):
     exchange = Currency(EUR)
     rate = exchange.rate
     if not db.exists.currency(EUR):
         db.inserts.add_currency(EUR, rate)
     curr_id = db.gets.get_currency_id(EUR)
     name = get_name()
     email = get_email()
     db.inserts.add_client(name, email, curr_id)
     cid = db.gets.get_client_id_byemail(email)
     self.assertTrue(db.exists.client_exists(cid))
Пример #8
0
 def test_banking_byemail(self):
     #db.init()
     #db.repeatable_read()
     #db.lock_advisory(lock)
     exchange = Currency(EUR)
     rate = exchange.rate
     if not db.exists.currency(EUR):
         db.inserts.add_currency(EUR, rate)
     curr_id = db.gets.get_currency_id(EUR)
     db.inserts.add_client(name, email, curr_id)
     self.assertTrue(db.exists.account_byemail(email))
     cid = db.gets.get_client_id_byemail(email)
     self.assertTrue(db.exists.client_exists(cid))
Пример #9
0
def get_balance():
    """ get balance of the current client

    @return {'balance': balance, 'base': base}
    """
    balance = None
    logger.info("balance requested")
    db.init()
    try:
        db.repeatable_read()
        cid = db.gets.credid2cid(session['credid'])
        if not db.exists.bank_account_bycid(cid):
            raise Exception("no bank account added yet!")
        #this would return balance in bank base
        balance = db.gets.get_balance_by_credid(session['credid'])
        # transform balance to user preference
        pref_cur = db.gets.get_preference_currency_bycid(cid)
        amount = balance['balance']
        base = balance['base']
        currency = Currency(pref_cur, base)
        pref_balance = currency.exchange(amount)
        payload = {'balance': pref_balance, 'base': pref_cur}
        db.commit()
    except psycopg2.DatabaseError as error:
        db.rollback()
        emsg = "failed request, error: {} ".format(+str(error))
        logger.critical()
        abort(300, emsg)
    except:
        db.rollback()
        emsg = "failed request"
        logger.critical(emsg)
        abort(300, emsg)
    finally:
        db.close()
    return jsonify(payload), 201
Пример #10
0
 def test_banking_byname(self):
     exchange = Currency(EUR)
     rate = exchange.rate
     if not db.exists.currency(EUR):
         db.inserts.add_currency(EUR, rate)
     curr_id = db.gets.get_currency_id(EUR)
     passcode = get_rand_pass()
     email = get_email()
     name = get_name()
     db.inserts.add_client(name, email, curr_id)
     cid = db.gets.get_client_id_byemail(email)
     db.inserts.register(cid, passcode, credid)
     self.assertTrue(db.exists.account_byname(name, passcode))
     cid = db.gets.get_client_id_byname(name, passcode)
     self.assertTrue(db.exists.client_exists(cid))
Пример #11
0
 def test_credid2cid(self):
     exchange = Currency(EUR)
     rate = exchange.rate
     if not db.exists.currency(EUR):
         db.inserts.add_currency(EUR, rate)
     curr_id = db.gets.get_currency_id(EUR)
     passcode = get_rand_pass()
     email = get_email()
     credid = get_credid(email)
     # add new client
     db.inserts.add_client(name, email, curr_id)
     cid = db.gets.get_client_id_byemail(email)
     # register client's credentials
     db.inserts.register(cid, passcode, credid)
     # credid2cid conversion
     cid_eq = db.gets.credid2cid(credid)
     self.assertEqual(cid, cid_eq)
     credid_eq = db.gets.cid2credid(cid)
     self.assertEqual(credid, credid_eq)
Пример #12
0
 def test_credential_exists(self):
     exchange = Currency(EUR)
     rate = exchange.rate
     if not db.exists.currency(EUR):
         db.inserts.add_currency(EUR, rate)
     curr_id = db.gets.get_currency_id(EUR)
     name = get_name()
     email = get_email()
     passcode = get_rand_pass()
     credid = get_credid(email)
     db.inserts.add_client(name, email, curr_id)
     db.commit()
     cid = db.gets.get_client_id_byemail(email)
     db.commit()
     self.assertFalse(db.exists.credential_exists(0))
     db.inserts.register(cid, passcode, credid)
     cid = db.gets.get_client_id_byname(name, passcode)
     db.commit()
     self.assertTrue(db.exists.credential_exists(cid))
Пример #13
0
 def test_add_bank_account(self):
     exchange = Currency(EUR)
     rate = exchange.rate
     if not db.exists.currency(EUR):
         db.inserts.add_currency(EUR, rate)
     curr_id = db.gets.get_currency_id(EUR)
     passcode = get_rand_pass()
     email = get_email()
     credid = get_credid(email)
     banalce = get_balance()
     email = get_email()
     name = get_name()
     db.inserts.add_client(name, email, curr_id)
     cid = db.gets.get_client_id_byemail(email)
     db.inserts.register(cid, passcode, credid)
     #add_bank_addount
     bid = db.inserts.add_bank_account(cid, balance, bank_name,
                                       branch_number, account_number,
                                       name_reference, curr_id)
     self.assertTrue(db.exists.bank_account_bycid(cid))
Пример #14
0
def update_balance_preference():
    """update balance preference

    """
    req = request.get_json(force=True)
    base = req.get('base', None)
    logger.info("updating balance preference")
    if not req or base == None:
        emsg = 'incomplete url'
        logger.cirtical(emsg)
        abort(401, emsg)
    CURRENCY_LOCK = 11
    lock = CURRENCY_LOCK
    db.init()
    try:
        db.lock_advisory(lock)
        if not db.exists.currency(base):
            currency = Currency(base)
            db.inserts.add_currency(basey, currency.rate)
        base_currency_id = db.gets.get_currency_id(base_currency)
        cid = db.gets.credid2cid(session['credid'])
        db.updates.currency_preference(cid, base)
        db.commit()
    except psycopg2.DatabaseError as error:
        db.rollback()
        emsg = "request failure, error: {} ".format(str(error))
        logger.critical(emsg)
        abort(500, emsg)
    except Exception as error:
        db.rollback()
        emsg = "request failure, error: {}".format(str(error))
        logger.critical(emsg)
        abort(401, emsg)
    finally:
        db.unlock_advisory(lock)
        db.close()
Пример #15
0
def make_transaction():
    print('XXX ---------- make transaction started')
    req = request.get_json(force=True)
    recipt_credid = req['credid']
    # the amount of transaction in Euro
    orig_amount = req['amount']
    currency_base = req.get('currency', EUR)
    #exchange amount to euro for processing
    to_euro = Currency(EUR, currency_base)
    amount = to_euro.exchange(orig_amount)
    trx_name = req.get('trx_name', '')
    #TRANSACTION LIMITS IN EUROS
    max_daily = daily_limit()
    max_weekly = weekly_limit()
    #here the weekly/daily conditions are pivoted by the current moment only, note that the bank system can have specific pivot hour (the first momemnt of the day, it's specific for the bank system, and need to be known before hand)
    week_past = datetime.datetime.now() - datetime.timedelta(days=7)
    day_past = datetime.datetime.now() - datetime.timedelta(days=1)
    #TODO abide to the  the constrains
    logger.info("making purchase")
    if not req or amount == None or recipt_credid == None:
        emsg = "incomplete URL empty request"
        logger.critical(emsg)
        abort(401, emsg)
    #gid=req['id']
    db.init()
    MAKE_TRANSACTION_LOCK = 9
    lock = MAKE_TRANSACTION_LOCK
    print('start transaction')
    try:
        db.lock_advisory(lock)
        #if this client have a bank account yet
        cid = db.gets.credid2cid(session['credid'])
        if not db.exists.bank_account_bycid(cid):
            raise Exception("client doesn't have any associated bank account!")
        #balance in bank base
        src_balance = db.gets.get_balance_by_credid(session['credid'])
        src_balance_exchange = Currency(EUR, src_balance['base'])
        src_balance_euro = src_balance_exchange.exchange(
            src_balance['balance'])
        if src_balance_euro < amount + FEE:
            emsg = "client doesn't have enough credit to make transaction"
            logger.critical(emsg)
            raise Exception(emsg)
        #get transaction sum in euro
        weekly_trx_sum = db.gets.get_transactions_sum(session['credid'],
                                                      week_past)
        daily_trx_sum = db.gets.get_transactions_sum(session['credid'],
                                                     day_past)
        print('got trx sum! weekly: {}, daily{}'.format(
            weekly_trx_sum, daily_trx_sum))
        if weekly_trx_sum + amount > max_weekly or daily_trx_sum + amount > max_daily:
            emsg = "client passed the daily/weekly limit"
            logger.info(emsg)
            raise Exception(emsg)
        cur_id = db.gets.get_currency_id(currency_base)
        #add transaction
        db.inserts.insert_trx(recipt_credid, session['credid'], amount, cur_id,
                              trx_name)
        #TODO this can be minimized directly by credid
        #dest balance in bank base
        print('XXX ---------- start of calculation')
        dest_balance = db.gets.get_balance_by_credid(recipt_credid)
        dest_balance_exchange = Currency(EUR, dest_balance['base'])
        dest_balance_euro = dest_balance_exchange.exchange(
            dest_balance['balance'])
        src_balance_new = src_balance_euro - (amount + FEE)
        dest_balance_new = dest_balance_euro + amount
        #exchange back to bank bas
        src_balance_new = src_balance_exchange.exchange_back(src_balance_new)
        dest_balance_new = dest_balance_exchange.exchange_back(
            dest_balance_new)
        src_cid = db.gets.credid2cid(session['credid'])
        des_cid = db.gets.credid2cid(recipt_credid)
        print('XXX ---------- end of calculation')
        if src_cid == des_cid:
            print("src/dest {}/{}".format(src_cid, des_cid))
            emsg = "you can't make transaction with oneself!"
            logger.critical(emsg)
            raise Exception(emsg)
        print('XXX ---------- update balance?!')
        db.updates.update_account(src_cid, src_balance_new)
        db.updates.update_account(des_cid, dest_balance_new)
        trx = {'trx_dest': recipt_credid,  \
               'trx_src': session['credid'], \
               'trx_cost': orig_amount, \
               'trx_name':trx_name}
        payload={'balance': src_balance_new, \
                 'transactions': trx}
        print('XXX ---------- finished transaction')
        db.commit()
    except psycopg2.DatabaseError as error:
        db.rollback()
        emsg = "transaction failed, error: {}".format(str(error))
        logger.critical(emsg)
        abort(500, emsg)
    except:
        db.rollback()
        emsg = "transaction failed"
        logger.critical(emsg)
        abort(401, emsg)
    finally:
        db.unlock_advisory(lock)
        db.close()
    return jsonify(payload), 201
Пример #16
0
    def test_transaction(self):
        """ create two clients, client_1, client_2

        procedure:
        - client_1 sends 10k to client_2
        - client_1 sends 20k to client_2
        - client_2 sends 5k to client_1
        - transaction sum 35k sent/received
        """
        exchange = Currency(EUR)
        rate = exchange.rate
        if not db.exists.currency(EUR):
            db.inserts.add_currency(EUR, rate)
        curr_id = db.gets.get_currency_id(EUR)
        c1_name = get_name()
        c1_email = get_email()
        c1_passcode = get_rand_pass()
        c1_credid = get_credid(c1_email)
        c1_bank_name = get_bank_name()
        c1_branch_number = get_branch_number()
        c1_account_number = get_account_number()
        c1_name_reference = get_name_reference()
        c1_balance = get_balance()
        db.inserts.add_client(c1_name, c1_email, curr_id)
        db.commit()
        c1_cid = db.gets.get_client_id_byemail(c1_email)
        db.inserts.register(c1_cid, c1_passcode, c1_credid)
        db.commit()
        db.inserts.add_bank_account(c1_cid, c1_balance, c1_bank_name,
                                    c1_branch_number, c1_account_number,
                                    c1_name_reference, curr_id)
        db.commit()
        #
        c2_name = get_name()
        c2_email = get_email()
        c2_passcode = get_rand_pass()
        c2_credid = get_credid(c2_email)
        c2_bank_name = get_bank_name()
        c2_branch_number = get_branch_number()
        c2_account_number = get_account_number()
        c2_name_reference = get_name_reference()
        c2_balance = get_balance()
        db.inserts.add_client(c2_name, c2_email, curr_id)
        db.commit()
        c2_cid = db.gets.get_client_id_byemail(c2_email)
        db.inserts.register(c2_cid, c2_passcode, c2_credid)
        db.commit()
        db.inserts.add_bank_account(c2_cid, c2_balance, c2_bank_name,
                                    c2_branch_number, c2_account_number,
                                    c2_name_reference, curr_id)
        db.commit()
        #
        ################
        # transactions
        ################
        costs = [10000, 20000, 5000]
        trx_st_0 = datetime.datetime.now().strftime(TIMESTAMP_FORMAT)
        db.inserts.insert_trx(c2_credid, c1_credid, costs[0], curr_id,
                              'transaction1')
        db.commit()
        trx_st_1 = datetime.datetime.now().strftime(TIMESTAMP_FORMAT)
        db.inserts.insert_trx(c2_credid, c1_credid, costs[1], curr_id,
                              'transaction2')
        db.commit()
        trx_st_2 = datetime.datetime.now().strftime(TIMESTAMP_FORMAT)
        db.inserts.insert_trx(c1_credid, c2_credid, costs[2], curr_id,
                              'transaction3')
        db.commit()
        trx_st_3 = datetime.datetime.now().strftime(TIMESTAMP_FORMAT)
        ##################
        # validation test
        ##################
        #epoch 1
        c1_trx_sum_0 = db.gets.get_transactions_sum(c1_credid, trx_st_0)
        db.commit()
        self.assertEqual(sum(costs), c1_trx_sum_0)
        #epoch 2
        c1_trx_sum_1 = db.gets.get_transactions_sum(c1_credid, trx_st_1)
        db.commit()
        self.assertEqual(sum(costs[1:]), c1_trx_sum_1)
        #epoch 3
        c1_trx_sum_2 = db.gets.get_transactions_sum(c1_credid, trx_st_2)
        db.commit()
        self.assertEqual(sum(costs[2:]), c1_trx_sum_2)