Subversion Repositories SmartDukaan

Rev

Rev 19932 | Rev 20750 | 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],
19932 amit.gupta 123
                      MStore.ORDER_SHIPPED : [9,10,16,17,81,80, 40,20],
18998 amit.gupta 124
                      MStore.ORDER_CANCELLED : [1,6,11,14,15,18,19,31,34,28,53,54,55,56,20,21,77,79, 78]
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']
18687 manish.sha 152
            if response.get('payment_option') is not None:
153
                s['payment_option'] = response ['payment_option']
14267 amit.gupta 154
            if self._saveToOrder(s):
155
                resp['result'] = 'ORDER_CREATED'
156
            else:
157
                #Order already created
14312 amit.gupta 158
                resp['result'] = 'ORDER_ALREADY_CREATED_IGNORED'
14220 amit.gupta 159
        except:
14227 amit.gupta 160
            traceback.print_exc()
14312 amit.gupta 161
            resp['result'] = 'ORDER_NOT_CREATED'
14227 amit.gupta 162
        return resp
14246 amit.gupta 163
 
164
    def createSubOrder(self, order, items):
165
            lineitem = order['lineitems'][0]
166
 
167
            item = items[str(lineitem['item_id'])]
168
            brand = lineitem.get('brand')
169
            modelNumber = lineitem.get('model_number')
170
            modelName = lineitem.get('model_name')
171
            color = lineitem.get('color')
172
            productTitle = brand + (" " + modelName if modelName else "") + (" "  + modelNumber if modelNumber is not None else "") + ("(" + color +")" if color else "")
18055 amit.gupta 173
            amountPaid = order['total_amount'] 
14246 amit.gupta 174
            subOrder = SubOrder(productTitle, None, datetime.strftime(datetime.fromtimestamp(order['created_timestamp']/1000),"%d %B %Y"), amountPaid)
18055 amit.gupta 175
            subOrder.amount = amountPaid - order['gvAmount']
14246 amit.gupta 176
            subOrder.merchantSubOrderId = str(order['id'])
177
            subOrder.orderDetailUrl = "http://m.saholic.com/order/" + subOrder.merchantSubOrderId 
17677 amit.gupta 178
            subOrder.quantity = int(lineitem['quantity'])
14246 amit.gupta 179
            subOrder.estimatedDeliveryDate = datetime.strftime(datetime.fromtimestamp(order['promised_delivery_time']/1000),"%d %B %Y")
18055 amit.gupta 180
            subOrder.imgUrl = item.get("imgUrl") 
14246 amit.gupta 181
            subOrder.productUrl = "http://m.saholic.com/" + item['url']
14301 amit.gupta 182
            subOrder.productCode = item['url'].split('-')[-1]
14246 amit.gupta 183
            subOrder.detailedStatus = order['statusDescription']
17677 amit.gupta 184
            (cashbackAmount, percentage) = self.getCashbackAmount(subOrder.productCode, amountPaid/subOrder.quantity)
16189 amit.gupta 185
            dealRank = getDealRank(subOrder.productCode, self.store_id, self.userId)
186
            subOrder.dealRank = dealRank.get('rank')
187
            subOrder.rankDesc = dealRank.get('description')
16283 amit.gupta 188
            subOrder.maxNlc = dealRank.get('maxNlc')
189
            subOrder.minNlc = dealRank.get('minNlc')
190
            subOrder.db = dealRank.get('dp')
191
            subOrder.itemStatus = dealRank.get('status')
14246 amit.gupta 192
            cashbackStatus = Store.CB_PENDING
193
            if cashbackAmount <= 0:
194
                cashbackStatus = Store.CB_NA
195
            subOrder.cashBackStatus = cashbackStatus
17677 amit.gupta 196
            subOrder.cashBackAmount = cashbackAmount*subOrder.quantity
14246 amit.gupta 197
            if percentage > 0:
198
                subOrder.cashBackPercentage = percentage
199
            return subOrder
14220 amit.gupta 200
    def _getStatusFromDetailedStatus(self, detailedStatus):
20172 aman.kumar 201
        print str(detailedStatus)
14220 amit.gupta 202
        for key, value in Store.OrderStatusMap.iteritems():
203
            if detailedStatus in value:
204
                return key
14349 amit.gupta 205
        print "Detailed Status need to be mapped", detailedStatus
16189 amit.gupta 206
        raise ParseException("_getStatusFromDetailedStatus", "Found new order status" + str(detailedStatus))
14220 amit.gupta 207
 
208
 
209
    def scrapeStoreOrders(self,):
18085 amit.gupta 210
        trs = self._getActiveOrders(collectionMap={'merchantOrderId':1, 'sUserId':1, 'userId':1})
14267 amit.gupta 211
        bulk = self.db.merchantOrder.initialize_ordered_bulk_op()
14246 amit.gupta 212
        for tr in trs:
18085 amit.gupta 213
            self.userId = tr['userId']
20172 aman.kumar 214
            orderRequest = urllib2.Request(SAHOLIC_ORDER_URL_TR %(tr['merchantOrderId'], tr['sUserId']), headers=headers)
14246 amit.gupta 215
            try:
216
                response = urllib2.urlopen(orderRequest).read()
19272 amit.gupta 217
                print "transaction_id----------", tr['merchantOrderId']
14246 amit.gupta 218
                response = json.loads(response)['response']
219
                items = response['itemsMap']
220
                orders = response['orders']
221
                closed = True
18254 amit.gupta 222
                splitSubOrdersMap={}
223
                ordersToClone = {}
14246 amit.gupta 224
                for order in orders:
19272 amit.gupta 225
                    #print "orderid---", order['id']
14269 amit.gupta 226
                    orderId = str(order['id'])
227
                    subOrder = self._isSubOrderActive(tr, orderId)
18254 amit.gupta 228
                    currentQty = int(order['lineitems'][0]['quantity'])
14246 amit.gupta 229
                    if subOrder:
230
                        if subOrder['closed']:
231
                            continue
232
                        else:
18254 amit.gupta 233
                            quantity = int(subOrder['quantity'])
14270 amit.gupta 234
                            findMap = {"orderId": tr['orderId'], "subOrders.merchantSubOrderId": orderId}
14246 amit.gupta 235
                            updateMap = {}
236
                            updateMap["subOrders.$.detailedStatus"] = order['statusDescription']
237
                            status = self._getStatusFromDetailedStatus(ORDERSTATUS[order['status']]) 
238
                            closedStatus = status in [Store.ORDER_DELIVERED, Store.ORDER_CANCELLED]
239
                            updateMap["subOrders.$.status"] = status
18254 amit.gupta 240
                            #Check if split
241
                            if quantity != currentQty:
242
                                updateMap["subOrders.$.quantity"] = currentQty
243
                                updateMap["subOrders.$.amount"] = int((subOrder['amount']*currentQty)/quantity)
244
                                updateMap["subOrders.$.cashBackAmount"] = int((subOrder['cashBackAmount']*currentQty)/quantity)
245
                                updateMap["subOrders.$.amountPaid"] = int((subOrder['amountPaid']*currentQty)/quantity)
246
                                splitSubOrdersMap[order['id']]=subOrder
14246 amit.gupta 247
                            if closedStatus:
248
                                #if status is closed then change the paybackStatus accordingly
249
                                updateMap["subOrders.$.closed"] = True
250
                                if status == Store.ORDER_DELIVERED:
251
                                    deliveredOn = datetime.strftime(datetime.fromtimestamp(order['delivery_timestamp']/1000),"%A %d %B %Y")
252
                                    updateMap['subOrders.$.deliveredOn'] = deliveredOn
253
                                    if subOrder.get("cashBackStatus") == Store.CB_PENDING:
254
                                        updateMap["subOrders.$.cashBackStatus"] = Store.CB_APPROVED
255
                                elif status == Store.ORDER_CANCELLED:
256
                                    if subOrder.get("cashBackStatus") == Store.CB_PENDING:
257
                                        updateMap["subOrders.$.cashBackStatus"] = Store.CB_CANCELLED
258
                            else:
259
                                expectedDelivery = datetime.strftime(datetime.fromtimestamp(order['promised_delivery_time']/1000),"%A %d %B %Y")
260
                                updateMap["subOrders.$.estimatedDeliveryDate"] = expectedDelivery
261
                                closed = False
262
                            bulk.find(findMap).update({'$set' : updateMap})
263
                    else:
18254 amit.gupta 264
                        if order['originalOrderId']:
265
                            ordersToClone[order['id']] = order
266
                        else:
267
                            subOrder = self.createSubOrder(order, items)
268
                            self.db.merchantOrder.update({"orderId":tr['orderId']},{'$push':{"subOrders":todict(subOrder)}})
269
                            print "Added new suborder with subOrder Id:", subOrder.merchantSubOrderId
270
                            closed = False
271
 
272
                for order in ordersToClone.values():
273
                    originalOrderId = self.getOriginalOrderId(order['id'], ordersToClone, splitSubOrdersMap)
274
                    subOrderToClone = splitSubOrdersMap[originalOrderId].copy()
19270 amit.gupta 275
                    subOrderToClone["merchantSubOrderId"] = str(order['id'])
18254 amit.gupta 276
                    currentQty = int(order['lineitems'][0]['quantity'])
277
                    quantity = int(subOrderToClone['quantity'])
278
                    subOrderToClone["detailedStatus"] = order['statusDescription']
279
                    status = self._getStatusFromDetailedStatus(ORDERSTATUS[order['status']]) 
280
                    closedStatus = status in [Store.ORDER_DELIVERED, Store.ORDER_CANCELLED]
281
                    print "status---", status, order['status']
282
                    subOrderToClone["status"] = status
283
                    subOrderToClone["quantity"] = currentQty
284
                    subOrderToClone["amount"] = int((subOrderToClone['amount']*currentQty)/quantity)
285
                    subOrderToClone["cashBackAmount"] = int((subOrderToClone['cashBackAmount']*currentQty)/quantity)
286
                    subOrderToClone["amountPaid"] = int((subOrderToClone['amountPaid']*currentQty)/quantity)
287
                    if closedStatus:
288
                        #if status is closed then change the paybackStatus accordingly
289
                        subOrderToClone["closed"] = True
290
                        if status == Store.ORDER_DELIVERED:
291
                            deliveredOn = datetime.strftime(datetime.fromtimestamp(order['delivery_timestamp']/1000),"%A %d %B %Y")
292
                            subOrderToClone['deliveredOn'] = deliveredOn
293
                            if subOrderToClone.get("cashBackStatus") == Store.CB_PENDING:
294
                                subOrderToClone["cashBackStatus"] = Store.CB_APPROVED
295
                        elif status == Store.ORDER_CANCELLED:
296
                            if subOrderToClone.get("cashBackStatus") == Store.CB_PENDING:
297
                                subOrderToClone["cashBackStatus"] = Store.CB_CANCELLED
298
                    else:
299
                        expectedDelivery = datetime.strftime(datetime.fromtimestamp(order['promised_delivery_time']/1000),"%A %d %B %Y")
300
                        subOrderToClone["estimatedDeliveryDate"] = expectedDelivery
14246 amit.gupta 301
                        closed = False
18254 amit.gupta 302
 
303
                    self.db.merchantOrder.update({"orderId":tr['orderId']},{'$push':{"subOrders":subOrderToClone}})
304
 
305
 
14283 amit.gupta 306
                bulk.find({"orderId":tr['orderId']}).update({'$set' : {'closed':closed}})
14246 amit.gupta 307
            except:
20172 aman.kumar 308
                print "something went wrong for request", orderRequest
14277 amit.gupta 309
                traceback.print_exc()
14870 amit.gupta 310
        try:
311
            bulk.execute()
312
        except:
20172 aman.kumar 313
            print "Could not execute bulk"
14870 amit.gupta 314
            traceback.print_exc()
14246 amit.gupta 315
 
316
 
317
 
14220 amit.gupta 318
 
18254 amit.gupta 319
    def getOriginalOrderId(self, orderId, ordersToClone, splitSubOrdersMap): 
320
        if splitSubOrdersMap.has_key(orderId):
321
            return orderId
322
        else:
323
            originalOrderId = ordersToClone[orderId]['originalOrderId']
324
            return self.getOriginalOrderId(originalOrderId, ordersToClone, splitSubOrdersMap) 
325
 
14220 amit.gupta 326
    def _saveToAffiliate(self, offers):
327
        if offers is None or len(offers)==0:
328
            print "no affiliate have been pushed"
329
            return
330
        collection = self.db.snapdealOrderAffiliateInfo
331
        try:
332
            collection.insert(offers,continue_on_error=True)
333
        except pymongo.errors.DuplicateKeyError as e:
334
            print e.details
335
 
336
 
337
    def covertToObj(self,offer):
338
        offerData = offer['Stat']
339
        offer1 = AffiliateInfo(offerData['affiliate_info1'], self.store_id, offerData['conversion_status'], offerData['ad_id'], 
340
                              offerData['datetime'], offerData['payout'], offer['Offer']['name'], offerData['ip'], offerData['conversion_sale_amount'])
341
 
342
        return offer1
343
def getPostData(token, page = 1, limit= 20, startDate=None, endDate=None):
344
    endDate=date.today() + timedelta(days=1)
345
    startDate=endDate - timedelta(days=31)
346
 
347
    parameters = (
348
        ("page",str(page)),
349
        ("limit",str(limit)),
350
        ("fields[]","Stat.offer_id"),
351
        ("fields[]","Stat.datetime"),
352
        ("fields[]","Offer.name"),
353
        ("fields[]","Stat.conversion_status"),
354
        ("fields[]","Stat.conversion_sale_amount"),
355
        ("fields[]","Stat.payout"),
356
        ("fields[]","Stat.ip"),
357
        ("fields[]","Stat.ad_id"),
358
        ("fields[]","Stat.affiliate_info1"),
359
        ("sort[Stat.datetime]","desc"),
360
        ("filters[Stat.date][conditional]","BETWEEN"),
361
        ("filters[Stat.date][values][]",startDate.strftime('%Y-%m-%d')),
362
        ("filters[Stat.date][values][]",endDate.strftime('%Y-%m-%d')),
363
        ("data_start",startDate.strftime('%Y-%m-%d')),
364
        ("data_end",endDate.strftime('%Y-%m-%d')),
365
        ("Method","getConversions"),
366
        ("NetworkId","jasper"),
367
        ("SessionToken",token),
368
    )
369
    #Encode the parameters
370
    return urllib.urlencode(parameters)
371
 
372
def main():
373
 
14301 amit.gupta 374
    store = getStore(4)
18254 amit.gupta 375
    store.scrapeStoreOrders()
14220 amit.gupta 376
    #store._isSubOrderActive(8, "5970688907")
377
    #store.scrapeAffiliate()
18254 amit.gupta 378
    #store.parseOrderRawHtml(112345, "subtagId", 1122323,  "html", 'http://www.saholic.com/pay-success?paymentId=1798123')
16967 amit.gupta 379
    #print store.getCashbackAmount('1011378', 500)
14220 amit.gupta 380
 
381
 
382
if __name__ == '__main__':
383
    main()
384
 
385
def todict(obj, classkey=None):
386
    if isinstance(obj, dict):
387
        data = {}
388
        for (k, v) in obj.items():
389
            data[k] = todict(v, classkey)
390
        return data
391
    elif hasattr(obj, "_ast"):
392
        return todict(obj._ast())
393
    elif hasattr(obj, "__iter__"):
394
        return [todict(v, classkey) for v in obj]
395
    elif hasattr(obj, "__dict__"):
396
        data = dict([(key, todict(value, classkey)) 
397
            for key, value in obj.__dict__.iteritems() 
398
            if not callable(value) and not key.startswith('_')])
399
        if classkey is not None and hasattr(obj, "__class__"):
400
            data[classkey] = obj.__class__.__name__
401
        return data
402
    else:
403
        return obj