Subversion Repositories SmartDukaan

Rev

Rev 13721 | Rev 13730 | 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
 
13721 amit.gupta 21
USERNAME='profittill2@gmail.com'
13569 amit.gupta 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:
13721 amit.gupta 71
                self._updateOrdersPayBackStatus({'subTagId':pyOffer['subTagId'], 'saleDate':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
 
82
 
83
    def _getLastSaleDate(self,):
84
        lastDaySaleObj = self.db.lastDaySale.find_one({"storeId":self.store_id})
85
        if lastDaySaleObj is None:
86
            return datetime.min
87
 
88
 
13576 amit.gupta 89
    def parseOrderRawHtml(self, orderId, subTagId, userId, rawHtml, orderSuccessUrl):
13582 amit.gupta 90
        try:
91
            br = getBrowserObject()
92
            url = ORDER_TRACK_URL + re.findall('.*(\?.*?)$', orderSuccessUrl,re.IGNORECASE)[0]
93
            response = br.open(url)
13680 amit.gupta 94
            page = ungzipResponse(response)
13582 amit.gupta 95
            #page=page.decode("utf-8")
96
            soup = BeautifulSoup(page,convertEntities=BeautifulSoup.HTML_ENTITIES)
97
            #orderHead = soup.find(name, attrs, recursive, text)
98
            sections = soup.findAll("section")
99
 
100
            #print sections
101
 
102
            order = sections[1]
103
            orderTrs = order.findAll("tr")
104
 
105
            placedOn = str(orderTrs[0].findAll("td")[1].text)
106
 
107
            #Pop two section elements
108
            sections.pop(0) 
109
            sections.pop(0)
110
            subOrders = sections
111
 
112
 
113
            merchantSubOrders = []
114
 
115
            merchantOrder = Order(orderId, userId, subTagId, self.store_id, orderSuccessUrl)
116
            merchantOrder.merchantOderId = re.findall(r'\d+', str(soup.find("div", {"class":"deals_heading"})))[1]
117
            for orderTr in orderTrs:
118
                orderTrString = str(orderTr)
119
                if "Total Amount" in orderTrString:
120
                    merchantOrder.totalAmount = re.findall(r'\d+', orderTrString)[0]
121
                elif "Delivery Charges" in orderTrString:
122
                    merchantOrder.deliveryCharges = re.findall(r'\d+', orderTrString)[0]
123
                elif "Discount Applied" in orderTrString:
124
                    merchantOrder.discountApplied = re.findall(r'\d+', orderTrString)[0]
125
                elif "Paid Amount" in orderTrString:
126
                    merchantOrder.paidAmount = re.findall(r'\d+', orderTrString)[0]
127
 
128
            for subOrderElement in subOrders:
129
                productUrl = str(subOrderElement.find("a")['href'])
130
                subTable = subOrderElement.find("table", {"class":"lrPad"})
131
                subTrs = subTable.findAll("tr")
132
                unitPrice=None
133
                offerDiscount = None
134
                deliveryCharges = None
135
                amountPaid = None
136
                for subTr in subTrs:
137
                    subTrString = str(subTr)
138
                    if "Unit Price" in subTrString:
139
                        unitPrice = re.findall(r'\d+', subTrString)[0]
140
                    if "Quantity" in subTrString:
141
                        qty = re.findall(r'\d+', subTrString)[0]
142
                    elif "Offer Discount" in subTrString:
143
                        offerDiscount =   re.findall(r'\d+', subTrString)[0]
144
                    elif "Delivery Charges" in subTrString:
145
                        deliveryCharges =   re.findall(r'\d+', subTrString)[0]
146
                    elif "Subtotal" in subTrString:
13603 amit.gupta 147
                        if int(qty) > 0:
148
                            amountPaid =   str(int(re.findall(r'\d+', subTrString)[0])/int(qty))
149
                        else:
150
                            amountPaid =   "0"
13662 amit.gupta 151
                if self.CONF_CB_AMOUNT == MStore.CONF_CB_SELLING_PRICE or offerDiscount is None:
152
                    amount = int(unitPrice)
153
                else:
154
                    amount = int(unitPrice) - int(offerDiscount)
13582 amit.gupta 155
 
156
                divs = subOrderElement.findAll("div", {"class": "blk lrPad subordrs"})
157
                if len(divs)<=0:
158
                    raise ParseException("subOrder", "Could not Parse suborders for Snapdeal")
159
 
160
                for div in divs:
161
                    productTitle = str(subOrderElement.find("a").text)
162
                    productUrl = "http://m.snapdeal.com/" + productUrl 
163
                    subOrder = SubOrder(productTitle, productUrl, placedOn, amountPaid)
164
 
165
                    subOrder.amountPaid = amountPaid
166
                    subOrder.deliveryCharges = deliveryCharges
167
                    subOrder.offerDiscount = offerDiscount
168
                    subOrder.unitPrice = unitPrice
169
                    subOrder.productCode = re.findall(r'\d+$', productUrl)[0]
13721 amit.gupta 170
                    (cashbackAmount, percentage) = self.getCashbackAmount(subOrder.productCode, amount)
13662 amit.gupta 171
                    cashbackStatus = Store.CB_INIT
172
                    if cashbackAmount <= 0:
173
                        cashbackStatus = Store.CB_NA
13610 amit.gupta 174
                    subOrder.cashBackStatus = cashbackStatus
175
                    subOrder.cashBackAmount = cashbackAmount
13721 amit.gupta 176
                    if percentage > 0:
177
                        subOrder.cashBackPercentage = percentage
13569 amit.gupta 178
 
13610 amit.gupta 179
 
13582 amit.gupta 180
                    trackAnchor = div.find("a")   
181
                    if trackAnchor is not None:
182
                        subOrder.tracingkUrl = str(trackAnchor['href'])
183
 
184
                    divStr = str(div)
185
                    divStr = divStr.replace("\n","").replace("\t", "")
186
 
187
                    for line in divStr.split("<br />"):
188
                        if "Suborder ID" in line:
189
                            subOrder.merchantSubOrderId = re.findall(r'\d+', line)[0]   
190
                        elif "Status" in line:
191
                            subOrder.detailedStatus = re.findall('>(.*?)</span>', line, re.IGNORECASE)[0]
192
                        elif "Est. Shipping Date" in line:
193
                            subOrder.estimatedShippingDate = line.split(":")[1].strip()
194
                        elif "Est. Delivery Date" in line:
195
                            subOrder.estimatedDeliveryDate = line.split(":")[1].strip()
196
                        elif "Courier Name" in line:
197
                            subOrder.courierName = line.split(":")[1].strip()
198
                        elif "Tracking No" in line:
199
                            subOrder.trackingNumber = line.split(":")[1].strip()
200
 
201
                merchantSubOrders.append(subOrder)   
13569 amit.gupta 202
 
13582 amit.gupta 203
            merchantOrder.subOrders = merchantSubOrders
204
            #print merchantOrder
205
 
206
            self._saveToOrder(todict(merchantOrder))
207
            return True
208
        except:
209
            print "Error occurred"
13603 amit.gupta 210
            traceback.print_exc()
13569 amit.gupta 211
 
13582 amit.gupta 212
        return False
13569 amit.gupta 213
        #soup = BeautifulSoup(rawHtml,convertEntities=BeautifulSoup.HTML_ENTITIES)
214
        #soup.find(name, attrs, recursive, text)
13576 amit.gupta 215
 
216
    def _getStatusFromDetailedStatus(self, detailedStatus):
217
        for key, value in Store.OrderStatusMap.iteritems():
218
            if detailedStatus in value:
219
                return key
13662 amit.gupta 220
            print "Detailed Status need to be mapped"
13576 amit.gupta 221
        raise ParseException("_getStatusFromDetailedStatus", "Found new order status" + detailedStatus)
13569 amit.gupta 222
 
13610 amit.gupta 223
 
13569 amit.gupta 224
    def scrapeStoreOrders(self,):
13576 amit.gupta 225
        orders = self._getActiveOrders()
226
        br = getBrowserObject()
227
        for order in orders:
228
            url = ORDER_TRACK_URL + re.findall('.*(\?.*?)$', order['orderSuccessUrl'],re.IGNORECASE)[0]
229
            response = br.open(url)
13680 amit.gupta 230
            page = ungzipResponse(response)
13576 amit.gupta 231
            #page=page.decode("utf-8")
232
            soup = BeautifulSoup(page,convertEntities=BeautifulSoup.HTML_ENTITIES)
233
            sections = soup.findAll("section")
234
            sections.pop(0)
235
            sections.pop(0)
236
 
237
            subOrders = sections
238
            bulk = self.db.merchantOrder.initialize_ordered_bulk_op()
239
            for subOrderElement in subOrders:
240
                closed = True
241
                divs = subOrderElement.findAll("div", {"class": "blk lrPad subordrs"})
242
                if len(divs)<=0:
243
                    raise ParseException("subOrder", "Could not Parse suborders for Snapdeal")
13721 amit.gupta 244
                subOrder = None
13576 amit.gupta 245
                for div in divs:
246
                    divStr = str(div)
247
                    divStr = divStr.replace("\n","").replace("\t", "")
248
                    updateMap = {}
249
                    for line in divStr.split("<br />"):
250
                        if "Suborder ID" in line:
13634 amit.gupta 251
                            merchantSubOrderId = re.findall(r'\d+', line)[0]
252
                            #break if suborder is inactive   
13610 amit.gupta 253
                            findMap = {"orderId": order['orderId'], "subOrders.merchantSubOrderId": merchantSubOrderId}
13721 amit.gupta 254
                            subOrder =  self._isSubOrderActive(order, merchantSubOrderId)
255
                            if subOrder is None:
13634 amit.gupta 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:
13721 amit.gupta 266
                                    if subOrder.get("cashBackStatus") == Store.CB_PENDING:
13634 amit.gupta 267
                                        updateMap["subOrders.$.cashBackStatus"] = Store.CB_APPROVED
268
                                elif closedStatus == Store.ORDER_CANCELLED:
13721 amit.gupta 269
                                    if subOrder.get("cashBackStatus") == Store.CB_PENDING:
13634 amit.gupta 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})
13721 amit.gupta 288
                bulk.find({'orderId': order['orderId']}).update({'$set':{'closed': closed}})
13576 amit.gupta 289
            result = bulk.execute()
290
            pprint(result)        
291
 
292
 
13569 amit.gupta 293
    def _saveToAffiliate(self, offers):
13725 amit.gupta 294
        if offers is None or len(offers)==0:
295
            print "no affiliate have been pushed"
296
            return
13576 amit.gupta 297
        collection = self.db.snapdealOrderAffiliateInfo
13569 amit.gupta 298
        try:
299
            collection.insert(offers,continue_on_error=True)
300
        except pymongo.errors.DuplicateKeyError as e:
301
            print e.details
302
 
303
 
304
    def _getAllOffers(self, br, token):
305
        allOffers = []
306
        nextPage = 1  
307
        while True:
308
            data = getPostData(token, nextPage)
309
            response = br.open(POST_URL, data)
13680 amit.gupta 310
            rmap = json.loads(ungzipResponse(response))
13569 amit.gupta 311
            if rmap is not None:
312
                rmap = rmap['response']
313
                if rmap is not None and len(rmap['errors'])==0:
314
                    allOffers += rmap['data']['data']
315
            nextPage += 1
316
            if rmap['data']['pageCount']<nextPage:
317
                break
318
 
319
        return allOffers
320
 
321
    def covertToObj(self,offer):
322
        offerData = offer['Stat']
323
        offer1 = AffiliateInfo(offerData['affiliate_info1'], self.store_id, offerData['conversion_status'], offerData['ad_id'], 
324
                              offerData['datetime'], offerData['payout'], offer['Offer']['name'], offerData['ip'], offerData['conversion_sale_amount'])
13680 amit.gupta 325
 
13569 amit.gupta 326
        return offer1
327
def getPostData(token, page = 1, limit= 20, startDate=None, endDate=None):
13680 amit.gupta 328
    endDate=date.today() + timedelta(days=1)
329
    startDate=endDate - timedelta(days=31)
13569 amit.gupta 330
 
331
    parameters = (
332
        ("page",str(page)),
333
        ("limit",str(limit)),
334
        ("fields[]","Stat.offer_id"),
335
        ("fields[]","Stat.datetime"),
336
        ("fields[]","Offer.name"),
337
        ("fields[]","Stat.conversion_status"),
338
        ("fields[]","Stat.conversion_sale_amount"),
339
        ("fields[]","Stat.payout"),
340
        ("fields[]","Stat.ip"),
341
        ("fields[]","Stat.ad_id"),
342
        ("fields[]","Stat.affiliate_info1"),
343
        ("sort[Stat.datetime]","desc"),
344
        ("filters[Stat.date][conditional]","BETWEEN"),
345
        ("filters[Stat.date][values][]",startDate.strftime('%Y-%m-%d')),
346
        ("filters[Stat.date][values][]",endDate.strftime('%Y-%m-%d')),
347
        ("data_start",startDate.strftime('%Y-%m-%d')),
348
        ("data_end",endDate.strftime('%Y-%m-%d')),
349
        ("Method","getConversions"),
350
        ("NetworkId","jasper"),
351
        ("SessionToken",token),
352
    )
353
    #Encode the parameters
354
    return urllib.urlencode(parameters)
355
 
356
def main():
13634 amit.gupta 357
 
13569 amit.gupta 358
    store = getStore(3)
13662 amit.gupta 359
    #store._isSubOrderActive(8, "5970688907")
360
    store.scrapeAffiliate()
13576 amit.gupta 361
    #store.parseOrderRawHtml(12345, "subtagId", 122323,  "html", 'https://m.snapdeal.com/purchaseMobileComplete?code=1f4166d13ea799b65aa9dea68b3e9e70&order=4509499363')
13569 amit.gupta 362
 
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