Subversion Repositories SmartDukaan

Rev

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