Subversion Repositories SmartDukaan

Rev

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