Subversion Repositories SmartDukaan

Rev

Rev 17047 | Rev 17054 | 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']
17045 manish.sha 164
                subOrder.offerDiscount = long(subOrderObj['cartItem']['price'])*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:
206
            print "Order", self.store_name, order['orderId'], order['orderTrackingUrl'], order['merchantOrderId']
207
            br1 = track(HS_ORDER_TRACK_URL, order['merchantOrderId'])
208
            ungzipResponseBr(br1.response(), br1)
209
            trackPageSoup = BeautifulSoup(br1.response().read())
210
            subOrderTable = trackPageSoup.body.find("table", {'class':'lower-table'})
211
            subOrders = subOrderTable.findAll('tr', recursive=False)
212
            firstRow = subOrders.pop(0)
213
 
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
226
                else:
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
 
252
 
253
 
254
def track(url, orderId):
255
    br = getBrowserObject()
256
    br.set_proxies({"http": PROXY_MESH_GENERAL})
257
    br.open(url)
258
    response = br.open(url)
259
    ungzipResponseBr(response, br)
260
    soup = BeautifulSoup(br.response())
261
    csrf = soup.find('input', {'name': '_csrf'}).get('value')
262
    print csrf
263
    #html = response.read()
264
    #print html
265
    br.select_form(name='trackForm')
266
    br.form['orderId'] = str(orderId)
267
    response = br.submit()
268
    print "********************"
269
    print "Attempting to Login"
270
    print "********************"
271
    #ungzipResponse(response, br)
272
    return br
273
 
274
def ungzipResponseBr(r,b):
275
    headers = r.info()
276
    if headers['Content-Encoding']=='gzip':
277
        import gzip
278
        print "********************"
279
        print "Deflating gzip response"
280
        print "********************"
281
        gz = gzip.GzipFile(fileobj=r, mode='rb')
282
        html = gz.read()
283
        gz.close()
284
        headers["Content-type"] = "text/html; charset=utf-8"
285
        r.set_data( html )
286
        b.set_response(r)
287
 
288
 
289
def to_py_date(java_timestamp):
290
    date = datetime.fromtimestamp(java_timestamp)
291
    return date       
292
 
293
def todict(obj, classkey=None):
294
    if isinstance(obj, dict):
295
        data = {}
296
        for (k, v) in obj.items():
297
            data[k] = todict(v, classkey)
298
        return data
299
    elif hasattr(obj, "_ast"):
300
        return todict(obj._ast())
301
    elif hasattr(obj, "__iter__"):
302
        return [todict(v, classkey) for v in obj]
303
    elif hasattr(obj, "__dict__"):
304
        data = dict([(key, todict(value, classkey)) 
305
            for key, value in obj.__dict__.iteritems() 
306
            if not callable(value) and not key.startswith('_')])
307
        if classkey is not None and hasattr(obj, "__class__"):
308
            data[classkey] = obj.__class__.__name__
309
        return data
310
    else:
311
        return obj