Subversion Repositories SmartDukaan

Rev

Rev 17013 | Rev 17046 | 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']))
17013 manish.sha 157
                subOrder.estimatedDeliveryDate = subOrderObj['cartItem']['shipment']['expectedDeliveryDate']
158
                subOrder.merchantSubOrderId = str(subOrderObj['subOrderId'])
159
                subOrder.detailedStatus = rawHtmlSoup.body.find("div", {'class':'sub-order-status'}).text
160
                subOrder.imgUrl = BASE_IMG_URL+subOrderObj['cartItem']['lineItemImageUrl']
17045 manish.sha 161
                subOrder.offerDiscount = long(subOrderObj['cartItem']['price'])*long(subOrderObj['cartItem']['itemQuantity'])-long(subOrderObj['pricing']['payablePrice'])
17013 manish.sha 162
                subOrder.unitPrice = long(subOrderObj['cartItem']['price'])
163
                subOrder.productCode = str(long(subOrderObj['cartItem']['productId']))
164
                subOrder.amountPaid = long(subOrderObj['cartItem']['pricing']['payablePrice'])
165
                subOrder.quantity = long(subOrderObj['cartItem']['itemQuantity'])
166
                subOrder.tracingkUrl = ORDER_TRACK_URL%(long(orderObj['orderId']))
167
                dealRank = getDealRank(subOrder.productCode, self.store_id, merchantOrder.userId)
168
                subOrder.dealRank = dealRank.get('rank')
169
                subOrder.rankDesc = dealRank.get('description')
170
                subOrder.maxNlc = dealRank.get('maxNlc')
171
                subOrder.minNlc = dealRank.get('minNlc')
172
                subOrder.db = dealRank.get('dp')
173
                subOrder.itemStatus = dealRank.get('status')
174
            merchantOrder.subOrders = self.updateCashbackInSubOrders(subOrders)
175
            return merchantOrder
176
 
177
 
178
    def parseOrderRawHtml(self, orderId, subTagId, userId, rawHtml, orderSuccessUrl):
179
        resp = {}
180
        try:
181
            rawHtmlSoup = BeautifulSoup(rawHtml)
182
            merchantOrder = self._parseUsingOrderJson(orderId, subTagId, userId, rawHtmlSoup, orderSuccessUrl)
183
            merchantOrder.orderTrackingUrl = ORDER_TRACK_URL%(long(merchantOrder.merchantOrderId))
184
            if self._saveToOrder(todict(merchantOrder)):
185
                resp['result'] = 'ORDER_CREATED'
186
            else:
187
                resp['result'] = 'ORDER_ALREADY_CREATED_IGNORED'
188
 
189
            return resp
190
        except:
191
            print "Error occurred"
192
            traceback.print_exc()
193
            resp['result'] = 'ORDER_NOT_CREATED'
194
            return resp
195
 
196
    def scrapeStoreOrders(self,):
197
        #collectionMap = {'palcedOn':1}
198
        searchMap = {}
199
        collectionMap = {"orderTrackingUrl":1,"merchantOrderId":1}
200
        orders = self._getActiveOrders(searchMap,collectionMap)
201
        for order in orders:
202
            print "Order", self.store_name, order['orderId'], order['orderTrackingUrl'], order['merchantOrderId']
203
            br1 = track(HS_ORDER_TRACK_URL, order['merchantOrderId'])
204
            ungzipResponseBr(br1.response(), br1)
205
            trackPageSoup = BeautifulSoup(br1.response().read())
206
            subOrderTable = trackPageSoup.body.find("table", {'class':'lower-table'})
207
            subOrders = subOrderTable.findAll('tr', recursive=False)
208
            firstRow = subOrders.pop(0)
209
 
210
            closed = True
211
            for row in subOrders:
212
                cols = row.find_all('td')
213
                subOrderId = cols[0].text.strip()
214
                subOrderStatus = cols[1].text.strip()
215
                subbulk = self.db.merchantOrder.initialize_ordered_bulk_op()
216
                print 'Sub Order Id', str(subOrderId)
217
                subOrder =  self._isSubOrderActive(order, str(subOrderId))
218
                if subOrder is None:
219
                    print 'No HS Sub Order Found for SubOrder Id:- '+ str(subOrderId)
220
                elif subOrder['closed']:
221
                    continue
222
                else:
223
                    findMap = {"orderId": order['orderId'], "subOrders.merchantSubOrderId": str(subOrderId)}
224
                    updateMap = {}
225
                    updateMap["subOrders.$.detailedStatus"] = subOrderStatus
226
                    status = self._getStatusFromDetailedStatus(subOrderStatus) 
227
                    closedStatus = status in [Store.ORDER_DELIVERED, Store.ORDER_CANCELLED]
228
                    if status is not None:
229
                        updateMap["subOrders.$.status"] = status
230
                    if closedStatus:
231
                        #if status is closed then change the paybackStatus accordingly
232
                        print 'Order Closed'
233
                        updateMap["subOrders.$.closed"] = True
234
                        if status == Store.ORDER_DELIVERED:
235
                            if subOrder.get("cashBackStatus") == Store.CB_PENDING:
236
                                updateMap["subOrders.$.cashBackStatus"] = Store.CB_APPROVED
237
                        elif status == Store.ORDER_CANCELLED:
238
                            if subOrder.get("cashBackStatus") == Store.CB_PENDING:
239
                                updateMap["subOrders.$.cashBackStatus"] = Store.CB_CANCELLED
240
                    else:
241
                        closed = False
242
                        print 'Order not Closed'
243
 
244
                    subbulk.find(findMap).update({'$set' : updateMap})
245
                    subresult = subbulk.execute()
246
                    tprint(subresult)
247
 
248
 
249
 
250
def track(url, orderId):
251
    br = getBrowserObject()
252
    br.set_proxies({"http": PROXY_MESH_GENERAL})
253
    br.open(url)
254
    response = br.open(url)
255
    ungzipResponseBr(response, br)
256
    soup = BeautifulSoup(br.response())
257
    csrf = soup.find('input', {'name': '_csrf'}).get('value')
258
    print csrf
259
    #html = response.read()
260
    #print html
261
    br.select_form(name='trackForm')
262
    br.form['orderId'] = str(orderId)
263
    response = br.submit()
264
    print "********************"
265
    print "Attempting to Login"
266
    print "********************"
267
    #ungzipResponse(response, br)
268
    return br
269
 
270
def ungzipResponseBr(r,b):
271
    headers = r.info()
272
    if headers['Content-Encoding']=='gzip':
273
        import gzip
274
        print "********************"
275
        print "Deflating gzip response"
276
        print "********************"
277
        gz = gzip.GzipFile(fileobj=r, mode='rb')
278
        html = gz.read()
279
        gz.close()
280
        headers["Content-type"] = "text/html; charset=utf-8"
281
        r.set_data( html )
282
        b.set_response(r)
283
 
284
 
285
def to_py_date(java_timestamp):
286
    date = datetime.fromtimestamp(java_timestamp)
287
    return date       
288
 
289
def todict(obj, classkey=None):
290
    if isinstance(obj, dict):
291
        data = {}
292
        for (k, v) in obj.items():
293
            data[k] = todict(v, classkey)
294
        return data
295
    elif hasattr(obj, "_ast"):
296
        return todict(obj._ast())
297
    elif hasattr(obj, "__iter__"):
298
        return [todict(v, classkey) for v in obj]
299
    elif hasattr(obj, "__dict__"):
300
        data = dict([(key, todict(value, classkey)) 
301
            for key, value in obj.__dict__.iteritems() 
302
            if not callable(value) and not key.startswith('_')])
303
        if classkey is not None and hasattr(obj, "__class__"):
304
            data[classkey] = obj.__class__.__name__
305
        return data
306
    else:
307
        return obj