Subversion Repositories SmartDukaan

Rev

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