Subversion Repositories SmartDukaan

Rev

Rev 19270 | Rev 19272 | 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],
19271 amit.gupta 123
                      MStore.ORDER_SHIPPED : [9,10,16,17,81,80, 40],
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):
201
        for key, value in Store.OrderStatusMap.iteritems():
202
            if detailedStatus in value:
203
                return key
14349 amit.gupta 204
        print "Detailed Status need to be mapped", detailedStatus
16189 amit.gupta 205
        raise ParseException("_getStatusFromDetailedStatus", "Found new order status" + str(detailedStatus))
14220 amit.gupta 206
 
207
 
208
    def scrapeStoreOrders(self,):
18085 amit.gupta 209
        trs = self._getActiveOrders(collectionMap={'merchantOrderId':1, 'sUserId':1, 'userId':1})
14267 amit.gupta 210
        bulk = self.db.merchantOrder.initialize_ordered_bulk_op()
14246 amit.gupta 211
        for tr in trs:
18085 amit.gupta 212
            self.userId = tr['userId']
14246 amit.gupta 213
            try:
214
                orderRequest = urllib2.Request(SAHOLIC_ORDER_URL_TR %(tr['merchantOrderId'], tr['sUserId']), headers=headers)
215
                response = urllib2.urlopen(orderRequest).read()
19264 amit.gupta 216
                #print response
14246 amit.gupta 217
                response = json.loads(response)['response']
218
                items = response['itemsMap']
219
                orders = response['orders']
220
                closed = True
18254 amit.gupta 221
                splitSubOrdersMap={}
222
                ordersToClone = {}
14246 amit.gupta 223
                for order in orders:
14272 amit.gupta 224
                    print "orderid---", order['id']
14269 amit.gupta 225
                    orderId = str(order['id'])
226
                    subOrder = self._isSubOrderActive(tr, orderId)
18254 amit.gupta 227
                    currentQty = int(order['lineitems'][0]['quantity'])
14246 amit.gupta 228
                    if subOrder:
229
                        if subOrder['closed']:
230
                            continue
231
                        else:
18254 amit.gupta 232
                            quantity = int(subOrder['quantity'])
14270 amit.gupta 233
                            findMap = {"orderId": tr['orderId'], "subOrders.merchantSubOrderId": orderId}
14246 amit.gupta 234
                            updateMap = {}
235
                            updateMap["subOrders.$.detailedStatus"] = order['statusDescription']
236
                            status = self._getStatusFromDetailedStatus(ORDERSTATUS[order['status']]) 
237
                            closedStatus = status in [Store.ORDER_DELIVERED, Store.ORDER_CANCELLED]
14271 amit.gupta 238
                            print "status---", status, order['status']
14246 amit.gupta 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:
14277 amit.gupta 308
                traceback.print_exc()
14870 amit.gupta 309
        try:
310
            bulk.execute()
311
        except:
312
            traceback.print_exc()
14246 amit.gupta 313
 
314
 
315
 
14220 amit.gupta 316
 
18254 amit.gupta 317
    def getOriginalOrderId(self, orderId, ordersToClone, splitSubOrdersMap): 
318
        if splitSubOrdersMap.has_key(orderId):
319
            return orderId
320
        else:
321
            originalOrderId = ordersToClone[orderId]['originalOrderId']
322
            return self.getOriginalOrderId(originalOrderId, ordersToClone, splitSubOrdersMap) 
323
 
14220 amit.gupta 324
    def _saveToAffiliate(self, offers):
325
        if offers is None or len(offers)==0:
326
            print "no affiliate have been pushed"
327
            return
328
        collection = self.db.snapdealOrderAffiliateInfo
329
        try:
330
            collection.insert(offers,continue_on_error=True)
331
        except pymongo.errors.DuplicateKeyError as e:
332
            print e.details
333
 
334
 
335
    def covertToObj(self,offer):
336
        offerData = offer['Stat']
337
        offer1 = AffiliateInfo(offerData['affiliate_info1'], self.store_id, offerData['conversion_status'], offerData['ad_id'], 
338
                              offerData['datetime'], offerData['payout'], offer['Offer']['name'], offerData['ip'], offerData['conversion_sale_amount'])
339
 
340
        return offer1
341
def getPostData(token, page = 1, limit= 20, startDate=None, endDate=None):
342
    endDate=date.today() + timedelta(days=1)
343
    startDate=endDate - timedelta(days=31)
344
 
345
    parameters = (
346
        ("page",str(page)),
347
        ("limit",str(limit)),
348
        ("fields[]","Stat.offer_id"),
349
        ("fields[]","Stat.datetime"),
350
        ("fields[]","Offer.name"),
351
        ("fields[]","Stat.conversion_status"),
352
        ("fields[]","Stat.conversion_sale_amount"),
353
        ("fields[]","Stat.payout"),
354
        ("fields[]","Stat.ip"),
355
        ("fields[]","Stat.ad_id"),
356
        ("fields[]","Stat.affiliate_info1"),
357
        ("sort[Stat.datetime]","desc"),
358
        ("filters[Stat.date][conditional]","BETWEEN"),
359
        ("filters[Stat.date][values][]",startDate.strftime('%Y-%m-%d')),
360
        ("filters[Stat.date][values][]",endDate.strftime('%Y-%m-%d')),
361
        ("data_start",startDate.strftime('%Y-%m-%d')),
362
        ("data_end",endDate.strftime('%Y-%m-%d')),
363
        ("Method","getConversions"),
364
        ("NetworkId","jasper"),
365
        ("SessionToken",token),
366
    )
367
    #Encode the parameters
368
    return urllib.urlencode(parameters)
369
 
370
def main():
371
 
14301 amit.gupta 372
    store = getStore(4)
18254 amit.gupta 373
    store.scrapeStoreOrders()
14220 amit.gupta 374
    #store._isSubOrderActive(8, "5970688907")
375
    #store.scrapeAffiliate()
18254 amit.gupta 376
    #store.parseOrderRawHtml(112345, "subtagId", 1122323,  "html", 'http://www.saholic.com/pay-success?paymentId=1798123')
16967 amit.gupta 377
    #print store.getCashbackAmount('1011378', 500)
14220 amit.gupta 378
 
379
 
380
if __name__ == '__main__':
381
    main()
382
 
383
def todict(obj, classkey=None):
384
    if isinstance(obj, dict):
385
        data = {}
386
        for (k, v) in obj.items():
387
            data[k] = todict(v, classkey)
388
        return data
389
    elif hasattr(obj, "_ast"):
390
        return todict(obj._ast())
391
    elif hasattr(obj, "__iter__"):
392
        return [todict(v, classkey) for v in obj]
393
    elif hasattr(obj, "__dict__"):
394
        data = dict([(key, todict(value, classkey)) 
395
            for key, value in obj.__dict__.iteritems() 
396
            if not callable(value) and not key.startswith('_')])
397
        if classkey is not None and hasattr(obj, "__class__"):
398
            data[classkey] = obj.__class__.__name__
399
        return data
400
    else:
401
        return obj