Subversion Repositories SmartDukaan

Rev

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