Subversion Repositories SmartDukaan

Rev

Rev 18085 | Rev 18687 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
14220 amit.gupta 1
'''
2
Created on Jan 15, 2015
3
 
4
@author: amit
5
'''
6
from BeautifulSoup import BeautifulSoup
7
from bson.binary import Binary
8
from datetime import datetime, date, timedelta
9
from dtr import main
10
from dtr.config import PythonPropertyReader
11
from dtr.dao import AffiliateInfo, Order, SubOrder
12
from dtr.main import getBrowserObject, ScrapeException, getStore, ParseException, \
13
    Store as MStore, ungzipResponse, tprint
14
from pprint import pprint
15
from pymongo import MongoClient
16
import json
17
import pymongo
18
import re
19
import traceback
20
import urllib
21
import urllib2
16189 amit.gupta 22
from dtr.storage.Mongo import getDealRank
14220 amit.gupta 23
 
14222 amit.gupta 24
ORDERSTATUS  = {"PAYMENT_PENDING" : 0,
25
"PAYMENT_FAILED" : 1,
26
"COD_VERIFICATION_PENDING" : 2,
27
"SUBMITTED_FOR_PROCESSING" : 3,
28
"ACCEPTED" : 4,
29
"INVENTORY_LOW" : 5,
30
"REJECTED" : 6,
31
"BILLED" : 7,
32
"PAYMENT_FLAGGED" : 8,
33
"SHIPPED_FROM_WH" : 9,
34
"SHIPPED_TO_LOGST" : 10,
35
"PAYMENT_FLAGGED_DENIED" : 11,
36
"DELIVERY_SUCCESS" : 12,
37
"CANCEL_REQUEST_RECEIVED" : 13,
38
"CANCEL_REQUEST_CONFIRMED" : 14,
39
"CANCELLED_ON_CUSTOMER_REQUEST" : 15,
40
"SHIPPED_TO_DESTINATION_CITY" : 16,
41
"REACHED_DESTINATION_CITY" : 17,
42
"COD_VERIFICATION_FAILED" : 18,
43
"FAILED" : 19,
44
"RTO_IN_TRANSIT" : 20,
45
"RTO_RECEIVED_PRESTINE" : 21,
46
"DOA_PICKUP_REQUEST_RAISED" : 22,
47
"DOA_PICKUP_CONFIRMED" : 23,
48
"DOA_RETURN_IN_TRANSIT" : 24,
49
"DOA_RECEIVED_PRESTINE" : 25,
50
"DOA_CERT_INVALID" : 26,
51
"DOA_CERT_VALID" : 27,
52
"RTO_RESHIPPED" : 28,
53
"DOA_INVALID_RESHIPPED" : 29,
54
"DOA_VALID_RESHIPPED" : 30,
55
"RTO_REFUNDED" : 31,
56
"DOA_VALID_REFUNDED" : 32,
57
"DOA_INVALID_REFUNDED" : 33,
58
"CANCELLED_DUE_TO_LOW_INVENTORY" : 34,
59
"LOW_INV_PO_RAISED" : 35,
60
"LOW_INV_REVERSAL_IN_PROCESS" : 36,
61
"LOW_INV_NOT_AVAILABLE_AT_HOTSPOT" : 37,
62
"LOW_INV_PO_RAISED_TIMEOUT" : 38,
63
"LOW_INV_REVERSAL_TIMEOUT" : 39,
64
"FIRST_DELIVERY_ATTEMPT_MADE" : 40,
65
"CAPTURE_IN_PROCESS" : 41,
66
"DOA_REQUEST_RECEIVED" : 42,
67
"DOA_REQUEST_AUTHORIZED" : 43,
68
"DOA_PICKUP_DENIED" : 44,
69
"DOA_RECEIVED_DAMAGED" : 45,
70
"DOA_LOST_IN_TRANSIT" : 46,
71
"DOA_RESHIPPED_RCVD_DAMAGED" : 47,
72
"DOA_REFUNDED_RCVD_DAMAGED" : 48,
73
"DOA_RESHIPPED_LOST_IN_TRANSIT" : 49,
74
"DOA_REFUNDED_LOST_IN_TRANSIT" : 50,
75
"RTO_RECEIVED_DAMAGED" : 51,
76
"RTO_LOST_IN_TRANSIT" : 52,
77
"RTO_DAMAGED_RESHIPPED" : 53,
78
"RTO_DAMAGED_REFUNDED" : 54,
79
"RTO_LOST_IN_TRANSIT_RESHIPPED" : 55,
80
"RTO_LOST_IN_TRANSIT_REFUNDED" : 56,
81
"RTO_INVENTORY_REVERSED" : 57,
82
"RET_REQUEST_RECEIVED" : 58,
83
"RET_REQUEST_AUTHORIZED" : 59,
84
"RET_PICKUP_REQUEST_RAISED" : 60,
85
"RET_PICKUP_DENIED" : 61,
86
"RET_PICKUP_CONFIRMED" : 62,
87
"RET_RETURN_IN_TRANSIT" : 63,
88
"RET_RECEIVED_PRESTINE" : 64,
89
"RET_RECEIVED_DAMAGED" : 65,
90
"RET_LOST_IN_TRANSIT" : 66,
91
"RET_PRODUCT_USABLE" : 67,
92
"RET_PRODUCT_UNUSABLE" : 68,
93
"RET_PRODUCT_USABLE_RESHIPPED" : 69,
94
"RET_PRODUCT_USABLE_REFUNDED" : 70,
95
"RET_PRODUCT_UNUSABLE_RESHIPPED" : 71,
96
"RET_PRODUCT_UNUSABLE_REFUNDED" : 72,
97
"RET_RESHIPPED_RCVD_DAMAGED" : 73,
98
"RET_REFUNDED_RCVD_DAMAGED" : 74,
99
"RET_RESHIPPED_LOST_IN_TRANSIT" : 75,
100
"RET_REFUNDED_LOST_IN_TRANSIT" : 76,
101
"LOST_IN_TRANSIT" : 77,
102
"LOST_IN_TRANSIT_RESHIPPED" : 78,
103
"LOST_IN_TRANSIT_REFUNDED" : 79,
104
"DELIVERED_AT_STORE" : 80,
105
"RECEIVED_AT_STORE" : 81}
14220 amit.gupta 106
headers = { 
107
           'User-agent':'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11',
108
            'Accept' : 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',      
109
            'Accept-Language' : 'en-US,en;q=0.8',                     
110
            'Accept-Charset' : 'ISO-8859-1,utf-8;q=0.7,*;q=0.3'
111
        }
112
SAHOLIC_ORDER_URL=PythonPropertyReader.getConfig('SAHOLIC_ORDER_URL')
14246 amit.gupta 113
SAHOLIC_ORDER_URL_TR=PythonPropertyReader.getConfig('SAHOLIC_ORDER_URL_TR')
14220 amit.gupta 114
class Store(MStore):
115
    '''
116
    This is to map order statuses of our system to order statuses of snapdeal.
117
    And our statuses will change accordingly.
118
 
119
    '''
120
    OrderStatusMap = {
121
                      MStore.ORDER_PLACED : [2,3,4,5,6,7,8,13],
122
                      MStore.ORDER_DELIVERED : [12],
123
                      MStore.ORDER_SHIPPED : [9,10,16,17,20,21,81,80],
16967 amit.gupta 124
                      MStore.ORDER_CANCELLED : [1,6,11,14,15,18,19,31,34,28,53,54,55,56,20,21,77,79]
14220 amit.gupta 125
                      }
126
 
127
 
128
    def parseOrderRawHtml(self, orderId, subTagId, userId, rawHtml, orderSuccessUrl):
14227 amit.gupta 129
        resp = {}
14237 amit.gupta 130
        paymentId = int(re.findall(r'=(.*)?',orderSuccessUrl)[0])
14220 amit.gupta 131
        orderRequest = urllib2.Request(SAHOLIC_ORDER_URL %(paymentId), headers=headers)
132
        try:
16189 amit.gupta 133
            self.userId = userId
14832 amit.gupta 134
            connection = urllib2.urlopen(orderRequest)
135
            response = connection.read()
136
            connection.close()
14220 amit.gupta 137
            response = json.loads(response)['response']
138
            payment = response['payment']
14246 amit.gupta 139
            subOrders = []
14220 amit.gupta 140
            orders = response['orders']
14228 amit.gupta 141
            items = response['itemsMap']
14220 amit.gupta 142
            merchantOrder = Order(orderId, userId, subTagId, self.store_id, orderSuccessUrl)
143
            merchantOrder.merchantOrderId = payment['merchantTxnId']
144
            merchantOrder.paidAmount = payment['amount']
14246 amit.gupta 145
 
14220 amit.gupta 146
            for o in orders:
14246 amit.gupta 147
                subOrders.append(self.createSubOrder(o, items))
14247 amit.gupta 148
            merchantOrder.subOrders = subOrders
14266 amit.gupta 149
            merchantOrder.placedOn = merchantOrder.subOrders[0].placedOn
14246 amit.gupta 150
            s = todict(merchantOrder)
151
            s['sUserId'] = orders[0]['customer_id']
14267 amit.gupta 152
            if self._saveToOrder(s):
153
                resp['result'] = 'ORDER_CREATED'
154
            else:
155
                #Order already created
14312 amit.gupta 156
                resp['result'] = 'ORDER_ALREADY_CREATED_IGNORED'
14220 amit.gupta 157
        except:
14227 amit.gupta 158
            traceback.print_exc()
14312 amit.gupta 159
            resp['result'] = 'ORDER_NOT_CREATED'
14227 amit.gupta 160
        return resp
14246 amit.gupta 161
 
162
    def createSubOrder(self, order, items):
163
            lineitem = order['lineitems'][0]
164
 
165
            item = items[str(lineitem['item_id'])]
166
            brand = lineitem.get('brand')
167
            modelNumber = lineitem.get('model_number')
168
            modelName = lineitem.get('model_name')
169
            color = lineitem.get('color')
170
            productTitle = brand + (" " + modelName if modelName else "") + (" "  + modelNumber if modelNumber is not None else "") + ("(" + color +")" if color else "")
18055 amit.gupta 171
            amountPaid = order['total_amount'] 
14246 amit.gupta 172
            subOrder = SubOrder(productTitle, None, datetime.strftime(datetime.fromtimestamp(order['created_timestamp']/1000),"%d %B %Y"), amountPaid)
18055 amit.gupta 173
            subOrder.amount = amountPaid - order['gvAmount']
14246 amit.gupta 174
            subOrder.merchantSubOrderId = str(order['id'])
175
            subOrder.orderDetailUrl = "http://m.saholic.com/order/" + subOrder.merchantSubOrderId 
17677 amit.gupta 176
            subOrder.quantity = int(lineitem['quantity'])
14246 amit.gupta 177
            subOrder.estimatedDeliveryDate = datetime.strftime(datetime.fromtimestamp(order['promised_delivery_time']/1000),"%d %B %Y")
18055 amit.gupta 178
            subOrder.imgUrl = item.get("imgUrl") 
14246 amit.gupta 179
            subOrder.productUrl = "http://m.saholic.com/" + item['url']
14301 amit.gupta 180
            subOrder.productCode = item['url'].split('-')[-1]
14246 amit.gupta 181
            subOrder.detailedStatus = order['statusDescription']
17677 amit.gupta 182
            (cashbackAmount, percentage) = self.getCashbackAmount(subOrder.productCode, amountPaid/subOrder.quantity)
16189 amit.gupta 183
            dealRank = getDealRank(subOrder.productCode, self.store_id, self.userId)
184
            subOrder.dealRank = dealRank.get('rank')
185
            subOrder.rankDesc = dealRank.get('description')
16283 amit.gupta 186
            subOrder.maxNlc = dealRank.get('maxNlc')
187
            subOrder.minNlc = dealRank.get('minNlc')
188
            subOrder.db = dealRank.get('dp')
189
            subOrder.itemStatus = dealRank.get('status')
14246 amit.gupta 190
            cashbackStatus = Store.CB_PENDING
191
            if cashbackAmount <= 0:
192
                cashbackStatus = Store.CB_NA
193
            subOrder.cashBackStatus = cashbackStatus
17677 amit.gupta 194
            subOrder.cashBackAmount = cashbackAmount*subOrder.quantity
14246 amit.gupta 195
            if percentage > 0:
196
                subOrder.cashBackPercentage = percentage
197
            return subOrder
14220 amit.gupta 198
    def _getStatusFromDetailedStatus(self, detailedStatus):
199
        for key, value in Store.OrderStatusMap.iteritems():
200
            if detailedStatus in value:
201
                return key
14349 amit.gupta 202
        print "Detailed Status need to be mapped", detailedStatus
16189 amit.gupta 203
        raise ParseException("_getStatusFromDetailedStatus", "Found new order status" + str(detailedStatus))
14220 amit.gupta 204
 
205
 
206
    def scrapeStoreOrders(self,):
18085 amit.gupta 207
        trs = self._getActiveOrders(collectionMap={'merchantOrderId':1, 'sUserId':1, 'userId':1})
14267 amit.gupta 208
        bulk = self.db.merchantOrder.initialize_ordered_bulk_op()
14246 amit.gupta 209
        for tr in trs:
18085 amit.gupta 210
            self.userId = tr['userId']
14246 amit.gupta 211
            try:
212
                orderRequest = urllib2.Request(SAHOLIC_ORDER_URL_TR %(tr['merchantOrderId'], tr['sUserId']), headers=headers)
213
                response = urllib2.urlopen(orderRequest).read()
14275 amit.gupta 214
                print response
14246 amit.gupta 215
                response = json.loads(response)['response']
216
                items = response['itemsMap']
217
                orders = response['orders']
218
                closed = True
18254 amit.gupta 219
                splitSubOrdersMap={}
220
                ordersToClone = {}
14246 amit.gupta 221
                for order in orders:
14272 amit.gupta 222
                    print "orderid---", order['id']
14269 amit.gupta 223
                    orderId = str(order['id'])
224
                    subOrder = self._isSubOrderActive(tr, orderId)
18254 amit.gupta 225
                    currentQty = int(order['lineitems'][0]['quantity'])
14246 amit.gupta 226
                    if subOrder:
227
                        if subOrder['closed']:
228
                            continue
229
                        else:
18254 amit.gupta 230
                            quantity = int(subOrder['quantity'])
14270 amit.gupta 231
                            findMap = {"orderId": tr['orderId'], "subOrders.merchantSubOrderId": orderId}
14246 amit.gupta 232
                            updateMap = {}
233
                            updateMap["subOrders.$.detailedStatus"] = order['statusDescription']
234
                            status = self._getStatusFromDetailedStatus(ORDERSTATUS[order['status']]) 
235
                            closedStatus = status in [Store.ORDER_DELIVERED, Store.ORDER_CANCELLED]
14271 amit.gupta 236
                            print "status---", status, order['status']
14246 amit.gupta 237
                            updateMap["subOrders.$.status"] = status
18254 amit.gupta 238
                            #Check if split
239
                            if quantity != currentQty:
240
                                updateMap["subOrders.$.quantity"] = currentQty
241
                                updateMap["subOrders.$.amount"] = int((subOrder['amount']*currentQty)/quantity)
242
                                updateMap["subOrders.$.cashBackAmount"] = int((subOrder['cashBackAmount']*currentQty)/quantity)
243
                                updateMap["subOrders.$.amountPaid"] = int((subOrder['amountPaid']*currentQty)/quantity)
244
                                splitSubOrdersMap[order['id']]=subOrder
14246 amit.gupta 245
                            if closedStatus:
246
                                #if status is closed then change the paybackStatus accordingly
247
                                updateMap["subOrders.$.closed"] = True
248
                                if status == Store.ORDER_DELIVERED:
249
                                    deliveredOn = datetime.strftime(datetime.fromtimestamp(order['delivery_timestamp']/1000),"%A %d %B %Y")
250
                                    updateMap['subOrders.$.deliveredOn'] = deliveredOn
251
                                    if subOrder.get("cashBackStatus") == Store.CB_PENDING:
252
                                        updateMap["subOrders.$.cashBackStatus"] = Store.CB_APPROVED
253
                                elif status == Store.ORDER_CANCELLED:
254
                                    if subOrder.get("cashBackStatus") == Store.CB_PENDING:
255
                                        updateMap["subOrders.$.cashBackStatus"] = Store.CB_CANCELLED
256
                            else:
257
                                expectedDelivery = datetime.strftime(datetime.fromtimestamp(order['promised_delivery_time']/1000),"%A %d %B %Y")
258
                                updateMap["subOrders.$.estimatedDeliveryDate"] = expectedDelivery
259
                                closed = False
260
                            bulk.find(findMap).update({'$set' : updateMap})
261
                    else:
18254 amit.gupta 262
                        if order['originalOrderId']:
263
                            ordersToClone[order['id']] = order
264
                        else:
265
                            subOrder = self.createSubOrder(order, items)
266
                            self.db.merchantOrder.update({"orderId":tr['orderId']},{'$push':{"subOrders":todict(subOrder)}})
267
                            print "Added new suborder with subOrder Id:", subOrder.merchantSubOrderId
268
                            closed = False
269
 
270
                for order in ordersToClone.values():
271
                    originalOrderId = self.getOriginalOrderId(order['id'], ordersToClone, splitSubOrdersMap)
272
                    subOrderToClone = splitSubOrdersMap[originalOrderId].copy()
273
                    subOrderToClone["merchantSubOrderId"] = order['id']
274
                    currentQty = int(order['lineitems'][0]['quantity'])
275
                    quantity = int(subOrderToClone['quantity'])
276
                    subOrderToClone["detailedStatus"] = order['statusDescription']
277
                    status = self._getStatusFromDetailedStatus(ORDERSTATUS[order['status']]) 
278
                    closedStatus = status in [Store.ORDER_DELIVERED, Store.ORDER_CANCELLED]
279
                    print "status---", status, order['status']
280
                    subOrderToClone["status"] = status
281
                    subOrderToClone["quantity"] = currentQty
282
                    subOrderToClone["amount"] = int((subOrderToClone['amount']*currentQty)/quantity)
283
                    subOrderToClone["cashBackAmount"] = int((subOrderToClone['cashBackAmount']*currentQty)/quantity)
284
                    subOrderToClone["amountPaid"] = int((subOrderToClone['amountPaid']*currentQty)/quantity)
285
                    if closedStatus:
286
                        #if status is closed then change the paybackStatus accordingly
287
                        subOrderToClone["closed"] = True
288
                        if status == Store.ORDER_DELIVERED:
289
                            deliveredOn = datetime.strftime(datetime.fromtimestamp(order['delivery_timestamp']/1000),"%A %d %B %Y")
290
                            subOrderToClone['deliveredOn'] = deliveredOn
291
                            if subOrderToClone.get("cashBackStatus") == Store.CB_PENDING:
292
                                subOrderToClone["cashBackStatus"] = Store.CB_APPROVED
293
                        elif status == Store.ORDER_CANCELLED:
294
                            if subOrderToClone.get("cashBackStatus") == Store.CB_PENDING:
295
                                subOrderToClone["cashBackStatus"] = Store.CB_CANCELLED
296
                    else:
297
                        expectedDelivery = datetime.strftime(datetime.fromtimestamp(order['promised_delivery_time']/1000),"%A %d %B %Y")
298
                        subOrderToClone["estimatedDeliveryDate"] = expectedDelivery
14246 amit.gupta 299
                        closed = False
18254 amit.gupta 300
 
301
                    self.db.merchantOrder.update({"orderId":tr['orderId']},{'$push':{"subOrders":subOrderToClone}})
302
 
303
 
14283 amit.gupta 304
                bulk.find({"orderId":tr['orderId']}).update({'$set' : {'closed':closed}})
14246 amit.gupta 305
            except:
14277 amit.gupta 306
                traceback.print_exc()
14870 amit.gupta 307
        try:
308
            bulk.execute()
309
        except:
310
            traceback.print_exc()
14246 amit.gupta 311
 
312
 
313
 
14220 amit.gupta 314
 
18254 amit.gupta 315
    def getOriginalOrderId(self, orderId, ordersToClone, splitSubOrdersMap): 
316
        if splitSubOrdersMap.has_key(orderId):
317
            return orderId
318
        else:
319
            originalOrderId = ordersToClone[orderId]['originalOrderId']
320
            return self.getOriginalOrderId(originalOrderId, ordersToClone, splitSubOrdersMap) 
321
 
14220 amit.gupta 322
    def _saveToAffiliate(self, offers):
323
        if offers is None or len(offers)==0:
324
            print "no affiliate have been pushed"
325
            return
326
        collection = self.db.snapdealOrderAffiliateInfo
327
        try:
328
            collection.insert(offers,continue_on_error=True)
329
        except pymongo.errors.DuplicateKeyError as e:
330
            print e.details
331
 
332
 
333
    def covertToObj(self,offer):
334
        offerData = offer['Stat']
335
        offer1 = AffiliateInfo(offerData['affiliate_info1'], self.store_id, offerData['conversion_status'], offerData['ad_id'], 
336
                              offerData['datetime'], offerData['payout'], offer['Offer']['name'], offerData['ip'], offerData['conversion_sale_amount'])
337
 
338
        return offer1
339
def getPostData(token, page = 1, limit= 20, startDate=None, endDate=None):
340
    endDate=date.today() + timedelta(days=1)
341
    startDate=endDate - 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():
369
 
14301 amit.gupta 370
    store = getStore(4)
18254 amit.gupta 371
    store.scrapeStoreOrders()
14220 amit.gupta 372
    #store._isSubOrderActive(8, "5970688907")
373
    #store.scrapeAffiliate()
18254 amit.gupta 374
    #store.parseOrderRawHtml(112345, "subtagId", 1122323,  "html", 'http://www.saholic.com/pay-success?paymentId=1798123')
16967 amit.gupta 375
    #print store.getCashbackAmount('1011378', 500)
14220 amit.gupta 376
 
377
 
378
if __name__ == '__main__':
379
    main()
380
 
381
def todict(obj, classkey=None):
382
    if isinstance(obj, dict):
383
        data = {}
384
        for (k, v) in obj.items():
385
            data[k] = todict(v, classkey)
386
        return data
387
    elif hasattr(obj, "_ast"):
388
        return todict(obj._ast())
389
    elif hasattr(obj, "__iter__"):
390
        return [todict(v, classkey) for v in obj]
391
    elif hasattr(obj, "__dict__"):
392
        data = dict([(key, todict(value, classkey)) 
393
            for key, value in obj.__dict__.iteritems() 
394
            if not callable(value) and not key.startswith('_')])
395
        if classkey is not None and hasattr(obj, "__class__"):
396
            data[classkey] = obj.__class__.__name__
397
        return data
398
    else:
399
        return obj