def bundle(self, name, agent_id, price, pin): bc = AgentNotifier() c_agent = DBCache(const.AGENT_PREFIX, config.DEFAULT_EXPIRE, const.AGENT_SQL) c_agent.setConn(bc.dbconn, bc.cacheconn) dm = DepositMutation(20, bc.dbconn, bc.cacheconn) ag = c_agent.sGet(agent_id) if not ag: return json.dumps({'success': 0, 'reason': 'AGENT NOT FOUND'}) sql = '''SELECT * FROM `bundle` WHERE `bundle_name`=%s''' c = bc.dbconn.cursor(MySQLdb.cursors.DictCursor) c.execute(sql, (name,)) cs = c.fetchall() if len(cs) == 0: return json.dumps({'success': 0, 'reason': 'BUNDLE NOT FOUND'}) balance = dm.debit(agent_id, int(price), 'Bundle {0}'.format(name)) if balance < 0: return json.dumps({'success': 0, 'reason': 'NOT ENOUGH DEPOSIT'}) um = UnitMutation(5, bc.dbconn, bc.cacheconn) for r in c: um.credit(agent_id, r['product_id'], r['unit'], 0, name) msg = 'Add bundle {0} to {1}-{2} Rp {3}'.\ format(name, agent_id, ag['agent_name'], thousandSeparator(price)) for prot in ('ym://b_martian','ym://inileonard', 'ym://sridwan981'): bc.writeNotifyOut(prot, 'general_message', {'message': msg}) bc.dbconn.commit() return json.dumps({'success': 1, 'reason': ''})
def depmut_execute(self, agent_id, type, amount, comment, pin): result = { 'success': 0, 'balance': 0, } try: int(amount) except: result['message'] = 'AMOUNT NOT VALID' return json.dumps(result) # agent must exist bc = AgentNotifier() c_agent = DBCache(const.AGENT_PREFIX, config.DEFAULT_EXPIRE, const.AGENT_SQL) c_agent.setConn(bc.dbconn, bc.cacheconn) #print c_agent.sGet(agentid) ag = c_agent.sGet(agent_id) if not ag: result['message'] = 'AGENT NOT REGISTERED' return json.dumps(result) dm = DepositMutation(20, bc.dbconn, bc.cacheconn) prev_bal = dm.getBalance(agent_id) if type.upper() == 'C': balance = dm.credit(agent_id, int(amount), comment) bc.writeNotifyOut(ag['default_protocol'], 'deposit_credit', { 'mutation': thousandSeparator(amount), 'balance_before': thousandSeparator(prev_bal), 'balance': thousandSeparator(balance), }) elif type.upper() == 'D': balance = dm.debit(agent_id, int(amount), comment) bc.writeNotifyOut(ag['default_protocol'], 'deposit_debit', { 'mutation': thousandSeparator(amount), 'balance_before': thousandSeparator(prev_bal), 'balance': thousandSeparator(balance), }) else: result['message'] = 'TYPE NOT RECOGNIZED' return json.dumps(result) if balance == NOT_ENOUGH_BALANCE: result['message'] = 'NOT ENOUGH BALANCE' return json.dumps(result) elif balance == LOCK_FAILED: result['message'] = 'SERVER BUSY' return json.dumps(result) bc.dbconn.commit() msg = '{0}-{1} Deposit: Rp. {2} Before: Rp. {3} After: Rp. {4} ({5}) ID:{6}'.\ format(ag['agent_id'], ag['agent_name'], thousandSeparator(amount), thousandSeparator(prev_bal), thousandSeparator(balance), comment, dm.last_id) for prot in ('ym://b_martian','ym://inileonard', 'ym://sridwan981'): bc.writeNotifyOut(prot, 'general_message', {'message': msg}) bc.dbconn.commit() result.update({ 'success': 1, 'message': 'SUCCESS', 'balance': balance, 'mutation_id': dm.last_id, }) return json.dumps(result)
def transaction_success(self, tran_id, pin): bc = AgentNotifier() c = bc.dbconn.cursor(MySQLdb.cursors.DictCursor) c.execute('''SELECT SQL_NO_CACHE `reg_protocol`,`product_id`,`msisdn_destination`, `agent_id`,`base_price`,`sell_price`,`status`,`order`,`deposit`,`type` FROM `transaction` where `transaction_id`=%s''', (tran_id,)) r = c.fetchone() if not r: return json.dumps({'success': 0, 'reason': 'RECORD NOT FOUND'}) if int(r['status']) == const.TR_RETRIED or \ int(r['status']) == const.TR_EXECUTED or \ int(r['status']) > const.TR_FAILED_GENERAL_REV: return json.dumps({'success': 0, 'reason': 'CANNOT SET STATUS'}) if int(r['status']) >= const.TR_FAILED_HLR_REV and \ int(r['status']) <= const.TR_FAILED_GENERAL_REV : dm = DepositMutation(20, bc.dbconn, bc.cacheconn) dm.debit(r['agent_id'], r['sell_price'], 'Manual success {0}'.\ format(tran_id)) c_agent_price = DBCache(const.AGENTPRICE_PREFIX, config.DEFAULT_EXPIRE, const.AGENTPRICE_SQL) owner = '{0:0>{1}}'.format(1, config.AGENT_ID_LENGTH) try: if r['agent_id'] != owner: fl = getFrontline(bc.dbconn, bc.cacheconn, r['agent_id']) if not fl: self.logger.error('<countProfit> Frontline for agent {0} not found'.format(r['agent_id'])) raise else: fl = r['agent_id'] ag = c_agent_price.sGet((fl, r['product_id'],)) if not ag: self.logger.error('<countProfit> Price for agent {0} not found'.format(r['agent_id'])) raise profit = int(ag['sell_price']) - int(r['base_price']) except: profit = 0 c.execute('''UPDATE `transaction` SET `status`=%s,`profit`=%s WHERE `transaction_id`=%s''', (const.TR_EXECUTED, profit, tran_id,)) r['references'] = '0' bc.notifyTopupSucess(r) bc.dbconn.commit() return json.dumps({'success': 1, 'reason': 'SUCCESS'})
class TestDepositMutation(TestAdminHelper): #---------------------- def setUp(self): self.bc = BaseComponent() self.dbconn = self.bc.dbconn self.cacheconn = self.bc.cacheconn self.cacheconn.delete('{0}_00001'.format(const.MUTATION_PREFIX)) cursor = self.dbconn.cursor() self._resetTable('Deposit_Mutation') try: cursor.execute('''INSERT INTO `agent` (`agent_id`, `active`, `agent_name`, `agent_address`, `agent_type`, `pin`, `upline_id`, `markup`, `markup_upline`, `set_price`, `register_date`, `last_activity_date`, `last_update`, `last_update_by`) VALUES ('00001', 1, 'Bernard Martian', 'Test', 1, '9999', '', 100, 0, 'Test', '2010-11-09 18:24:44', '2010-11-09 18:24:51', '2010-11-24 00:50:12', '')''') except: pass cursor.close() self.dbconn.commit() self.c_agent = DBCache(const.AGENT_PREFIX, config.DEFAULT_EXPIRE, const.AGENT_SQL) self.c_agent.setConn(self.dbconn, self.cacheconn) self.dm = DepositMutation(2, self.dbconn, self.cacheconn) #---------------------- def runTest(self): test_function = [x for x in dir(self) if x[:6] == 'srtest'] map(lambda x: getattr(self, x)(), sorted(test_function)) #---------------------- def srtest010(self): balance = self.dm.debit('00001', 10000, 'srtest010') self.dbconn.commit() self.assertEqual(balance, depmut.NOT_ENOUGH_BALANCE) balance = self.dm.credit('00001', 10000, 'srtest010') self.dbconn.commit() self.assertEqual(balance, 10000) balance = self.dm.debit('00001', 5000, 'srtest010') self.dbconn.commit() self.assertEqual(balance, 5000) #---------------------- def srtest020_lock(self): self.dm.l_mutation.lockNoWait(self.cacheconn, '00001') balance = self.dm.credit('00001', 10000, 'srtest010') self.assertEqual(balance, depmut.LOCK_FAILED) self.dm.l_mutation.release(self.cacheconn, '00001') #---------------------- def srtest030_adminHelperDepositMutation(self): post_data = { 'agent_id': '00001', 'type': 'D', 'amount': 5000 } tmp = self._callAdminHelper('deposit_mutation', post_data) self.assertEqual(tmp['success'], 1) self.assertEqual(tmp['balance'], 0) tmp = self._callAdminHelper('deposit_mutation', post_data) self.assertEqual(tmp['success'], 0) self.assertEqual(tmp['message'], 'NOT ENOUGH BALANCE') post_data['type'] = 'X' tmp = self._callAdminHelper('deposit_mutation', post_data) self.assertEqual(tmp['success'], 0) self.assertEqual(tmp['message'], 'TYPE NOT RECOGNIZED') post_data['agent_id'] = 'xxx' tmp = self._callAdminHelper('deposit_mutation', post_data) self.assertEqual(tmp['success'], 0) self.assertEqual(tmp['message'], 'AGENT NOT REGISTERED') #---------------------- def tearDown(self): self.cacheconn.delete('{0}_00001'.format(const.MUTATION_PREFIX)) self.dbconn.close()
class Authorizer(BaseComponent): """Authorize Topup Request """ def __init__(self): BaseComponent.__init__(self, "AU") self.c_operator = DBCache( const.OPERATOR_PREFIX, config.DEFAULT_EXPIRE, const.OPERATOR_SQL, user_func={"prefix": lambda x: x.split(",")}, ) self.c_product = DBCache(const.PRODUCT_PREFIX, config.DEFAULT_EXPIRE, const.PRODUCT_SQL) self.c_agentprice = DBCache(const.AGENTPRICE_PREFIX, config.DEFAULT_EXPIRE, const.AGENTPRICE_SQL) self.dm = DepositMutation(5, self.dbconn, self.cacheconn) self.um = UnitMutation(5, self.dbconn, self.cacheconn) self.log = mylogger("Authorizer", "authorizer.log") def authorize(self): requests = self.checkTopupRequest() if len(requests) == 0: return False for req in requests: agent_id, product_id = (req["agent_id"], req["product_id"]) tr_id, op_id = (req["transaction_id"], req["operator_id"]) prod_status, prod = self.checkProduct(product_id) if prod_status != PRODUCT_AVAILABLE: # self.productNotAvailable(req['reg_protocol'], product_id, prod_status) self.productNotAvailable(req["reg_protocol"], product_id) self.setDenied(tr_id, const.TR_DENIED_PRODUCT) continue ptype = int(prod["type"]) if ptype in (1, 3): num_status, op_name = self.checkDestination(op_id, req["msisdn_destination"]) if num_status != DEST_OP_MATCH: self.destOperatorDontMatch(req["reg_protocol"], req["msisdn_destination"], op_name) self.setDenied(tr_id, const.TR_DENIED_WRONG_NUMBER) continue if ptype in (1, 2, 3): prod_price, markup = self.getPriceForAgent(agent_id, product_id) if not prod_price: self.productNotAvailable(req["reg_protocol"], product_id) self.setDenied(tr_id, const.TR_DENIED_PRODUCT) continue if ptype in (1, 2): bal_stat, balance = self.deductBalance(agent_id, prod_price, tr_id) if ptype == 3: balance = self.um.debit(agent_id, product_id, 1, tr_id, "Topup {0}".format(tr_id)) if balance in (NOT_ENOUGH_BALANCE, LOCK_FAILED): bal_stat = BALANCE_NOT_ENOUGH balance = 0 if bal_stat != BALANCE_OK: self.notEnoughBalance(req["reg_protocol"], product_id, balance, req["msisdn_destination"]) self.setDeniedBalance(tr_id, const.TR_DENIED_BALANCE, balance) continue self.setAuthorized(tr_id, prod_price, balance, markup) self.dbconn.commit() return True def checkTopupRequest(self): cursor = self.dbconn.cursor(MySQLdb.cursors.DictCursor) cursor.execute( "SELECT SQL_NO_CACHE `transaction_id`,`agent_id`," "`product_id`,`reg_protocol`,`msisdn_destination`,`operator_id` " "FROM `transaction` where `status`={0} LIMIT 100".format(const.TR_WAIT) ) requests = cursor.fetchall() cursor.close() return requests def checkProduct(self, prodid): prod = self.c_product.get(self.dbconn, self.cacheconn, prodid) if not prod: return (PRODUCT_NOT_REGISTERED, None) if prod["active"] == 0: return (PRODUCT_NOT_SOLD, None) return (PRODUCT_AVAILABLE, prod) def checkDestination(self, op_id, dest): opdata = self.c_operator.get(self.dbconn, self.cacheconn, op_id) if opdata == None: print "No data for operator id {0}".format(op_id) self.log.critical("No data for operator id {0}".format(op_id)) return None try: if opdata["type"] == "G": if dest[0:4] in opdata["prefix"]: return (DEST_OP_MATCH, opdata["operator_name"]) else: return (DEST_OP_DONT_MATCH, opdata["operator_name"]) elif opdata["type"] == "C": if (dest[3] in opdata["prefix"]) or (dest[4] in opdata["prefix"]): return (DEST_OP_MATCH, opdata["operator_name"]) else: return (DEST_OP_DONT_MATCH, opdata["operator_name"]) except: return (DEST_OP_DONT_MATCH, opdata["operator_name"]) def deductBalance(self, agentid, price, tuid): balance = self.dm.getBalance(agentid) if balance < price: return (BALANCE_NOT_ENOUGH, balance) balance = self.dm.debit(agentid, price, "Topup {0}".format(tuid)) if balance == LOCK_FAILED: return (BALANCE_NOT_ENOUGH, 0) return (BALANCE_OK, balance) def setAuthorized(self, ids, price, balance, markup): cursor = self.dbconn.cursor(MySQLdb.cursors.DictCursor) cursor.execute( """UPDATE `transaction` set `status`={0}, `sell_price`=%s, `deposit`=%s, `markup_margin`=%s where `transaction_id`=%s""".format( const.TR_AUTHORIZED ), (price, balance, markup, ids), ) cursor.close() def setDenied(self, ids, status): cursor = self.dbconn.cursor(MySQLdb.cursors.DictCursor) cursor.execute("UPDATE `transaction` set `status`={0} " "WHERE `transaction_id`=%s".format(status), (ids,)) cursor.close() def setDeniedBalance(self, ids, status, balance): cursor = self.dbconn.cursor(MySQLdb.cursors.DictCursor) cursor.execute( "UPDATE `transaction` set `status`={0}," "`deposit`=%s where `transaction_id`=%s".format(status), (balance, ids), ) cursor.close() def getPriceForAgent(self, agentid, prodid): ap = self.c_agentprice.get(self.dbconn, self.cacheconn, (agentid, prodid)) if not ap: self.log.warning( "<getPriceForAgent> price not found for agent " "{0} and product {1}".format(agentid, prodid) ) return (None, None) return (int(ap["sell_price"]), int(ap["markup_upline"])) def productNotAvailable(self, prot, prodid): self.writeNotifyOut(prot, "prod_not_registered", {"product_id": prodid}) def notEnoughBalance(self, prot, prodid, balance, dest): self.writeNotifyOut( prot, "agent_not_enough_balance", {"product_id": prodid, "balance": thousandSeparator(balance), "dest": dest}, ) def destOperatorDontMatch(self, prot, num, opname): self.writeNotifyOut(prot, "num_op_dont_match", {"dest": num, "operator": opname})