Subversion Repositories SmartDukaan

Rev

Rev 17118 | Rev 17120 | 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'], 
64
                            MStore.ORDER_CANCELLED : ['has been cancelled', 'has been rejected','is returned back to us']
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'], 
71
                            "Order Cancelled" : ['has been cancelled', 'has been rejected','is returned back to us']
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]
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'])
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):
17118 manish.sha 117
        for key, value in Store.OrderStatusStringMap.iteritems():
118
            if value in detailedStatus.lower():
17013 manish.sha 119
                return key
120
        print "Detailed Status need to be mapped", detailedStatus, self.store_id
121
        return None
122
 
17119 manish.sha 123
    def _getDisplayStatusFromDetailedStatus(self, detailedStatus):
124
        for key, value in Store.OrderStatusShownMap.iteritems():
125
            if value in detailedStatus.lower():
126
                return key
127
        print "Display Status need to be mapped", detailedStatus, self.store_id
128
        return None
129
 
17013 manish.sha 130
    def updateCashbackInSubOrders(self, subOrders):
131
        for subOrder in subOrders:
132
            cashbackStatus = Store.CB_NA
133
            cashbackAmount = 0
134
            percentage = 0
135
            amount = subOrder.amountPaid
136
            if amount > 0:
137
                (cashbackAmount, percentage) = self.getCashbackAmount(subOrder.productCode, amount)
138
                if cashbackAmount > 0:
139
                    cashbackStatus = Store.CB_PENDING
140
            subOrder.cashBackStatus = cashbackStatus
141
            subOrder.cashBackAmount = cashbackAmount
142
            subOrder.cashBackPercentage = percentage
143
        return subOrders
144
 
145
    def _parseUsingOrderJson(self, orderId, subTagId, userId, rawHtmlSoup, orderSuccessUrl):
146
        orderObj = None
147
 
148
        scripts = rawHtmlSoup.find_all('script')
149
        for script in scripts:
150
            if 'var order =' in script.text:
151
                requiredObjList = script.text.strip().split('\n')
152
                for val in requiredObjList:
153
                    if "$.parseJSON('" in val:
154
                        print val.split("$.parseJSON('")[1].split("');")[0]
155
                        orderObj = json.loads(val.split("$.parseJSON('")[1].split("');")[0])
156
                        print orderObj
157
                        break
158
                break
159
 
160
        if orderObj is not None:
161
            merchantOrder = Order(orderId, userId, subTagId, self.store_id, orderSuccessUrl)
162
            merchantOrder.placedOn = orderObj['orderDate']
163
            merchantOrder.merchantOrderId = str(long(orderObj['orderId']))
164
            merchantOrder.paidAmount = long(orderObj['pricing']['orderNetPrice'])
165
            merchantOrder.totalAmount = long(orderObj['pricing']['orderGrossPrice'])
166
            merchantOrder.discountApplied = long(orderObj['pricing']['discountCouponRedemptionAmount'])+long(orderObj['pricing']['giftCouponRedemptionAmount'])
167
            merchantOrder.deliveryCharges = long(orderObj['totalShipmentCharges'])
168
            subOrders= []
169
            for subOrderObj in orderObj['subOrders']:
17045 manish.sha 170
                subOrder = SubOrder(subOrderObj['cartItem']['cartItemTitle'], BASE_PRODUCT_URL%(long(subOrderObj['cartItem']['productId'])), orderObj['orderDate'], long(subOrderObj['pricing']['payablePrice']))
17046 manish.sha 171
                subOrder.estimatedDeliveryDate = subOrderObj['shipment']['expectedDeliveryDate']
17013 manish.sha 172
                subOrder.merchantSubOrderId = str(subOrderObj['subOrderId'])
17047 manish.sha 173
                if rawHtmlSoup.body.find("div", {'class':'sub-order-status'}) is not None:
174
                    subOrder.detailedStatus = rawHtmlSoup.body.find("div", {'class':'sub-order-status'}).text
175
                else:
176
                    subOrder.detailedStatus = 'Order Placed'
17013 manish.sha 177
                subOrder.imgUrl = BASE_IMG_URL+subOrderObj['cartItem']['lineItemImageUrl']
17054 manish.sha 178
                subOrder.offerDiscount = (long(subOrderObj['cartItem']['price'])+long(subOrderObj['shipment']['shipmentCharge']))*long(subOrderObj['cartItem']['itemQuantity'])-long(subOrderObj['pricing']['payablePrice'])
17013 manish.sha 179
                subOrder.unitPrice = long(subOrderObj['cartItem']['price'])
180
                subOrder.productCode = str(long(subOrderObj['cartItem']['productId']))
17046 manish.sha 181
                subOrder.amountPaid = long(subOrderObj['pricing']['payablePrice'])
17013 manish.sha 182
                subOrder.quantity = long(subOrderObj['cartItem']['itemQuantity'])
183
                subOrder.tracingkUrl = ORDER_TRACK_URL%(long(orderObj['orderId']))
184
                dealRank = getDealRank(subOrder.productCode, self.store_id, merchantOrder.userId)
185
                subOrder.dealRank = dealRank.get('rank')
186
                subOrder.rankDesc = dealRank.get('description')
187
                subOrder.maxNlc = dealRank.get('maxNlc')
188
                subOrder.minNlc = dealRank.get('minNlc')
189
                subOrder.db = dealRank.get('dp')
190
                subOrder.itemStatus = dealRank.get('status')
17051 manish.sha 191
                subOrders.append(subOrder)
17013 manish.sha 192
            merchantOrder.subOrders = self.updateCashbackInSubOrders(subOrders)
193
            return merchantOrder
194
 
195
 
196
    def parseOrderRawHtml(self, orderId, subTagId, userId, rawHtml, orderSuccessUrl):
197
        resp = {}
198
        try:
199
            rawHtmlSoup = BeautifulSoup(rawHtml)
200
            merchantOrder = self._parseUsingOrderJson(orderId, subTagId, userId, rawHtmlSoup, orderSuccessUrl)
201
            merchantOrder.orderTrackingUrl = ORDER_TRACK_URL%(long(merchantOrder.merchantOrderId))
202
            if self._saveToOrder(todict(merchantOrder)):
203
                resp['result'] = 'ORDER_CREATED'
204
            else:
205
                resp['result'] = 'ORDER_ALREADY_CREATED_IGNORED'
206
 
207
            return resp
208
        except:
209
            print "Error occurred"
210
            traceback.print_exc()
211
            resp['result'] = 'ORDER_NOT_CREATED'
212
            return resp
213
 
214
    def scrapeStoreOrders(self,):
215
        #collectionMap = {'palcedOn':1}
216
        searchMap = {}
217
        collectionMap = {"orderTrackingUrl":1,"merchantOrderId":1}
218
        orders = self._getActiveOrders(searchMap,collectionMap)
219
        for order in orders:
17112 manish.sha 220
            bulk = self.db.merchantOrder.initialize_ordered_bulk_op()
17098 manish.sha 221
            try:
222
                print "Order", self.store_name, order['orderId'], order['orderTrackingUrl'], order['merchantOrderId']
223
                br1 = track(HS_ORDER_TRACK_URL, order['merchantOrderId'])
224
                ungzipResponseBr(br1.response(), br1)
17112 manish.sha 225
                trackPageSoup = BeautifulSoup(br1.response())
17098 manish.sha 226
                subOrderTable = trackPageSoup.body.find("table", {'class':'lower-table'})
17112 manish.sha 227
                subOrders = subOrderTable.find_all('tr')
17098 manish.sha 228
                firstRow = subOrders.pop(0)
229
                closed = True
230
                for row in subOrders:
231
                    cols = row.find_all('td')
232
                    subOrderId = cols[0].text.strip()
233
                    subOrderStatus = cols[1].text.strip()
234
                    subbulk = self.db.merchantOrder.initialize_ordered_bulk_op()
235
                    print 'Sub Order Id', str(subOrderId)
236
                    subOrder =  self._isSubOrderActive(order, str(subOrderId))
237
                    if subOrder is None:
238
                        print 'No HS Sub Order Found for SubOrder Id:- '+ str(subOrderId)
239
                    elif subOrder['closed']:
240
                        continue
17013 manish.sha 241
                    else:
17098 manish.sha 242
                        findMap = {"orderId": order['orderId'], "subOrders.merchantSubOrderId": str(subOrderId)}
243
                        updateMap = {}
17119 manish.sha 244
                        displayStatus = self._getDisplayStatusFromDetailedStatus(subOrderStatus)
17098 manish.sha 245
                        status = self._getStatusFromDetailedStatus(subOrderStatus) 
17119 manish.sha 246
                        if displayStatus is not None:
247
                            updateMap["subOrders.$.detailedStatus"] = displayStatus
17098 manish.sha 248
                        closedStatus = status in [Store.ORDER_DELIVERED, Store.ORDER_CANCELLED]
249
                        if status is not None:
250
                            updateMap["subOrders.$.status"] = status
251
                        if closedStatus:
252
                            #if status is closed then change the paybackStatus accordingly
253
                            print 'Order Closed'
254
                            updateMap["subOrders.$.closed"] = True
255
                            if status == Store.ORDER_DELIVERED:
256
                                if subOrder.get("cashBackStatus") == Store.CB_PENDING:
257
                                    updateMap["subOrders.$.cashBackStatus"] = Store.CB_APPROVED
258
                            elif status == Store.ORDER_CANCELLED:
259
                                if subOrder.get("cashBackStatus") == Store.CB_PENDING:
260
                                    updateMap["subOrders.$.cashBackStatus"] = Store.CB_CANCELLED
261
                        else:
262
                            closed = False
263
                            print 'Order not Closed'
264
 
265
                        subbulk.find(findMap).update({'$set' : updateMap})
266
                        subresult = subbulk.execute()
267
                        tprint(subresult)
17112 manish.sha 268
                bulk.find({'orderId': order['orderId']}).update({'$set':{'closed': closed,"parseError":False}})
269
                result = bulk.execute()
270
                tprint(result)
17098 manish.sha 271
            except:
272
                print "Error occurred for tracking order... "+str(order['merchantOrderId'])
273
                traceback.print_exc()
274
                continue
17013 manish.sha 275
 
276
 
277
 
278
def track(url, orderId):
279
    br = getBrowserObject()
280
    br.set_proxies({"http": PROXY_MESH_GENERAL})
281
    response = br.open(url)
282
    ungzipResponseBr(response, br)
283
    soup = BeautifulSoup(br.response())
284
    csrf = soup.find('input', {'name': '_csrf'}).get('value')
285
    print csrf
286
    #html = response.read()
287
    #print html
288
    br.select_form(name='trackForm')
289
    br.form['orderId'] = str(orderId)
290
    response = br.submit()
291
    print "********************"
292
    print "Attempting to Login"
293
    print "********************"
294
    #ungzipResponse(response, br)
295
    return br
296
 
297
def ungzipResponseBr(r,b):
298
    headers = r.info()
299
    if headers['Content-Encoding']=='gzip':
300
        import gzip
301
        print "********************"
302
        print "Deflating gzip response"
303
        print "********************"
304
        gz = gzip.GzipFile(fileobj=r, mode='rb')
305
        html = gz.read()
306
        gz.close()
307
        headers["Content-type"] = "text/html; charset=utf-8"
308
        r.set_data( html )
309
        b.set_response(r)
310
 
311
 
312
def to_py_date(java_timestamp):
313
    date = datetime.fromtimestamp(java_timestamp)
314
    return date       
315
 
316
def todict(obj, classkey=None):
317
    if isinstance(obj, dict):
318
        data = {}
319
        for (k, v) in obj.items():
320
            data[k] = todict(v, classkey)
321
        return data
322
    elif hasattr(obj, "_ast"):
323
        return todict(obj._ast())
324
    elif hasattr(obj, "__iter__"):
325
        return [todict(v, classkey) for v in obj]
326
    elif hasattr(obj, "__dict__"):
327
        data = dict([(key, todict(value, classkey)) 
328
            for key, value in obj.__dict__.iteritems() 
329
            if not callable(value) and not key.startswith('_')])
330
        if classkey is not None and hasattr(obj, "__class__"):
331
            data[classkey] = obj.__class__.__name__
332
        return data
333
    else:
334
        return obj