Rev 13995 | Rev 14213 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
'''Created on Jan 15, 2015@author: amit'''from datetime import datetimeimport timefrom pprint import pprintfrom pymongo.mongo_client import MongoClientimport importlibimport jsonimport mathimport mechanizeimport tracebackimport urllibimport urllib2sourceMap = {1:"amazon", 2:"flipkart", 3:"snapdeal", 4:"spice", 5:"homeshop18"}headers = {'User-agent':'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11','Accept' : 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8','Accept-Language' : 'en-US,en;q=0.8','Accept-Charset' : 'ISO-8859-1,utf-8;q=0.7,*;q=0.3'}CASHBACK_URL = 'http://104.200.25.40:8057/Catalog/cashBack/?identifier=%s&source_id=%s'USER_LOOKUP_URL = 'http://api.profittill.com/user_accounts/saholic/%s'WALLET_CREDIT_URL = 'http://shop2020.in:8080/mobileapi/wallet!batchUpdate'def getStore(source_id):#module = sourceMap[source_id]store = Store(source_id)try:module = importlib.import_module("dtr.sources." + sourceMap[source_id])store = getattr(module, "Store")(source_id)return storeexcept:traceback.print_exc()return Noneclass ScrapeException(Exception):"""Exception raised for errors in the input.Attributes:expr -- input expression in which the error occurredmsg -- explanation of the error"""def __init__(self, expr, msg):self.expr = exprself.msg = msgclass ParseException(Exception):"""Exception raised for errors in the input.Attributes:expr -- input expression in which the error occurredmsg -- explanation of the error"""def __init__(self, expr, msg):self.expr = exprself.msg = msgclient = MongoClient('mongodb://localhost:27017/')class Store(object):ORDER_PLACED = 'Order Placed'ORDER_DELIVERED = 'Delivered'ORDER_SHIPPED = 'Shipped' #Lets see if we can make use of itORDER_CANCELLED = 'Cancelled'CB_INIT = 'Waiting Confirmation'CB_PENDING = 'Pending'CB_CREDIT_IN_PROCESS = 'Credit in process'CB_CREDITED = 'Credited to wallet'CB_NA = 'Not Applicable'CB_APPROVED = 'Approved'CB_CANCELLED = 'Cancelled'CONF_CB_SELLING_PRICE = 0CONF_CB_DISCOUNTED_PRICE = 1def __init__(self, store_id):self.db = client.Dtrself.store_id = store_idself.store_name = sourceMap[store_id]'''To Settle payback for respective stores.Also ensures that settlement happens only for approved orders'''def getName(self):raise NotImplementedErrordef scrapeAffiliate(self, startDate=None, endDate=None):raise NotImplementedErrordef saveToAffiliate(self, offers):raise NotImplementedErrordef scrapeStoreOrders(self,):raise NotImplementedErrordef _saveToOrder(self, order):collection = self.db.merchantOrdertry:order = collection.insert(order)#merchantOderexcept Exception as e:traceback.print_exc()def _updateToOrder(self, order):collection = self.db.merchantOrdertry:collection.update({"orderId":order['orderId']},{"$set":order}, upsert = True)#merchantOderexcept Exception as e:traceback.print_exc()def getCashbackAmount(self, productCode, amount):alagvar = CASHBACK_URL % (productCode,self.store_id)filehandle = urllib2.Request(alagvar,headers=headers)x= urllib2.urlopen(filehandle)rmap = json.loads(str(x.read()))if len(rmap)==0:return (0,0)else:if rmap['cash_back_description'] == 'PERCENTAGE':return (math.floor((amount * rmap['cash_back_status'])/100), rmap['cash_back_status'])else:return (rmap['cash_back_status'], 0)'''Parses the order for specific storeorder id, total amount, created on(now() if could not parsesuborder id, title, quantity, unit price, expected delivery date,status (default would be Order placed)once products are identified, each suborder can then be updatedwith respective cashback.Possible fields to display for Not yet delivered orders areProduct/Quantity/Amount/Store/CashbackAmount/OrderDate/ExpectedDelivery/OrderStaus/DetailedStatus/CashbackStatusNo need to show cancelled orders.CashbackStatus - NotApplicable/Pending/Approved/Cancelled/CreditedToWalletOrderStatus - Placed/Cancelled/Delivered'''def parseOrderRawHtml(self, orderId, subTagId, userId, rawHtml, orderSuccessUrl):passdef _updateOrdersPayBackStatus(self, searchMap, updateMap):searchMap['subOrders.missingAff'] = FalseupdateMap['subOrders.$.missingAff'] = Trueself.db.merchantOrder.update(searchMap, { '$set': updateMap }, multi=True)def _getActiveOrders(self, searchMap={}, collectionMap={}):collection = self.db.merchantOrdersearchMap = dict(searchMap.items()+ {"closed": False, "storeId" : self.store_id}.items())collectionMap = dict(collectionMap.items() + {"orderSuccessUrl":1, "orderId":1,"subOrders":1, "placedOn":1}.items())stores = collection.find(searchMap, collectionMap)return [store for store in stores]def _getMissingOrders(self,searchMap={}):collection = self.db.merchantOrdersearchMap = dict(searchMap.items()+ {"subOrders":{"$exists":False}}.items())orders = collection.find(searchMap)return list(orders)def _isSubOrderActive(self,order, merchantSubOrderId):subOrders = order.get("subOrders")for subOrder in subOrders:if merchantSubOrderId == subOrder.get("merchantSubOrderId"):return subOrderreturn Nonedef settlePayBack():client.Dtr.merchantOrder.update({'subOrders.cashBackStatus':Store.CB_APPROVED},{'$set':{'subOrders.$.cashBackStatus':Store.CB_CREDIT_IN_PROCESS}}, multi=True)result = client.Dtr.merchantOrder\.aggregate([{'$match':{'subOrders.cashBackStatus':Store.CB_CREDIT_IN_PROCESS}},{'$unwind':"$subOrders"},{'$group':{'_id':'$userId','amount': { '$sum':'$subOrders.cashBackAmount'},}}])['result']userAmountMap = {}print resultfor res in result:userAmountMap[res['_id']] = res['amount']datetimeNow = datetime.now()batchId = int(time.mktime(datetimeNow.timetuple()))if refundToWallet(batchId, userAmountMap):client.Dtr.merchantOrder.update({'subOrders.cashBackStatus':Store.CB_CREDIT_IN_PROCESS},{'$set':{'subOrders.$.cashBackStatus':Store.CB_CREDITED, 'subOrders.$.batchId':batchId}}, multi=True)for key, value in userAmountMap.iteritems():client.Dtr.refund.insert({"userId": key, "batch":batchId, "userAmount":value, "timestamp":datetime.strftime(datetimeNow,"%Y-%m-%d %H:%M:%S")})client.Dtr.user.update({"userId":key}, {'$inc': { "credited": value}}, upsert=True)tprint("PayBack Settled")else:tprint("Error Occurred while running batch. Rolling Back")client.Dtr.merchantOrder.update({'subOrders.cashBackStatus':Store.CB_CREDIT_IN_PROCESS},{'$set':{'subOrders.$.cashBackStatus':Store.CB_APPROVED}}, multi=True)def refundToWallet(batchId, userAmountMap):batchUpdateMap = {}try :saholicUserAmountMap = {}for key, value in userAmountMap.iteritems():userLookupRequest = urllib2.Request(USER_LOOKUP_URL %(key), headers=headers)try:response = urllib2.urlopen(userLookupRequest).read()saholicUserId = json.loads(response)['account_key']saholicUserAmountMap[saholicUserId] = valueexcept:tprint("Could not fetch saholic id for user : " + str(key))continueif len(saholicUserAmountMap) > 0:batchUpdateMap['userAmount'] = json.dumps(saholicUserAmountMap)batchUpdateMap['batchId'] = batchIdrequest = urllib2.Request(WALLET_CREDIT_URL, headers=headers)data = urllib.urlencode(batchUpdateMap)response = urllib2.urlopen(request, data)return json.loads(response.read())['response']['credited']else:tprint("Nothing to Refund")return Falseexcept:traceback.print_exc()tprint("Could not batch refund")return Falsedef main():store = getStore(3)print store.getCashbackAmount('832308321', 100)#data = urllib.urlencode({'orderId':6000, 'amount':200})#request = urllib2.Request(WALLET_CREDIT_URL % (483649), headers=headers)#response = urllib2.urlopen(request, data)#print response.read()#settlePayBack()####Settlement process is suposed to be a batch and run weekly#It is should be running on first hour of mondays. As cron should# Maintain a batch id.def getBrowserObject():import cookielibbr = mechanize.Browser(factory=mechanize.RobustFactory())cj = cookielib.LWPCookieJar()br.set_cookiejar(cj)br.set_handle_equiv(True)br.set_handle_redirect(True)br.set_handle_referer(True)br.set_handle_robots(False)br.set_debug_http(False)br.set_debug_redirects(False)br.set_debug_responses(False)br.set_handle_refresh(mechanize._http.HTTPRefreshProcessor(), max_time=1)br.addheaders = [('User-agent','Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11'),('Accept', 'text/html,application/xhtml+xml,application/json,application/xml;q=0.9,*/*;q=0.8'),('Accept-Encoding', 'gzip,deflate,sdch'),('Accept-Language', 'en-US,en;q=0.8'),('Accept-Charset', 'ISO-8859-1,utf-8;q=0.7,*;q=0.3')]return brdef ungzipResponse(r):headers = r.info()if headers['Content-Encoding']=='gzip':import gzipgz = gzip.GzipFile(fileobj=r, mode='rb')html = gz.read()gz.close()return htmldef tprint(*msg):print datetime.now(), "-", msgif __name__ == '__main__':main()