示例#1
0
 def cancel(self):
     sql = '''SELECT * FROM `ticket` WHERE `status`=0 ORDER BY `checked_dt` ASC'''
     c = self.execSQL(MySQLdb.cursors.DictCursor, sql)
     tickets = c.fetchall()
     sql = '''UPDATE `ticket` SET `status`=3 WHERE `id`=%s'''
     c_agent = DBCache(const.AGENT_PREFIX, config.DEFAULT_EXPIRE,
                       const.AGENT_SQL)
     for t in tickets:
         self.execSQL(None, sql, (t['id'],))
         ag = c_agent.get(self.dbconn, self.cacheconn, t['agent_id'])
         self.writeNotifyOut(ag['default_protocol'], 'ticket_canceled', {})
     self.dbconn.commit()
示例#2
0
文件: admin.py 项目: sridwan/meong
 def web_trx(self, agent_id, product, msisdn, pin):
     bc = AgentNotifier()
     ma = ManageAgent(bc.dbconn, bc.cacheconn)
     hlrmap = HLRMap(bc.dbconn, bc.cacheconn)
     x = ma.verifyAgent(agent_id, '1234', True, False)
     if x['code'] in (agent.AGST_NOTFOUND, agent.AGST_NOTACTIVE):
         return json.dumps({'success': 0, 'reason': 'Agent not registered / not active'})
     prod_c = DBCache(const.PRODUCT_PREFIX, config.DEFAULT_EXPIRE,
                          const.PRODUCT_SQL)
     prod = prod_c.get(bc.dbconn, bc.cacheconn, product)
     if not prod:
         return json.dumps({'success': 0, 'reason': 'Invalid product id'})
     msisdn = sanitizeMSISDN(msisdn)
     method = firstMethod(hlrmap, prod, msisdn)
     tran_id = self.topup(bc, x['agent'], msisdn, prod, method)
     return json.dumps({'success': 1, 'reason': '', 'tranid': tran_id})
示例#3
0
 def _expired(self, ticket):
     if (ticket['request_dt'] + timedelta(hours=1)) >= datetime.now():
         return False
     sql = '''UPDATE `ticket` SET `status`=2 WHERE `id`=%s'''
     self.execSQL(None, sql, (ticket['id'],))
     c_agent = DBCache(const.AGENT_PREFIX, config.DEFAULT_EXPIRE,
                       const.AGENT_SQL)
     ag = c_agent.get(self.dbconn, self.cacheconn, ticket['agent_id'])
     if not ag:
         return True
     self.writeNotifyOut(ag['default_protocol'], 'ticket_expired', {
                             'agent_id': ag['agent_id'],
                             'name': ag['agent_name'],
                             'ticket': thousandSeparator(ticket['given_amount']),
                             'datetime': ticket['request_dt'].strftime('%d-%m-%y %H:%M'),
                         })
     c_agent = None
     return True
示例#4
0
文件: admin.py 项目: sridwan/sd
 def thUSSD(self, bc, msg, msisdn):
     sql = '''SELECT `device_id` FROM `sd` WHERE `sd_id`=%s'''
     c = bc.dbconn.cursor(MySQLdb.cursors.DictCursor)
     c.execute(sql, (ACTIVE_SD,))
     x = c.fetchone()
     if not x:
         print 'INVALID SD'
         return
     c_device = DBCache(const.DEVICES_PREFIX, config.DEFAULT_EXPIRE,
                             const.DEVICES_SQL)
     sd_dev = c_device.get(bc.dbconn, bc.cacheconn, x['device_id'])
     if not sd_dev:
         print 'INVALID DEVICE_ID FOR SD'
         return
     msg = msg.format(msisdn=msisdn, pin=sd_dev['pin'],
                            device_id=sd_dev['device_id'])
     leaf_server = '{0}@{2}/{1}'.format(config.LEAFSERVER, sd_dev['server_id'],
                                        config.MSG_SERVER)
     bc.sendMessage(leaf_server, 'JBDV', msg, commit=True)
示例#5
0
class MassStockCheck(BaseComponent):
    def __init__(self):
        BaseComponent.__init__(self, 'MC')
        self.c_dev = DBCache(const.DEVICES_PREFIX, config.DEFAULT_EXPIRE,
            const.DEVICES_SQL)
        self.logger = mylogger('MassStockCheck')
#----------------------
    def check(self):
        cursor = self.dbconn.cursor(MySQLdb.cursors.DictCursor)
        cursor.execute('''SELECT `device_id` from `devices`
            WHERE `function`=3 and `active`=1 and `status`=1''')
        rows = cursor.fetchall()
        for r in rows:
            if not self.stock_check(r['device_id']):
                self.logger.warning('<check> check stock device {0} fail'.format(r['device_id']))
        cursor.close()
#----------------------
    def stock_check(self, dev_id):
        dev = self.c_dev.get(self.dbconn, self.cacheconn, dev_id)
        if not dev:
            return False
        cursor = self.dbconn.cursor(MySQLdb.cursors.DictCursor)
        cursor.execute('''SELECT `check_stock_counter` from `devices` WHERE
            `device_id`=%s LIMIT 1''', (dev_id,))
        old_count = int(cursor.fetchone()['check_stock_counter'])
        cursor.execute('''SELECT `stock_check_1`,`stock_check_2` from `operator`
        WHERE `operator_id`=%s''', (dev['operator_id'],))
        r = cursor.fetchone()
        server_id, port = dev_id.split('.')
        leaf_server = '{0}@{2}/{1}'.format(config.LEAFSERVER, server_id,
            config.MSG_SERVER)
        parse = multipleReplace({'<pin>': dev['pin'],}, r['stock_check_1'])
        msg = '{0},{1},{2}'.format(port, '0', parse)
        self.sendMessage(leaf_server, 'JBDV', msg, commit=False)
        if len(r['stock_check_2']) > 0:
            parse = multipleReplace({'<pin>': dev['pin'],}, r['stock_check_2'])
            msg = '{0},{1},{2}'.format(port, '0', parse)
            self.sendMessage(leaf_server, 'JBDV', msg, commit=False)
        self.dbconn.commit()
        cursor.close()
        return True
示例#6
0
文件: GetInfo.py 项目: sridwan/meong
class GetInfo(BaseComponent):
    '''Class for getting info from an operator or supplier response such as
       destination MSISDN
    '''
    def __init__(self):
        BaseComponent.__init__(self, 'GI')
        self.c_words = DBCache(const.WORDS_PREFIX, config.DEFAULT_EXPIRE,
                               const.WORDS_SQL)
        self.reloadWords()
        self.haystack = None
        self.ref = None
        self.prefix = None
        self.success = None
        self.found_msisdn = None
        self.reload = datetime.now() + timedelta(seconds=RELOAD_WORDS)

    def __repr__(self):
        return 'Haystack: {0}\nPrefix: {1}\nRef marker: {2}\nSuccess: {3}\n' \
               'MSISDN: {4}\nMSISDN SQL text: {5}\nFound Ref: {6}'.\
                    format(self.haystack, self.prefix, self.ref, self.success, 
                           self.found_msisdn, self.getMSISDNSQL(), self.getSN())
    
    def reloadWords(self):
        tmp = self.c_words.get(self.dbconn, self.cacheconn, 1)
        self.success_words = map(lambda x: x['word'].lower(), tmp)
        tmp = self.c_words.get(self.dbconn, self.cacheconn, 0)
        self.fail_words = map(lambda x: x['word'].lower(), tmp)

    def process(self, haystack, prefix=None, ref='', ussd=False):
        self.haystack = haystack
        if ref == None:
            ref = ''
        try:
            ref = str(ref)
        except:
            ref = ''
        self.ref = ref
        self.prefix = prefix
        self.success = self.determineSuccessOrFail()
        self.found_msisdn = self.getMSISDN()
        if len(self.found_msisdn) == 0 and not ussd:
            self.success = 2

    def determineSuccessOrFail(self):
        if datetime.now() > self.reload:
            self.reload = datetime.now() + timedelta(seconds=RELOAD_WORDS)
            self.reloadWords()
        hs = self.haystack.lower()
        # fail = [x['word'] for x in self.fail_words if x['word'] in hs]
        fail = [x for x in self.fail_words if x in hs]
        if len(fail) > 0:
            return 0
        # success = [x['word'] for x in self.success_words if x['word'] in hs]
        success = [x for x in self.success_words if x in hs]
        if len(success) > 0:
            return 1
        return 2

    def getMSISDN(self):
        def remove62(nums):
            result = []
            for i in nums:
                if i[:2] == '62':
                    result.append('0{0}'.format(i[2:]))
                else:
                    result.append(i)
            return result
        def addZero(nums):
            result = []
            for i in nums:
                if i[0] != '0':
                    result.append('0{0}'.format(i))
                else:
                    result.append(i)
            return result
        def prefixFilterGSM(nums):
            result = []
            for i in nums:
                if i[:4] in self.prefix:
                    result.append(i)
            return result
        def prefixFilterCDMA(nums):
            result = []
            for i in nums:
                if i[3] in self.prefix or i[4] in self.prefix:
                    result.append(i)
            return result
        
        tmp = re.findall(r'(\d{9,})', self.haystack)
        tmp = remove62(tmp)
        tmp = addZero(tmp)
        # tmp = [x for x in tmp if len(x) > 9]
        if not self.prefix:
            return tmp
        if len(self.prefix[0]) == 4:
            tmp = prefixFilterGSM(tmp)
        elif len(self.prefix[0]) == 1:
            tmp = prefixFilterCDMA(tmp)
        return tmp

    def getMSISDNSQL(self, field='msisdn_destination'):
        first = True
        result = ''
        for i in self.found_msisdn:
            if first:
                result = '`{1}`="{0}"'.format(i, field)
                first = False;
            else:
                result = '{0} OR `{2}`="{1}"'.format(result, i, field)
        return result

    def getSN(self):
        if self.ref != '':
            hs = self.haystack.find(self.ref) + len(self.ref)
            tmp = re.search(r'\b(\w+)\b', self.haystack[hs:])
            if not tmp:
                return None
            return tmp.group(0)
        tmp = re.findall(r'\b(\w+)\b', self.haystack)
        tmp.sort(lambda x,y: cmp(len(x), len(y)), None, True)
        if not self.found_msisdn:
            return tmp[0]
        elif len(self.found_msisdn) > 1:
            return tmp[0]
        elif len(self.found_msisdn) == 1:
            for i in tmp:
                found = [x for x in self.found_msisdn if i[-9:] in x]
                if len(found) == 0:
                    return i
                    break
示例#7
0
文件: Sync.py 项目: sridwan/sd
class SDLPSync(LowPrioritySync):
    '''
    '''
    def __init__(self):
        super(SDLPSync, self).__init__()
        self.notifyin_handler = {
                'ceksaldo': self._checkDeposit,
                'sd_daftar': self._sd_daftar,
                'sd_transfer': self._sd_t,
                'sd_t500m': self._sd_t500m,
                'sd_t1g': self._sd_t1g,
                'sd_t2g': self._sd_t2g,
                'sd_t5g': self._sd_t5g,
                'sd_transfer_ord': self._sd_t,
                'sd_t500m_ord': self._sd_t500m,
                'sd_t1g_ord': self._sd_t1g,
                'sd_t2g_ord': self._sd_t2g,
                'sd_t5g_ord': self._sd_t5g,
                '3sakti_t': self._3sakti_t,
                '3sakti_t_ord': self._3sakti_t,
            }
        self.c_device = DBCache(const.DEVICES_PREFIX, config.DEFAULT_EXPIRE,
                                const.DEVICES_SQL)
        self.tran_parse = {
                't': '{device_id},0,ussd://*897*1*1*{msisdn}*{amount}*{pin}#',
                't500m': '{device_id},0,ussd://*897*1*2*{msisdn}*{amount}*{pin}#',
                't1g': '{device_id},0,ussd://*897*1*3*{msisdn}*{amount}*{pin}#',
                't2g': '{device_id},0,ussd://*897*1*4*{msisdn}*{amount}*{pin}#',
                't5g': '{device_id},0,ussd://*897*1*5*{msisdn}*{amount}*{pin}#',
            }
        self.price = {
                't500m': 33500,
                't1g': 48000,
                't2g': 72000,
                't5g': 120000,
            }

    def doPoint(self):
        return

    def doBonus(self):
        return
    
    @verifyAgent2
    def _3sakti_t(self, p, ag):
        try:
            am = int(p['amount'])
        except:
            self.writeNotifyOut(p['protocol'], 'amount_not_number',
                                {'amount': p['amount']})
            return        
        c = self.dbconn.cursor(MySQLdb.cursors.DictCursor)
        sql = '''SELECT * FROM `devices` WHERE `operator_id`=13 LIMIT 1'''
        c.execute(sql)
        sd_dev = c.fetchone()
        # sd_dev = self.c_device.get(self.dbconn, self.cacheconn, ch['device_id'])
        if not sd_dev:
            self.writeNotifyOut(p['protocol'], 'topup_fail', {})
            print 'INVALID DEVICE_ID'
            return
        if am < 10000 or am > 100000000:
            self.writeNotifyOut(p['protocol'], 'amount_not_number',
                                {'amount': p['amount']})
        msisdn = sanitizeMSISDN(p['msisdn'])
        if 'order' not in p:
            p['order'] = 1
        prod_id = '3S*{0}'.format(thousandSeparator(am))
        if self.checkTrx(p['protocol'], ag['agent_id'], prod_id, p['order'], msisdn):
            return
        cur_bal = self.dm.getBalance(ag['agent_id'])
        if cur_bal < am:
            self.writeNotifyOut(p['protocol'], 'agent_not_enough_balance', 
                                {'product_id': am, 'dest': msisdn, 'balance': cur_bal,})
            return
        new_deposit = self.dm.debit(ag['agent_id'], am,
                                    'transfer ke {0}'.format(msisdn))
        # new_deposit = 999
        sql = '''INSERT INTO `transaction` (`method`,`agent_id`,`agent_name`,
                 `reg_protocol`,`deposit`,`base_price`,`sell_price`,`profit`,
                 `product_id`,`operator_product_id`,`hlr_id`,`operator_id`,
                 `msisdn_destination`,`order`,`transaction_datetime`,`device_id`,
                 `status`) VALUES (%(method)s,%(agent_id)s,%(agent_name)s,
                 %(reg_protocol)s,%(deposit)s,%(base_price)s,%(sell_price)s,%(profit)s,
                 %(product_id)s,%(operator_product_id)s,%(hlr_id)s,%(operator_id)s,
                 %(msisdn_destination)s,%(order)s,%(transaction_datetime)s,%(device_id)s,
                 %(status)s)'''
        c.execute(sql, {
                'method': 'CH',
                'agent_id': ag['agent_id'],
                'agent_name': ag['agent_name'],
                'reg_protocol': p['protocol'],
                'deposit': new_deposit,
                'base_price': am,
                'sell_price': am,
                'profit': 0,
                'product_id': prod_id,
                'operator_product_id': prod_id,
                'hlr_id': 0,
                'operator_id': 13,
                'msisdn_destination': msisdn,
                'order': p['order'],
                'transaction_datetime': datetime.now(),
                'device_id': sd_dev['device_id'],
                'status': const.TR_INPROGRESS,
            })
        template = '{device_id},0,sms://089611223344,trf.{msisdn}.{amount}.{pin}'
        msg = template.format(msisdn=msisdn, amount=p['amount'],
                           pin=sd_dev['pin'], device_id=sd_dev['device_id'])
        leaf_server = '{0}@{2}/{1}'.format(config.LEAFSERVER, sd_dev['server_id'],
                                           config.MSG_SERVER)
        self.sendMessage(leaf_server, 'JBDV', msg, commit=False)
        print msg

    @verifyAgent2
    def _sd_daftar(self, p, ag):
        c = self.dbconn.cursor(MySQLdb.cursors.DictCursor)
        sql = '''SELECT `msisdn` FROM `rs` WHERE `msisdn`=%s'''
        msisdn = sanitizeMSISDN(p['msisdn'])
        c.execute(sql, (msisdn,))
        if c.fetchone():
            self.writeNotifyOut(p['protocol'], 'rs_exist', {'msisdn': p['msisdn']})
            return
        sql = '''SELECT `device_id` FROM `sd` WHERE `sd_id`=%s'''
        c.execute(sql, (ACTIVE_SD,))
        x = c.fetchone()
        if not x:
            print 'INVALID SD'
            return
        sd_dev = self.c_device.get(self.dbconn, self.cacheconn, x['device_id'])
        if not sd_dev:
            print 'INVALID DEVICE_ID FOR SD'
            return
        msg = SD_DAFTAR.format(msisdn=msisdn, pin=sd_dev['pin'],
                               device_id=sd_dev['device_id'])
        leaf_server = '{0}@{2}/{1}'.format(config.LEAFSERVER, sd_dev['server_id'],
                                           config.MSG_SERVER)
        self.sendMessage(leaf_server, 'JBDV', msg, commit=False)
        sql = '''INSERT INTO `rs` (`msisdn`,`sd_id`,`name`,`address`,`agent_id`,`status`)
                 VALUES (%(msisdn)s,%(sd_id)s,%(name)s,%(address)s,%(agent_id)s,%(status)s)'''
        c.execute(sql, {
                'msisdn': msisdn,
                'sd_id': ACTIVE_SD,
                'name': p['name'],
                'address': p['address'],
                'agent_id': ag['agent_id'],
                'status': 9,
            })
        self.writeNotifyOut(p['protocol'], 'begin_rs_register', {'msisdn': msisdn})
    
    @verifyAgent2
    def _sd_t(self, p, ag):
        self._sd_transfer(p, ag, 't')

    @verifyAgent2
    def _sd_t500m(self, p, ag):
        self._sd_transfer(p, ag, 't500m')

    @verifyAgent2
    def _sd_t1g(self, p, ag):
        self._sd_transfer(p, ag, 't1g')

    @verifyAgent2
    def _sd_t2g(self, p, ag):
        self._sd_transfer(p, ag, 't2g')

    @verifyAgent2
    def _sd_t5g(self, p, ag):
        self._sd_transfer(p, ag, 't5g')

    def _sd_transfer(self, p, ag, prod='t'):
        try:
            am = int(p['amount'])
        except:
            self.writeNotifyOut(p['protocol'], 'amount_not_number',
                                {'amount': p['amount']})
            return
        min_am = 1
        if prod == 't':
            min_am = 10000
        if am < min_am or am > 100000000:
            self.writeNotifyOut(p['protocol'], 'amount_not_number',
                                {'amount': p['amount']})
            return
        msisdn = sanitizeMSISDN(p['msisdn'])
        if 'order' not in p:
            p['order'] = 1
        sql = '''SELECT `rs`.`msisdn`,`rs`.`status`,`sd`.`device_id` FROM `rs`
                 INNER JOIN `sd` ON `sd`.`sd_id` = `rs`.`sd_id`
                 WHERE `rs`.`msisdn`=%s'''
        c = self.dbconn.cursor(MySQLdb.cursors.DictCursor)
        c.execute(sql, (msisdn,))
        ch = c.fetchone()
        if not ch:
            self.writeNotifyOut(p['protocol'], 'rs_not_registered',
                                {'msisdn': msisdn})
            return
        if int(ch['status']) == 9:
            self.writeNotifyOut(p['protocol'], 'rs_not_registered',
                                {'msisdn': msisdn})
            return
        if int(ch['status']) == 0:
            self.writeNotifyOut(p['protocol'], 'rs_suspended',
                                {'msisdn': msisdn})
            return
        sd_dev = self.c_device.get(self.dbconn, self.cacheconn, ch['device_id'])
        if not sd_dev:
            self.writeNotifyOut(p['protocol'], 'topup_fail', {})
            print 'INVALID DEVICE_ID'
            return
        if prod == 't':
            prod_id = 'S#{0}'.format(thousandSeparator(am))
        else:
            prod_id = '{0}#{1}'.format(prod.upper(), am)
            am = self.price[prod] * am
        if self.checkTrx(p['protocol'], ag['agent_id'], prod_id, p['order'], msisdn):
            return
        cur_bal = self.dm.getBalance(ag['agent_id'])
        if cur_bal < am:
            self.writeNotifyOut(p['protocol'], 'agent_not_enough_balance', 
                                {'product_id': am, 'dest': msisdn, 'balance': cur_bal,})
            return
        new_deposit = self.dm.debit(ag['agent_id'], am,
                                    'transfer ke {0}'.format(msisdn))
        sql = '''INSERT INTO `transaction` (`method`,`agent_id`,`agent_name`,
                 `reg_protocol`,`deposit`,`base_price`,`sell_price`,`profit`,
                 `product_id`,`operator_product_id`,`hlr_id`,`operator_id`,
                 `msisdn_destination`,`order`,`transaction_datetime`,`device_id`,
                 `status`) VALUES (%(method)s,%(agent_id)s,%(agent_name)s,
                 %(reg_protocol)s,%(deposit)s,%(base_price)s,%(sell_price)s,%(profit)s,
                 %(product_id)s,%(operator_product_id)s,%(hlr_id)s,%(operator_id)s,
                 %(msisdn_destination)s,%(order)s,%(transaction_datetime)s,%(device_id)s,
                 %(status)s)'''
        c.execute(sql, {
                'method': 'CH',
                'agent_id': ag['agent_id'],
                'agent_name': ag['agent_name'],
                'reg_protocol': p['protocol'],
                'deposit': new_deposit,
                'base_price': am,
                'sell_price': am,
                'profit': 0,
                'product_id': prod_id,
                'operator_product_id': prod_id,
                'hlr_id': 0,
                'operator_id': 4,
                'msisdn_destination': msisdn,
                'order': p['order'],
                'transaction_datetime': datetime.now(),
                'device_id': sd_dev['device_id'],
                'status': const.TR_INPROGRESS,
            })
        template = self.tran_parse[prod]
        msg = template.format(msisdn=msisdn, amount=p['amount'],
                           pin=sd_dev['pin'], device_id=sd_dev['device_id'])
        leaf_server = '{0}@{2}/{1}'.format(config.LEAFSERVER, sd_dev['server_id'],
                                           config.MSG_SERVER)
        self.sendMessage(leaf_server, 'JBDV', msg, commit=False)

    def checkTrx(self, prot, agent_id, prod_id, order, msisdn):
        def getStatusMsg(status):
            if status < const.TR_EXECUTED:
                return 'DALAM PROSES'
            elif status == const.TR_RETRIED:
                return 'DALAM PROSES'
            elif status >= const.TR_EXECUTED and status < const.TR_FAILED_HLR:
                return 'BERHASIL'
            return 'GAGAL'
        
        sql = '''SELECT `product_id`,`status`,`order`,`references`,`transaction_datetime`
                 FROM `transaction`
                 WHERE `transaction_datetime`>=%s and `transaction_datetime`<=%s
                 AND `agent_id`=%s and `msisdn_destination`=%s
                 AND `product_id`=%s and `order`=%s
                 ORDER BY `transaction_id` DESC LIMIT 1'''
        tmp = datetime.now()
        start_date = datetime(tmp.year, tmp.month, tmp.day, 0, 0, 0, 0)
        end_date = datetime(tmp.year, tmp.month, tmp.day, 23, 59, 59)
        cursor = self.dbconn.cursor(MySQLdb.cursors.DictCursor)
        cursor.execute(sql, (start_date, end_date, agent_id, msisdn, prod_id,
                             order))
        r = cursor.fetchone()
        if r:  # trx exist, return status
            topup_status = getStatusMsg(r['status'])
            st = int(r['status'])
            if st == const.TR_RETRIED:
                ref = ''
            elif st >= const.TR_EXECUTED and st < const.TR_FAILED_HLR:
                ref = 'SN:{0}'.format(r['references'])
            else:
                ref = ''
            self.writeNotifyOut(prot, 'transaction_exist', {
                'product_id': self.productIdAndOrder(r['product_id'],
                                                     r['order']),
                'dest': msisdn,
                'timestamp': r['transaction_datetime'].\
                             strftime('%d/%m/%y %H:%M:%S'),
                'status': topup_status,
                'ref': ref,
              })
            return True
        return False
示例#8
0
文件: agent.py 项目: sridwan/meong
class ManageAgent(object):
    '''Agent management like new agent, change markup, etc'''
    def __init__(self, dbconn=None, cacheconn=None):
        self.dbconn = dbconn
        self.cacheconn = cacheconn
        self.c_agent = DBCache(const.AGENT_PREFIX, config.DEFAULT_EXPIRE,
            const.AGENT_SQL)
        self.c_regprotocol = DBCache(const.REGPROTOCOL_PREFIX, config.DEFAULT_EXPIRE,
            const.REGPROTOCOL_SQL)
        self.c_agprice = DBCache(const.AGENTPRICE_PREFIX, config.DEFAULT_EXPIRE,
            const.AGENTPRICE_SQL)

    def setConn(self, dbconn, cacheconn):
        self.dbconn = dbconn
        self.cacheconn = cacheconn

    def getAgentData(self, agent_id):
        return self.c_agent.get(self.dbconn, self.cacheconn, agent_id)

    def resolveProtocol(self, prot):
        agent = self.c_regprotocol.get(self.dbconn, self.cacheconn, prot)
        if not agent:
            return None
        return agent['agent_id']

    def newAgent(self, name, addr, atype, pin, upline, markup, setprice, defprot):
        cursor = self.dbconn.cursor(MySQLdb.cursors.DictCursor)
        cursor.execute('''SELECT `agent_id` from `agent` order by `agent_id` DESC
          LIMIT 1 FOR UPDATE''')
        r = cursor.fetchone()
        if not r:
            next_id = '{0:0>{1}}'.format(1, config.AGENT_ID_LENGTH)
            markup_upline = 0
        else:
            next_id = '{0:0>{1}}'.format(int(r['agent_id']) + 1, config.AGENT_ID_LENGTH)
            cursor.execute('SELECT `markup` from `agent` where `agent_id`=%s', (upline,))
            markup_upline = int(cursor.fetchone()['markup'])
        try:
            cursor.execute('''INSERT INTO `agent` (`agent_id`,`active`,`agent_name`,
              `agent_address`,`agent_type`,`pin`,`upline_id`,`set_price`,
              `register_date`,`last_update_by`,`markup`,`markup_upline`,
              `default_protocol`) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)''',
              (next_id, 1, name, addr, atype, pin, upline,
              setprice, datetime.now(), 'comp:ManageAgent', markup, markup_upline,
              defprot))
            self.generatePrice(next_id, markup_upline, setprice)
            cursor.close()
        except:
            cursor.close()
            raise
            # return None
        return next_id

    def registerProtocols(self, agent_id, protocols):
        '''Register an agent's protocol(s) with the system.
        protocols is a comma separated values string'''
        cursor = self.dbconn.cursor()
        to_db = []
        prots = protocols.split(',')
        for p in prots:
            if p.strip() == '':
                continue
            cursor.execute('''SELECT `reg_protocol` from `regprotocol` WHERE
              `reg_protocol`=%s LIMIT 1''', (p,))
            if cursor.fetchone():
                continue
            to_db.append({'protocol': p, 'agent_id': agent_id})
        if len(to_db) ==  0:
            return False
        cursor.executemany('''INSERT INTO `regprotocol` (`reg_protocol`,`agent_id`)
          VALUES (%(protocol)s,%(agent_id)s)''', to_db)
        return True

    def clearAgentCache(self, agent_id):
        '''Clear an agent's cached data from memcache
        '''
        self.c_agent.delete(self.cacheconn, agent_id)
        cursor = self.dbconn.cursor()
        cursor.execute('''SELECT `reg_protocol` from `regprotocol` WHERE
          `agent_id`=%s''', (agent_id,))
        for row in cursor:
            self.cacheconn.delete('{0}_{1}'.format(const.REGPROTOCOL_PREFIX, row[0]))
        cursor.close()

    def verifyAgent(self, agent_id, pin, cache=True, strict=True):
        '''Verify and fetch an agent's data
        Returns a dictionary, key "code" & "agent"'''
        if cache:
            agent = self.c_agent.get(self.dbconn, self.cacheconn, agent_id)
        else:
            cursor = self.dbconn.cursor(MySQLdb.cursors.DictCursor)
            cursor.execute(const.AGENT_SQL, (agent_id,))
            agent = cursor.fetchone()
            cursor.close()
        if not agent:
            return {
              'code': AGST_NOTFOUND,
              'agent': None,
            }
        if strict:
            stagent = None
        else:
            stagent = agent
        if int(agent['active']) == 0:
            return {
                      'code': AGST_NOTACTIVE,
                      'agent': stagent,
                   }
        if pin != agent['pin']:
            return {
                      'code': AGST_WRONGPIN,
                      'agent': stagent,
                   }
        return {
                  'code': AGST_FOUND,
                  'agent': agent,
               }

    def verifyFrontline(self, agent_id, front_id):
        '''Verify upline-frontline relationship. Returns True or False'''
        cursor = self.dbconn.cursor()
        cursor.execute('''SELECT `agent_id` from `agent` where `agent_id`=%s
          AND `upline_id`=%s LIMIT 1''', (front_id, agent_id))
        exist = cursor.fetchone()
        cursor.close()
        if exist:
            return True
        return False
    
    def verifyDownline(self, agent_id, dl_id):
        '''Verify upline-downline relationship including frontline.
           Returns True or False'''
        c = self.dbconn.cursor()
        found_id = dl_id
        ag_type = 1
        while found_id != agent_id and ag_type != 0:
            c.execute('''SELECT `agent_type`,`upline_id` FROM `agent`
                         WHERE `agent_id`=%s''', (found_id,))
            ag = c.fetchone()
            if not ag:
                return False
            found_id = ag['upline_id']
            ag_type = int(ag['agent_type'])
        if found_id != agent_id or ag_type != 0:
            return False
        elif found_id == agent_id:
            return True
        return False

    def countMarkupDifference(self, agent_id, new_markup):
        '''Returns markup difference from the old markup value'''
        cursor = self.dbconn.cursor()
        cursor.execute('''SELECT `markup_upline` from `agent` where `agent_id`=%s
          LIMIT 1''', (agent_id,))
        exist = cursor.fetchone()
        cursor.close()
        if not exist:
            return 0
        markup_change = new_markup - int(exist[0])
        return markup_change

    def changeDownlineMarkup(self, _agent_id, new_markup):
        cursor = self.dbconn.cursor()
        cursor.execute('SELECT SQL_NO_CACHE `markup_upline` from `agent` where `agent_id`=%s',
          (_agent_id,))
        old_markup = cursor.fetchone()[0]
        self.changeDownlineMarkup2(_agent_id, old_markup, new_markup, True)

    def changeDownlineMarkup2(self, _agent_id, old_markup, new_markup,
      self_update=True):
        '''Change all price of an agent and his/her downline(s)
        '''
        diff_markup = new_markup - old_markup
        to_change = self._genDownlineList(_agent_id)
        to_change.append(_agent_id)
        cursor = self.dbconn.cursor(MySQLdb.cursors.DictCursor)
        for agent_id in to_change:
            cursor.execute('''SELECT `agent_id`,`product_id`,`sell_price`,`markup_upline`
            FROM `agent_price` where `agent_id`=%s''', (agent_id,))
            for r in cursor:
                cursor.execute('''UPDATE `agent_price` set `sell_price`=%s WHERE
                  `agent_id`=%s and `product_id`=%s''', (int(r['sell_price'])+diff_markup,
                  r['agent_id'], r['product_id']))
                self.c_agprice.delete(self.cacheconn, (r['agent_id'], r['product_id']))
        cursor.execute('UPDATE `agent_price` set `markup_upline`=%s WHERE \
          `agent_id`=%s', (new_markup, _agent_id,))
        if not self_update:
            cursor.close()
            return
        cursor.execute('UPDATE `agent` set `markup_upline`=%s where `agent_id`=%s \
          LIMIT 1', (new_markup, _agent_id))
        cursor.close()

    def changeGlobalMarkup(self, agent_id, new_markup, self_update=True):
        '''Change prices for all downlines
        '''
        frontlines_ = self._getFrontlineList(agent_id)
        for frontline in frontlines_:
            self.changeDownlineMarkup(frontline, new_markup)
        if not self_update:
            return
        cursor = self.dbconn.cursor()
        cursor.execute('UPDATE `agent` set `markup`=%s where `agent_id`=%s LIMIT 1',
          (new_markup, agent_id))
        cursor.close()

    def generatePrice(self, agent_id, markup_=-1, setpriceid=1):
        '''Generate an agent's price based on his/her upline's price and markup
        '''
        cursor = self.dbconn.cursor(MySQLdb.cursors.DictCursor)
        cursor.execute('SELECT `upline_id`,`markup_upline` from `agent` WHERE \
          `agent_id`=%s', (agent_id,))
        exist = cursor.fetchone()
        if not exist:
            return False
        upline_id = exist['upline_id']
        if markup_ < 0:
            markup_upline = int(exist['markup_upline'])
        else:
            markup_upline = markup_
        if int(setpriceid) == 1:
            cursor.execute('SELECT `agent_id`,`product_id`,`sell_price`,`markup_upline` \
                FROM `agent_price` where `agent_id`=%s', (upline_id,))
        else:
            cursor.execute('SELECT `product_id`,`sell_price` \
                FROM `set_price` where `set_price_id`=%s', (setpriceid,))
        for r in cursor:
            cursor.execute('''REPLACE INTO `agent_price` set `sell_price`=%s,
                `agent_id`=%s, `product_id`=%s, `markup_upline`=%s''',
                (int(r['sell_price'])+markup_upline, agent_id, r['product_id'],
                markup_upline))
            self.c_agprice.delete(self.cacheconn, (agent_id, r['product_id']))
        if markup_ < 0:
            cursor.close()
            return True
        cursor.execute('UPDATE `agent` set `markup_upline`=%s where `agent_id`=%s LIMIT 1',
            (markup_upline, agent_id))
        cursor.close()
        self.c_agent.delete(self.cacheconn, agent_id)
        return True

    def _genDownlineList(self, agent_id):
        result = []
        cursor = self.dbconn.cursor(MySQLdb.cursors.DictCursor)
        get_agent = [agent_id,]
        while len(get_agent) > 0:
            ag = get_agent.pop()
            cursor.execute('SELECT `agent_id` from `agent` where `upline_id`=%s', (ag,))
            rows = cursor.fetchall()
            tmp = map(lambda i: i['agent_id'], rows)
            result += tmp
            get_agent += tmp
            if ag == agent_id:
                continue
                #result.append('-')
        cursor.close()
        return result

    def _getFrontlineList(self, agent_id):
        '''List all frontline. Return a list'''

        cursor = self.dbconn.cursor(MySQLdb.cursors.DictCursor)
        # get frontline
        cursor.execute('SELECT `agent_id` from `agent` where `upline_id`=%s', (agent_id,))
        result = map(lambda x: x['agent_id'], cursor.fetchall())
        cursor.close()
        return result
示例#9
0
 def getProduct(self, bc, prodid):
     prod_c = DBCache(const.PRODUCT_PREFIX, config.DEFAULT_EXPIRE,
                          const.PRODUCT_SQL)
     return prod_c.get(bc.dbconn, bc.cacheconn, prodid)
示例#10
0
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})