Subversion Repositories SmartDukaan

Rev

Rev 13603 | Rev 13634 | 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:
228
                            merchantSubOrderId = re.findall(r'\d+', line)[0]   
13610 amit.gupta 229
                            findMap = {"orderId": order['orderId'], "subOrders.merchantSubOrderId": merchantSubOrderId}
13576 amit.gupta 230
                        elif "Status" in line:
231
                            detailedStatus = re.findall('>(.*?)</span>', line, re.IGNORECASE)[0]
232
                            detailedStatus = re.findall('>(.*?)</span>', line, re.IGNORECASE)[0]
233
                            updateMap["subOrders.$.detailedStatus"] = detailedStatus
234
                            status = self._getStatusFromDetailedStatus(detailedStatus) 
235
                            if closed:
13610 amit.gupta 236
                                closed = status in [Store.ORDER_DELIVERED, Store.ORDER_CANCELLED]
13576 amit.gupta 237
                        elif "Est. Shipping Date" in line:
238
                            estimatedShippingDate = line.split(":")[1].strip()
239
                            updateMap["subOrders.$.estimatedShippingDate"] = estimatedShippingDate
240
                        elif "Est. Delivery Date" in line:
241
                            estimatedDeliveryDate = line.split(":")[1].strip()
242
                            updateMap["subOrders.$.estimatedDeliveryDate"] = estimatedDeliveryDate
243
                        elif "Courier Name" in line:
244
                            courierName = line.split(":")[1].strip()
245
                            updateMap["subOrders.$.courierName"] = courierName
246
                        elif "Tracking No" in line:
247
                            trackingNumber = line.split(":")[1].strip()
248
                            updateMap["subOrders.$.trackingNumber"] = trackingNumber
249
 
250
                    bulk.find(findMap).update({'$set' : updateMap})
13610 amit.gupta 251
                    bulk.find({'orderId': order['orderId']}).update({'$set':{'closed': closed}})
13576 amit.gupta 252
            result = bulk.execute()
253
            pprint(result)        
254
 
13569 amit.gupta 255
    """
256
    This will insert records with changes only 
257
    """
13576 amit.gupta 258
 
259
    def _getActiveOrders(self):
260
        collection = self.db.merchantOrder
13610 amit.gupta 261
        collectionMap =  {"orderSuccessUrl":1, "orderId":1,"subOrders.merchantSubOrderId":1,"subOrders.closed":1}
262
        stores = collection.find({"closed": False, "storeId" : self.store_id}, collectionMap)
13576 amit.gupta 263
        return [store for store in stores]
264
 
265
 
266
 
13569 amit.gupta 267
    def _saveToAffiliate(self, offers):
13576 amit.gupta 268
        collection = self.db.snapdealOrderAffiliateInfo
13569 amit.gupta 269
        try:
270
            collection.insert(offers,continue_on_error=True)
271
        except pymongo.errors.DuplicateKeyError as e:
272
            print e.details
273
 
13576 amit.gupta 274
    def _saveToOrder(self, order):
275
        collection = self.db.merchantOrder
276
        try:
277
            order = collection.insert(order)
278
            #merchantOder 
279
        except Exception as e:
13603 amit.gupta 280
            traceback.print_exc()
13569 amit.gupta 281
 
282
    def _getAllOffers(self, br, token):
283
        allOffers = []
284
        nextPage = 1  
285
        while True:
286
            data = getPostData(token, nextPage)
287
            response = br.open(POST_URL, data)
288
            rmap = json.loads(ungzipResponse(response, br))
289
            if rmap is not None:
290
                rmap = rmap['response']
291
                if rmap is not None and len(rmap['errors'])==0:
292
                    allOffers += rmap['data']['data']
293
                    print allOffers
294
            nextPage += 1
295
            if rmap['data']['pageCount']<nextPage:
296
                break
297
 
298
        return allOffers
299
 
300
    def covertToObj(self,offer):
301
        offerData = offer['Stat']
302
        offer1 = AffiliateInfo(offerData['affiliate_info1'], self.store_id, offerData['conversion_status'], offerData['ad_id'], 
303
                              offerData['datetime'], offerData['payout'], offer['Offer']['name'], offerData['ip'], offerData['conversion_sale_amount'])
304
        return offer1
305
def getPostData(token, page = 1, limit= 20, startDate=None, endDate=None):
306
    endDate=datetime.date.today() + datetime.timedelta(days=1)
307
    startDate=endDate - datetime.timedelta(days=31)
308
 
309
    parameters = (
310
        ("page",str(page)),
311
        ("limit",str(limit)),
312
        ("fields[]","Stat.offer_id"),
313
        ("fields[]","Stat.datetime"),
314
        ("fields[]","Offer.name"),
315
        ("fields[]","Stat.conversion_status"),
316
        ("fields[]","Stat.conversion_sale_amount"),
317
        ("fields[]","Stat.payout"),
318
        ("fields[]","Stat.ip"),
319
        ("fields[]","Stat.ad_id"),
320
        ("fields[]","Stat.affiliate_info1"),
321
        ("sort[Stat.datetime]","desc"),
322
        ("filters[Stat.date][conditional]","BETWEEN"),
323
        ("filters[Stat.date][values][]",startDate.strftime('%Y-%m-%d')),
324
        ("filters[Stat.date][values][]",endDate.strftime('%Y-%m-%d')),
325
        ("data_start",startDate.strftime('%Y-%m-%d')),
326
        ("data_end",endDate.strftime('%Y-%m-%d')),
327
        ("Method","getConversions"),
328
        ("NetworkId","jasper"),
329
        ("SessionToken",token),
330
    )
331
    #Encode the parameters
332
    return urllib.urlencode(parameters)
333
 
334
def main():
335
    store = getStore(3)
13576 amit.gupta 336
    store.scrapeStoreOrders()
13569 amit.gupta 337
 
13576 amit.gupta 338
    #store.parseOrderRawHtml(12345, "subtagId", 122323,  "html", 'https://m.snapdeal.com/purchaseMobileComplete?code=1f4166d13ea799b65aa9dea68b3e9e70&order=4509499363')
13569 amit.gupta 339
 
340
def ungzipResponse(r,b):
341
    headers = r.info()
342
    if headers['Content-Encoding']=='gzip':
343
        import gzip
344
        print "********************"
345
        print "Deflating gzip response"
346
        print "********************"
347
        gz = gzip.GzipFile(fileobj=r, mode='rb')
348
        html = gz.read()
349
        gz.close()
350
        return html
351
 
352
if __name__ == '__main__':
353
    main()
13576 amit.gupta 354
 
355
def todict(obj, classkey=None):
356
    if isinstance(obj, dict):
357
        data = {}
358
        for (k, v) in obj.items():
359
            data[k] = todict(v, classkey)
360
        return data
361
    elif hasattr(obj, "_ast"):
362
        return todict(obj._ast())
363
    elif hasattr(obj, "__iter__"):
364
        return [todict(v, classkey) for v in obj]
365
    elif hasattr(obj, "__dict__"):
366
        data = dict([(key, todict(value, classkey)) 
367
            for key, value in obj.__dict__.iteritems() 
368
            if not callable(value) and not key.startswith('_')])
369
        if classkey is not None and hasattr(obj, "__class__"):
370
            data[classkey] = obj.__class__.__name__
371
        return data
372
    else:
373
        return obj