Subversion Repositories SmartDukaan

Rev

Rev 17054 | Rev 17112 | 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
 
67
    CONF_CB_AMOUNT = MStore.CONF_CB_DISCOUNTED_PRICE
68
 
69
 
70
    def __init__(self,store_id):
71
        super(Store, self).__init__(store_id)
72
 
73
    def convertToObj(self,offer):
74
        orderRef = offer['MerchantRef']
75
        if len(orderRef)>15:
76
            orderRef = orderRef[0:len(orderRef)-10]
77
        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'])
78
        return offer1
79
 
80
    def _saveToAffiliate(self, offers):
81
        collection = self.db.homeshopOrderAffiliateInfo
82
        mcollection = self.db.merchantOrder
83
        for offerObj in offers:
84
            offer = self.convertToObj(offerObj)
85
            collection.update({"transactionId":offer.transactionId, "subTagId":offer.subTagId, "payOut":offer.payOut},{"$set":todict(offer)}, upsert=True)
86
            mcollection.update({"subTagId":offer.subTagId, "storeId":self.store_id, "subOrders.missingAff":True}, {"$set":{"subOrders.$.missingAff":False}})
87
 
88
    def scrapeAffiliate(self, startDate=datetime.today() - timedelta(days=10), endDate=datetime.today()):
89
        uri = AFFLIATE_TRASACTIONS_URL%(startDate.year,startDate.month,startDate.day,endDate.year,endDate.month,endDate.day)
90
        root = ET.parse(urllib2.urlopen(uri)).getroot()
91
        if len(root)> 0 and len(root[0])> 0:
92
            offers = []
93
            for child in root[0][0]:
94
                offers.append(child.attrib)
95
            self._saveToAffiliate(offers)
96
 
97
    def _setLastSaleDate(self, saleDate):
98
        self.db.lastSaleDtate.update({'storeId':self.store_id}, {'$set':{'saleDate':saleDate}})
99
 
100
    def getName(self):
101
        return "homeshop18"  
102
 
103
 
104
    def _getLastSaleDate(self,):
105
        lastDaySaleObj = self.db.lastDaySale.find_one({"storeId":self.store_id})
106
        if lastDaySaleObj is None:
107
            return datetime.min
108
 
109
    def _getStatusFromDetailedStatus(self, detailedStatus):
110
        for key, value in Store.OrderStatusMap.iteritems():
111
            if detailedStatus.lower() in value:
112
                return key
113
        print "Detailed Status need to be mapped", detailedStatus, self.store_id
114
        return None
115
 
116
    def updateCashbackInSubOrders(self, subOrders):
117
        for subOrder in subOrders:
118
            cashbackStatus = Store.CB_NA
119
            cashbackAmount = 0
120
            percentage = 0
121
            amount = subOrder.amountPaid
122
            if amount > 0:
123
                (cashbackAmount, percentage) = self.getCashbackAmount(subOrder.productCode, amount)
124
                if cashbackAmount > 0:
125
                    cashbackStatus = Store.CB_PENDING
126
            subOrder.cashBackStatus = cashbackStatus
127
            subOrder.cashBackAmount = cashbackAmount
128
            subOrder.cashBackPercentage = percentage
129
        return subOrders
130
 
131
    def _parseUsingOrderJson(self, orderId, subTagId, userId, rawHtmlSoup, orderSuccessUrl):
132
        orderObj = None
133
 
134
        scripts = rawHtmlSoup.find_all('script')
135
        for script in scripts:
136
            if 'var order =' in script.text:
137
                requiredObjList = script.text.strip().split('\n')
138
                for val in requiredObjList:
139
                    if "$.parseJSON('" in val:
140
                        print val.split("$.parseJSON('")[1].split("');")[0]
141
                        orderObj = json.loads(val.split("$.parseJSON('")[1].split("');")[0])
142
                        print orderObj
143
                        break
144
                break
145
 
146
        if orderObj is not None:
147
            merchantOrder = Order(orderId, userId, subTagId, self.store_id, orderSuccessUrl)
148
            merchantOrder.placedOn = orderObj['orderDate']
149
            merchantOrder.merchantOrderId = str(long(orderObj['orderId']))
150
            merchantOrder.paidAmount = long(orderObj['pricing']['orderNetPrice'])
151
            merchantOrder.totalAmount = long(orderObj['pricing']['orderGrossPrice'])
152
            merchantOrder.discountApplied = long(orderObj['pricing']['discountCouponRedemptionAmount'])+long(orderObj['pricing']['giftCouponRedemptionAmount'])
153
            merchantOrder.deliveryCharges = long(orderObj['totalShipmentCharges'])
154
            subOrders= []
155
            for subOrderObj in orderObj['subOrders']:
17045 manish.sha 156
                subOrder = SubOrder(subOrderObj['cartItem']['cartItemTitle'], BASE_PRODUCT_URL%(long(subOrderObj['cartItem']['productId'])), orderObj['orderDate'], long(subOrderObj['pricing']['payablePrice']))
17046 manish.sha 157
                subOrder.estimatedDeliveryDate = subOrderObj['shipment']['expectedDeliveryDate']
17013 manish.sha 158
                subOrder.merchantSubOrderId = str(subOrderObj['subOrderId'])
17047 manish.sha 159
                if rawHtmlSoup.body.find("div", {'class':'sub-order-status'}) is not None:
160
                    subOrder.detailedStatus = rawHtmlSoup.body.find("div", {'class':'sub-order-status'}).text
161
                else:
162
                    subOrder.detailedStatus = 'Order Placed'
17013 manish.sha 163
                subOrder.imgUrl = BASE_IMG_URL+subOrderObj['cartItem']['lineItemImageUrl']
17054 manish.sha 164
                subOrder.offerDiscount = (long(subOrderObj['cartItem']['price'])+long(subOrderObj['shipment']['shipmentCharge']))*long(subOrderObj['cartItem']['itemQuantity'])-long(subOrderObj['pricing']['payablePrice'])
17013 manish.sha 165
                subOrder.unitPrice = long(subOrderObj['cartItem']['price'])
166
                subOrder.productCode = str(long(subOrderObj['cartItem']['productId']))
17046 manish.sha 167
                subOrder.amountPaid = long(subOrderObj['pricing']['payablePrice'])
17013 manish.sha 168
                subOrder.quantity = long(subOrderObj['cartItem']['itemQuantity'])
169
                subOrder.tracingkUrl = ORDER_TRACK_URL%(long(orderObj['orderId']))
170
                dealRank = getDealRank(subOrder.productCode, self.store_id, merchantOrder.userId)
171
                subOrder.dealRank = dealRank.get('rank')
172
                subOrder.rankDesc = dealRank.get('description')
173
                subOrder.maxNlc = dealRank.get('maxNlc')
174
                subOrder.minNlc = dealRank.get('minNlc')
175
                subOrder.db = dealRank.get('dp')
176
                subOrder.itemStatus = dealRank.get('status')
17051 manish.sha 177
                subOrders.append(subOrder)
17013 manish.sha 178
            merchantOrder.subOrders = self.updateCashbackInSubOrders(subOrders)
179
            return merchantOrder
180
 
181
 
182
    def parseOrderRawHtml(self, orderId, subTagId, userId, rawHtml, orderSuccessUrl):
183
        resp = {}
184
        try:
185
            rawHtmlSoup = BeautifulSoup(rawHtml)
186
            merchantOrder = self._parseUsingOrderJson(orderId, subTagId, userId, rawHtmlSoup, orderSuccessUrl)
187
            merchantOrder.orderTrackingUrl = ORDER_TRACK_URL%(long(merchantOrder.merchantOrderId))
188
            if self._saveToOrder(todict(merchantOrder)):
189
                resp['result'] = 'ORDER_CREATED'
190
            else:
191
                resp['result'] = 'ORDER_ALREADY_CREATED_IGNORED'
192
 
193
            return resp
194
        except:
195
            print "Error occurred"
196
            traceback.print_exc()
197
            resp['result'] = 'ORDER_NOT_CREATED'
198
            return resp
199
 
200
    def scrapeStoreOrders(self,):
201
        #collectionMap = {'palcedOn':1}
202
        searchMap = {}
203
        collectionMap = {"orderTrackingUrl":1,"merchantOrderId":1}
204
        orders = self._getActiveOrders(searchMap,collectionMap)
205
        for order in orders:
17098 manish.sha 206
            try:
207
                print "Order", self.store_name, order['orderId'], order['orderTrackingUrl'], order['merchantOrderId']
208
                br1 = track(HS_ORDER_TRACK_URL, order['merchantOrderId'])
209
                ungzipResponseBr(br1.response(), br1)
210
                trackPageSoup = BeautifulSoup(br1.response().read())
211
                subOrderTable = trackPageSoup.body.find("table", {'class':'lower-table'})
212
                subOrders = subOrderTable.findAll('tr', recursive=False)
213
                firstRow = subOrders.pop(0)
214
                closed = True
215
                for row in subOrders:
216
                    cols = row.find_all('td')
217
                    subOrderId = cols[0].text.strip()
218
                    subOrderStatus = cols[1].text.strip()
219
                    subbulk = self.db.merchantOrder.initialize_ordered_bulk_op()
220
                    print 'Sub Order Id', str(subOrderId)
221
                    subOrder =  self._isSubOrderActive(order, str(subOrderId))
222
                    if subOrder is None:
223
                        print 'No HS Sub Order Found for SubOrder Id:- '+ str(subOrderId)
224
                    elif subOrder['closed']:
225
                        continue
17013 manish.sha 226
                    else:
17098 manish.sha 227
                        findMap = {"orderId": order['orderId'], "subOrders.merchantSubOrderId": str(subOrderId)}
228
                        updateMap = {}
229
                        updateMap["subOrders.$.detailedStatus"] = subOrderStatus
230
                        status = self._getStatusFromDetailedStatus(subOrderStatus) 
231
                        closedStatus = status in [Store.ORDER_DELIVERED, Store.ORDER_CANCELLED]
232
                        if status is not None:
233
                            updateMap["subOrders.$.status"] = status
234
                        if closedStatus:
235
                            #if status is closed then change the paybackStatus accordingly
236
                            print 'Order Closed'
237
                            updateMap["subOrders.$.closed"] = True
238
                            if status == Store.ORDER_DELIVERED:
239
                                if subOrder.get("cashBackStatus") == Store.CB_PENDING:
240
                                    updateMap["subOrders.$.cashBackStatus"] = Store.CB_APPROVED
241
                            elif status == Store.ORDER_CANCELLED:
242
                                if subOrder.get("cashBackStatus") == Store.CB_PENDING:
243
                                    updateMap["subOrders.$.cashBackStatus"] = Store.CB_CANCELLED
244
                        else:
245
                            closed = False
246
                            print 'Order not Closed'
247
 
248
                        subbulk.find(findMap).update({'$set' : updateMap})
249
                        subresult = subbulk.execute()
250
                        tprint(subresult)
251
            except:
252
                print "Error occurred for tracking order... "+str(order['merchantOrderId'])
253
                traceback.print_exc()
254
                continue
17013 manish.sha 255
 
256
 
257
 
258
def track(url, orderId):
259
    br = getBrowserObject()
260
    br.set_proxies({"http": PROXY_MESH_GENERAL})
261
    br.open(url)
262
    response = br.open(url)
263
    ungzipResponseBr(response, br)
264
    soup = BeautifulSoup(br.response())
265
    csrf = soup.find('input', {'name': '_csrf'}).get('value')
266
    print csrf
267
    #html = response.read()
268
    #print html
269
    br.select_form(name='trackForm')
270
    br.form['orderId'] = str(orderId)
17098 manish.sha 271
    br.form['_csrf'] = str(csrf)
17013 manish.sha 272
    response = br.submit()
273
    print "********************"
274
    print "Attempting to Login"
275
    print "********************"
276
    #ungzipResponse(response, br)
277
    return br
278
 
279
def ungzipResponseBr(r,b):
280
    headers = r.info()
281
    if headers['Content-Encoding']=='gzip':
282
        import gzip
283
        print "********************"
284
        print "Deflating gzip response"
285
        print "********************"
286
        gz = gzip.GzipFile(fileobj=r, mode='rb')
287
        html = gz.read()
288
        gz.close()
289
        headers["Content-type"] = "text/html; charset=utf-8"
290
        r.set_data( html )
291
        b.set_response(r)
292
 
293
 
294
def to_py_date(java_timestamp):
295
    date = datetime.fromtimestamp(java_timestamp)
296
    return date       
297
 
298
def todict(obj, classkey=None):
299
    if isinstance(obj, dict):
300
        data = {}
301
        for (k, v) in obj.items():
302
            data[k] = todict(v, classkey)
303
        return data
304
    elif hasattr(obj, "_ast"):
305
        return todict(obj._ast())
306
    elif hasattr(obj, "__iter__"):
307
        return [todict(v, classkey) for v in obj]
308
    elif hasattr(obj, "__dict__"):
309
        data = dict([(key, todict(value, classkey)) 
310
            for key, value in obj.__dict__.iteritems() 
311
            if not callable(value) and not key.startswith('_')])
312
        if classkey is not None and hasattr(obj, "__class__"):
313
            data[classkey] = obj.__class__.__name__
314
        return data
315
    else:
316
        return obj