Rev 19194 | Rev 19631 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
import pymongofrom elixir import *from shop2020.model.v1.catalog.impl import DataServicefrom shop2020.model.v1.catalog.impl.DataService import Itemfrom shop2020.clients.InventoryClient import InventoryClientfrom dtr.utils.utils import to_java_date, getCashBackfrom datetime import datetime, timedeltaimport timeimport optparsefrom dtr.storage.MemCache import MemCacheimport tracebackimport mathparser = optparse.OptionParser()parser.add_option("-H", "--host", dest="hostname",default="localhost",type="string", help="The HOST where the DB server is running",metavar="host")parser.add_option("-m", "--m", dest="mongoHost",default="localhost",type="string", help="The HOST where the mongo server is running",metavar="mongo_host")(options, args) = parser.parse_args()mc = MemCache(options.mongoHost)DataService.initialize(db_hostname=options.hostname)con = NoneSOURCE_MAP = {'AMAZON':1,'FLIPKART':2,'SNAPDEAL':3,'SAHOLIC':4, 'SHOPCLUES.COM':5,'PAYTM.COM':6,'HOMESHOP18.COM':7}DISCOUNT_TYPE = {'MRP':1,'DP':2}LATEST_UPDATED_ITEMS = []STATUS_WEIGHTAGE = {1 : 1.0, 2 : 2.0, 3 : 1.0, 4 : 0.5}DEAL_POINTS_MAP = {}now = datetime.now()class __DealPoints:def __init__(self, manualDealThresholdPrice, points):self.manualDealThresholdPrice = manualDealThresholdPriceself.points = pointsclass __SkuInfo:def __init__(self, _id, skuBundleId, category_id, mrp, available_price, source_id, rank, maxNlc, minNlc, schemeAmount, minDiscount, \maxDiscount, discountType, dp, nlcPoints, status, in_stock, maxprice, brand, dealType, brand_id, manualDealThresholdPrice,\codAvailable,showDp,gross_price, subCategoryId,subCategory,shippingCost,netPriceAfterCashBack):self._id = _idself.skuBundleId = skuBundleIdself.category_id = category_idself.mrp = mrpself.available_price = available_priceself.source_id = source_idself.rank = rankself.maxNlc = maxNlcself.minNlc = minNlcself.schemeAmount = schemeAmountself.minDiscount = minDiscountself.maxDiscount = maxDiscountself.discountType = discountTypeself.dp = dpself.nlcPoints = nlcPointsself.status = statusself.in_stock = in_stockself.maxprice = maxpriceself.brand = brandself.dealType = dealTypeself.brand_id = brand_idself.manualDealThresholdPrice = manualDealThresholdPriceself.codAvailable = codAvailableself.showDp = showDpself.gross_price = gross_priceself.subCategoryId = subCategoryIdself.subCategory = subCategoryself.shippingCost = shippingCostself.netPriceAfterCashBack = netPriceAfterCashBackdef get_mongo_connection(host=options.mongoHost, port=27017):global conif con is None:print "Establishing connection %s host and port %d" %(host,port)try:con = pymongo.MongoClient(host, port)except Exception, e:print ereturn Nonereturn condef populateStuff():print "Inside populate"global LATEST_UPDATED_ITEMS"""Fetch latest updated items across portalsand calculate max and min R-Nlc"""offset= 0while(True):print "Fetching records offset %d and limit %d" %(offset,300)topSkus = list(get_mongo_connection().Catalog.MasterData.find( {"$and":[{'updatedOn': { "$gt": to_java_date(now - timedelta(hours=1))} }, { 'source_id' : { "$in": SOURCE_MAP.values() } }] }).skip(offset).limit(300))if len((topSkus)) == 0:break#topSkus = collection.find( {'_id':664})for sku in topSkus:"""Fix this """#TODO Compute deal flags else where.if sku['source_id'] != SOURCE_MAP.get('PAYTM.COM'):netPriceAfterCashBack = getNetPriceForItem(sku['_id'], sku['source_id'], sku['category_id'], sku['available_price'])else:if sku['codAvailable'] ==0:netPriceAfterCashBack = getNetPriceForItem(sku['_id'], sku['source_id'], sku['category_id'], sku['gross_price'])else:netPriceAfterCashBack = getNetPriceForItem(sku['_id'], sku['source_id'], sku['category_id'], sku['available_price'])info = __SkuInfo(sku['_id'], sku['skuBundleId'], sku['category_id'], sku['mrp'], sku['available_price'], sku['source_id'], sku['rank'], None, None, 0.0, None, \None, None, None, None, sku['status'], sku['in_stock'],sku['maxPrice'],sku['brand'].strip().upper(), 0, sku['brand_id'], None, sku['codAvailable'], 0, sku['gross_price'], sku['subCategoryId'], \sku['subCategory'],sku['shippingCost'],netPriceAfterCashBack)exceptionalNlc = list(get_mongo_connection().Catalog.ExceptionalNlc.find( {"$and" : [ {'skuBundleId':info.skuBundleId}, {'overrideNlc':1} ]} ))if len(exceptionalNlc) > 0:"""Exceptional nlc found, no need to calculate max and min R-nlc"""info.maxNlc = exceptionalNlc[0]['maxNlc']info.minNlc = exceptionalNlc[0]['minNlc']if info.maxprice == 0:info.maxprice = exceptionalNlc[0]['maxNlc']LATEST_UPDATED_ITEMS.append(info)continueskuSchemeDetails = list(get_mongo_connection().Catalog.SkuSchemeDetails.find( {'skuBundleId':info.skuBundleId}))if len(skuSchemeDetails) > 0:"""Sku scheme details, populate scheme amount (Recently added)"""#TODO Add start date and end date of scehemsinfo.schemeAmount = float(skuSchemeDetails[0]['schemeAmount'])skuDealerPrices = list(get_mongo_connection().Catalog.SkuDealerPrices.find( {'skuBundleId':info.skuBundleId} ) )if len(skuDealerPrices) > 0:info.dp = skuDealerPrices[0]['dp']info.showDp = skuDealerPrices[0]['showDp']skuDiscount = list(get_mongo_connection().Catalog.SkuDiscountInfo.find( {'skuBundleId':info.skuBundleId} ) )if len(skuDiscount) > 0:"""Sku rule found, populate max , min Discount and discount type"""info.maxDiscount = skuDiscount[0]['max_discount']info.minDiscount = skuDiscount[0]['min_discount']info.discountType = DISCOUNT_TYPE.get(skuDiscount[0]['discountType'].upper())LATEST_UPDATED_ITEMS.append(info)continuecategoryDiscount = list(get_mongo_connection().Catalog.CategoryDiscount.find( {"$and" : [{'brand':sku['brand'].strip().upper()}, {'category_id':sku['category_id']} ]} ))if len(categoryDiscount) > 0:info.maxDiscount = categoryDiscount[0]['max_discount']info.minDiscount = categoryDiscount[0]['min_discount']info.discountType = DISCOUNT_TYPE.get(categoryDiscount[0]['discountType'].upper())LATEST_UPDATED_ITEMS.append(info)offset = offset + 300for lol in LATEST_UPDATED_ITEMS:print lol.__dict__def calculateNlc():global LATEST_UPDATED_ITEMSpopulated = 0while(populated <= len(LATEST_UPDATED_ITEMS)):inventory_client = InventoryClient().get_client()for obj in LATEST_UPDATED_ITEMS[populated:300+populated]:if obj.maxNlc > 0 and obj.minNlc > 0:continuesaholic_sku = list(get_mongo_connection().Catalog.MasterData.find( {"$and":[{'skuBundleId': obj.skuBundleId}, { 'source_id' : SOURCE_MAP.get('SAHOLIC')}] }))identifier = Noneif len(saholic_sku) > 0:identifier = saholic_sku[0]['identifier']if obj.discountType == DISCOUNT_TYPE.get('MRP'):if obj.mrp == 0:"""Now mrp is zero, so we have to use saholic MRP"""if identifier is not None:it = Item.query.filter_by(catalog_item_id=identifier).first()obj.mrp = it.mrpif obj.mrp > 0:print obj._idobj.minNlc = obj.mrp - (obj.mrp * obj.maxDiscount/100) - obj.schemeAmountobj.maxNlc = obj.mrp - (obj.mrp * obj.minDiscount/100) - obj.schemeAmountif obj.maxprice == 0:obj.maxprice = obj.maxNlcelif obj.discountType == DISCOUNT_TYPE.get('DP'):if obj.dp == 0:"""Now dp is zero, so we have to use saholic minimum dp for item"""if identifier is not None:it = Item.query.filter_by(catalog_item_id=identifier).first()try:vendorPricing = inventory_client.getAllItemPricing(it.id)min_dp = min(pricing.dealerPrice for pricing in vendorPricing)obj.dp = min_dpobj.showDp = 1except:passif obj.dp > 0:obj.minNlc = obj.dp - (obj.dp * obj.maxDiscount/100) - obj.schemeAmountobj.maxNlc = obj.dp - (obj.dp * obj.minDiscount/100) - obj.schemeAmountif obj.maxprice == 0:obj.maxprice = obj.maxNlcelse:"""No rule found, use saholic min nlc as max and min R-Nlc"""if identifier is not None:it = Item.query.filter_by(catalog_item_id=identifier).first()try:vendorPricing = inventory_client.getAllItemPricing(it.id)min_nlc = min(pricing.nlc for pricing in vendorPricing)obj.maxNlc = min_nlcobj.minNlc = min_nlcif obj.maxprice == 0:obj.maxprice = obj.maxNlcexcept:passpopulated = populated + 300time.sleep(10)def addManualDealsInfo():for sku in LATEST_UPDATED_ITEMS:manualDeal = list(get_mongo_connection().Catalog.ManualDeals.find({'startDate':{'$lte':to_java_date(datetime.now())},'endDate':{'$gte':to_java_date(datetime.now())},'source_id':sku.source_id, 'sku':sku._id}))if len(manualDeal) > 0:sku.dealType = manualDeal[0]['dealType']"""Remove deal flag from expired deals"""manualDeals = list(get_mongo_connection().Catalog.Deals.find({'dealType':1}))for manualDeal in manualDeals:d_manualDeal = list(get_mongo_connection().Catalog.ManualDeals.find({'startDate':{'$lte':to_java_date(datetime.now())},'endDate':{'$gte':to_java_date(datetime.now())},'source_id':manualDeal['source_id'], 'sku':manualDeal['_id']}))if len(d_manualDeal) > 0:continueelse:get_mongo_connection().Catalog.Deals.update({'_id':manualDeal['_id']},{"$set":{'dealType':0}},upsert=False, multi=False)def calculateNlcPoints():global LATEST_UPDATED_ITEMSprint "inside nlc oints"for sku in LATEST_UPDATED_ITEMS:if sku.maxNlc and sku.minNlc:print sku._id"""Create map - TODO"""if sku.status == 2:eolWeight = .60else:eolWeight = 1.0if sku.category_id == 3:basePointPercentage = 5.0maxNlcPoints = 200elif sku.category_id == 5:basePointPercentage = 8.0maxNlcPoints = 150elif sku.category_id == 6:basePointPercentage = 5.0maxNlcPoints = 200else:basePointPercentage = 10.0maxNlcPoints = 150discFromMinNlc = float((sku.minNlc - sku.available_price))/sku.available_price *100discFromMaxNlc = float((sku.maxNlc - sku.available_price))/sku.available_price *100print discFromMinNlcprint discFromMaxNlcif discFromMinNlc > 0:nlcPoints = 100/basePointPercentage * discFromMinNlcelif discFromMinNlc < 0 and discFromMaxNlc > 0:nlcPoints = 0else:nlcPoints = 100/basePointPercentage * discFromMinNlcif (min(nlcPoints,maxNlcPoints)) > 0:sku.nlcPoints = (min(nlcPoints,maxNlcPoints)) * eolWeightelse:sku.nlcPoints = (min(nlcPoints,maxNlcPoints))else:sku.nlcPoints = 0def commitData():global LATEST_UPDATED_ITEMSfor sku in LATEST_UPDATED_ITEMS:#get_mongo_connection().Catalog.Deals.update({'_id':sku._id},{'$set' : sku.__dict__},upsert=True,multi=True)get_mongo_connection().Catalog.Deals.update({'_id':sku._id},{"$set":sku.__dict__},upsert=True)def addBestSellerPoints():allItems = list(get_mongo_connection().Catalog.Deals.find({}))for sku in allItems:bestSellerPoints = list(get_mongo_connection().Catalog.BestSellerPoints.find( {"$and":[{'min_rank': { "$lte": sku['rank'] } }, {'max_rank': { "$gte": sku['rank'] } } , { 'category_id' : sku['category_id'] }, { 'source_id' : sku['source_id'] }] } ))if len(bestSellerPoints) > 0:print bestSellerPoints[0]['points']if (bestSellerPoints[0]['points']) > 0:sku['bestSellerPoints'] = (bestSellerPoints[0]['points']) * bestSellerPoints[0]['weightage'] * STATUS_WEIGHTAGE.get(sku['status'])else:sku['bestSellerPoints'] = (bestSellerPoints[0]['points'])else:if sku['category_id'] == 6:sku['bestSellerPoints'] = 0else:sku['bestSellerPoints'] = -120#sku['totalPoints'] = sku['bestSellerPoints'] + sku['nlcPoints']get_mongo_connection().Catalog.Deals.update({'_id':sku['_id']},{'$set':{'bestSellerPoints':sku['bestSellerPoints']}},multi=False)shortageSkus = get_mongo_connection().Catalog.MasterData.find({"$and":[{'is_shortage': 1 }, { 'source_id' : { "$in": SOURCE_MAP.values() } }] }).distinct('_id')print "Shortage skus"print shortageSkusfor sku in allItems:deal_item = list(get_mongo_connection().Catalog.Deals.find({'skuBundleId':sku['skuBundleId']}).sort('bestSellerPoints',pymongo.DESCENDING).limit(1))sku['catalogBestSellerPoints'] = deal_item[0]['bestSellerPoints']shortagePoints = 50 if sku['_id'] in shortageSkus else 0print "Shortage points for ",sku['_id']print shortagePointsdealPoints = DEAL_POINTS_MAP.get(sku['skuBundleId'])if dealPoints is not None and dealPoints.manualDealThresholdPrice >= sku['available_price']:sku['dealPoints'] = dealPoints.pointssku['manualDealThresholdPrice'] = dealPoints.manualDealThresholdPriceelse:sku['dealPoints'] = 0sku['manualDealThresholdPrice'] = Nonesku['totalPoints'] = sku['catalogBestSellerPoints'] + sku['nlcPoints'] + shortagePoints + sku['dealPoints']get_mongo_connection().Catalog.Deals.update({'_id':sku['_id']},{'$set':{'catalogBestSellerPoints':sku['catalogBestSellerPoints'],'totalPoints':sku['totalPoints'],'dealPoints':sku['dealPoints'], \'manualDealThresholdPrice':sku['manualDealThresholdPrice']}},multi=False)def populateNegativeDeals():negativeDeals = get_mongo_connection().Catalog.NegativeDeals.find().distinct('sku')mc.set("negative_deals", negativeDeals, 600)def eliminateSimilarDeals():allItems = get_mongo_connection().Catalog.Deals.find().distinct('skuBundleId')for skuBundleId in allItems:print skuBundleIdsimilarItems = list(get_mongo_connection().Catalog.Deals.find({'skuBundleId':skuBundleId}).sort([('netPriceAfterCashBack',pymongo.ASCENDING)]))bestPrice = float("inf")bestOne = NonebestSellerPoints = 0toUpdate = []prepaidBestPrice = float("inf")prepaidBestOne = NoneprepaidBestSellerPoints = 0for similarItem in similarItems:if similarItem['codAvailable'] ==1:if mc.get("negative_deals") is None:populateNegativeDeals()if similarItem['in_stock'] == 0 or similarItem['_id'] in mc.get("negative_deals"):get_mongo_connection().Catalog.Deals.update({ '_id' : similarItem['_id'] }, {'$set':{'showDeal':0, 'prepaidDeal':0 }})continueif similarItem['source_id'] == SOURCE_MAP.get('SHOPCLUES.COM') and similarItem['rank']==0 and similarItem['category_id']!=6:get_mongo_connection().Catalog.Deals.update({ '_id' : similarItem['_id'] }, {'$set':{'showDeal':0,'prepaidDeal':0 }})continueif similarItem['netPriceAfterCashBack'] < bestPrice:bestOne = similarItembestPrice = similarItem['netPriceAfterCashBack']bestSellerPoints = similarItem['bestSellerPoints']elif similarItem['netPriceAfterCashBack'] == bestPrice and bestSellerPoints < similarItem['bestSellerPoints']:bestOne = similarItembestPrice = similarItem['netPriceAfterCashBack']bestSellerPoints = similarItem['bestSellerPoints']else:passelse:if mc.get("negative_deals") is None:populateNegativeDeals()if similarItem['in_stock'] == 0 or similarItem['_id'] in mc.get("negative_deals"):get_mongo_connection().Catalog.Deals.update({ '_id' : similarItem['_id'] }, {'$set':{'showDeal':0, 'prepaidDeal':0 }})continueif similarItem['source_id'] == SOURCE_MAP.get('SHOPCLUES.COM') and similarItem['rank']==0 and similarItem['category_id']!=6:get_mongo_connection().Catalog.Deals.update({ '_id' : similarItem['_id'] }, {'$set':{'showDeal':0,'prepaidDeal':0 }})continueif similarItem['netPriceAfterCashBack'] < prepaidBestPrice:prepaidBestOne = similarItemprepaidBestPrice = similarItem['netPriceAfterCashBack']prepaidBestSellerPoints = similarItem['bestSellerPoints']elif similarItem['netPriceAfterCashBack'] == prepaidBestPrice and prepaidBestSellerPoints < similarItem['bestSellerPoints']:prepaidBestOne = similarItemprepaidBestPrice = similarItem['netPriceAfterCashBack']prepaidBestSellerPoints = similarItem['bestSellerPoints']else:passif bestOne is not None or prepaidBestOne is not None:for similarItem in similarItems:toUpdate.append(similarItem['_id'])if bestOne is not None:toUpdate.remove(bestOne['_id'])get_mongo_connection().Catalog.Deals.update({ '_id' : bestOne['_id'] }, {'$set':{'showDeal':1,'prepaidDeal':0 }})if prepaidBestOne is not None:if bestOne is not None:if prepaidBestOne['netPriceAfterCashBack'] < bestOne['netPriceAfterCashBack']:toUpdate.remove(prepaidBestOne['_id'])get_mongo_connection().Catalog.Deals.update({ '_id' : prepaidBestOne['_id'] }, {'$set':{'showDeal':0,'prepaidDeal':1 }})else:toUpdate.remove(prepaidBestOne['_id'])get_mongo_connection().Catalog.Deals.update({ '_id' : prepaidBestOne['_id'] }, {'$set':{'showDeal':0,'prepaidDeal':1 }})if len(toUpdate) > 0:get_mongo_connection().Catalog.Deals.update({ '_id' : { "$in": toUpdate } }, {'$set':{'showDeal':0,'prepaidDeal':0 }},upsert=False, multi=True)def populateDealPointsBundle():global DEAL_POINTS_MAPactiveDealPoints = get_mongo_connection().Catalog.DealPoints.find({'startDate':{'$lte':to_java_date(datetime.now())},'endDate':{'$gte':to_java_date(datetime.now())}})for activeDeal in activeDealPoints:dealPoints = __DealPoints(activeDeal['dealThresholdPrice'], activeDeal['dealPoints'])DEAL_POINTS_MAP[activeDeal['skuBundleId']] = dealPointsdef getNetPriceForItem(itemId, source_id, category_id ,price):cash_back_type = 0cash_back = 0try:cashBack = getCashBack(itemId, source_id, category_id, mc, options.mongoHost)if not cashBack or cashBack.get('cash_back_status')!=1:cash_back_type = 0cash_back = 0else:if cashBack['cash_back_type'] in (1,2):if cashBack.get('maxCashBack') is not None:if cashBack.get('cash_back_type') ==1 and (float(cashBack.get('cash_back'))*price)/100 > cashBack.get('maxCashBack'):cashBack['cash_back_type'] = 2cashBack['cash_back'] = cashBack['maxCashBack']elif cashBack.get('cash_back_type') ==2 and cashBack.get('cash_back') > cashBack.get('maxCashBack'):cashBack['cash_back'] = cashBack['maxCashBack']else:passcash_back_type = cashBack['cash_back_type']cash_back = float(cashBack['cash_back'])except Exception as cashBackEx:passif cash_back_type ==1:return (price - math.floor(float(cash_back)*price/100))elif cash_back_type ==2:return (price - cash_back)else:return price# def calculateNetPriceAfterCashback():# for data in LATEST_UPDATED_ITEMS:# master = list(get_mongo_connection().Catalog.MasterData.find({'_id':data._id}))# if master[0]['source_id'] != SOURCE_MAP.get('PAYTM.COM'):# netPriceAfterCashBack = getNetPriceForItem(data._id, master[0]['source_id'], master[0]['category_id'], master[0]['available_price'])# get_mongo_connection().Catalog.Deals.update({'_id':data._id},{"$set":{'available_price':master[0]['available_price'],'in_stock':master[0]['in_stock'],'netPriceAfterCashBack':netPriceAfterCashBack}})# else:# if master[0]['codAvailable'] ==0:# netPriceAfterCashBack = getNetPriceForItem(data._id, master[0]['source_id'], master[0]['category_id'], master[0]['gross_price'])# else:# netPriceAfterCashBack = getNetPriceForItem(data._id, master[0]['source_id'], master[0]['category_id'], master[0]['available_price'])# get_mongo_connection().Catalog.Deals.update({'_id':data._id},{"$set":{'available_price':master[0]['available_price'],'gross_price':master[0]['gross_price'],'in_stock':master[0]['in_stock'],'netPriceAfterCashBack':netPriceAfterCashBack}})#def main():try:print "Starting populating stuff ", datetime.now()populateStuff()print "Starting calculate nlc stuff ", datetime.now()calculateNlc()print "Starting adding manualdeals stuff ", datetime.now()addManualDealsInfo()finally:session.close()print "Starting calculate nlc points ", datetime.now()calculateNlcPoints()print "commiting data ", datetime.now()commitData()print "Populate deal points bundle ", datetime.now()populateDealPointsBundle()print "Add best seller points ", datetime.now()addBestSellerPoints()print "eliminate similar deals ", datetime.now()eliminateSimilarDeals()print "done ", datetime.now()if __name__=='__main__':main()