Subversion Repositories SmartDukaan

Rev

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

import pymongo
from elixir import *
from datetime import datetime
from datetime import timedelta
from dtr.main import Store
from dtr.utils.utils import to_java_date
from operator import itemgetter
from bson.objectid import ObjectId
from dtr.storage import DataService
from dtr.storage.DataService import price_preferences, brand_preferences, \
user_actions
from dtr.storage.MemCache import MemCache

con = None
cashBackMap = {}
itemCashBackMap = {}

DataService.initialize(db_hostname="localhost")
mc = MemCache("127.0.0.1")

def get_mongo_connection(host='localhost', port=27017):
    global con
    if con is None:
        print "Establishing connection %s host and port %d" %(host,port)
        try:
            con = pymongo.MongoClient(host, port)
        except Exception, e:
            print e
            return None
    return con

def populateCashBack():
    print "Populating cashback"
    global cashBackMap
    global itemCashBackMap
    cashBackMap = {}
    itemCashBackMap = {}
    cashBack = list(get_mongo_connection().Catalog.CategoryCashBack.find())
    for row in cashBack:
        temp_map = {}
        temp_list = []
        if cashBackMap.has_key(row['source_id']):
            arr = cashBackMap.get(row['source_id'])
            for val in arr:
                temp_list.append(val)
            temp_map[row['category_id']] = row
            temp_list.append(temp_map)
            cashBackMap[row['source_id']] = temp_list 
        else:
            temp_map[row['category_id']] = row
            temp_list.append(temp_map)
            cashBackMap[row['source_id']] = temp_list
    itemCashBack = list(get_mongo_connection().Catalog.ItemCashBack.find())
    for row in itemCashBack:
        if not itemCashBackMap.has_key(row['skuId']):
            itemCashBackMap[row['skuId']] = row

def addCategoryDiscount(data):
    collection = get_mongo_connection().Catalog.CategoryDiscount
    query = []
    data['brand'] = data['brand'].strip().upper()
    data['discountType'] = data['discountType'].upper().strip()
    query.append({"brand":data['brand']})
    query.append({"category_id":data['category_id']})
    r = collection.find({"$and":query})
    if r.count() > 0:
        return {0:"Brand & Category info already present."}
    else:
        collection.insert(data)
        get_mongo_connection().Catalog.MasterData.update({'brand':data['brand'],'category_id':data['category_id']},{"$set":{'updatedOn':to_java_date(datetime.now())}},multi=True)
        return {1:"Data added successfully"}

def updateCategoryDiscount(data,_id):
    try:
        collection = get_mongo_connection().Catalog.CategoryDiscount
        collection.update({'_id':ObjectId(_id)},{"$set":{'min_discount':data['min_discount'],'max_discount':data['max_discount'],'discountType':data['discountType'].upper().strip()}},upsert=False, multi = False)
        get_mongo_connection().Catalog.MasterData.update({'brand':data['brand'],'category_id':data['category_id']},{"$set":{'updatedOn':to_java_date(datetime.now())}},multi=True)
        return {1:"Data updated successfully"}
    except:
        return {0:"Data not updated."}
    

def getAllCategoryDiscount():
    data = []
    collection = get_mongo_connection().Catalog.CategoryDiscount
    cursor = collection.find()
    for val in cursor:
        data.append(val)
    return data

def addSchemeDetailsForSku(data):
    collection = get_mongo_connection().Catalog.SkuSchemeDetails
    data['addedOn'] = to_java_date(datetime.now())
    collection.insert(data)
    return {1:"Data added successfully"}

def getAllSkuWiseSchemeDetails(offset, limit):
    data = []
    collection = get_mongo_connection().Catalog.SkuSchemeDetails
    cursor = collection.find().skip(offset).limit(limit)
    for val in cursor:
        master = list(get_mongo_connection().Catalog.MasterData.find({'_id':val['sku']}))
        if len(master) > 0:
            val['brand'] = master[0]['brand']
            val['source_product_name'] = master[0]['source_product_name']
            val['skuBundleId'] = master[0]['skuBundleId']
        else:
            val['brand'] = ""
            val['source_product_name'] = ""
            val['skuBundleId'] = ""
        data.append(val)
    return data

def addSkuDiscountInfo(data):
    collection = get_mongo_connection().Catalog.SkuDiscountInfo
    cursor = collection.find({"sku":data['sku']})
    if cursor.count() > 0:
        return {0:"Sku information already present."}
    else:
        collection.insert(data)
        get_mongo_connection().Catalog.MasterData.update({'_id':data['sku']},{"$set":{'updatedOn':to_java_date(datetime.now())}},multi=False)
        return {1:"Data added successfully"}

def getallSkuDiscountInfo(offset, limit):
    data = []
    collection = get_mongo_connection().Catalog.SkuDiscountInfo
    cursor = collection.find().skip(offset).limit(limit)
    for val in cursor:
        master = list(get_mongo_connection().Catalog.MasterData.find({'_id':val['sku']}))
        if len(master) > 0:
            val['brand'] = master[0]['brand']
            val['source_product_name'] = master[0]['source_product_name']
            val['skuBundleId'] = master[0]['skuBundleId']
        else:
            val['brand'] = ""
            val['source_product_name'] = ""
            val['skuBundleId'] = ""
        data.append(val)
    return data

def updateSkuDiscount(data,_id):
    try:
        collection = get_mongo_connection().Catalog.SkuDiscountInfo
        collection.update({'_id':ObjectId(_id)},{"$set":{'min_discount':data['min_discount'],'max_discount':data['max_discount'],'discountType':data['discountType'].upper().strip()}},upsert=False, multi = False)
        get_mongo_connection().Catalog.MasterData.update({'_id':data['sku']},{"$set":{'updatedOn':to_java_date(datetime.now())}},multi=False)
        return {1:"Data updated successfully"}
    except:
        return {0:"Data not updated."}


def addExceptionalNlc(data):
    collection = get_mongo_connection().Catalog.ExceptionalNlc
    cursor = collection.find({"sku":data['sku']})
    if cursor.count() > 0:
        return {0:"Sku information already present."}
    else:
        collection.insert(data)
        get_mongo_connection().Catalog.MasterData.update({'_id':data['sku']},{"$set":{'updatedOn':to_java_date(datetime.now())}},multi=False)
        return {1:"Data added successfully"}

def getAllExceptionlNlcItems(offset, limit):
    data = []
    collection = get_mongo_connection().Catalog.ExceptionalNlc
    cursor = collection.find().skip(offset).limit(limit)
    for val in cursor:
        master = list(get_mongo_connection().Catalog.MasterData.find({'_id':val['sku']}))
        if len(master) > 0:
            val['brand'] = master[0]['brand']
            val['source_product_name'] = master[0]['source_product_name']
            val['skuBundleId'] = master[0]['skuBundleId']
        else:
            val['brand'] = ""
            val['source_product_name'] = ""
            val['skuBundleId'] = ""
        data.append(val)
    return data

def getMerchantOrdersByUser(userId, page=1, window=50, searchMap={}):
    if searchMap is None:
        searchMap = {}
    if page==None:
        page = 1
        
    if window==None:
        window = 50
    result = {}
    skip = (page-1)*window
    
    searchMap['userId'] = userId
    collection = get_mongo_connection().Dtr.merchantOrder
    cursor = collection.find(searchMap).sort("_id",-1)
    total_count = cursor.count()
    pages = total_count/window + (0 if total_count%window==0 else 1)  
    print "total_count", total_count
    if total_count > skip:
        cursor = cursor.skip(skip).limit(window)
        orders = []
        for order in cursor:
            del(order["_id"])
            orders.append(order)
        result['data'] = orders
        result['window'] = window
        result['totalCount'] = total_count 
        result['currCount'] = cursor.count()
        result['totalPages'] = pages
        result['currPage'] = page    
        return result
    else:
        return result

def getRefunds(userId, page=1, window=10):
    if page==None:
        page = 1
        
    if window==None:
        window = 10
    result = {}
    skip = (page-1)*window
    collection = get_mongo_connection().Dtr.refund
    cursor = collection.find({"userId":userId})
    total_count = cursor.count()
    pages = total_count/window + (0 if total_count%window==0 else 1)  
    print "total_count", total_count
    if total_count > skip:
        cursor = cursor.skip(skip).limit(window).sort([('batchId',-1)])
        refunds = []
        for refund in cursor:
            del(refund["_id"])
            refunds.append(refund)
        result['data'] = refunds
        result['window'] = window
        result['totalCount'] = total_count 
        result['currCount'] = cursor.count()
        result['totalPages'] = pages
        result['currPage'] = page    
        return result
    else:
        return result
    
def getPendingRefunds(userId):
    print type(userId)
    result = get_mongo_connection().Dtr.merchantOrder\
        .aggregate([
                    {'$match':{'subOrders.cashBackStatus':Store.CB_APPROVED, 'userId':userId}},
                    {'$unwind':"$subOrders"},
                    { 
                     '$group':{
                               '_id':None,
                               'amount': { '$sum':'$subOrders.cashBackAmount'},
                               }
                     }
                ])['result']

    if len(result)>0:
        result = result[0]        
        result.pop("_id")
    else:
        result={}
        result['amount'] = 0.0
    result['nextCredit'] = datetime.strftime(next_weekday(datetime.now(), 0),"%Y-%m-%d %H:%M:%S")
    return result

def __populateCache(userId):
    print "Populating memcache for userId",userId
    outer_query = []
    outer_query.append({"showDeal":1})
    query = {}
    query['$gt'] = 0
    outer_query.append({'totalPoints':query})
    brandPrefMap = {}
    pricePrefMap = {}
    actionsMap = {}
    brand_p = session.query(price_preferences).filter_by(user_id=userId).all()
    for x in brand_p:
        pricePrefMap[x.category_id] = [x.min_price,x.max_price]
    for x in session.query(brand_preferences).filter_by(user_id=userId).all():
        temp_map = {}
        if brandPrefMap.has_key((x.brand).strip().upper()):
            val = brandPrefMap.get((x.brand).strip().upper())
            temp_map[x.category_id] = 1 if x.status == 'show' else 0
            val.append(temp_map)
        else:
            temp = []
            temp_map[x.category_id] = 1 if x.status == 'show' else 0
            temp.append(temp_map)
            brandPrefMap[(x.brand).strip().upper()] = temp
        
    for x in session.query(user_actions).filter_by(user_id=userId).all():
        actionsMap[x.store_product_id] = 1 if x.action == 'like' else 0
    all_deals = list(get_mongo_connection().Catalog.Deals.find({"$and":outer_query},{'_id':1,'category_id':1,'brand':1,'totalPoints':1,'bestSellerPoints':1,'nlcPoints':1,'rank':1,'available_price':1}).sort([('totalPoints',pymongo.DESCENDING),('bestSellerPoints',pymongo.DESCENDING),('nlcPoints',pymongo.DESCENDING),('rank',pymongo.DESCENDING)]))
    all_category_deals = []
    mobile_deals = []
    tablet_deals = []
    for deal in all_deals:
        if actionsMap.get(deal['_id']) == 0:
            fav_weight =.25
        elif actionsMap.get(deal['_id']) == 1:
            fav_weight = 1.5
        else:
            fav_weight = 1
        
        if brandPrefMap.get(deal['brand'].strip().upper()) is not None:
            brand_weight = 1
            for brandInfo in brandPrefMap.get(deal['brand'].strip().upper()):
                if brandInfo.get(deal['category_id']) is not None:
                    if brandInfo.get(deal['category_id']) == 1:
                        brand_weight = 2.0
        else:
            brand_weight = 1
        
        if pricePrefMap.get(deal['category_id']) is not None:
        
            if deal['available_price'] >= pricePrefMap.get(deal['category_id'])[0] and deal['available_price'] <= pricePrefMap.get(deal['category_id'])[1]:
                asp_weight = 1.5
            elif  deal['available_price'] >= pricePrefMap.get(deal['category_id'])[0] - 0.5 * pricePrefMap.get(deal['category_id'])[0] and deal['available_price'] <= pricePrefMap.get(deal['category_id'])[1] + 0.5 * pricePrefMap.get(deal['category_id'])[1]:
                asp_weight = 1.2
            else:
                asp_weight = 1
        else:
            asp_weight = 1
        
        persPoints = deal['totalPoints'] * fav_weight * brand_weight * asp_weight
        deal['persPoints'] = persPoints
        
        if deal['category_id'] ==3:
            mobile_deals.append(deal)
        elif deal['category_id'] ==5:
            tablet_deals.append(deal)
        else:
            continue
        all_category_deals.append(deal)
    
        
    mem_cache_val = {3:mobile_deals, 5:tablet_deals, 0:all_deals}
    mc.set(str(userId), mem_cache_val)
    


def getNewDeals(userId, category_id, offset, limit, sort, direction):
    if not bool(cashBackMap):
        populateCashBack()
    
    rank = 1
    dealsMap = {}
    user_specific_deals = mc.get(str(userId))
    if user_specific_deals is None:
        __populateCache(userId)
        user_specific_deals = mc.get(str(userId))
    else:
        print "Getting user deals from cache"
    category_specific_deals = user_specific_deals.get(category_id)
    
    if sort is None or direction is None:
        sorted_deals = sorted(category_specific_deals, key = lambda x: (x['persPoints'],x['totalPoints'],x['bestSellerPoints'], x['nlcPoints'], x['rank']),reverse=True)
    else:
        if sort == "bestSellerPoints":
            sorted_deals = sorted(category_specific_deals, key = lambda x: (x['bestSellerPoints'], x['rank'], x['nlcPoints']),reverse=True)
        else:
            if direction == -1:
                rev = True
            else:
                rev = False
            sorted_deals = sorted(category_specific_deals, key = lambda x: (x['available_price']),reverse=rev)
    
    for d in sorted_deals[offset:offset+limit]:
        item = list(get_mongo_connection().Catalog.MasterData.find({'_id':d['_id']}))
        if not dealsMap.has_key(item[0]['identifier']):
            item[0]['dealRank'] = rank
            item[0]['persPoints'] = d['persPoints']
            try:
                cashBack = __getCashBack(item[0]['_id'], item[0]['source_id'], item[0]['category_id'])
                if not cashBack or cashBack.get('cash_back_status')!=1:
                    item[0]['cash_back_type'] = 0
                    item[0]['cash_back'] = 0
                else:
                    item[0]['cash_back_type'] = cashBack['cash_back_type']
                    item[0]['cash_back'] = cashBack['cash_back']
            except:
                print "Error in adding cashback to deals"
                item[0]['cash_back_type'] = 0
                item[0]['cash_back'] = 0
            dealsMap[item[0]['identifier']] = item[0]
            
            rank +=1
    return sorted(dealsMap.values(), key=itemgetter('dealRank'))
        

def getDeals(userId, category_id, offset, limit, sort, direction):
    if not bool(cashBackMap):
        populateCashBack()
    rank = 1
    deals = {}
    outer_query = []
    outer_query.append({"showDeal":1})
    query = {}
    query['$gt'] = 0
    outer_query.append({'totalPoints':query})
    if category_id in (3,5):
        outer_query.append({'category_id':category_id})
    if sort is None or direction is None:
        direct = -1
        print outer_query
        data = list(get_mongo_connection().Catalog.Deals.find({"$and":outer_query}).sort([('totalPoints',direct),('bestSellerPoints',direct),('nlcPoints',direct),('rank',direct)]).skip(offset).limit(limit))
    else:
        print outer_query
        direct = direction
        if sort == "bestSellerPoints":
            print "yes,sorting by bestSellerPoints"
            data = list(get_mongo_connection().Catalog.Deals.find({"$and":outer_query}).sort([('bestSellerPoints',direct),('rank',direct),('nlcPoints',direct)]).skip(offset).limit(limit))
        else:
            data = list(get_mongo_connection().Catalog.Deals.find({"$and":outer_query}).sort([(sort,direct)]).skip(offset).limit(limit))
    for d in data:
        item = list(get_mongo_connection().Catalog.MasterData.find({'_id':d['_id']}))
        if not deals.has_key(item[0]['identifier']):
            item[0]['dealRank'] = rank
            try:
                cashBack = __getCashBack(item[0]['_id'], item[0]['source_id'], item[0]['category_id'])
                if not cashBack or cashBack.get('cash_back_status')!=1:
                    item[0]['cash_back_type'] = 0
                    item[0]['cash_back'] = 0
                else:
                    item[0]['cash_back_type'] = cashBack['cash_back_type']
                    item[0]['cash_back'] = cashBack['cash_back']
            except:
                print "Error in adding cashback to deals"
                item[0]['cash_back_type'] = 0
                item[0]['cash_back'] = 0
            deals[item[0]['identifier']] = item[0]
            
            rank +=1
    return sorted(deals.values(), key=itemgetter('dealRank'))

def getItem(skuId):
    try:
        skuData = list(get_mongo_connection().Catalog.MasterData.find({'_id':int(skuId)}))
        return skuData
    except:
        return [{}]

def __getCashBack(skuId, source_id, category_id):
    itemCashBack = itemCashBackMap.get(skuId)
    if itemCashBack is not None:
        return itemCashBack

    sourceCashBack = cashBackMap.get(source_id)
    if sourceCashBack is not None and len(sourceCashBack) > 0:
        for cashBack in sourceCashBack:
            if cashBack.get(category_id) is None:
                continue
            else:
                return cashBack.get(category_id)
    else:
        return {}

def getCashBackDetails(identifier, source_id):
    if not bool(cashBackMap):
        populateCashBack()
        
    """Need to add item level cashback, no data available right now."""
    
    if source_id in (1,2,4,5):
        skuData = list(get_mongo_connection().Catalog.MasterData.find({'identifier':identifier.strip(), 'source_id':source_id}))
    elif source_id == 3:
        skuData = list(get_mongo_connection().Catalog.MasterData.find({'secondaryIdentifier':identifier.strip(), 'source_id':source_id}))
    else:
        return {}
    if len(skuData) > 0:
        
        itemCashBack = itemCashBackMap.get(skuData[0]['_id'])
        if itemCashBack is not None:
            return itemCashBack
    
        sourceCashBack = cashBackMap.get(source_id)
        if sourceCashBack is not None and len(sourceCashBack) > 0:
            for cashBack in sourceCashBack:
                if cashBack.get(skuData[0]['category_id']) is None:
                    continue
                else:
                    return cashBack.get(skuData[0]['category_id'])
        else:
            return {} 
    else:
        return {}
    
    
def next_weekday(d, weekday):
    days_ahead = weekday - d.weekday()
    if days_ahead <= 0: # Target day already happened this week
        days_ahead += 7
    return d + timedelta(days_ahead)
    

def getAllDealerPrices(offset, limit):
    data = []
    collection = get_mongo_connection().Catalog.SkuDealerPrices
    cursor = collection.find().skip(offset).limit(limit)
    for val in cursor:
        master = list(get_mongo_connection().Catalog.MasterData.find({'_id':val['sku']}))
        if len(master) > 0:
            val['brand'] = master[0]['brand']
            val['source_product_name'] = master[0]['source_product_name']
            val['skuBundleId'] = master[0]['skuBundleId']
        else:
            val['brand'] = ""
            val['source_product_name'] = ""
            val['skuBundleId'] = ""
        data.append(val)
    return data

def addSkuDealerPrice(data):
    collection = get_mongo_connection().Catalog.SkuDealerPrices
    cursor = collection.find({"sku":data['sku']})
    if cursor.count() > 0:
        return {0:"Sku information already present."}
    else:
        collection.insert(data)
        get_mongo_connection().Catalog.MasterData.update({'_id':data['sku']},{"$set":{'updatedOn':to_java_date(datetime.now())}},multi=False)
        return {1:"Data added successfully"}

def updateSkuDealerPrice(data, _id):
    try:
        collection = get_mongo_connection().Catalog.SkuDealerPrices
        collection.update({'_id':ObjectId(_id)},{"$set":{'dp':data['dp']}},upsert=False, multi = False)
        get_mongo_connection().Catalog.MasterData.update({'_id':data['sku']},{"$set":{'updatedOn':to_java_date(datetime.now())}},multi=False)
        return {1:"Data updated successfully"}
    except:
        return {0:"Data not updated."}

def updateExceptionalNlc(data, _id):
    try:
        collection = get_mongo_connection().Catalog.ExceptionalNlc
        collection.update({'_id':ObjectId(_id)},{"$set":{'maxNlc':data['maxNlc'], 'minNlc':data['minNlc'], 'overrideNlc':data['overrideNlc']}},upsert=False, multi = False)
        get_mongo_connection().Catalog.MasterData.update({'_id':data['sku']},{"$set":{'updatedOn':to_java_date(datetime.now())}},multi=False)
        return {1:"Data updated successfully"}
    except:
        return {0:"Data not updated."}

def resetCache(userId):
    try:
        mc.delete(userId)
        return {1:'Cache cleared.'}
    except:
        return {0:'Unable to clear cache.'}
    
def updateCollection(data):
    print data
    try:
        collection = get_mongo_connection().Catalog[data['class']]
        data.pop('class')
        _id = data.pop('oid')
        result = collection.update({'_id':ObjectId(_id)},{"$set":data},upsert=False, multi = False)
        print result
        #get_mongo_connection().Catalog.MasterData.update({'brand':data['brand'],'category_id':data['category_id']},{"$set":{'updatedOn':to_java_date(datetime.now())}},multi=True)
        return {1:"Data updated successfully"}
    except:
        return {0:"Data not updated."}
    
    

def main():
    x = getNewDeals(1, 0, 0, 500, None, None)
    for i in x:
        print i['_id'],
        print '\t',
        print i['persPoints']
    
    
if __name__=='__main__':
    main()