Subversion Repositories SmartDukaan

Rev

Rev 13610 | Rev 13662 | 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
'''
13576 amit.gupta 6
from BeautifulSoup import BeautifulSoup
13569 amit.gupta 7
from bson.binary import Binary
8
from dtr import main
13576 amit.gupta 9
from dtr.dao import AffiliateInfo, Order, SubOrder
13569 amit.gupta 10
from dtr.main import getBrowserObject, ScrapeException, getStore, ParseException
11
from pymongo import MongoClient
12
import datetime
13
import json
14
import pymongo
15
import re
16
import urllib
13603 amit.gupta 17
import traceback
18
 
13576 amit.gupta 19
from pprint import pprint
13569 amit.gupta 20
USERNAME='saholic1@gmail.com'
21
PASSWORD='spice@2020'
22
AFFILIATE_URL='http://affiliate.snapdeal.com'
23
POST_URL='https://api-p03.hasoffers.com/v3/Affiliate_Report.json'
24
ORDER_TRACK_URL='https://m.snapdeal.com/orderSummary'
25
CONFIG_URL='http://affiliate.snapdeal.com/publisher/js/config.php'
26
 
27
 
28
class Store(main.Store):
29
 
30
    '''
31
    This is to map order statuses of our system to order statuses of snapdeal.
32
    And our statuses will change accordingly.
33
 
34
    '''
35
    OrderStatusMap = {
36
                      main.Store.ORDER_PLACED : ['In Progress','N/A'],
37
                      main.Store.ORDER_DELIVERED : ['Delivered'],
38
                      main.Store.ORDER_SHIPPED : ['In Transit'],
39
                      main.Store.ORDER_CANCELLED : ['Closed For Vendor Reallocation']
40
 
41
                      }
42
    def __init__(self,store_id):
13576 amit.gupta 43
        client = MongoClient('mongodb://localhost:27017/')
13582 amit.gupta 44
        self.db = client.Dtr
13569 amit.gupta 45
        super(Store, self).__init__(store_id)
46
 
47
    def getName(self):
48
        return "snapdeal"
49
 
50
    def scrapeAffiliate(self, startDate=None, endDate=None):
51
        br = getBrowserObject()
52
        br.open(AFFILIATE_URL)
53
        br.select_form(nr=0)
54
        br.form['data[User][password]'] = PASSWORD 
55
        br.form['data[User][email]'] = USERNAME
56
        br.submit()
57
        response = br.open(CONFIG_URL)
58
 
59
        token =  re.findall('"session_token":"(.*?)"', ungzipResponse(response, br), re.IGNORECASE)[0]
60
 
61
        allOffers = self._getAllOffers(br, token)
62
 
63
        allPyOffers = [self.covertToObj(offer).__dict__ for offer in allOffers]
64
        self._saveToAffiliate(allPyOffers)
65
 
66
 
13576 amit.gupta 67
    def parseOrderRawHtml(self, orderId, subTagId, userId, rawHtml, orderSuccessUrl):
13582 amit.gupta 68
        try:
69
            br = getBrowserObject()
70
            url = ORDER_TRACK_URL + re.findall('.*(\?.*?)$', orderSuccessUrl,re.IGNORECASE)[0]
71
            response = br.open(url)
72
            page = ungzipResponse(response, br)
73
            #page=page.decode("utf-8")
74
            soup = BeautifulSoup(page,convertEntities=BeautifulSoup.HTML_ENTITIES)
75
            #orderHead = soup.find(name, attrs, recursive, text)
76
            sections = soup.findAll("section")
77
 
78
            #print sections
79
 
80
            order = sections[1]
81
            orderTrs = order.findAll("tr")
82
 
83
            placedOn = str(orderTrs[0].findAll("td")[1].text)
84
 
85
            #Pop two section elements
86
            sections.pop(0) 
87
            sections.pop(0)
88
            subOrders = sections
89
 
90
 
91
            merchantSubOrders = []
92
 
93
            merchantOrder = Order(orderId, userId, subTagId, self.store_id, orderSuccessUrl)
94
            merchantOrder.merchantOderId = re.findall(r'\d+', str(soup.find("div", {"class":"deals_heading"})))[1]
95
            for orderTr in orderTrs:
96
                orderTrString = str(orderTr)
97
                if "Total Amount" in orderTrString:
98
                    merchantOrder.totalAmount = re.findall(r'\d+', orderTrString)[0]
99
                elif "Delivery Charges" in orderTrString:
100
                    merchantOrder.deliveryCharges = re.findall(r'\d+', orderTrString)[0]
101
                elif "Discount Applied" in orderTrString:
102
                    merchantOrder.discountApplied = re.findall(r'\d+', orderTrString)[0]
103
                elif "Paid Amount" in orderTrString:
104
                    merchantOrder.paidAmount = re.findall(r'\d+', orderTrString)[0]
105
 
106
            for subOrderElement in subOrders:
107
                productUrl = str(subOrderElement.find("a")['href'])
108
                subTable = subOrderElement.find("table", {"class":"lrPad"})
109
                subTrs = subTable.findAll("tr")
110
                unitPrice=None
111
                offerDiscount = None
112
                deliveryCharges = None
113
                amountPaid = None
114
                for subTr in subTrs:
115
                    subTrString = str(subTr)
116
                    if "Unit Price" in subTrString:
117
                        unitPrice = re.findall(r'\d+', subTrString)[0]
118
                    if "Quantity" in subTrString:
119
                        qty = re.findall(r'\d+', subTrString)[0]
120
                    elif "Offer Discount" in subTrString:
121
                        offerDiscount =   re.findall(r'\d+', subTrString)[0]
122
                    elif "Delivery Charges" in subTrString:
123
                        deliveryCharges =   re.findall(r'\d+', subTrString)[0]
124
                    elif "Subtotal" in subTrString:
13603 amit.gupta 125
                        if int(qty) > 0:
126
                            amountPaid =   str(int(re.findall(r'\d+', subTrString)[0])/int(qty))
127
                        else:
128
                            amountPaid =   "0"
13610 amit.gupta 129
 
130
                #TODO: cashbackAmount = getCashbackAmount()
131
                cashbackAmount = 0
132
                cashbackStatus = Store.CB_PENDING
133
                if cashbackAmount <= 0:
134
                    cashbackStatus = Store.CB_NA
13582 amit.gupta 135
 
136
                divs = subOrderElement.findAll("div", {"class": "blk lrPad subordrs"})
137
                if len(divs)<=0:
138
                    raise ParseException("subOrder", "Could not Parse suborders for Snapdeal")
139
 
140
                for div in divs:
141
                    productTitle = str(subOrderElement.find("a").text)
142
                    productUrl = "http://m.snapdeal.com/" + productUrl 
143
                    subOrder = SubOrder(productTitle, productUrl, placedOn, amountPaid)
144
 
145
                    subOrder.amountPaid = amountPaid
146
                    subOrder.deliveryCharges = deliveryCharges
147
                    subOrder.offerDiscount = offerDiscount
148
                    subOrder.unitPrice = unitPrice
149
                    subOrder.productCode = re.findall(r'\d+$', productUrl)[0]
13610 amit.gupta 150
                    subOrder.cashBackStatus = cashbackStatus
151
                    subOrder.cashBackAmount = cashbackAmount
13569 amit.gupta 152
 
13610 amit.gupta 153
 
13582 amit.gupta 154
                    trackAnchor = div.find("a")   
155
                    if trackAnchor is not None:
156
                        subOrder.tracingkUrl = str(trackAnchor['href'])
157
 
158
                    divStr = str(div)
159
                    divStr = divStr.replace("\n","").replace("\t", "")
160
 
161
                    for line in divStr.split("<br />"):
162
                        if "Suborder ID" in line:
163
                            subOrder.merchantSubOrderId = re.findall(r'\d+', line)[0]   
164
                        elif "Status" in line:
165
                            subOrder.detailedStatus = re.findall('>(.*?)</span>', line, re.IGNORECASE)[0]
166
                        elif "Est. Shipping Date" in line:
167
                            subOrder.estimatedShippingDate = line.split(":")[1].strip()
168
                        elif "Est. Delivery Date" in line:
169
                            subOrder.estimatedDeliveryDate = line.split(":")[1].strip()
170
                        elif "Courier Name" in line:
171
                            subOrder.courierName = line.split(":")[1].strip()
172
                        elif "Tracking No" in line:
173
                            subOrder.trackingNumber = line.split(":")[1].strip()
174
 
175
                merchantSubOrders.append(subOrder)   
13569 amit.gupta 176
 
13582 amit.gupta 177
            merchantOrder.subOrders = merchantSubOrders
178
            #print merchantOrder
179
 
180
            self._saveToOrder(todict(merchantOrder))
181
            return True
182
        except:
183
            print "Error occurred"
13603 amit.gupta 184
            traceback.print_exc()
13569 amit.gupta 185
 
13582 amit.gupta 186
        return False
13569 amit.gupta 187
        #soup = BeautifulSoup(rawHtml,convertEntities=BeautifulSoup.HTML_ENTITIES)
188
        #soup.find(name, attrs, recursive, text)
189
 
13576 amit.gupta 190
 
191
 
192
    def _getStatusFromDetailedStatus(self, detailedStatus):
193
        for key, value in Store.OrderStatusMap.iteritems():
194
            if detailedStatus in value:
195
                return key
196
        raise ParseException("_getStatusFromDetailedStatus", "Found new order status" + detailedStatus)
13569 amit.gupta 197
 
13610 amit.gupta 198
    def settlePayBack(self):
199
        pass
200
 
13569 amit.gupta 201
    def scrapeStoreOrders(self,):
13576 amit.gupta 202
        orders = self._getActiveOrders()
203
        br = getBrowserObject()
204
        for order in orders:
205
            url = ORDER_TRACK_URL + re.findall('.*(\?.*?)$', order['orderSuccessUrl'],re.IGNORECASE)[0]
206
            response = br.open(url)
207
            page = ungzipResponse(response, br)
208
            #page=page.decode("utf-8")
209
            soup = BeautifulSoup(page,convertEntities=BeautifulSoup.HTML_ENTITIES)
210
            sections = soup.findAll("section")
211
            sections.pop(0)
212
            sections.pop(0)
213
 
214
            subOrders = sections
215
            bulk = self.db.merchantOrder.initialize_ordered_bulk_op()
216
            for subOrderElement in subOrders:
217
                closed = True
218
                divs = subOrderElement.findAll("div", {"class": "blk lrPad subordrs"})
219
                if len(divs)<=0:
220
                    raise ParseException("subOrder", "Could not Parse suborders for Snapdeal")
221
 
222
                for div in divs:
223
                    divStr = str(div)
224
                    divStr = divStr.replace("\n","").replace("\t", "")
225
                    updateMap = {}
226
                    for line in divStr.split("<br />"):
227
                        if "Suborder ID" in line:
13634 amit.gupta 228
                            merchantSubOrderId = re.findall(r'\d+', line)[0]
229
                            #break if suborder is inactive   
13610 amit.gupta 230
                            findMap = {"orderId": order['orderId'], "subOrders.merchantSubOrderId": merchantSubOrderId}
13634 amit.gupta 231
                            if not self._isSubOrderActive(order, merchantSubOrderId):
232
                                break
13576 amit.gupta 233
                        elif "Status" in line:
234
                            detailedStatus = re.findall('>(.*?)</span>', line, re.IGNORECASE)[0]
235
                            detailedStatus = re.findall('>(.*?)</span>', line, re.IGNORECASE)[0]
236
                            updateMap["subOrders.$.detailedStatus"] = detailedStatus
237
                            status = self._getStatusFromDetailedStatus(detailedStatus) 
13634 amit.gupta 238
                            closedStatus = status in [Store.ORDER_DELIVERED, Store.ORDER_CANCELLED]
239
                            if closedStatus:
240
                                #if status is closed then change the paybackStatus accordingly
241
                                if closedStatus == Store.ORDER_DELIVERED:
242
                                    if order.get("cashBackStatus") == Store.CB_PENDING:
243
                                        updateMap["subOrders.$.cashBackStatus"] = Store.CB_APPROVED
244
                                elif closedStatus == Store.ORDER_CANCELLED:
245
                                    if order.get("cashBackStatus") == Store.CB_PENDING:
246
                                        updateMap["subOrders.$.cashBackStatus"] = Store.CB_CANCELLED
247
 
248
                            else:
249
                                closed = False
13576 amit.gupta 250
                        elif "Est. Shipping Date" in line:
251
                            estimatedShippingDate = line.split(":")[1].strip()
252
                            updateMap["subOrders.$.estimatedShippingDate"] = estimatedShippingDate
253
                        elif "Est. Delivery Date" in line:
254
                            estimatedDeliveryDate = line.split(":")[1].strip()
255
                            updateMap["subOrders.$.estimatedDeliveryDate"] = estimatedDeliveryDate
256
                        elif "Courier Name" in line:
257
                            courierName = line.split(":")[1].strip()
258
                            updateMap["subOrders.$.courierName"] = courierName
259
                        elif "Tracking No" in line:
260
                            trackingNumber = line.split(":")[1].strip()
261
                            updateMap["subOrders.$.trackingNumber"] = trackingNumber
262
 
263
                    bulk.find(findMap).update({'$set' : updateMap})
13610 amit.gupta 264
                    bulk.find({'orderId': order['orderId']}).update({'$set':{'closed': closed}})
13576 amit.gupta 265
            result = bulk.execute()
266
            pprint(result)        
267
 
268
 
13634 amit.gupta 269
    def _isSubOrderActive(self,order, merchantSubOrderId):
270
        subOrders = order.get("subOrders")
271
        for subOrder in subOrders:
272
            if merchantSubOrderId == subOrder.get("merchantSubOrderId"):
273
                return True
274
        return False
275
 
13576 amit.gupta 276
 
277
 
13569 amit.gupta 278
    def _saveToAffiliate(self, offers):
13576 amit.gupta 279
        collection = self.db.snapdealOrderAffiliateInfo
13569 amit.gupta 280
        try:
281
            collection.insert(offers,continue_on_error=True)
282
        except pymongo.errors.DuplicateKeyError as e:
283
            print e.details
284
 
13576 amit.gupta 285
    def _saveToOrder(self, order):
286
        collection = self.db.merchantOrder
287
        try:
288
            order = collection.insert(order)
289
            #merchantOder 
290
        except Exception as e:
13603 amit.gupta 291
            traceback.print_exc()
13569 amit.gupta 292
 
293
    def _getAllOffers(self, br, token):
294
        allOffers = []
295
        nextPage = 1  
296
        while True:
297
            data = getPostData(token, nextPage)
298
            response = br.open(POST_URL, data)
299
            rmap = json.loads(ungzipResponse(response, br))
300
            if rmap is not None:
301
                rmap = rmap['response']
302
                if rmap is not None and len(rmap['errors'])==0:
303
                    allOffers += rmap['data']['data']
304
                    print allOffers
305
            nextPage += 1
306
            if rmap['data']['pageCount']<nextPage:
307
                break
308
 
309
        return allOffers
310
 
311
    def covertToObj(self,offer):
312
        offerData = offer['Stat']
313
        offer1 = AffiliateInfo(offerData['affiliate_info1'], self.store_id, offerData['conversion_status'], offerData['ad_id'], 
314
                              offerData['datetime'], offerData['payout'], offer['Offer']['name'], offerData['ip'], offerData['conversion_sale_amount'])
315
        return offer1
316
def getPostData(token, page = 1, limit= 20, startDate=None, endDate=None):
317
    endDate=datetime.date.today() + datetime.timedelta(days=1)
318
    startDate=endDate - datetime.timedelta(days=31)
319
 
320
    parameters = (
321
        ("page",str(page)),
322
        ("limit",str(limit)),
323
        ("fields[]","Stat.offer_id"),
324
        ("fields[]","Stat.datetime"),
325
        ("fields[]","Offer.name"),
326
        ("fields[]","Stat.conversion_status"),
327
        ("fields[]","Stat.conversion_sale_amount"),
328
        ("fields[]","Stat.payout"),
329
        ("fields[]","Stat.ip"),
330
        ("fields[]","Stat.ad_id"),
331
        ("fields[]","Stat.affiliate_info1"),
332
        ("sort[Stat.datetime]","desc"),
333
        ("filters[Stat.date][conditional]","BETWEEN"),
334
        ("filters[Stat.date][values][]",startDate.strftime('%Y-%m-%d')),
335
        ("filters[Stat.date][values][]",endDate.strftime('%Y-%m-%d')),
336
        ("data_start",startDate.strftime('%Y-%m-%d')),
337
        ("data_end",endDate.strftime('%Y-%m-%d')),
338
        ("Method","getConversions"),
339
        ("NetworkId","jasper"),
340
        ("SessionToken",token),
341
    )
342
    #Encode the parameters
343
    return urllib.urlencode(parameters)
344
 
345
def main():
13634 amit.gupta 346
 
13569 amit.gupta 347
    store = getStore(3)
13634 amit.gupta 348
    store._isSubOrderActive(8, "5970688907")
13569 amit.gupta 349
 
13576 amit.gupta 350
    #store.parseOrderRawHtml(12345, "subtagId", 122323,  "html", 'https://m.snapdeal.com/purchaseMobileComplete?code=1f4166d13ea799b65aa9dea68b3e9e70&order=4509499363')
13569 amit.gupta 351
 
352
def ungzipResponse(r,b):
353
    headers = r.info()
354
    if headers['Content-Encoding']=='gzip':
355
        import gzip
356
        print "********************"
357
        print "Deflating gzip response"
358
        print "********************"
359
        gz = gzip.GzipFile(fileobj=r, mode='rb')
360
        html = gz.read()
361
        gz.close()
362
        return html
363
 
364
if __name__ == '__main__':
365
    main()
13576 amit.gupta 366
 
367
def todict(obj, classkey=None):
368
    if isinstance(obj, dict):
369
        data = {}
370
        for (k, v) in obj.items():
371
            data[k] = todict(v, classkey)
372
        return data
373
    elif hasattr(obj, "_ast"):
374
        return todict(obj._ast())
375
    elif hasattr(obj, "__iter__"):
376
        return [todict(v, classkey) for v in obj]
377
    elif hasattr(obj, "__dict__"):
378
        data = dict([(key, todict(value, classkey)) 
379
            for key, value in obj.__dict__.iteritems() 
380
            if not callable(value) and not key.startswith('_')])
381
        if classkey is not None and hasattr(obj, "__class__"):
382
            data[classkey] = obj.__class__.__name__
383
        return data
384
    else:
385
        return obj