Subversion Repositories SmartDukaan

Rev

Rev 17112 | Rev 17118 | 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:
17112 manish.sha 206
            bulk = self.db.merchantOrder.initialize_ordered_bulk_op()
17098 manish.sha 207
            try:
208
                print "Order", self.store_name, order['orderId'], order['orderTrackingUrl'], order['merchantOrderId']
209
                br1 = track(HS_ORDER_TRACK_URL, order['merchantOrderId'])
210
                ungzipResponseBr(br1.response(), br1)
17112 manish.sha 211
                trackPageSoup = BeautifulSoup(br1.response())
17098 manish.sha 212
                subOrderTable = trackPageSoup.body.find("table", {'class':'lower-table'})
17112 manish.sha 213
                subOrders = subOrderTable.find_all('tr')
17098 manish.sha 214
                firstRow = subOrders.pop(0)
215
                closed = True
216
                for row in subOrders:
217
                    cols = row.find_all('td')
218
                    subOrderId = cols[0].text.strip()
219
                    subOrderStatus = cols[1].text.strip()
220
                    subbulk = self.db.merchantOrder.initialize_ordered_bulk_op()
221
                    print 'Sub Order Id', str(subOrderId)
222
                    subOrder =  self._isSubOrderActive(order, str(subOrderId))
223
                    if subOrder is None:
224
                        print 'No HS Sub Order Found for SubOrder Id:- '+ str(subOrderId)
225
                    elif subOrder['closed']:
226
                        continue
17013 manish.sha 227
                    else:
17098 manish.sha 228
                        findMap = {"orderId": order['orderId'], "subOrders.merchantSubOrderId": str(subOrderId)}
229
                        updateMap = {}
230
                        updateMap["subOrders.$.detailedStatus"] = subOrderStatus
231
                        status = self._getStatusFromDetailedStatus(subOrderStatus) 
232
                        closedStatus = status in [Store.ORDER_DELIVERED, Store.ORDER_CANCELLED]
233
                        if status is not None:
234
                            updateMap["subOrders.$.status"] = status
235
                        if closedStatus:
236
                            #if status is closed then change the paybackStatus accordingly
237
                            print 'Order Closed'
238
                            updateMap["subOrders.$.closed"] = True
239
                            if status == Store.ORDER_DELIVERED:
240
                                if subOrder.get("cashBackStatus") == Store.CB_PENDING:
241
                                    updateMap["subOrders.$.cashBackStatus"] = Store.CB_APPROVED
242
                            elif status == Store.ORDER_CANCELLED:
243
                                if subOrder.get("cashBackStatus") == Store.CB_PENDING:
244
                                    updateMap["subOrders.$.cashBackStatus"] = Store.CB_CANCELLED
245
                        else:
246
                            closed = False
247
                            print 'Order not Closed'
248
 
249
                        subbulk.find(findMap).update({'$set' : updateMap})
250
                        subresult = subbulk.execute()
251
                        tprint(subresult)
17112 manish.sha 252
                bulk.find({'orderId': order['orderId']}).update({'$set':{'closed': closed,"parseError":False}})
253
                result = bulk.execute()
254
                tprint(result)
17098 manish.sha 255
            except:
256
                print "Error occurred for tracking order... "+str(order['merchantOrderId'])
257
                traceback.print_exc()
258
                continue
17013 manish.sha 259
 
260
 
261
 
262
def track(url, orderId):
263
    br = getBrowserObject()
264
    br.set_proxies({"http": PROXY_MESH_GENERAL})
265
    response = br.open(url)
266
    ungzipResponseBr(response, br)
267
    soup = BeautifulSoup(br.response())
268
    csrf = soup.find('input', {'name': '_csrf'}).get('value')
269
    print csrf
270
    #html = response.read()
271
    #print html
272
    br.select_form(name='trackForm')
273
    br.form['orderId'] = str(orderId)
274
    response = br.submit()
275
    print "********************"
276
    print "Attempting to Login"
277
    print "********************"
278
    #ungzipResponse(response, br)
279
    return br
280
 
281
def ungzipResponseBr(r,b):
282
    headers = r.info()
283
    if headers['Content-Encoding']=='gzip':
284
        import gzip
285
        print "********************"
286
        print "Deflating gzip response"
287
        print "********************"
288
        gz = gzip.GzipFile(fileobj=r, mode='rb')
289
        html = gz.read()
290
        gz.close()
291
        headers["Content-type"] = "text/html; charset=utf-8"
292
        r.set_data( html )
293
        b.set_response(r)
294
 
295
 
296
def to_py_date(java_timestamp):
297
    date = datetime.fromtimestamp(java_timestamp)
298
    return date       
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