Subversion Repositories SmartDukaan

Rev

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