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
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
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