Subversion Repositories SmartDukaan

Rev

Rev 14692 | Rev 14847 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
13569 amit.gupta 1
'''
2
Created on Jan 15, 2015
3
 
4
@author: amit
5
'''
13690 amit.gupta 6
from BeautifulSoup import BeautifulSoup
13721 amit.gupta 7
from datetime import datetime, date, timedelta
13569 amit.gupta 8
from dtr import main
14412 amit.gupta 9
from dtr.dao import AffiliateInfo, Order, SubOrder, FlipkartAffiliateInfo
13690 amit.gupta 10
from dtr.main import getBrowserObject, getStore, ParseException, ungzipResponse, \
14398 amit.gupta 11
    Store as MStore, sourceMap, tprint
13690 amit.gupta 12
from pprint import pprint
13
from pymongo.mongo_client import MongoClient
14
import hashlib
13658 manas 15
import importlib
13690 amit.gupta 16
import json
17
import mechanize
14412 amit.gupta 18
import pymongo
13658 manas 19
import re
14338 amit.gupta 20
import traceback
13658 manas 21
import urllib
14757 amit.gupta 22
from dtr.utils.utils import fetchResponseUsingProxy
13658 manas 23
 
24
USERNAME='saholic1@gmail.com'
25
PASSWORD='spice@2020'
26
ORDER_TRACK_URL='https://m.flipkart.com/order_details'
13679 manas 27
AFFILIATE_URL='https://www.flipkart.com/affiliate/login'
13690 amit.gupta 28
AFFILIATE_LOGIN_URL='https://www.flipkart.com/affiliate/a_login'
29
AFF_REPORT_URL='http://www.flipkart.com/affiliate/reports/ordersReport?order_status_filter=%s&startdate=%s&enddate=%s'
30
AFF_STATUS_CANCELLED='cancelled'
31
AFF_STATUS_APPROVED='approved'
32
AFF_STATUS_DISAPPROVED='disapproved'
33
AFF_STATUS_PENDING='pending'
13658 manas 34
 
13679 manas 35
 
13781 amit.gupta 36
class Store(MStore):
13658 manas 37
    OrderStatusMap = {
14679 amit.gupta 38
                      main.Store.ORDER_PLACED : ['approval', 'processing', 'shipping'],
39
                      main.Store.ORDER_DELIVERED : ['your item has been delivered'],
14680 amit.gupta 40
                      main.Store.ORDER_SHIPPED : ['in transit', 'shipment yet to be delivered'],
41
                      main.Store.ORDER_CANCELLED : ['shipment is returned', 'your item has been returned', 'your shipment has been cancelled', 'your shipment has been cancelled.']
13658 manas 42
 
43
                      }
44
    def __init__(self,store_id):
45
        client = MongoClient('mongodb://localhost:27017/')
46
        self.db = client.dtr
47
        super(Store, self).__init__(store_id)
48
 
13569 amit.gupta 49
    def getName(self):
50
        return "flipkart"
51
 
13690 amit.gupta 52
    def scrapeStoreOrders(self,):
53
        orders = self._getActiveOrders()
13721 amit.gupta 54
        for order in orders:
14692 amit.gupta 55
            print "Order", self.store_name, order['orderId']
14398 amit.gupta 56
            try:
57
                closed = True
58
                url = ORDER_TRACK_URL + re.findall('.*(\?.*?)$', order['orderSuccessUrl'],re.IGNORECASE)[0]
14757 amit.gupta 59
                page = fetchResponseUsingProxy(url)
14398 amit.gupta 60
                soup = BeautifulSoup(page,convertEntities=BeautifulSoup.HTML_ENTITIES)
61
 
62
                sections = soup.findAll("div", {"class":"ui-app-card-body"})
63
                sections.pop(1)
13721 amit.gupta 64
 
14398 amit.gupta 65
                mainOrder = soup.find("ul",{"class":"m-bottom p-cart"})
66
                fkSubOrders = mainOrder.findAll("li")
67
 
68
                #remove unwanted list
69
                fkSubOrders.pop(-1)
70
 
71
 
72
                bulk = self.db.merchantOrder.initialize_ordered_bulk_op()
73
                #fetching suborders details
74
                for subOrder in fkSubOrders:
75
                    updateMap = {}
76
                    y = subOrder.find("header").findAll("span")
77
                    for suborderId in y:
78
                        if "value emp" in str(suborderId):
79
                            merchantSubOrderId = suborderId.text
80
                            break
14692 amit.gupta 81
                    ul = subOrder.find("ul")
82
                    if ul is None:
83
                        ul = subOrder.findAll("div", recursive=False)[0].div.div
84
                    orderItems = ul.findAll("div", recursive=False)
14398 amit.gupta 85
                    i=0
86
                    for orderItem in orderItems:
87
                        closedStatus = False
88
                        merchantSubOrderId = merchantSubOrderId + str(i)
89
                        subOrder =  self._isSubOrderActive(order, merchantSubOrderId)
90
                        if subOrder is None:
91
                            break
14460 amit.gupta 92
                        elif subOrder['closed']:
93
                            break
14398 amit.gupta 94
                        findMap = {"orderId": order['orderId'], "subOrders.merchantSubOrderId": merchantSubOrderId}
95
                        divs = orderItem.findAll('div', recursive=False)
96
                        orderTracking = divs[2]
97
                        orderTrackingDetDiv = divs[3].find('div',{'class':'c-tabs-content m-top active'})
98
                        orderTrackingDet = orderTrackingDetDiv.find('div',{'class':re.compile('tracking-remark')}).text
99
                        updateMap["subOrders.$.detailedStatus"] = orderTrackingDet
14617 amit.gupta 100
                        status = self._getStatusFromDetailedStatus(orderTrackingDet)
14398 amit.gupta 101
                        tr = orderTracking.findAll("div",{"class":"tap-bullet-area c-tab-trigger"})
102
 
103
                        cashbackStatus = subOrder.get("cashBackStatus") 
104
                        if "approveDetails-complete" in str(tr):
105
                            if "processingDetails-complete" in str(tr):
106
                                if "shippingDetails-complete" in str(tr):
107
                                    if "delivery-complete" in str(tr):
108
                                        status = MStore.ORDER_DELIVERED
109
                                        if cashbackStatus == Store.CB_PENDING:
110
                                            cashbackStatus = Store.CB_APPROVED
111
                                        closedStatus = True
112
                                    else:     
113
                                        status = MStore.ORDER_SHIPPED
114
                                        courierTrackAnchor = orderTrackingDetDiv.find('a')
115
                                        trackingUrl = courierTrackAnchor("href")
116
                                        trackingText = courierTrackAnchor.text
117
                                        courierArr = trackingText.split(' : ')
118
                                        updateMap["subOrders.$.trackingUrl"] = trackingUrl
119
                                        updateMap["subOrders.$.trackingNumber"] = courierArr[1]
120
                                        updateMap["subOrders.$.courierName"] = courierArr[0]
121
                                else:
14692 amit.gupta 122
                                    status = MStore.ORDER_CANCELLED
123
                                    closedStatus = True
124
                                    if cashbackStatus == Store.CB_PENDING:
125
                                        cashbackStatus = Store.CB_CANCELLED
14398 amit.gupta 126
                            else: 
13721 amit.gupta 127
                                status = MStore.ORDER_PLACED
14398 amit.gupta 128
                        elif str(tr) in ["approveDetails-ongoing"]:
129
                            status=MStore.ORDER_PLACED             
14617 amit.gupta 130
                        if "dead" in str(tr) or status==MStore.ORDER_CANCELLED:
14398 amit.gupta 131
                            status = MStore.ORDER_CANCELLED
132
                            closedStatus = True
133
                            if cashbackStatus == Store.CB_PENDING:
134
                                cashbackStatus = Store.CB_CANCELLED
135
 
136
                        updateMap["subOrders.$.cashBackStatus"] = cashbackStatus
137
                        updateMap["subOrders.$.status"] = status
138
                        updateMap["subOrders.$.closed"] = closedStatus
139
                        if closed:
140
                            closed = closedStatus
141
                        bulk.find(findMap).update({'$set' : updateMap})
14692 amit.gupta 142
                bulk.find({'orderId': order['orderId']}).update({'$set':{'closed': closed, 'parseError':False}})
14398 amit.gupta 143
                bulk.execute()            
144
            except:
14692 amit.gupta 145
                self.db.merchantOrder.update({"orderId":order['orderId']}, {"$set":{"parseError":True}})
14398 amit.gupta 146
                tprint("Could not update " + str(order['orderId']))
147
                traceback.print_exc()
13721 amit.gupta 148
    def scrapeAffiliate(self, startDate=None, endDate=None):
149
        #get all yesterday's affiliate in pending or cancelled state and update to system
14461 amit.gupta 150
        offers = []
151
        br = getBrowserObject()
152
        br.open(AFFILIATE_URL)
153
        response = br.response()  # copy
154
        token =  re.findall('window.__FK = "(.*?)"', ungzipResponse(response), re.IGNORECASE)[0]
155
        data = {'__FK':token,
156
                'email':'saholic1@gmail.com',
157
                'password':'e8aacf6fc1e3998186a4a8e56e428f66'
158
        }
159
        br.open(AFFILIATE_LOGIN_URL, urllib.urlencode(data))
14474 amit.gupta 160
        for delta in range(0,45):
14461 amit.gupta 161
            yester5date = date.today() - timedelta(delta)
162
            syester5date = yester5date.strftime('%Y-%m-%d')
163
            for status in [AFF_STATUS_PENDING, AFF_STATUS_CANCELLED, AFF_STATUS_DISAPPROVED]:
164
                try:
165
                    br.open(AFF_REPORT_URL % (status, syester5date, syester5date))
166
                except:
167
                    tprint("Could not fetch data for Status %s and date %s"%(status, syester5date))
168
                page = ungzipResponse(br.response())
169
                soup = BeautifulSoup(page,convertEntities=BeautifulSoup.HTML_ENTITIES)
170
                soup.table
171
                try:
172
                    tableElement = soup.findAll('table', {'class':'report-table fixtable'})[1]
173
                except:
174
                    continue
175
                trElements = tableElement.findAll('tr')
176
                trElements.pop(0)
177
                for trElement in trElements:
178
                    tdElements = trElement.findAll('td')
179
                    productCode = re.findall(r'pid=(.*)$', tdElements[0].find('a')['href'])[0]
180
                    quantity =int(tdElements[3].text)
181
                    price = int(float(tdElements[2].text.strip().replace(",","")))
182
                    payOut = int(float(tdElements[6].text.strip().replace(",","")))
183
                    saleAmount = int(float(tdElements[4].text.strip().replace(",","")))
184
                    subTagId = tdElements[7].text.strip()
185
                    category = tdElements[1].text.strip()
14648 amit.gupta 186
                    affiliateInfo = FlipkartAffiliateInfo(subTagId, syester5date, productCode, price, quantity, saleAmount, payOut, status, category)
187
                    affiliateInfo.productTitle =  tdElements[0].find('a').text
14461 amit.gupta 188
                    #updateMap['subOrders.$.unitPrice'] = price
189
                    #updateMap['subOrders.$.cashBackAmount'], updateMap['subOrders.$.cashBacPercentage'] = self.getCashbackAmount(productCode, price)
190
                    offers.append(affiliateInfo)
191
        self._saveToAffiliate(offers)
13721 amit.gupta 192
 
14412 amit.gupta 193
    def _saveToAffiliate(self, offers):
194
        collection = self.db.flipkartOrderAffiliateInfo
14460 amit.gupta 195
        mcollection = self.db.merchantOrder
196
        for offer in offers:
197
            result1 = collection.update({"subTagId":offer.subTagId, "price":offer.price, "quantity":offer.quantity, "saleDate":offer.saleDate, "productCode":offer.productCode},{"$set":todict(offer)}, upsert=True)
198
            if result1.get("upserted") is not None:
199
                result2 = mcollection.update({"subTagId":offer.subTagId, "storeId":self.store_id, "subOrders.missingAff":True, "subOrders.productCode":offer.productCode}, {"$set":{"subOrders.$.missingAff":False}}, multi=True)
200
                if result2.get("updatedExisting") is True:
201
                    mcollection.update({"_id":result1.get("upserted")}, {"missingOrders":False})
202
 
14412 amit.gupta 203
 
204
 
13658 manas 205
    def parseOrderRawHtml(self, orderId, subTagId, userId, rawHtml, orderSuccessUrl):
13796 amit.gupta 206
        resp= {}
13781 amit.gupta 207
        try:
208
            br = getBrowserObject()
209
            url = ORDER_TRACK_URL + re.findall('.*(\?.*?)$', orderSuccessUrl,re.IGNORECASE)[0]
210
 
211
            response = br.open(url)
212
            page = ungzipResponse(response)
213
 
214
            merchantOrderId = re.findall('reference_id=(.*?)&', orderSuccessUrl,re.IGNORECASE)[0]
215
            print merchantOrderId
216
 
217
            soup = BeautifulSoup(page,convertEntities=BeautifulSoup.HTML_ENTITIES)
218
 
219
            sections = soup.findAll("div", {"class":"ui-app-card-body"})
220
            sections.pop(1)
221
 
222
            merchantOrder = Order(orderId, userId, subTagId, self.store_id, orderSuccessUrl)
14145 amit.gupta 223
            merchantOrder.orderTrackingUrl = url
13781 amit.gupta 224
            for data in sections:
225
                name = data.findAll("span")
226
                i=0
227
                while i< len(name):
228
                    if "key" in str(name[i]):
229
                        if "Grand Total" in str(name[i]):
230
                            #Total Amount
231
                            merchantOrder.paidAmount = int(re.findall(r'\d+', name[i+1].text)[0])
232
                        elif "Order Date" in str(name[i]):
233
                            merchantOrder.placedOn = name[i+1].text 
234
                    i=i+1    
235
 
236
            merchantOrder.merchantOrderId = merchantOrderId
237
 
238
            mainOrder = soup.find("ul",{"class":"m-bottom p-cart"})
239
            fkSubOrders = mainOrder.findAll("li")
240
            #remove unwanted list
241
            fkSubOrders.pop(-1)
242
            subOrders = []
243
            merchantOrder.subOrders = subOrders
244
 
245
            #fetching suborders details
246
            for subOrder in fkSubOrders:
247
                y = subOrder.find("header").findAll("span")
248
                for suborderId in y:
249
                    if "value emp" in str(suborderId):
250
                        merchantSubOrderId = suborderId.text
251
                        break
252
                orderItems = subOrder.find("ul").findAll("div", recursive=False)
253
                i=0
254
                for orderItem in orderItems:
255
                    merchantOrder.placedOn
256
                    merchantSubOrderId = merchantSubOrderId + str(i)
257
                    divs = orderItem.findAll('div', recursive=False)
258
                    content = divs[0]
259
                    orderTracking = divs[2]
260
                    orderTrackingDet = divs[3]
261
 
262
 
263
                    imgUrl = content.find('img')['src']
264
                    lineDet = content.find("div",{"class":"product-info"})
265
                    productTitle = lineDet.find("a",{"class":"product-title"}).text
266
                    productUrl =  str(lineDet.find("a")['href'])
267
 
268
                    start='pid='
269
                    s=str(lineDet.find("a")['href'])
14339 amit.gupta 270
                    productCode = re.findall(re.escape(start)+"(.*)",s)[0].strip()
13781 amit.gupta 271
                    mname = lineDet.findAll("span")
272
                    k=0
273
                    while k<len(mname):
274
                        if "note" in str(mname[k]):
275
                            if "Color:" in str(mname[k]):
276
                                productTitle = productTitle + " " + mname[k+1].text
277
 
278
                            elif "Qty:" in str(mname[k]):
279
                                quantity = int(mname[k+1].text)
280
                            elif "Subtotal:" in str(mname[k]):
14343 amit.gupta 281
                                amountPaid = int(re.findall(r'\d+', mname[k+1].text)[0])
13781 amit.gupta 282
                            elif "Delivery:" in str(mname[k]):
283
                                #Delivery Date for sub order
284
                                print "Delivery Date " +mname[k+1].text
285
                        k=k+1
14343 amit.gupta 286
                    merchantsubOrder = SubOrder(productTitle, productUrl, merchantOrder.placedOn, amountPaid,MStore.ORDER_PLACED, quantity)
13781 amit.gupta 287
                    merchantsubOrder.imgUrl  = imgUrl
288
                    merchantsubOrder.productCode = productCode
289
                    merchantsubOrder.merchantSubOrderId = merchantSubOrderId
14337 amit.gupta 290
                    print "productCode", productCode
14340 amit.gupta 291
                    print "amountPaid", amountPaid
14336 amit.gupta 292
                    cashbackAmount, cashbackPercent = self.getCashbackAmount(productCode, amountPaid)
13781 amit.gupta 293
                    cashbackStatus = Store.CB_PENDING
294
                    if cashbackAmount <= 0:
295
                        cashbackStatus = Store.CB_NA
296
                    merchantsubOrder.cashBackAmount = cashbackAmount
297
                    merchantsubOrder.cashBackStatus = cashbackStatus      
298
                    merchantsubOrder.cashBackPercentage = cashbackPercent      
299
 
300
                    subOrders.append(merchantsubOrder)
301
                    #To track shipping details         
302
                    status=-1    
303
                    tr = orderTracking.findAll("div",{"class":"tap-bullet-area c-tab-trigger"})
304
                    if "approveDetails-complete" in str(tr):
305
                        if "processingDetails-complete" in str(tr):
306
                            if "shippingDetails-complete" in str(tr):
307
                                if "delivery-complete" in str(tr):
308
                                    status = MStore.ORDER_DELIVERED
309
                                else:     
310
                                    status = MStore.ORDER_SHIPPED
311
                                    orderTracking.find('div', {'class':'tracking-remark active'})
312
                            else:
313
                                status = MStore.ORDER_PLACED
314
                        else: 
13690 amit.gupta 315
                            status = MStore.ORDER_PLACED
13781 amit.gupta 316
                    elif str(tr) in ["approveDetails-ongoing"]:
317
                        status=MStore.ORDER_PLACED             
14692 amit.gupta 318
                    if "dead" in str(tr) or "shippingDetails-returnOngoing" in str(tr) or "shippingDetails-return" in str(tr):
13781 amit.gupta 319
                        status = MStore.ORDER_CANCELLED    
320
                    print "Sub Order Status " + str(status)                      
321
 
322
                    trackingDetailsActive = orderTrackingDet.find("div",{"class":"c-tabs-content m-top active"})
323
                    print "Sub order tracking description " + trackingDetailsActive.text
14312 amit.gupta 324
            if self._saveToOrder(todict(merchantOrder)):
325
                resp['result'] = 'ORDER_CREATED'
326
            else:
327
                resp['result'] = 'ORDER_ALREADY_CREATED_IGNORED'
328
 
13796 amit.gupta 329
            return resp 
13781 amit.gupta 330
        except:
14338 amit.gupta 331
            traceback.print_exc()
14312 amit.gupta 332
            resp['result'] = 'ORDER_NOT_CREATED'
13796 amit.gupta 333
            return resp 
13781 amit.gupta 334
 
14617 amit.gupta 335
    def _getStatusFromDetailedStatus(self, detailedStatus):
336
        for key, value in Store.OrderStatusMap.iteritems():
14626 amit.gupta 337
            if detailedStatus.lower() in value:
14617 amit.gupta 338
                return key
14676 amit.gupta 339
        print "Detailed Status need to be mapped", detailedStatus, "Store:", self.store_name
14617 amit.gupta 340
        raise ParseException("_getStatusFromDetailedStatus", "Found new order status" + detailedStatus)
13658 manas 341
 
342
    def flipkartOrderTracking(self, orderId, subTagId, userId, rawHtml, orderSuccessUrl):
343
        br = getBrowserObject()
344
        url = ORDER_TRACK_URL + re.findall('.*(\?.*?)$', orderSuccessUrl,re.IGNORECASE)[0]
345
 
346
        response = br.open(url)
347
        page = ungzipResponse(response, br)
348
 
349
 
350
        soup = BeautifulSoup(page,convertEntities=BeautifulSoup.HTML_ENTITIES)
351
 
352
 
353
        mainOrder = soup.findAll("ul",{"class":"m-bottom p-cart"})
354
        #fetching suborders details
355
        for subOrder in mainOrder:
356
            subOrd = subOrder.findAll("li")
357
 
358
            subOrd.pop(len(subOrd)-1)
359
            for productInfo in subOrd:
360
                status=-1    
361
                #To track shipping details         
362
                n = productInfo.findAll("div",{"class":"tracking-progress grid-row cf"})
363
                for trackingStatus in n:
364
                    tr = trackingStatus.findAll("div",{"class":"tap-bullet-area c-tab-trigger"})
365
                    if "approveDetails-complete" in str(tr):
13679 manas 366
                        print "Here"
13658 manas 367
                        if "processingDetails-complete" in str(tr):
13679 manas 368
                            print "There"
13658 manas 369
                            if "shippingDetails-complete" in str(tr):
13679 manas 370
                                print "Share"
13658 manas 371
                                if "delivery-complete" in str(tr):
13679 manas 372
                                    print "Last"
13658 manas 373
                                    status = 3
374
                                else:     
375
                                    status = 2
376
                            else:
377
                                status = 1 
378
                        else: 
379
                            status = 0     
380
                    if "dead" in str(tr):
381
                        status = 4    
382
                print status                      
383
 
384
 
385
def _saveToOrderFlipkart(self, order):
386
        collection = self.db.merchantOrder
387
        order = collection.insert(order)
388
 
13690 amit.gupta 389
 
390
 
391
def hex_md5(password):
392
    m = hashlib.md5()
393
    print(m.digest())
394
 
13658 manas 395
def main():
396
 
397
    store = getStore(2)
14692 amit.gupta 398
    #store.scrapeAffiliate()
399
    store.scrapeStoreOrders()
13658 manas 400
    #store.parseOrderRawHtml(12346, "subtagId", 122324,  "html", 'https://m.flipkart.com/orderresponse?reference_id=OD3016502908102575&token=0db4c692bacbfbfc158b52358ac9e91e&src=or&pr=1')
401
    #store.parseOrderRawHtml(12346, "subtagId", 122324,  "html", 'https://m.flipkart.com/orderresponse?reference_id=OD3018701137253850&token=f7402ddcf2b63b37cc6bc528cc115d2f&src=or&pr=1')
13679 manas 402
    #store.parseOrderRawHtml(12346, "subtagId", 122324,  "html", 'https://m.flipkart.com/orderresponse?reference_id=OD0019279584515727&token=7d85d8c24d36b5a1efc8008634390c7e&src=or&pr=1')
13658 manas 403
    #store.flipkartOrderTracking(12346, "subtagId", 122324,  "html", 'https://m.flipkart.com/orderresponse?reference_id=OD0019279584515727&token=7d85d8c24d36b5a1efc8008634390c7e&src=or&pr=1')
13679 manas 404
    #store.parseOrderRawHtml(12346, "subtagId", 122324,  "html", 'https://m.flipkart.com/orderresponse?reference_id=OD0019365336126533&token=dbce2bd4dc4023295b436a7d3c7986c9&src=or&pr=1')
405
    #store.parseOrderRawHtml(12346, "subtagId", 122324,  "html", 'https://dl.flipkart.com/orderresponse?reference_id=OD1019453634552336&token=e8e04871ad65b532aa53fa82bb34b901&src=or&pr=1')
13690 amit.gupta 406
    #hex_md5('spice@2020')
14351 amit.gupta 407
    #store.getCashbackAmount('MOBDVHC6XKKPZ3GZ', 5999)
13679 manas 408
 
13690 amit.gupta 409
 
13658 manas 410
if __name__ == '__main__':
411
        main()
412
 
13690 amit.gupta 413
 
414
 
415
 
13658 manas 416
def todict(obj, classkey=None):
417
    if isinstance(obj, dict):
418
        data = {}
419
        for (k, v) in obj.items():
420
            data[k] = todict(v, classkey)
421
        return data
422
    elif hasattr(obj, "_ast"):
423
        return todict(obj._ast())
424
    elif hasattr(obj, "__iter__"):
425
        return [todict(v, classkey) for v in obj]
426
    elif hasattr(obj, "__dict__"):
427
        data = dict([(key, todict(value, classkey)) 
428
            for key, value in obj.__dict__.iteritems() 
429
            if not callable(value) and not key.startswith('_')])
430
        if classkey is not None and hasattr(obj, "__class__"):
431
            data[classkey] = obj.__class__.__name__
432
        return data
433
    else:
13690 amit.gupta 434
        return obj
435
 
14145 amit.gupta 436