Subversion Repositories SmartDukaan

Rev

Rev 14265 | Rev 14267 | 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']
148
            self._saveToOrder(s)
14227 amit.gupta 149
            resp['result'] = 'ORDER_CREATED'
14220 amit.gupta 150
        except:
14227 amit.gupta 151
            traceback.print_exc()
152
            resp['result'] = 'PARSE_ERROR'
153
        return resp
14246 amit.gupta 154
 
155
    def createSubOrder(self, order, items):
156
            lineitem = order['lineitems'][0]
157
 
158
            item = items[str(lineitem['item_id'])]
159
            brand = lineitem.get('brand')
160
            modelNumber = lineitem.get('model_number')
161
            modelName = lineitem.get('model_name')
162
            color = lineitem.get('color')
163
            productTitle = brand + (" " + modelName if modelName else "") + (" "  + modelNumber if modelNumber is not None else "") + ("(" + color +")" if color else "")
164
            amountPaid = order['total_amount']- order['gvAmount']
165
            subOrder = SubOrder(productTitle, None, datetime.strftime(datetime.fromtimestamp(order['created_timestamp']/1000),"%d %B %Y"), amountPaid)
166
            subOrder.merchantSubOrderId = str(order['id'])
167
            subOrder.orderDetailUrl = "http://m.saholic.com/order/" + subOrder.merchantSubOrderId 
168
 
169
            subOrder.estimatedDeliveryDate = datetime.strftime(datetime.fromtimestamp(order['promised_delivery_time']/1000),"%d %B %Y")
170
            subOrder.imgUrl = item['imgUrl'] 
171
            subOrder.productUrl = "http://m.saholic.com/" + item['url']
172
            subOrder.detailedStatus = order['statusDescription']
173
            (cashbackAmount, percentage) = self.getCashbackAmount(subOrder.productCode, amountPaid)
174
            cashbackStatus = Store.CB_PENDING
175
            if cashbackAmount <= 0:
176
                cashbackStatus = Store.CB_NA
177
            subOrder.cashBackStatus = cashbackStatus
178
            subOrder.cashBackAmount = cashbackAmount
179
            if percentage > 0:
180
                subOrder.cashBackPercentage = percentage
181
            return subOrder
14220 amit.gupta 182
    def _getStatusFromDetailedStatus(self, detailedStatus):
183
        for key, value in Store.OrderStatusMap.iteritems():
184
            if detailedStatus in value:
185
                return key
186
            print "Detailed Status need to be mapped"
187
        raise ParseException("_getStatusFromDetailedStatus", "Found new order status" + detailedStatus)
188
 
189
 
190
    def scrapeStoreOrders(self,):
14246 amit.gupta 191
        trs = self._getActiveOrders()
192
        for tr in trs:
193
            bulk = self.db.merchantOrder.initialize_ordered_bulk_op()
194
            try:
195
                orderRequest = urllib2.Request(SAHOLIC_ORDER_URL_TR %(tr['merchantOrderId'], tr['sUserId']), headers=headers)
196
                response = urllib2.urlopen(orderRequest).read()
197
                response = json.loads(response)['response']
198
                items = response['itemsMap']
199
                orders = response['orders']
200
                closed = True
201
                for order in orders:
202
                    subOrder = self._isSubOrderActive(tr, order['id'])
203
                    if subOrder:
204
                        if subOrder['closed']:
205
                            continue
206
                        else:
207
                            findMap = {"orderId": order['orderId'], "subOrders.merchantSubOrderId": order['id']}
208
                            updateMap = {}
209
                            updateMap["subOrders.$.detailedStatus"] = order['statusDescription']
210
                            status = self._getStatusFromDetailedStatus(ORDERSTATUS[order['status']]) 
211
                            closedStatus = status in [Store.ORDER_DELIVERED, Store.ORDER_CANCELLED]
212
                            updateMap["subOrders.$.status"] = status
213
                            if closedStatus:
214
                                #if status is closed then change the paybackStatus accordingly
215
                                updateMap["subOrders.$.closed"] = True
216
                                if status == Store.ORDER_DELIVERED:
217
                                    deliveredOn = datetime.strftime(datetime.fromtimestamp(order['delivery_timestamp']/1000),"%A %d %B %Y")
218
                                    updateMap['subOrders.$.deliveredOn'] = deliveredOn
219
                                    if subOrder.get("cashBackStatus") == Store.CB_PENDING:
220
                                        updateMap["subOrders.$.cashBackStatus"] = Store.CB_APPROVED
221
                                elif status == Store.ORDER_CANCELLED:
222
                                    if subOrder.get("cashBackStatus") == Store.CB_PENDING:
223
                                        updateMap["subOrders.$.cashBackStatus"] = Store.CB_CANCELLED
224
                            else:
225
                                expectedDelivery = datetime.strftime(datetime.fromtimestamp(order['promised_delivery_time']/1000),"%A %d %B %Y")
226
                                updateMap["subOrders.$.estimatedDeliveryDate"] = expectedDelivery
227
                                closed = False
228
                            bulk.find(findMap).update({'$set' : updateMap})
229
                    else:
230
                        subOrder = self.parseSubOrder(order, items)
231
                        self.db.merchantOrder.update({"orderId":order['orderId']},{'$push':{"subOrders":todict(subOrder)}})
232
                        print "Added new suborder with subOrder Id:", subOrder.merchantSubOrderId
233
                        closed = False
234
                bulk.find({"order":order['id']}).update({'$set' : {'closed':closed}})
235
            except:
236
                pass
237
 
238
 
239
 
14220 amit.gupta 240
 
241
    def _saveToAffiliate(self, offers):
242
        if offers is None or len(offers)==0:
243
            print "no affiliate have been pushed"
244
            return
245
        collection = self.db.snapdealOrderAffiliateInfo
246
        try:
247
            collection.insert(offers,continue_on_error=True)
248
        except pymongo.errors.DuplicateKeyError as e:
249
            print e.details
250
 
251
 
252
    def covertToObj(self,offer):
253
        offerData = offer['Stat']
254
        offer1 = AffiliateInfo(offerData['affiliate_info1'], self.store_id, offerData['conversion_status'], offerData['ad_id'], 
255
                              offerData['datetime'], offerData['payout'], offer['Offer']['name'], offerData['ip'], offerData['conversion_sale_amount'])
256
 
257
        return offer1
258
def getPostData(token, page = 1, limit= 20, startDate=None, endDate=None):
259
    endDate=date.today() + timedelta(days=1)
260
    startDate=endDate - timedelta(days=31)
261
 
262
    parameters = (
263
        ("page",str(page)),
264
        ("limit",str(limit)),
265
        ("fields[]","Stat.offer_id"),
266
        ("fields[]","Stat.datetime"),
267
        ("fields[]","Offer.name"),
268
        ("fields[]","Stat.conversion_status"),
269
        ("fields[]","Stat.conversion_sale_amount"),
270
        ("fields[]","Stat.payout"),
271
        ("fields[]","Stat.ip"),
272
        ("fields[]","Stat.ad_id"),
273
        ("fields[]","Stat.affiliate_info1"),
274
        ("sort[Stat.datetime]","desc"),
275
        ("filters[Stat.date][conditional]","BETWEEN"),
276
        ("filters[Stat.date][values][]",startDate.strftime('%Y-%m-%d')),
277
        ("filters[Stat.date][values][]",endDate.strftime('%Y-%m-%d')),
278
        ("data_start",startDate.strftime('%Y-%m-%d')),
279
        ("data_end",endDate.strftime('%Y-%m-%d')),
280
        ("Method","getConversions"),
281
        ("NetworkId","jasper"),
282
        ("SessionToken",token),
283
    )
284
    #Encode the parameters
285
    return urllib.urlencode(parameters)
286
 
287
def main():
288
 
289
    store = getStore(3)
290
    #store.scrapeStoreOrders()
291
    #store._isSubOrderActive(8, "5970688907")
292
    #store.scrapeAffiliate()
293
    store.parseOrderRawHtml(12345, "subtagId", 122323,  "html", 'http://www.saholic.com/pay-success?paymentId=1528903')
294
 
295
 
296
if __name__ == '__main__':
297
    main()
298
 
299
def todict(obj, classkey=None):
300
    if isinstance(obj, dict):
301
        data = {}
302
        for (k, v) in obj.items():
303
            data[k] = todict(v, classkey)
304
        return data
305
    elif hasattr(obj, "_ast"):
306
        return todict(obj._ast())
307
    elif hasattr(obj, "__iter__"):
308
        return [todict(v, classkey) for v in obj]
309
    elif hasattr(obj, "__dict__"):
310
        data = dict([(key, todict(value, classkey)) 
311
            for key, value in obj.__dict__.iteritems() 
312
            if not callable(value) and not key.startswith('_')])
313
        if classkey is not None and hasattr(obj, "__class__"):
314
            data[classkey] = obj.__class__.__name__
315
        return data
316
    else:
317
        return obj