Subversion Repositories SmartDukaan

Rev

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