Subversion Repositories SmartDukaan

Rev

Rev 16366 | Rev 16545 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

from bson import json_util
from bson.json_util import dumps
from datetime import datetime, timedelta
from pyshorteners.shorteners  import Shortener
from dtr import main
from dtr.config import PythonPropertyReader
from dtr.storage import Mongo
from dtr.storage.DataService import Retailers, Users, CallHistory, RetryConfig, \
    RetailerLinks, Activation_Codes, Agents, Agent_Roles, AgentLoginTimings, \
    FetchDataHistory, RetailerContacts, Orders, OnboardedRetailerChecklists,\
    RetailerAddresses, Pincodeavailability
from dtr.storage.Mongo import get_mongo_connection
from dtr.storage.Mysql import fetchResult
from dtr.utils import FetchLivePrices, DealSheet as X_DealSheet, \
    UserSpecificDeals
from dtr.utils.utils import getLogger
from elixir import *
from operator import and_
from sqlalchemy.sql.expression import func, func, or_
from urllib import urlencode
import contextlib
import falcon
import json
import re
import string
import traceback
import urllib
import urllib2
import uuid
import gdshortener
alphalist = list(string.uppercase)
alphalist.remove('O')
numList = ['1','2','3','4','5','6','7','8','9']
codesys = [alphalist, alphalist, numList, numList, numList]
CONTACT_PRIORITY = ['sms', 'called', 'ringing']
RETRY_MAP = {'fresh':'retry', 'followup':'fretry', 'onboarding':'oretry'}
ASSIGN_MAP = {'retry':'assigned', 'fretry':'fassigned', 'oretry':'oassigned'}

def getNextCode(codesys, code=None):
    if code is None:
        code = []
        for charcode in codesys:
            code.append(charcode[0])
        return string.join(code, '')
    carry = True
    code = list(code)
    lastindex = len(codesys) - 1
    while carry:
        listChar = codesys[lastindex]
        newIndex = (listChar.index(code[lastindex])+1)%len(listChar)
        print newIndex
        code[lastindex] = listChar[newIndex]
        if newIndex != 0:
            carry = False
        lastindex -= 1
        if lastindex ==-1:
            raise BaseException("All codes are exhausted")
        
    return string.join(code, '')
        
        


global RETAILER_DETAIL_CALL_COUNTER
RETAILER_DETAIL_CALL_COUNTER = 0

lgr = getLogger('/var/log/retailer-acquisition-api.log')
DEALER_RETRY_FACTOR = int(PythonPropertyReader.getConfig('DEALER_RETRY_FACTOR'))
class CategoryDiscountInfo(object):
    
    def on_get(self, req, resp):
        
        result = Mongo.getAllCategoryDiscount()
        json_docs = [json.dumps(doc, default=json_util.default) for doc in result]
        resp.body = json.dumps(json_docs, encoding='utf-8')
    
    def on_post(self, req, resp):
        try:
            result_json = json.loads(req.stream.read(), encoding='utf-8')
        except ValueError:
            raise falcon.HTTPError(falcon.HTTP_400,
                'Malformed JSON',
                'Could not decode the request body. The '
                'JSON was incorrect.')
            
        result = Mongo.addCategoryDiscount(result_json)
        resp.body = json.dumps(result, encoding='utf-8')
    
    def on_put(self, req, resp, _id):
        try:
            result_json = json.loads(req.stream.read(), encoding='utf-8')
        except ValueError:
            raise falcon.HTTPError(falcon.HTTP_400,
                'Malformed JSON',
                'Could not decode the request body. The '
                'JSON was incorrect.')
            
        result = Mongo.updateCategoryDiscount(result_json, _id)
        resp.body = json.dumps(result, encoding='utf-8')
            
        
        
class SkuSchemeDetails(object):
    
    def on_get(self, req, resp):
        
        offset = req.get_param_as_int("offset")
        limit = req.get_param_as_int("limit")
        
        result = Mongo.getAllSkuWiseSchemeDetails(offset, limit)
        json_docs = [json.dumps(doc, default=json_util.default) for doc in result]
        resp.body = json.dumps(json_docs, encoding='utf-8')

    
    def on_post(self, req, resp):
        
        multi = req.get_param_as_int("multi")
        
        try:
            result_json = json.loads(req.stream.read(), encoding='utf-8')
        except ValueError:
            raise falcon.HTTPError(falcon.HTTP_400,
                'Malformed JSON',
                'Could not decode the request body. The '
                'JSON was incorrect.')
            
        result = Mongo.addSchemeDetailsForSku(result_json)
        resp.body = json.dumps(result, encoding='utf-8')
        
class SkuDiscountInfo():
    
    def on_get(self, req, resp):
        
        offset = req.get_param_as_int("offset")
        limit = req.get_param_as_int("limit")
        result = Mongo.getallSkuDiscountInfo(offset,limit)
        json_docs = [json.dumps(doc, default=json_util.default) for doc in result]
        resp.body = json.dumps(json_docs, encoding='utf-8')

    
    def on_post(self, req, resp):
        
        multi = req.get_param_as_int("multi")
        
        try:
            result_json = json.loads(req.stream.read(), encoding='utf-8')
        except ValueError:
            raise falcon.HTTPError(falcon.HTTP_400,
                'Malformed JSON',
                'Could not decode the request body. The '
                'JSON was incorrect.')
            
        result = Mongo.addSkuDiscountInfo(result_json)
        resp.body = json.dumps(result, encoding='utf-8')
        
    def on_put(self, req, resp, _id):
        try:
            result_json = json.loads(req.stream.read(), encoding='utf-8')
        except ValueError:
            raise falcon.HTTPError(falcon.HTTP_400,
                'Malformed JSON',
                'Could not decode the request body. The '
                'JSON was incorrect.')
            
        result = Mongo.updateSkuDiscount(result_json, _id)
        resp.body = json.dumps(result, encoding='utf-8')

class ExceptionalNlc():
    
    def on_get(self, req, resp):
        
        offset = req.get_param_as_int("offset")
        limit = req.get_param_as_int("limit")
        
        result = Mongo.getAllExceptionlNlcItems(offset, limit)
        json_docs = [json.dumps(doc, default=json_util.default) for doc in result]
        resp.body = json.dumps(json_docs, encoding='utf-8')
    
    def on_post(self, req, resp):
        
        multi = req.get_param_as_int("multi")
        
        try:
            result_json = json.loads(req.stream.read(), encoding='utf-8')
        except ValueError:
            raise falcon.HTTPError(falcon.HTTP_400,
                'Malformed JSON',
                'Could not decode the request body. The '
                'JSON was incorrect.')
            
        result = Mongo.addExceptionalNlc(result_json)
        resp.body = json.dumps(result, encoding='utf-8')
    
    def on_put(self, req, resp, _id):
        try:
            result_json = json.loads(req.stream.read(), encoding='utf-8')
        except ValueError:
            raise falcon.HTTPError(falcon.HTTP_400,
                'Malformed JSON',
                'Could not decode the request body. The '
                'JSON was incorrect.')
            
        result = Mongo.updateExceptionalNlc(result_json, _id)
        resp.body = json.dumps(result, encoding='utf-8')
        
class Deals():
    def on_get(self,req, resp, userId):
        categoryId = req.get_param_as_int("categoryId")
        offset = req.get_param_as_int("offset")
        limit = req.get_param_as_int("limit")
        sort = req.get_param("sort")
        direction = req.get_param_as_int("direction")
        filterData = req.get_param('filterData')
        result = Mongo.getNewDeals(int(userId), categoryId, offset, limit, sort, direction, filterData)
        resp.body = dumps(result) 

class MasterData():
    def on_get(self,req, resp, skuId):
        showDp = req.get_param_as_int("showDp")
        result = Mongo.getItem(skuId, showDp)
        try:
            json_docs = [json.dumps(doc, default=json_util.default) for doc in result]
            resp.body = json.dumps(json_docs, encoding='utf-8')
        except:
            json_docs = [json.dumps(doc, default=json_util.default) for doc in result]
            resp.body = json.dumps(json_docs, encoding='utf-8')
    
    def on_post(self,req, resp):
        
        addNew = req.get_param_as_int("addNew")
        update = req.get_param_as_int("update")
        addToExisting = req.get_param_as_int("addToExisting")
        multi = req.get_param_as_int("multi")
        
        try:
            result_json = json.loads(req.stream.read(), encoding='utf-8')
        except ValueError:
            raise falcon.HTTPError(falcon.HTTP_400,
                'Malformed JSON',
                'Could not decode the request body. The '
                'JSON was incorrect.')
            
        if addNew == 1:
            result = Mongo.addNewItem(result_json)
        elif update == 1:
            result = Mongo.updateMaster(result_json, multi)
        elif addToExisting == 1:
            result = Mongo.addItemToExistingBundle(result_json)
        else:
            raise
        resp.body = dumps(result)
    
class LiveData():
    def on_get(self,req, resp):
        if req.get_param_as_int("id") is not None:
            print "****getting only for id"
            id = req.get_param_as_int("id")
            try:
                result = FetchLivePrices.getLatestPriceById(id)
                json_docs = json.dumps(result, default=json_util.default)
                resp.body = json.dumps(json_docs, encoding='utf-8')
            except:
                json_docs = json.dumps({}, default=json_util.default)
                resp.body = json.dumps(json_docs, encoding='utf-8')
            
        else:
            print "****getting only for skuId"
            skuBundleId = req.get_param_as_int("skuBundleId")
            source_id = req.get_param_as_int("source_id")
            try:
                result = FetchLivePrices.getLatestPrice(skuBundleId, source_id)
                json_docs = [json.dumps(doc, default=json_util.default) for doc in result]
                resp.body = json.dumps(json_docs, encoding='utf-8')
            except:
                json_docs = [json.dumps(doc, default=json_util.default) for doc in [{}]]
                resp.body = json.dumps(json_docs, encoding='utf-8')
                
class CashBack():
    def on_get(self,req, resp):
        identifier = req.get_param("identifier")
        source_id = req.get_param_as_int("source_id")
        try:
            result = Mongo.getCashBackDetails(identifier, source_id)
            json_docs = json.dumps(result, default=json_util.default)
            resp.body = json_docs
        except:
            json_docs = json.dumps({}, default=json_util.default)
            resp.body = json_docs

class ImgSrc():
    def on_get(self,req, resp):
        identifier = req.get_param("identifier")
        source_id = req.get_param_as_int("source_id")
        try:
            result = Mongo.getImgSrc(identifier, source_id)
            json_docs = json.dumps(result, default=json_util.default)
            resp.body = json_docs
        except:
            json_docs = json.dumps({}, default=json_util.default)
            resp.body = json_docs

class DealSheet():
    def on_get(self,req, resp):
        X_DealSheet.sendMail()
        json_docs = json.dumps({'True':'Sheet generated, mail sent.'}, default=json_util.default)
        resp.body = json.dumps(json_docs, encoding='utf-8')
    
class DealerPrice():
    
    def on_get(self, req, resp):
        
        offset = req.get_param_as_int("offset")
        limit = req.get_param_as_int("limit")
        result = Mongo.getAllDealerPrices(offset,limit)
        json_docs = [json.dumps(doc, default=json_util.default) for doc in result]
        resp.body = json.dumps(json_docs, encoding='utf-8')
    
    def on_post(self, req, resp):
        
        multi = req.get_param_as_int("multi")
        
        try:
            result_json = json.loads(req.stream.read(), encoding='utf-8')
        except ValueError:
            raise falcon.HTTPError(falcon.HTTP_400,
                'Malformed JSON',
                'Could not decode the request body. The '
                'JSON was incorrect.')
            
        result = Mongo.addSkuDealerPrice(result_json)
        resp.body = json.dumps(result, encoding='utf-8')
    
    def on_put(self, req, resp, _id):
        try:
            result_json = json.loads(req.stream.read(), encoding='utf-8')
        except ValueError:
            raise falcon.HTTPError(falcon.HTTP_400,
                'Malformed JSON',
                'Could not decode the request body. The '
                'JSON was incorrect.')
            
        result = Mongo.updateSkuDealerPrice(result_json, _id)
        resp.body = json.dumps(result, encoding='utf-8')

    
class ResetCache():
    
    def on_get(self,req, resp, userId):
        result = Mongo.resetCache(userId)
        resp.body = json.dumps(result, encoding='utf-8')
        
class UserDeals():
    def on_get(self,req,resp,userId):
        UserSpecificDeals.generateSheet(userId)
        json_docs = json.dumps({'True':'Sheet generated, mail sent.'}, default=json_util.default)
        resp.body = json.dumps(json_docs, encoding='utf-8')

class CommonUpdate():
    
    def on_post(self,req,resp):
        
        multi = req.get_param_as_int("multi")
        
        try:
            result_json = json.loads(req.stream.read(), encoding='utf-8')
        except ValueError:
            raise falcon.HTTPError(falcon.HTTP_400,
                'Malformed JSON',
                'Could not decode the request body. The '
                'JSON was incorrect.')
            
        result = Mongo.updateCollection(result_json)
        resp.body = json.dumps(result, encoding='utf-8')
        resp.content_type = "application/json; charset=utf-8"

class NegativeDeals():
    
    def on_get(self, req, resp):
        
        offset = req.get_param_as_int("offset")
        limit = req.get_param_as_int("limit")
        
        result = Mongo.getAllNegativeDeals(offset, limit)
        resp.body = dumps(result) 

    
    def on_post(self, req, resp):
        
        multi = req.get_param_as_int("multi")
        
        try:
            result_json = json.loads(req.stream.read(), encoding='utf-8')
        except ValueError:
            raise falcon.HTTPError(falcon.HTTP_400,
                'Malformed JSON',
                'Could not decode the request body. The '
                'JSON was incorrect.')
            
        result = Mongo.addNegativeDeals(result_json, multi)
        resp.body = json.dumps(result, encoding='utf-8')

class ManualDeals():
    
    def on_get(self, req, resp):
        
        offset = req.get_param_as_int("offset")
        limit = req.get_param_as_int("limit")
        
        result = Mongo.getAllManualDeals(offset, limit)
        resp.body = dumps(result)

    
    def on_post(self, req, resp):
        
        multi = req.get_param_as_int("multi")
        
        try:
            result_json = json.loads(req.stream.read(), encoding='utf-8')
        except ValueError:
            raise falcon.HTTPError(falcon.HTTP_400,
                'Malformed JSON',
                'Could not decode the request body. The '
                'JSON was incorrect.')
            
        result = Mongo.addManualDeal(result_json, multi)
        resp.body = json.dumps(result, encoding='utf-8')
        
class CommonDelete():
    
    def on_post(self,req,resp):
        try:
            result_json = json.loads(req.stream.read(), encoding='utf-8')
        except ValueError:
            raise falcon.HTTPError(falcon.HTTP_400,
                'Malformed JSON',
                'Could not decode the request body. The '
                'JSON was incorrect.')
            
        result = Mongo.deleteDocument(result_json)
        resp.body = json.dumps(result, encoding='utf-8')
        resp.content_type = "application/json; charset=utf-8"

class SearchProduct():
    
    def on_get(self,req,resp):
        offset = req.get_param_as_int("offset")
        limit = req.get_param_as_int("limit")
        search_term = req.get_param("search")
        
        result = Mongo.searchMaster(offset, limit, search_term)
        resp.body = dumps(result) 

        
class FeaturedDeals():
    
    def on_get(self, req, resp):
        
        offset = req.get_param_as_int("offset")
        limit = req.get_param_as_int("limit")
        
        result = Mongo.getAllFeaturedDeals(offset, limit)
        resp.body = dumps(result)

    
    def on_post(self, req, resp):
        
        multi = req.get_param_as_int("multi")
        
        try:
            result_json = json.loads(req.stream.read(), encoding='utf-8')
        except ValueError:
            raise falcon.HTTPError(falcon.HTTP_400,
                'Malformed JSON',
                'Could not decode the request body. The '
                'JSON was incorrect.')
            
        result = Mongo.addFeaturedDeal(result_json, multi)
        resp.body = json.dumps(result, encoding='utf-8')


class CommonSearch():
    
    def on_get(self,req,resp):
        class_name = req.get_param("class")
        sku = req.get_param_as_int("sku")
        skuBundleId = req.get_param_as_int("skuBundleId")

        result = Mongo.searchCollection(class_name, sku, skuBundleId)
        resp.body = dumps(result)

class CricScore():
    
    def on_get(self,req,resp):

        result = Mongo.getLiveCricScore()
        resp.body = dumps(result)

class Notification():
    
    def on_post(self, req, resp):
        
        try:
            result_json = json.loads(req.stream.read(), encoding='utf-8')
        except ValueError:
            raise falcon.HTTPError(falcon.HTTP_400,
                'Malformed JSON',
                'Could not decode the request body. The '
                'JSON was incorrect.')
            
        result = Mongo.addBundleToNotification(result_json)
        resp.body = json.dumps(result, encoding='utf-8')
    
    def on_get(self, req, resp):

        offset = req.get_param_as_int("offset")
        limit = req.get_param_as_int("limit")
        
        result = Mongo.getAllNotifications(offset, limit)
        resp.body = dumps(result)

class DealBrands():
    
    def on_get(self, req, resp):
        
        category_id = req.get_param_as_int("category_id")
        result = Mongo.getBrandsForFilter(category_id)
        resp.body = dumps(result)

class DealRank():
    
    def on_get(self, req, resp):
        identifier = req.get_param("identifier")
        source_id = req.get_param_as_int("source_id")
        user_id = req.get_param_as_int("user_id")
        result = Mongo.getDealRank(identifier, source_id, user_id)
        json_docs = json.dumps(result, default=json_util.default)
        resp.body = json_docs
        
    

class RetailerDetail():
    global RETAILER_DETAIL_CALL_COUNTER
    def getRetryRetailer(self,failback=True):
        status = RETRY_MAP.get(self.callType)
        retailer = session.query(Retailers).filter_by(status=status).filter(Retailers.next_call_time<=datetime.now()).order_by(Retailers.call_priority).order_by(Retailers.next_call_time).with_lockmode("update").first()
        if retailer is not None:
            lgr.info( "getRetryRetailer " + str(retailer.id))
        else:
            if failback:
                retailer = self.getNewRetailer(False)
                return retailer
            else:
                #No further calls for now
                return None
        retailer.status = ASSIGN_MAP.get(status)
        retailer.next_call_time = None
        lgr.info( "getRetryRetailer " + str(retailer.id))
        return retailer
            
    def getNotActiveRetailer(self):
        try:
            user = session.query(Users).filter_by(activated=0).filter_by(status=1).filter(Users.mobile_number != None).filter(~Users.mobile_number.like("0%")).filter(Users.created>datetime(2015,06,29)).order_by(Users.created.desc()).with_lockmode("update").first()
            if user is None: 
                return None
            else:
                retailerContact = session.query(RetailerContacts).filter_by(mobile_number=user.mobile_number).first()
                if retailerContact is not None:
                    retailer = session.query(Retailers).filter_by(id=retailerContact.retailer_id).first()
                else:
                    retailer = session.query(Retailers).filter_by(contact1=user.mobile_number).first()
                    if retailer is None:
                        retailer = session.query(Retailers).filter_by(contact2=user.mobile_number).first()
                        if retailer is None:
                            retailer = Retailers()
                            retailer.contact1 = user.mobile_number
                            retailer.status = 'assigned'
                            retailer.retry_count = 0
                            retailer.invalid_retry_count = 0
                            retailer.is_elavated=1
                user.status = 2
                session.commit()
                print "retailer id", retailer.id
                retailer.contact = user.mobile_number
                return retailer
        finally:
            session.close()
            
    def getNewRetailer(self,failback=True):
        if self.callType == 'fresh':
            retailer = self.getNotActiveRetailer()
            if retailer is not None:
                return retailer
        retry = True
        retailer = None 
        try:
            while(retry):
                lgr.info( "Calltype " + self.callType)
                status=self.callType
                query = session.query(Retailers).filter(Retailers.status==status).filter(or_(Retailers.agent_id==self.agentId, Retailers.agent_id==None))
                if status=='fresh':
                    query = query.filter_by(is_or=False, is_std=False).filter(Retailers.pin==Pincodeavailability.code).filter(Pincodeavailability.amount > 19999).order_by(Retailers.is_elavated.desc(), Retailers.agent_id.desc())
                elif status=='followup':
                    query = query.filter(Retailers.next_call_time<=datetime.now()).order_by(Retailers.agent_id.desc(),Retailers.next_call_time)
                else:
                    query = query.filter(Retailers.modified<=datetime.now()).order_by(Retailers.agent_id.desc(), Retailers.modified)
                    
                retailer = query.with_lockmode("update").first()
                if retailer is not None:
                    lgr.info( "retailer " +str(retailer.id))
                    if status=="fresh":
                        userquery = session.query(Users)
                        if retailer.contact2 is not None:
                            userquery = userquery.filter(Users.mobile_number.in_([retailer.contact1,retailer.contact2]))
                        else:
                            userquery = userquery.filter_by(mobile_number=retailer.contact1)
                        user = userquery.first()
                        if user is not None:
                            retailer.status = 'alreadyuser'
                            lgr.info( "retailer.status " + retailer.status)
                            session.commit()
                            continue
                        retailer.status = 'assigned'
                    elif status=='followup':
                        if isActivated(retailer.id):
                            print "Retailer Already %d activated and marked onboarded"%(retailer.id)
                            continue
                        retailer.status = 'fassigned'
                    else:
                        retailer.status = 'oassigned'
                    retailer.retry_count = 0
                    retailer.invalid_retry_count = 0
                    lgr.info( "Found Retailer " +  str(retailer.id) + " with status " + status + " assigned to " + str(self.agentId))
                        
                else:
                    lgr.info( "No fresh/followup retailers found")
                    if failback:
                        retailer = self.getRetryRetailer(False)
                        return retailer
                retry=False
        except:
            print traceback.print_exc()
        return retailer
    
    def on_get(self, req, resp, agentId, callType=None, retailerId=None):
        global RETAILER_DETAIL_CALL_COUNTER
        RETAILER_DETAIL_CALL_COUNTER += 1
        lgr.info( "RETAILER_DETAIL_CALL_COUNTER " +  str(RETAILER_DETAIL_CALL_COUNTER))
        self.agentId = int(agentId)
        self.callType = callType
        if retailerId is not None:
            self.retailerId = int(retailerId)
            retailerLink = session.query(RetailerLinks).filter_by(retailer_id=self.retailerId).first()
            if retailerLink is not None:
                code = retailerLink.code
            else: 
                code = self.getCode()
                retailerLink = RetailerLinks()
                retailerLink.code = code
                retailerLink.agent_id = self.agentId
                retailerLink.retailer_id = self.retailerId
                
                activationCode=Activation_Codes()
                activationCode.code = code
                session.commit()
            session.close()
            resp.body =  json.dumps({"result":{"code":code,"link":make_tiny(code)}}, encoding='utf-8')
            return 
        retryFlag = False 
        if RETAILER_DETAIL_CALL_COUNTER % DEALER_RETRY_FACTOR ==0:
            retryFlag=True
        try:
            if retryFlag:
                retailer = self.getRetryRetailer()
            else:
                retailer = self.getNewRetailer()
            if retailer is None:
                resp.body = "{}"
                return
            fetchInfo = FetchDataHistory()
            fetchInfo.agent_id = self.agentId
            fetchInfo.call_type = self.callType
            agent = session.query(Agents).filter_by(id=self.agentId).first()
            last_disposition = session.query(CallHistory).filter_by(agent_id=self.agentId).order_by(CallHistory.id.desc()).first()
            if last_disposition is None or last_disposition.created < agent.last_login:
                fetchInfo.last_action = 'login'
                fetchInfo.last_action_time = agent.last_login 
            else:
                fetchInfo.last_action = 'disposition'
                fetchInfo.last_action_time = last_disposition.created
            fetchInfo.retailer_id = retailer.id
            session.commit()
            
            otherContacts = [r for r, in session.query(RetailerContacts.mobile_number).filter_by(retailer_id=retailer.id).order_by(RetailerContacts.contact_type).all()]
            resp.body = json.dumps(todict(getRetailerObj(retailer, otherContacts, self.callType)), encoding='utf-8')
            
            return
            
        finally:
            session.close()

        if retailer is None:
            resp.body = "{}"
        else:
            print "It should never come here"
            resp.body = json.dumps(todict(getRetailerObj(retailer)), encoding='utf-8')
        
        
    def on_post(self, req, resp, agentId, callType):
        returned = False
        self.agentId = int(agentId)
        self.callType = callType
        jsonReq = json.loads(req.stream.read(), encoding='utf-8')
        lgr.info( "Request ----\n"  + str(jsonReq))
        self.jsonReq = jsonReq
        invalidNumber = self.invalidNumber
        callLater = self.callLater
        alreadyUser = self.alReadyUser
        verifiedLinkSent = self.verifiedLinkSent
        onboarded = self.onboarded
        self.address = jsonReq.get('address')
        self.retailerId = int(jsonReq.get('retailerid'))
        self.smsNumber = jsonReq.get('smsnumber')
        if self.smsNumber is not None:
            self.smsNumber = self.smsNumber.strip().lstrip("0") 
        try:
            self.retailer = session.query(Retailers).filter_by(id=self.retailerId).first()
            if self.address:
                self.retailer.address_new = self.address
            self.callDisposition = jsonReq.get('calldispositiontype')
            self.callHistory = CallHistory()
            self.callHistory.agent_id=self.agentId
            self.callHistory.call_disposition = self.callDisposition
            self.callHistory.retailer_id=self.retailerId
            self.callHistory.call_type=self.callType
            self.callHistory.duration_sec = int(jsonReq.get("callduration"))
            self.callHistory.disposition_description = jsonReq.get('calldispositiondescritption')
            self.callHistory.disposition_comments = jsonReq.get('calldispositioncomments')
            lgr.info(self.callHistory.disposition_comments)
            self.callHistory.call_time = datetime.strptime(jsonReq.get("calltime"), '%d/%m/%Y %H:%M:%S')
            self.callHistory.mobile_number = jsonReq.get('number')
            self.callHistory.sms_verified = int(jsonReq.get("verified"))
            lastFetchData = session.query(FetchDataHistory).filter_by(agent_id=self.agentId).order_by(FetchDataHistory.id.desc()).first()
            if self.callDisposition == 'onboarded':
                self.checkList = jsonReq.get('checklist')
                
            if lastFetchData is None:
                raise
            self.callHistory.last_fetch_time= lastFetchData.created  
            
            dispositionMap = {  'call_later':callLater,
                        'ringing_no_answer':callLater,
                        'not_reachable':callLater,
                        'switch_off':callLater,
                        'not_retailer':invalidNumber,
                        'invalid_no':invalidNumber,
                        'wrong_no':invalidNumber,
                        'hang_up':invalidNumber,
                        'retailer_not_interested':invalidNumber,
                        'recharge_retailer':invalidNumber,
                        'accessory_retailer':invalidNumber,
                        'service_center_retailer':invalidNumber,
                        'alreadyuser':alreadyUser,
                        'verified_link_sent':verifiedLinkSent,
                        'onboarded':onboarded
                      }
            returned = dispositionMap[jsonReq.get('calldispositiontype')]()
        finally:
            session.close()
        
        if returned:
            resp.body = "{\"result\":\"success\"}"
        else:
            resp.body = "{\"result\":\"failed\"}"

    def invalidNumber(self,):
        #self.retailer.status = 'retry' if self.callType == 'fresh' else 'fretry'
        if self.callDisposition == 'invalid_no':
            self.retailer.status='failed'
            self.callHistory.disposition_description = 'Invalid Number'
        elif self.callDisposition == 'wrong_no':
            self.retailer.status='failed'
            self.callHistory.disposition_description = 'Wrong Number'
        elif self.callDisposition == 'hang_up':
            self.retailer.status='failed'
            self.callHistory.disposition_description = 'Hang Up'
        elif self.callDisposition == 'retailer_not_interested':
            self.retailer.status='failed'
            if self.callHistory.disposition_description is None:
                self.callHistory.disposition_description = 'NA'
            self.callHistory.disposition_description = 'Reason Retailer Not Interested ' + self.callHistory.disposition_description
        elif self.callDisposition == 'recharge_retailer':
            self.retailer.status='failed'
            self.callHistory.disposition_description = 'Recharge related. Not a retailer '
        elif self.callDisposition == 'accessory_retailer':
            self.retailer.status='failed'
            self.callHistory.disposition_description = 'Accessory related. Not a retailer'
        elif self.callDisposition == 'service_center_retailer':
            self.retailer.status='failed'
            self.callHistory.disposition_description = 'Service Center related. Not a retailer'
        elif self.callDisposition == 'not_retailer':
            self.retailer.status='failed'
            self.callHistory.disposition_description = 'Not a retailer'    
        session.commit()
        return True   
        
    def getCode(self,):
        newCode = None
        lastLink = session.query(RetailerLinks).order_by(RetailerLinks.id.desc()).with_lockmode("update").first()
        if lastLink is not None:
            if len(lastLink.code)==len(codesys):
                newCode=lastLink.code
        return getNextCode(codesys, newCode)
    
    
    def callLater(self,):
        self.retailer.status = RETRY_MAP.get(self.callType)
        self.retailer.call_priority = None
        if self.callDisposition == 'call_later':
            if self.callHistory.disposition_description is not None:
                self.retailer.call_priority = 'user_initiated'
                self.retailer.next_call_time = datetime.strptime(self.callHistory.disposition_description, '%d/%m/%Y %H:%M:%S')
                self.callHistory.disposition_description = 'User requested to call on ' + self.callHistory.disposition_description
            else:
                self.retailer.call_priority = 'system_initiated'
                self.retailer.next_call_time = self.callHistory.call_time + timedelta(days=1)
                self.callHistory.disposition_description = 'Call scheduled on ' + datetime.strftime(self.retailer.next_call_time, '%d/%m/%Y %H:%M:%S')
        else: 
            if self.callDisposition == 'ringing_no_answer':
                if self.retailer.disposition == 'ringing_no_answer':
                    self.retailer.retry_count += 1
                else:
                    self.retailer.disposition = 'ringing_no_answer'
                    self.retailer.retry_count = 1
            else:
                if self.retailer.disposition == 'ringing_no_answer':
                    pass
                else:
                    self.retailer.disposition = 'not_reachable'
                self.retailer.retry_count += 1
                self.retailer.invalid_retry_count += 1
                    
            retryConfig = session.query(RetryConfig).filter_by(call_type=self.callType, disposition_type=self.retailer.disposition, retry_count=self.retailer.retry_count).first()
            if retryConfig is not None:
                self.retailer.next_call_time = self.callHistory.call_time + timedelta(minutes = retryConfig.minutes_ahead)
                self.callHistory.disposition_description = 'Call scheduled on ' + datetime.strftime(self.retailer.next_call_time, '%d/%m/%Y %H:%M:%S')
            else:
                self.retailer.status = 'failed'
                self.callHistory.disposition_description = 'Call failed as all attempts exhausted'
            
        session.commit()
        return True
            
            
    def alReadyUser(self,):
        self.retailer.status = self.callDisposition
        if self.callHistory.disposition_description is None:
            self.callHistory.disposition_description = 'Retailer already user' 
        session.commit()
        return True
    def verifiedLinkSent(self,):
        if self.callType == 'fresh':
            self.retailer.status = 'followup'
            self.retailer.agent_id = None
            self.retailer.next_call_time = self.callHistory.call_time + timedelta(days=1)
            self.callHistory.disposition_description = 'App link sent via ' + self.callHistory.disposition_description+ '. followup on' + datetime.strftime(self.retailer.next_call_time, '%d/%m/%Y %H:%M:%S') 
        else:
            self.retailer.status = 'followup'
            self.retailer.agent_id = None
            self.retailer.next_call_time = self.callHistory.call_time + timedelta(days=7)
            self.callHistory.disposition_description = 'App link sent via' + self.callHistory.disposition_description + '. Followup again on ' + datetime.strftime(self.retailer.next_call_time, '%d/%m/%Y %H:%M:%S')
        addContactToRetailer(self.agentId, self.retailerId, self.smsNumber, self.callType, 'sms')     
        session.commit()
        return True
    def onboarded(self,):
        self.retailer.status = self.callDisposition
        checkList = OnboardedRetailerChecklists()
        checkList.contact_us = self.checkList.get('contactus')
        checkList.doa_return_policy = self.checkList.get('doareturnpolicy')
        checkList.number_verification = self.checkList.get('numberverification')
        checkList.payment_option = self.checkList.get('paymentoption')
        checkList.preferences = self.checkList.get('preferences')
        checkList.product_info = self.checkList.get('productinfo')
        checkList.redeem = self.checkList.get('redeem')
        checkList.retailer_id = self.retailerId
        session.commit()
        return True
        
        
def isActivated(retailerId):
    retailerLink = session.query(RetailerLinks).filter_by(retailer_id=retailerId).first()
    user = session.query(Users).filter(or_(func.lower(Users.referrer)==retailerLink.code.lower(), Users.utm_campaign==retailerLink.code)).first()
    if user is None:
        mobileNumbers = list(session.query(RetailerContacts.mobile_number).filter_by(retailer_id=retailerId).all())
        user = session.query(Users).filter(Users.mobile_number.in_(mobileNumbers)).first()
        if user is None:
            if retailerLink.created < datetime(2015,5,26):
                historyNumbers = [number for number, in session.query(CallHistory.mobile_number).filter_by(retailer_id = retailerId).all()]
                user = session.query(Users).filter(Users.mobile_number.in_(historyNumbers)).first()
                if user is None:
                    return False
                else:
                    mapped_with = 'contact'
            else:
                return False
        else:
            mapped_with = 'contact'
    else:
        mapped_with = 'code'
    retailerLink.mapped_with = mapped_with
    if user.activation_time is not None:
        retailerLink.activated = user.activation_time
    retailerLink.activated = user.created
    retailerLink.user_id = user.id
    retailer = session.query(Retailers).filter_by(id=retailerId).first()
    if retailer.status == 'followup' or retailer.status == 'fretry':
        retailer.status = 'onboarding'
        retailer.agent_id = None
        retailer.call_priority = None
        retailer.next_call_time = None
        retailer.retry_count = 0
        retailer.invalid_retry_count = 0
    session.commit()
    print "retailerLink.retailer_id", retailerLink.retailer_id
    print "retailer", retailer.id
    session.close()
    return True
    
class AddContactToRetailer():
    def on_post(self,req,resp, agentId):
        agentId = int(agentId)
        try:
            jsonReq = json.loads(req.stream.read(), encoding='utf-8')
            retailerId = int(jsonReq.get("retailerid"))
            mobile = jsonReq.get("mobile")
            callType = jsonReq.get("calltype")
            contactType = jsonReq.get("contacttype")
            addContactToRetailer(agentId, retailerId, mobile, callType, contactType)
            session.commit()
        finally:
            session.close()

class AddAddressToRetailer():
    def on_post(self,req,resp, agentId):
        agentId = int(agentId)
        jsonReq = json.loads(req.stream.read(), encoding='utf-8')
        retailerId = int(jsonReq.get("retailerid"))
        address = str(jsonReq.get("address"))
        storeName = str(jsonReq.get("storename"))
        pin = str(jsonReq.get("pin"))
        city = str(jsonReq.get("city"))
        state = str(jsonReq.get("state"))
        updateType = str(jsonReq.get("updatetype"))
        addAddressToRetailer(agentId, retailerId, address, storeName, pin, city,state, updateType)
            
def addContactToRetailer(agentId, retailerId, mobile, callType, contactType):
    retailerContact = session.query(RetailerContacts).filter_by(retailer_id=retailerId).filter_by(mobile_number=mobile).first()
    if retailerContact is None:
        retailerContact = RetailerContacts()
        retailerContact.retailer_id = retailerId
        retailerContact.agent_id = agentId
        retailerContact.call_type = callType
        retailerContact.contact_type = contactType
        retailerContact.mobile_number = mobile
    else:
        if CONTACT_PRIORITY.index(retailerContact.contact_type) > CONTACT_PRIORITY.index(contactType):
            retailerContact.contact_type = contactType

def addAddressToRetailer(agentId, retailerId, address, storeName, pin, city,state, updateType):
    print "I am in addAddress"
    print agentId, retailerId, address, storeName, pin, city, state, updateType
    try:
        if updateType=='new':
            retailer = session.query(Retailers).filter_by(id=retailerId).first()
            retailer.address = address
            retailer.title = storeName
            retailer.city = city
            retailer.state = state
            retailer.pin = pin
        raddress = RetailerAddresses()
        raddress.address = address
        raddress.title = storeName
        raddress.agent_id = agentId
        raddress.city = city
        raddress.pin = pin
        raddress.retailer_id = retailerId
        raddress.state = state
        session.commit()
    finally:
        session.close() 
        
        
class Login():
    
    def on_get(self, req, resp, agentId, role):
        try:
            self.agentId = int(agentId)
            self.role = role
            print str(self.agentId) + self.role;
            agents=AgentLoginTimings()
            lastLoginTime = session.query(Agents).filter(Agents.id==self.agentId).first()
            print 'lastLogintime' + str(lastLoginTime)
            agents.loginTime=lastLoginTime.last_login
            agents.logoutTime=datetime.now()
            agents.role =self.role
            agents.agent_id = self.agentId
            session.add(agents)    
            session.commit()
            resp.body =  json.dumps({"result":{"success":"true","message":"Success"}}, encoding='utf-8')
        finally:
            session.close()        
        
    def on_post(self,req,resp):
        try:
            jsonReq = json.loads(req.stream.read(), encoding='utf-8')
            lgr.info( "Request ----\n"  + str(jsonReq))
            email=jsonReq.get('email')
            password = jsonReq.get('password')
            role=jsonReq.get('role')    
            agent = session.query(Agents).filter(and_(Agents.email==email,Agents.password==password)).first()
            if agent is None:
                resp.body =  json.dumps({"result":{"success":"false","message":"Invalid User"}}, encoding='utf-8')
            else:
                print agent.id
                checkRole = session.query(Agent_Roles.id).filter(and_(Agent_Roles.agent_id==agent.id,Agent_Roles.role==role)).first()
                if checkRole is None:
                    resp.body =  json.dumps({"result":{"success":"false","message":"Invalid Role"}}, encoding='utf-8')
                else:
                    agent.last_login = datetime.now()
                    agent.login_type = role
                    resp.body =  json.dumps({"result":{"success":"true","message":"Valid User","id":agent.id}}, encoding='utf-8')
                    session.commit()
                    #session.query(Agents).filter_by(id = checkUser[0]).    
        finally:
            session.close()    
            
    def test(self,email,password,role):
        checkUser = session.query(Agents.id).filter(and_(Agents.email==email,Agents.password==password)).first()
        if checkUser is None:
            print checkUser

        else:
            print checkUser[0]
            checkRole = session.query(Agent_Roles.id).filter(and_(Agent_Roles.agent_id==checkUser[0],Agent_Roles.role==role)).first()
            if checkRole is None:
                pass
            else:
                agents=AgentLoginTimings()
                agents.loginTime=datetime.now()
                agents.logoutTime=datetime.now()
                agents.role =role
                agents.agent_id = 2
                #session.query(AgentLoginTimings).filter_by(id = checkUser[0]).update({"last_login":datetime.now()}, synchronize_session=False)
                session.add(agents)    
                session.commit()
                session.close()
                
                #session.query(Agents).filter(Agents.id==checkUser[0]).update({"last_login":Agents.last_login})

class RetailerActivation():
    def on_get(self, req, resp, userId):
        res =  markDealerActivation(int(userId))
        if res:
            resp.body = "{\"activated\":true}"
        else:
            resp.body = "{\"activated\":false}"
            

def markDealerActivation(userId):
    try:
        user = session.query(Users).filter_by(id=userId).first()
        result = False                
        mappedWith = 'contact'
        retailer = None
        if user is not None:
            referrer = None if user.referrer is None else user.referrer.upper()
            retailerLink = session.query(RetailerLinks).filter(or_(RetailerLinks.code==referrer, RetailerLinks.code==user.utm_campaign)).first()
            if retailerLink is None:
                if user.mobile_number is not None:
                    retailerContact = session.query(RetailerContacts).filter_by(mobile_number=user.mobile_number).first()
                    if retailerContact is None:
                        retailer = session.query(Retailers).filter(Retailers.status.in_(['followup', 'fretry', 'fdone'])).filter(or_(Retailers.contact1==user.mobile_number,Retailers.contact2==user.mobile_number)).first()
                    else:
                        retailer = session.query(Retailers).filter_by(id = retailerContact.retailer_id).first()
            else:
                retailer = session.query(Retailers).filter_by(id = retailerLink.retailer_id).first()
                mappedWith='code'
            if retailer is not None:
                retailerLink = session.query(RetailerLinks).filter_by(retailer_id=retailer.id).first()
                if retailerLink is not None:
                    retailerLink.user_id = user.id
                    retailerLink.mapped_with=mappedWith
                    retailer.status = 'onboarding'
                    result = True
                    session.commit()
        return result
    finally:
        session.close()
                    
            
def todict(obj, classkey=None):
    if isinstance(obj, dict):
        data = {}
        for (k, v) in obj.items():
            data[k] = todict(v, classkey)
        return data
    elif hasattr(obj, "_ast"):
        return todict(obj._ast())
    elif hasattr(obj, "__iter__"):
        return [todict(v, classkey) for v in obj]
    elif hasattr(obj, "__dict__"):
        data = dict([(key, todict(value, classkey)) 
            for key, value in obj.__dict__.iteritems() 
            if not callable(value) and not key.startswith('_')])
        if classkey is not None and hasattr(obj, "__class__"):
            data[classkey] = obj.__class__.__name__
        return data
    else:
        return obj
    
def getRetailerObj(retailer, otherContacts1=None, callType=None):
    print "before otherContacts1",otherContacts1
    otherContacts = [] if otherContacts1 is None else otherContacts1
    print "after otherContacts1",otherContacts
    obj = Mock()
    obj.id = retailer.id
    
        
    if retailer.contact1 is not None and retailer.contact1 not in otherContacts:
        otherContacts.append(retailer.contact1)
    if retailer.contact2 is not None and retailer.contact2 not in otherContacts:
        otherContacts.append(retailer.contact2)
    obj.contact1 = None if len(otherContacts)==0 else otherContacts[0]
    if obj.contact1 is not None:
        obj.contact2 = None if len(otherContacts)==1 else otherContacts[1]
    obj.scheduled = (retailer.call_priority is not None)
    address = None
    try:
        address = session.query(RetailerAddresses).filter_by(retailer_id=retailer.id).order_by(RetailerAddresses.created.desc()).first()
    finally:
        session.close()
    if address is not None:
        obj.address = address.address
        obj.title = address.title
        obj.city = address.city
        obj.state = address.state
        obj.pin = address.pin 
    else:
        obj.address = retailer.address_new if retailer.address_new is not None else retailer.address
        obj.title = retailer.title
        obj.city = retailer.city
        obj.state = retailer.state
        obj.pin = retailer.pin 
    obj.status = retailer.status
        
    if hasattr(retailer, 'contact'):
        obj.contact = retailer.contact
    if callType == 'onboarding':
        try:
            userId, activatedTime = session.query(RetailerLinks.user_id, RetailerLinks.activated).filter(RetailerLinks.retailer_id==retailer.id).first()
            activated, = session.query(Users.activation_time).filter(Users.id==userId).first()
            if activated is not None:
                activatedTime = activated
            obj.user_id = userId
            obj.created = datetime.strftime(activatedTime, '%d/%m/%Y %H:%M:%S')
            result = fetchResult("select * from useractive where user_id=%d"%(userId))
            if result == ():
                obj.last_active = None
            else:
                obj.last_active =datetime.strftime(result[0][1], '%d/%m/%Y %H:%M:%S')
            ordersCount = session.query(Orders).filter_by(user_id = userId).filter(~Orders.status.in_(['ORDER_NOT_CREATED_KNOWN', 'ORDER_ALREADY_CREATED_IGNORED'])).count()
            obj.orders = ordersCount
        finally:
            session.close()
    return obj

def make_tiny(code):
    url = 'https://play.google.com/store/apps/details?id=com.saholic.profittill&referrer=utm_source%3D0%26utm_medium%3DCRM%26utm_term%3D001%26utm_campaign%3D' + code
    #request_url = ('http://tinyurl.com/api-create.php?' + urlencode({'url':url}))
    #filehandle = urllib2.Request(request_url)
    #x= urllib2.urlopen(filehandle)
    try:
        shortener = Shortener('TinyurlShortener')
        returnUrl =  shortener.short(url)
    except:
        shortener = Shortener('SentalaShortener')
        returnlUrl =  shortener.short(url)
    return returnUrl

class SearchUser():
            
    def on_post(self, req, resp, agentId, searchType):
        retailersJsonArray = []
        try:
            jsonReq = json.loads(req.stream.read(), encoding='utf-8')
            lgr.info( "Request in Search----\n"  + str(jsonReq))
            contact=jsonReq.get('searchTerm')
            if(searchType=="number"):
                retailer_ids = session.query(RetailerContacts.retailer_id).filter_by(mobile_number=contact).all()
                retailer_ids = [r for r, in retailer_ids]    
                anotherCondition = or_(Retailers.contact1==contact,Retailers.contact2==contact, Retailers.id.in_(retailer_ids))
            else:
                m = re.match("(.*?)(\d{6})(.*?)", contact)
                if m is not None:
                    pin = m.group(2)
                    contact = m.group(1) if m.group(1) != '' else m.group(3)
                    anotherCondition = and_(Retailers.title.ilike('%%%s%%'%(contact)), Retailers.pin==pin)
                else:
                    anotherCondition = Retailers.title.ilike('%%%s%%'%(contact))
            
            retailers = session.query(Retailers).filter(anotherCondition).limit(20).all()
            if retailers is None:
                resp.body = json.dumps("{}")
            else:
                for retailer in retailers:
                    otherContacts = [r for r, in session.query(RetailerContacts.mobile_number).filter_by(retailer_id=retailer.id).order_by(RetailerContacts.contact_type).all()]
                    retailersJsonArray.append(todict(getRetailerObj(retailer, otherContacts)))    
            resp.body = json.dumps({"Retailers":retailersJsonArray}, encoding='utf-8')
            return
        finally:
            session.close()

    
class Mock(object):
    pass

def tagActivatedReatilers():
    retailerIds = [r for  r, in session.query(RetailerLinks.retailer_id).filter_by(user_id = None).all()]
    session.close()
    for retailerId in retailerIds:
        isActivated(retailerId)
    session.close()

class StaticDeals():
    
    def on_get(self, req, resp):

        offset = req.get_param_as_int("offset")
        limit = req.get_param_as_int("limit")
        categoryId = req.get_param_as_int("categoryId")
        direction = req.get_param_as_int("direction")
        
        result = Mongo.getStaticDeals(offset, limit, categoryId, direction)
        resp.body = dumps(result)

class DealNotification():
    
    def on_get(self,req,resp,skuBundleIds):
        result = Mongo.getDealsForNotification(skuBundleIds)
        resp.body = dumps(result)
        



def main():
    #tagActivatedReatilers()
    a = RetailerDetail()
    retailer = a.getNotActiveRetailer()
    otherContacts = [r for r, in session.query(RetailerContacts.mobile_number).filter_by(retailer_id=retailer.id).order_by(RetailerContacts.contact_type).all()]
    print json.dumps(todict(getRetailerObj(retailer, otherContacts, 'fresh')), encoding='utf-8')
    #print make_tiny("AA")
    
if __name__ == '__main__':
    main()