Subversion Repositories SmartDukaan

Rev

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