Subversion Repositories SmartDukaan

Rev

Rev 17121 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
17013 manish.sha 1
'''
2
Created on Jan 15, 2015
3
 
4
@author: Manish 
5
'''
6
from bs4 import BeautifulSoup
7
from bson.binary import Binary
8
from datetime import datetime, date, timedelta
9
from dtr import main
10
from dtr.dao import AffiliateInfo, Order, SubOrder, HomeShopAffiliateInfo
11
from dtr.main import getBrowserObject, ScrapeException, getStore, ParseException, \
12
    Store as MStore, ungzipResponse, tprint
13
from dtr.storage import Mongo
14
from dtr.storage.Mongo import getImgSrc
15
from dtr.utils.utils import fetchResponseUsingProxy, PROXY_MESH_GENERAL
16
from pprint import pprint
17
from pymongo import MongoClient
18
import json
19
import pymongo
20
import re
21
import time
22
import traceback
23
import urllib
24
import urllib2
25
from urlparse import urlparse, parse_qs
26
import xml.etree.ElementTree as ET
27
from dtr.storage import MemCache
28
from dtr.storage.Mongo import getDealRank
29
 
30
 
31
AFFLIATE_TRASACTIONS_URL = "https://admin.optimisemedia.com/v2/reports/affiliate/leads/leadsummaryexport.aspx?Contact=796881&Country=26&Agency=95&Merchant=331902&Status=-1&Year=%d&Month=%d&Day=%d&EndYear=%d&EndMonth=%d&EndDay=%d&DateType=0&Sort=CompletionDate&Login=1347562DA5E3EFF6FB1561765C47C782&Format=XML&RestrictURL=0"
32
ORDER_TRACK_URL='https://m.homeshop18.com/order/orderDetail.mobi?orderId=%d'
33
HS_ORDER_TRACK_URL='http://www.homeshop18.com/track-your-order.html'
34
BASE_URL= 'http://www.shopclues.com'
35
BASE_MURL= 'http://m.shopclues.com'
36
BASE_PRODUCT_URL= 'http://m.homeshop18.com/product.mobi?productId=%d'
37
BASE_IMG_URL='http://stat.homeshop18.com/homeshop18'
38
 
39
 
40
#http://m.homeshop18.com/checkout/paySuccess.mobi?orderComplete=true
41
 
42
class Store(MStore):
43
    '''
44
    This is to map order statuses of our system to order statuses of snapdeal.
45
    And our statuses will change accordingly.
46
 
47
    '''
48
    OrderStatusMap = {
49
                      MStore.ORDER_PLACED : ['payment successful', 'new order - cod confirmation pending', 'processing', 'quality check','on schedule', 'processing - pickup initiated', 'processing - ready to dispatch','processing - procurement delay from merchant','processing - slight procurment delay from merchant','cod order confirmed by customer'],
50
                      MStore.ORDER_DELIVERED : ['delivered', 'complete'],
51
                      MStore.ORDER_SHIPPED : ['in transit', 'dispatched','shipped','order handed to courier','order handed over to courier'],
52
                      MStore.ORDER_CANCELLED : ['payment failed', 'canceled', 'payment declined', 'order on hold - cancellation requested by customer', 'courier returned', 'canceled on customer request', 'canceled by customer','order canceled by customer','canceled - address not shippable','return complete','undelivered - returning to origin']
53
                      }
54
    OrderStatusConfirmationMap= {
55
                                 "P" : "Payment Successful",
56
                                 "D" : "Order Declined",
57
                                 "O" : "New Order - COD confirmation Pending"
58
                                 }
59
 
60
    OrderStatusStringMap = {
61
                            MStore.ORDER_PLACED : ['expect the order to reach', 'received your payment'],
62
                            MStore.ORDER_DELIVERED : ['has been delivered'],
63
                            MStore.ORDER_SHIPPED : ['has been shipped', 'has been dispatched'], 
17121 manish.sha 64
                            MStore.ORDER_CANCELLED : ['has been cancelled', 'has been rejected','is returned back to us','payment failed']
17013 manish.sha 65
                            }
66
 
17119 manish.sha 67
    OrderStatusShownMap = {
68
                            "Under Process" : ['expect the order to reach', 'received your payment'],
69
                            "Order Delivered" : ['has been delivered'],
70
                            "Order Shipped" : ['has been shipped', 'has been dispatched'], 
17121 manish.sha 71
                            "Order Cancelled" : ['has been cancelled', 'has been rejected','is returned back to us','payment failed']
17119 manish.sha 72
                           }
73
 
17013 manish.sha 74
    CONF_CB_AMOUNT = MStore.CONF_CB_DISCOUNTED_PRICE
75
 
76
 
77
    def __init__(self,store_id):
78
        super(Store, self).__init__(store_id)
79
 
80
    def convertToObj(self,offer):
81
        orderRef = offer['MerchantRef']
82
        if len(orderRef)>15:
83
            orderRef = orderRef[0:len(orderRef)-10]
17248 manish.sha 84
        offer1 = HomeShopAffiliateInfo(offer['UID'], offer['TransactionTime'], offer['TransactionID'], orderRef,  orderRef, offer['Merchant'], offer['PID'], offer['Product'], float(str(offer['SR'])), float(str(offer['TransactionValue'])), offer['UKey'], offer['ClickTime'], offer['Status'])
17013 manish.sha 85
        return offer1
86
 
87
    def _saveToAffiliate(self, offers):
88
        collection = self.db.homeshopOrderAffiliateInfo
89
        mcollection = self.db.merchantOrder
90
        for offerObj in offers:
91
            offer = self.convertToObj(offerObj)
92
            collection.update({"transactionId":offer.transactionId, "subTagId":offer.subTagId, "payOut":offer.payOut},{"$set":todict(offer)}, upsert=True)
93
            mcollection.update({"subTagId":offer.subTagId, "storeId":self.store_id, "subOrders.missingAff":True}, {"$set":{"subOrders.$.missingAff":False}})
94
 
95
    def scrapeAffiliate(self, startDate=datetime.today() - timedelta(days=10), endDate=datetime.today()):
96
        uri = AFFLIATE_TRASACTIONS_URL%(startDate.year,startDate.month,startDate.day,endDate.year,endDate.month,endDate.day)
97
        root = ET.parse(urllib2.urlopen(uri)).getroot()
98
        if len(root)> 0 and len(root[0])> 0:
99
            offers = []
100
            for child in root[0][0]:
101
                offers.append(child.attrib)
102
            self._saveToAffiliate(offers)
103
 
104
    def _setLastSaleDate(self, saleDate):
105
        self.db.lastSaleDtate.update({'storeId':self.store_id}, {'$set':{'saleDate':saleDate}})
106
 
107
    def getName(self):
108
        return "homeshop18"  
109
 
110
 
111
    def _getLastSaleDate(self,):
112
        lastDaySaleObj = self.db.lastDaySale.find_one({"storeId":self.store_id})
113
        if lastDaySaleObj is None:
114
            return datetime.min
115
 
116
    def _getStatusFromDetailedStatus(self, detailedStatus):
17120 manish.sha 117
        for key, statusList in Store.OrderStatusStringMap.iteritems():
118
            for value in statusList:
119
                if value in detailedStatus.lower():
120
                    return key
17013 manish.sha 121
        print "Detailed Status need to be mapped", detailedStatus, self.store_id
122
        return None
123
 
17119 manish.sha 124
    def _getDisplayStatusFromDetailedStatus(self, detailedStatus):
17120 manish.sha 125
        for key, statusList in Store.OrderStatusShownMap.iteritems():
126
            for value in statusList:
127
                if value in detailedStatus.lower():
128
                    return key
17119 manish.sha 129
        print "Display Status need to be mapped", detailedStatus, self.store_id
130
        return None
131
 
17013 manish.sha 132
    def updateCashbackInSubOrders(self, subOrders):
133
        for subOrder in subOrders:
134
            cashbackStatus = Store.CB_NA
135
            cashbackAmount = 0
136
            percentage = 0
137
            amount = subOrder.amountPaid
138
            if amount > 0:
139
                (cashbackAmount, percentage) = self.getCashbackAmount(subOrder.productCode, amount)
140
                if cashbackAmount > 0:
141
                    cashbackStatus = Store.CB_PENDING
142
            subOrder.cashBackStatus = cashbackStatus
143
            subOrder.cashBackAmount = cashbackAmount
144
            subOrder.cashBackPercentage = percentage
145
        return subOrders
146
 
147
    def _parseUsingOrderJson(self, orderId, subTagId, userId, rawHtmlSoup, orderSuccessUrl):
148
        orderObj = None
149
 
150
        scripts = rawHtmlSoup.find_all('script')
151
        for script in scripts:
152
            if 'var order =' in script.text:
153
                requiredObjList = script.text.strip().split('\n')
154
                for val in requiredObjList:
155
                    if "$.parseJSON('" in val:
156
                        print val.split("$.parseJSON('")[1].split("');")[0]
157
                        orderObj = json.loads(val.split("$.parseJSON('")[1].split("');")[0])
158
                        print orderObj
159
                        break
160
                break
161
 
162
        if orderObj is not None:
163
            merchantOrder = Order(orderId, userId, subTagId, self.store_id, orderSuccessUrl)
164
            merchantOrder.placedOn = orderObj['orderDate']
165
            merchantOrder.merchantOrderId = str(long(orderObj['orderId']))
166
            merchantOrder.paidAmount = long(orderObj['pricing']['orderNetPrice'])
167
            merchantOrder.totalAmount = long(orderObj['pricing']['orderGrossPrice'])
168
            merchantOrder.discountApplied = long(orderObj['pricing']['discountCouponRedemptionAmount'])+long(orderObj['pricing']['giftCouponRedemptionAmount'])
169
            merchantOrder.deliveryCharges = long(orderObj['totalShipmentCharges'])
170
            subOrders= []
171
            for subOrderObj in orderObj['subOrders']:
17045 manish.sha 172
                subOrder = SubOrder(subOrderObj['cartItem']['cartItemTitle'], BASE_PRODUCT_URL%(long(subOrderObj['cartItem']['productId'])), orderObj['orderDate'], long(subOrderObj['pricing']['payablePrice']))
17046 manish.sha 173
                subOrder.estimatedDeliveryDate = subOrderObj['shipment']['expectedDeliveryDate']
17013 manish.sha 174
                subOrder.merchantSubOrderId = str(subOrderObj['subOrderId'])
17047 manish.sha 175
                if rawHtmlSoup.body.find("div", {'class':'sub-order-status'}) is not None:
176
                    subOrder.detailedStatus = rawHtmlSoup.body.find("div", {'class':'sub-order-status'}).text
177
                else:
178
                    subOrder.detailedStatus = 'Order Placed'
17013 manish.sha 179
                subOrder.imgUrl = BASE_IMG_URL+subOrderObj['cartItem']['lineItemImageUrl']
17054 manish.sha 180
                subOrder.offerDiscount = (long(subOrderObj['cartItem']['price'])+long(subOrderObj['shipment']['shipmentCharge']))*long(subOrderObj['cartItem']['itemQuantity'])-long(subOrderObj['pricing']['payablePrice'])
17013 manish.sha 181
                subOrder.unitPrice = long(subOrderObj['cartItem']['price'])
182
                subOrder.productCode = str(long(subOrderObj['cartItem']['productId']))
17046 manish.sha 183
                subOrder.amountPaid = long(subOrderObj['pricing']['payablePrice'])
17013 manish.sha 184
                subOrder.quantity = long(subOrderObj['cartItem']['itemQuantity'])
185
                subOrder.tracingkUrl = ORDER_TRACK_URL%(long(orderObj['orderId']))
186
                dealRank = getDealRank(subOrder.productCode, self.store_id, merchantOrder.userId)
187
                subOrder.dealRank = dealRank.get('rank')
188
                subOrder.rankDesc = dealRank.get('description')
189
                subOrder.maxNlc = dealRank.get('maxNlc')
190
                subOrder.minNlc = dealRank.get('minNlc')
191
                subOrder.db = dealRank.get('dp')
192
                subOrder.itemStatus = dealRank.get('status')
17051 manish.sha 193
                subOrders.append(subOrder)
17013 manish.sha 194
            merchantOrder.subOrders = self.updateCashbackInSubOrders(subOrders)
195
            return merchantOrder
196
 
197
 
198
    def parseOrderRawHtml(self, orderId, subTagId, userId, rawHtml, orderSuccessUrl):
199
        resp = {}
200
        try:
201
            rawHtmlSoup = BeautifulSoup(rawHtml)
202
            merchantOrder = self._parseUsingOrderJson(orderId, subTagId, userId, rawHtmlSoup, orderSuccessUrl)
203
            merchantOrder.orderTrackingUrl = ORDER_TRACK_URL%(long(merchantOrder.merchantOrderId))
204
            if self._saveToOrder(todict(merchantOrder)):
205
                resp['result'] = 'ORDER_CREATED'
206
            else:
207
                resp['result'] = 'ORDER_ALREADY_CREATED_IGNORED'
208
 
209
            return resp
210
        except:
211
            print "Error occurred"
212
            traceback.print_exc()
213
            resp['result'] = 'ORDER_NOT_CREATED'
214
            return resp
215
 
216
    def scrapeStoreOrders(self,):
217
        #collectionMap = {'palcedOn':1}
218
        searchMap = {}
219
        collectionMap = {"orderTrackingUrl":1,"merchantOrderId":1}
220
        orders = self._getActiveOrders(searchMap,collectionMap)
221
        for order in orders:
17112 manish.sha 222
            bulk = self.db.merchantOrder.initialize_ordered_bulk_op()
17098 manish.sha 223
            try:
224
                print "Order", self.store_name, order['orderId'], order['orderTrackingUrl'], order['merchantOrderId']
225
                br1 = track(HS_ORDER_TRACK_URL, order['merchantOrderId'])
226
                ungzipResponseBr(br1.response(), br1)
17112 manish.sha 227
                trackPageSoup = BeautifulSoup(br1.response())
17098 manish.sha 228
                subOrderTable = trackPageSoup.body.find("table", {'class':'lower-table'})
17112 manish.sha 229
                subOrders = subOrderTable.find_all('tr')
17098 manish.sha 230
                firstRow = subOrders.pop(0)
231
                closed = True
232
                for row in subOrders:
233
                    cols = row.find_all('td')
234
                    subOrderId = cols[0].text.strip()
235
                    subOrderStatus = cols[1].text.strip()
236
                    subbulk = self.db.merchantOrder.initialize_ordered_bulk_op()
237
                    print 'Sub Order Id', str(subOrderId)
238
                    subOrder =  self._isSubOrderActive(order, str(subOrderId))
239
                    if subOrder is None:
240
                        print 'No HS Sub Order Found for SubOrder Id:- '+ str(subOrderId)
241
                    elif subOrder['closed']:
242
                        continue
17013 manish.sha 243
                    else:
17098 manish.sha 244
                        findMap = {"orderId": order['orderId'], "subOrders.merchantSubOrderId": str(subOrderId)}
245
                        updateMap = {}
17119 manish.sha 246
                        displayStatus = self._getDisplayStatusFromDetailedStatus(subOrderStatus)
17098 manish.sha 247
                        status = self._getStatusFromDetailedStatus(subOrderStatus) 
17119 manish.sha 248
                        if displayStatus is not None:
249
                            updateMap["subOrders.$.detailedStatus"] = displayStatus
17098 manish.sha 250
                        closedStatus = status in [Store.ORDER_DELIVERED, Store.ORDER_CANCELLED]
251
                        if status is not None:
252
                            updateMap["subOrders.$.status"] = status
253
                        if closedStatus:
254
                            #if status is closed then change the paybackStatus accordingly
255
                            print 'Order Closed'
256
                            updateMap["subOrders.$.closed"] = True
257
                            if status == Store.ORDER_DELIVERED:
258
                                if subOrder.get("cashBackStatus") == Store.CB_PENDING:
259
                                    updateMap["subOrders.$.cashBackStatus"] = Store.CB_APPROVED
260
                            elif status == Store.ORDER_CANCELLED:
261
                                if subOrder.get("cashBackStatus") == Store.CB_PENDING:
262
                                    updateMap["subOrders.$.cashBackStatus"] = Store.CB_CANCELLED
263
                        else:
264
                            closed = False
265
                            print 'Order not Closed'
266
 
267
                        subbulk.find(findMap).update({'$set' : updateMap})
268
                        subresult = subbulk.execute()
269
                        tprint(subresult)
17112 manish.sha 270
                bulk.find({'orderId': order['orderId']}).update({'$set':{'closed': closed,"parseError":False}})
271
                result = bulk.execute()
272
                tprint(result)
17098 manish.sha 273
            except:
274
                print "Error occurred for tracking order... "+str(order['merchantOrderId'])
275
                traceback.print_exc()
276
                continue
17013 manish.sha 277
 
278
 
279
 
280
def track(url, orderId):
281
    br = getBrowserObject()
282
    br.set_proxies({"http": PROXY_MESH_GENERAL})
283
    response = br.open(url)
284
    ungzipResponseBr(response, br)
285
    soup = BeautifulSoup(br.response())
286
    csrf = soup.find('input', {'name': '_csrf'}).get('value')
287
    print csrf
288
    #html = response.read()
289
    #print html
290
    br.select_form(name='trackForm')
291
    br.form['orderId'] = str(orderId)
292
    response = br.submit()
293
    print "********************"
294
    print "Attempting to Login"
295
    print "********************"
296
    #ungzipResponse(response, br)
297
    return br
298
 
299
def ungzipResponseBr(r,b):
300
    headers = r.info()
301
    if headers['Content-Encoding']=='gzip':
302
        import gzip
303
        print "********************"
304
        print "Deflating gzip response"
305
        print "********************"
306
        gz = gzip.GzipFile(fileobj=r, mode='rb')
307
        html = gz.read()
308
        gz.close()
309
        headers["Content-type"] = "text/html; charset=utf-8"
310
        r.set_data( html )
311
        b.set_response(r)
312
 
313
 
314
def to_py_date(java_timestamp):
315
    date = datetime.fromtimestamp(java_timestamp)
316
    return date       
317
 
318
def todict(obj, classkey=None):
319
    if isinstance(obj, dict):
320
        data = {}
321
        for (k, v) in obj.items():
322
            data[k] = todict(v, classkey)
323
        return data
324
    elif hasattr(obj, "_ast"):
325
        return todict(obj._ast())
326
    elif hasattr(obj, "__iter__"):
327
        return [todict(v, classkey) for v in obj]
328
    elif hasattr(obj, "__dict__"):
329
        data = dict([(key, todict(value, classkey)) 
330
            for key, value in obj.__dict__.iteritems() 
331
            if not callable(value) and not key.startswith('_')])
332
        if classkey is not None and hasattr(obj, "__class__"):
333
            data[classkey] = obj.__class__.__name__
334
        return data
335
    else:
336
        return obj