Subversion Repositories SmartDukaan

Rev

Rev 14465 | Rev 14545 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
13774 amit.gupta 1
# coding=utf-8
13569 amit.gupta 2
'''
3
Created on Jan 15, 2015
4
 
5
@author: amit
6
'''
13774 amit.gupta 7
from base64 import encode
8
from bs4 import BeautifulSoup
14162 amit.gupta 9
from datetime import datetime
13774 amit.gupta 10
from dtr.dao import Order, SubOrder
14464 amit.gupta 11
from dtr.main import getStore, Store as MStore, ParseException, getBrowserObject, \
12
    ungzipResponse
13774 amit.gupta 13
from dtr.sources.flipkart import todict
14162 amit.gupta 14
from paramiko import sftp
15
from paramiko.client import SSHClient
16
from paramiko.sftp_client import SFTPClient
14285 amit.gupta 17
import os.path
14162 amit.gupta 18
import paramiko
13774 amit.gupta 19
import re
14033 amit.gupta 20
import time
13809 amit.gupta 21
import traceback
13774 amit.gupta 22
 
23
ORDER_REDIRECT_URL = 'https://www.amazon.in/gp/css/summary/edit.html?orderID=%s'
13810 amit.gupta 24
ORDER_SUCCESS_URL = 'https://www.amazon.in/gp/buy/spc/handlers/static-submit-decoupled.html'
13823 amit.gupta 25
THANKYOU_URL = 'https://www.amazon.in/gp/buy/thankyou/handlers/display.html'
13774 amit.gupta 26
class Store(MStore):
13821 amit.gupta 27
 
14032 amit.gupta 28
    orderStatusRegexMap = { MStore.ORDER_PLACED : ['ordered from', 'not yet dispatched','dispatching now', 'preparing for dispatch'],
14064 amit.gupta 29
                            MStore.ORDER_SHIPPED : ['dispatched on','dispatched', 'on the way', 'out for delivery', 'Out for delivery'],
14032 amit.gupta 30
                            MStore.ORDER_CANCELLED : ['return complete', 'refunded', 'cancelled'],
31
                            MStore.ORDER_DELIVERED : ['delivered']
13821 amit.gupta 32
                           }
13774 amit.gupta 33
 
34
    def __init__(self,store_id):
35
        super(Store, self).__init__(store_id)
36
 
37
    def getName(self):
38
        return "flipkart"
39
 
14202 amit.gupta 40
    def parseOrderRawHtml(self, orderId, subTagId, userId, rawHtml, orderSuccessUrl, insert=False):
13796 amit.gupta 41
        resp = {}
13821 amit.gupta 42
        if ORDER_SUCCESS_URL in orderSuccessUrl or THANKYOU_URL in orderSuccessUrl:
13774 amit.gupta 43
            try:
44
                soup = BeautifulSoup(rawHtml)
45
                orderUrl = soup.find('div', {"id":"thank-you-box-wrapper"}).div.findAll('div', recursive=False)[1].a['href']
14202 amit.gupta 46
                merchantOrderId = re.findall(r'.*&oid=(.*)&?.*?', orderUrl)[0]
14211 amit.gupta 47
                order = Order(orderId, userId, subTagId, self.store_id, orderSuccessUrl, False)
48
                order.orderSuccessUrl = ORDER_REDIRECT_URL % (merchantOrderId)
49
                order.merchantOrderId = merchantOrderId
14291 amit.gupta 50
                order.requireDetail = True
14297 amit.gupta 51
                order.closed = None
14312 amit.gupta 52
                if self._saveToOrder(todict(order)):
53
                    resp['result'] = 'ORDER_CREATED'
54
                    resp["url"] = ORDER_REDIRECT_URL % (merchantOrderId)
55
                    resp["htmlRequired"] = True
56
                    resp['orderId'] = orderId
57
                else:
58
                    resp['result'] = 'ORDER_ALREADY_CREATED_IGNORED'
59
 
13796 amit.gupta 60
                return resp
13774 amit.gupta 61
            except:
14312 amit.gupta 62
                resp["result"] = 'ORDER_NOT_CREATED'
13796 amit.gupta 63
                return resp
13774 amit.gupta 64
 
65
        else:
13781 amit.gupta 66
            try:
67
                merchantOrder = Order(orderId, userId, subTagId, self.store_id, orderSuccessUrl)
14464 amit.gupta 68
                soup = BeautifulSoup(rawHtml)
69
                try:
70
                    self.parseOldStlye(merchantOrder, soup)
71
                except:
72
                    self.parseNewStlye(merchantOrder, soup)
14319 amit.gupta 73
                resp['result'] = 'ORDER_CREATED'
74
                return resp    
13781 amit.gupta 75
            except:
13809 amit.gupta 76
                print "Error occurred"
77
                traceback.print_exc()
14312 amit.gupta 78
                resp['result'] = 'ORDER_NOT_CREATED'
13796 amit.gupta 79
                return resp    
13774 amit.gupta 80
 
13868 amit.gupta 81
    #This should be exposed from api for specific sources
82
    def scrapeStoreOrders(self):
83
        pass
84
 
14464 amit.gupta 85
    def parseOldStlye(self, merchantOrder, soup):
86
        merchantOrder.orderTrackingUrl = merchantOrder.orderSuccessUrl
87
        table = soup.body.findAll("table", recursive=False)[1]
88
        #print table
89
        tables = table.tr.td.findAll("table", recursive=False)
90
        for tr in tables[2].findAll("tr"):
91
            boldElement = tr.td.b
92
            if "Order Placed" in str(boldElement):
93
                merchantOrder.placedOn = boldElement.next_sibling.strip()
94
            if "order number" in str(boldElement):
95
                merchantOrder.merchantOrderId = boldElement.next_sibling.strip()
96
            if "Order Total" in str(boldElement):
97
                merchantOrder.paidAmount = int(float(boldElement.find('span').contents[-1].replace(',','')))
98
        anchors = table.tr.td.findAll("a", recursive=False)
99
        paymentAnchor = anchors.pop(-1)
100
 
101
        count = 0
102
        subOrders = []
103
        merchantOrder.subOrders = subOrders
104
        counter = 0 
105
        for anchor in anchors:
106
            count += 1
107
            tab = anchor.next_sibling
108
            status = MStore.ORDER_PLACED
109
            subStr = "Delivery #" + str(count) + ":"
110
            if subStr in  tab.find("b").text:
111
                detailedStatus = tab.find("b").text.replace(subStr, '').strip()
112
 
113
            tab = tab.next_sibling.next_sibling
114
            trs = tab.find("table").find('tbody').findAll("tr", recursive = False)
115
 
116
            estimatedDelivery = trs[0].td.find("b").next_sibling.strip()
117
 
118
            orderItemTrs = trs[1].findAll("td", recursive=False)[1].table.tbody.findAll("tr", recursive = False)
119
            i = -1
120
            for orderItemTr in orderItemTrs:
121
                i += 1
122
                if i%2 == 0:
123
                    continue
124
                counter += 1
125
                quantity =  int(re.findall(r'\d+', orderItemTr.td.contents[0])[0])
126
 
127
                productUrl = orderItemTr.td.contents[1].a["href"]
128
                productTitle = orderItemTr.td.contents[1].a.text
129
 
130
                unitPrice = int(float(orderItemTr.findAll('td')[1].span.text.replace('Rs. ','').replace(',','')))
131
 
132
 
133
                subOrder = SubOrder(productTitle, productUrl, merchantOrder.placedOn, unitPrice*quantity, status, quantity)
134
                subOrder.merchantSubOrderId = str(counter) + " of " + merchantOrder.merchantOrderId
135
                subOrder.estimatedDeliveryDate = estimatedDelivery
136
                subOrder.productCode = productUrl.split('/')[5]
137
                subOrder.detailedStatus = detailedStatus
138
                (cashbackAmount, percentage) = self.getCashbackAmount(subOrder.productCode, unitPrice*quantity)
139
                cashbackStatus = Store.CB_PENDING
140
                if cashbackAmount <= 0:
141
                    cashbackStatus = Store.CB_NA
142
                subOrder.cashBackStatus = cashbackStatus
143
                subOrder.cashBackAmount = cashbackAmount
144
                if percentage > 0:
145
                    subOrder.cashBackPercentage = percentage
146
                subOrders.append(subOrder)
147
        priceList = paymentAnchor.next_sibling.next_sibling.next_sibling.table.table.tbody.tbody.tbody.findAll('tr', recursive=False)
148
        totalAmount = 0
149
        grandAmount = 0
150
        for price in priceList:
151
            labelTd = price.td
152
            if 'Subtotal:' in labelTd.text:
153
                totalAmount += int(float(labelTd.next_sibling.next_sibling.find('span').contents[-1].replace(',','')))
154
            elif 'Grand Total:' in labelTd.text:
155
                grandAmount += int(float(labelTd.next_sibling.next_sibling.find('span').contents[-1].replace(',','')))
156
        if grandAmount < totalAmount:
157
            diff = totalAmount - grandAmount
158
            for subOrder in merchantOrder.subOrders:
159
                subOrder.amountPaid -= int(diff*(1-subOrder.amountPaid/totalAmount))
160
        self._updateToOrder(todict(merchantOrder))
161
 
162
    def parseNewStlye(self, merchantOrder, soup):
163
        merchantOrder.orderTrackingUrl = merchantOrder.orderSuccessUrl
164
        orderDetailsContainer = soup.body.find(id="orderDetails")
165
        orderLeftDiv = orderDetailsContainer.h1.next_sibling.next_sibling.div
166
        placedOnSpan = orderLeftDiv.find("span", {'class':'order-date-invoice-item'})
167
        merchantOrder.placedOn =placedOnSpan.text.split('Ordered on')[1].strip()
168
        merchantOrder.merchantOrderId = placedOnSpan.next_sibling.next_sibling.text.split('Order#')[1].strip()
169
        priceBox = orderDetailsContainer.find('div', {'class':re.compile(r'\ba-box-inner\b')}).div.div.findAll('div', recursive=False)[-1]
170
        priceRows = priceBox.findAll('div', {'class':'a-row'})
171
        subTotal = 0
172
        shippingPrice = 0
173
        promoApplied = 0
174
        for priceRow in priceRows:
175
            if "Item(s) Subtotal:" in str(priceRow):
176
                subTotal = int(float(priceRow.div.next_sibling.next_sibling.span.span.text.replace('Rs.','').replace(',', '')))
177
            elif "Shipping:" in str(priceRow):
178
                shippingPrice  = int(float(priceRow.div.next_sibling.next_sibling.span.span.text.replace('Rs.','').replace(',', '')))
179
            elif "Grand Total:" in str(priceRow):
180
                grandPrice  = int(float(priceRow.div.next_sibling.next_sibling.span.span.text.replace('Rs.','').replace(',', '')))
181
                merchantOrder.paidAmount = grandPrice
182
            elif "Total:" in str(priceRow):
183
                totalPrice  = int(float(priceRow.div.next_sibling.next_sibling.span.span.text.replace('Rs.','').replace(',', '')))
184
            elif "Promotion Applied:" in str(priceRow):
185
                promoApplied  += int(float(priceRow.div.next_sibling.next_sibling.span.span.text.replace('Rs.','').replace(',', '')))
186
        totalPaid = subTotal        
187
        if promoApplied > 0:
188
            totalPaid -= promoApplied
189
            if shippingPrice <= promoApplied:
190
                totalPaid  += shippingPrice
191
 
192
        shipmentDivs = orderDetailsContainer.find('div', {'class':'a-box shipment'}).findAll('div', recursive = False)
193
        subOrders = []
194
        merchantOrder.subOrders = subOrders
195
        i=1
196
        for shipmentDiv in shipmentDivs:
197
            innerBoxes = shipmentDiv.findAll('div', recursive = False)
198
            statusDiv = innerBoxes[0]
199
            subOrderStatus = statusDiv.div.span.text.strip()
200
            estimatedDeliveryDate = statusDiv.div.div.find_next_sibling('div').span.span.text.strip()
201
            productDivs = innerBoxes[-1].div.div.div.findAll('div', recursive=False)
202
            subOrders = []
203
            merchantOrder.subOrders = subOrders
204
            for i, productDiv in enumerate(productDivs):
205
                i +=1 
206
                imgDiv  = productDiv.div.div
207
                detailDiv = imgDiv.find_next_sibling('div')
208
                detailDivs = detailDiv.findAll('div', recursive=False)
209
                arr = detailDivs[0].a.text.strip().split(" of ", 1)
14465 amit.gupta 210
                (productTitle, quantity) = (arr[-1], (1 if len(arr)==1 else int(arr[0])) )
14464 amit.gupta 211
                unitPrice = int(float(detailDivs[2].span.text.replace('Rs. ','').replace(',','')))
212
                amountPaid = int((unitPrice*quantity*totalPaid)/subTotal)
213
                productUrl = "http://www.amazon.in" + detailDivs[0].a.get('href')
214
                subOrder = SubOrder(productTitle, productUrl, merchantOrder.placedOn, amountPaid, MStore.ORDER_PLACED, quantity)
215
                subOrder.productCode = productUrl.split('/')[5]
216
                subOrder.unitPrice = unitPrice
217
                subOrder.merchantSubOrderId = str(i) + " of " + merchantOrder.merchantOrderId 
218
                subOrder.estimatedDeliveryDate = estimatedDeliveryDate
219
                subOrder.detailedStatus = subOrderStatus
220
                subOrder.deliveryCharges = shippingPrice
14466 amit.gupta 221
                subOrder.imgUrl = imgDiv.img["src"]
14464 amit.gupta 222
                (cashbackAmount, percentage) = self.getCashbackAmount(subOrder.productCode, amountPaid)
223
                cashbackStatus = Store.CB_PENDING
224
                if cashbackAmount <= 0:
225
                    cashbackStatus = Store.CB_NA
226
                subOrder.cashBackStatus = cashbackStatus
227
                subOrder.cashBackAmount = cashbackAmount
228
                if percentage > 0:
229
                    subOrder.cashBackPercentage = percentage
230
                subOrders.append(subOrder)
231
        self._updateToOrder(todict(merchantOrder))
232
 
13868 amit.gupta 233
    def getTrackingUrls(self, userId):
14074 amit.gupta 234
 
235
        missingOrderUrls = []
236
        missingOrders = self._getMissingOrders({'userId':userId})
237
        for missingOrder in missingOrders:
238
            missingOrderUrls.append(ORDER_REDIRECT_URL%(missingOrder['merchantOrderId']))
13879 amit.gupta 239
        orders = self._getActiveOrders({'userId':userId})
13882 amit.gupta 240
        count = len(orders)
13879 amit.gupta 241
        print "count", count
13868 amit.gupta 242
        if count > 0:
14320 amit.gupta 243
            return missingOrderUrls + ['https://www.amazon.in/gp/css/order-history', 'https://www.amazon.in/gp/css/order-history/?orderFilter=cancelled', 'https://www.amazon.in/gp/css/order-history?orderFilter=cancelled&startIndex=10']
13959 amit.gupta 244
        else: 
14074 amit.gupta 245
            return missingOrderUrls
13927 amit.gupta 246
 
247
    def trackOrdersForUser(self, userId, url, rawHtml):
14285 amit.gupta 248
        directory = "/tmp/User" + str(userId)
249
        if not os.path.exists(directory):
250
            os.makedirs(directory)
14298 amit.gupta 251
        filename = directory + "/" + str(datetime.now())
252
        print "filename---", filename
253
        f = open(filename,'w')
14173 amit.gupta 254
        f.write(rawHtml) # python will convert \n to os.linesep
255
        f.close() # you can omit in most cases as the destructor will call if
256
 
13995 amit.gupta 257
        try:
258
            searchMap = {'userId':userId}
259
            collectionMap = {'merchantOrderId':1}
260
            activeOrders = self._getActiveOrders(searchMap, collectionMap)
14033 amit.gupta 261
            datetimeNow = datetime.now()
262
            timestamp = int(time.mktime(datetimeNow.timetuple()))
14009 amit.gupta 263
            print "url----------------", url
14008 amit.gupta 264
 
14320 amit.gupta 265
            if url == 'https://www.amazon.in/gp/css/order-history' or 'https://www.amazon.in/gp/css/order-history/?orderFilter=cancelled' in url:
13995 amit.gupta 266
                soup = BeautifulSoup(rawHtml)
267
                allOrders = soup.find(id="ordersContainer").findAll('div', {'class':'a-box-group a-spacing-base order'})
268
                bulk = self.db.merchantOrder.initialize_ordered_bulk_op()
269
                for activeOrder in activeOrders:
270
                    for orderEle in allOrders:
271
                        orderdiv = orderEle.find('div', {'class':'a-box a-color-offset-background order-info'}).find('div', {'class':'a-fixed-right-grid-col actions a-col-right'})
272
                        merchantOrderId = orderdiv.find('span', {'class':'a-color-secondary value'}).text.strip()
273
                        if merchantOrderId==activeOrder['merchantOrderId']:
274
                            closed = True
275
                            shipments = orderEle.findAll('div',{'class':re.compile('.*?a-box.*?')}, recursive=False)
276
                            shipments.pop(0)
277
                            for shipment in shipments:
278
                                shipdiv = shipment.find('div', {'class':'a-box-inner'})
14050 amit.gupta 279
                                sdivs = shipment.div.div.findAll('div', recursive=False)
14065 amit.gupta 280
                                orderStatus = sdivs[0].span.text.strip()
14050 amit.gupta 281
                                status = self._getStatusFromDetailedStatus(orderStatus)
282
                                if status == MStore.ORDER_DELIVERED:
14299 amit.gupta 283
                                    deliveredOn = sdivs[0].findAll('span')[-1].text.strip()
14050 amit.gupta 284
                                    deliveredOn = deliveredOn.split(":")[1].strip()
14335 amit.gupta 285
                                deliveryestimatespan = sdivs[0].find('span', {'class':'a-color-success'})
286
                                deliveryEstimate = None
287
                                if deliveryestimatespan is not None:
288
                                    deliveryEstimate = deliveryestimatespan.find('span', {'class':'a-text-bold'}).text.strip()
289
                                productDivs = shipdiv.find('div', {'class':re.compile('.*?a-spacing-top-medium.*?')}).find('div', {'class':'a-row'}).findAll('div', recursive=False)
13995 amit.gupta 290
                                trackingUrl = None
291
                                for buttonDiv in shipdiv.findAll('span', {'class':'a-button-inner'}):
292
                                    if buttonDiv.find('a').text.strip()=='Track package':
293
                                        trackingUrl = buttonDiv.find('a')['href'].strip()
294
                                        if not trackingUrl.startswith("http"):
295
                                            trackingUrl = "https://www.amazon.in/" + trackingUrl
296
                                        break
297
                                for prodDiv in productDivs:
298
                                    prodDiv.find('div', {'class':'a-fixed-left-grid-inner'})
299
                                    productTitle = prodDiv.find('div', {'class':'a-fixed-left-grid-inner'}).find("div", {'class':'a-row'}).find('a').text.strip()
300
                                    imgUrl = prodDiv.find("img")["src"]
301
                                    for subOrder in activeOrder['subOrders']:
302
                                        if subOrder['productTitle'] == productTitle:
303
                                            findMap = {"orderId": activeOrder['orderId'], "subOrders.merchantSubOrderId": subOrder.get("merchantSubOrderId")}
304
                                            updateMap = {}
305
                                            closedStatus = False
306
                                            updateMap['subOrders.$.imgUrl'] = imgUrl
14033 amit.gupta 307
                                            updateMap['subOrders.$.lastTracked'] = timestamp
13995 amit.gupta 308
                                            updateMap['subOrders.$.detailedStatus'] = orderStatus
309
                                            cashbackStatus = subOrder.get("cashBackStatus")
310
                                            updateMap['subOrders.$.status'] = status 
311
 
312
                                            if status==MStore.ORDER_DELIVERED:                               
14291 amit.gupta 313
                                                updateMap['subOrders.$.deliveredOn'] = deliveredOn
13995 amit.gupta 314
                                                closedStatus = True
315
                                                updateMap['subOrders.$.closed'] = True
316
                                                if cashbackStatus == Store.CB_PENDING:
317
                                                    updateMap['subOrders.$.cashbackStatus'] = Store.CB_APPROVED
318
                                            if status==MStore.ORDER_CANCELLED:     
319
                                                closedStatus = True
320
                                                updateMap['subOrders.$.closed'] = True
321
                                                if cashbackStatus == Store.CB_PENDING:
322
                                                    updateMap['subOrders.$.cashBackStatus'] = Store.CB_CANCELLED
323
                                            if status==MStore.ORDER_SHIPPED:   
324
                                                updateMap['subOrders.$.estimatedDeliveryDate'] = deliveryEstimate
325
                                                if trackingUrl is not None:
326
                                                    updateMap['subOrders.$.trackingUrl'] = trackingUrl
327
                                            if not closedStatus:
328
                                                closed = False
329
                                            bulk.find(findMap).update({'$set' : updateMap})
330
                                            break
331
                            bulk.find({'orderId': activeOrder['orderId']}).update({'$set':{'closed': closed}})            
14080 amit.gupta 332
                bulk.execute()
333
                return 'PARSED_SUCCESS'
334
            else:
14086 amit.gupta 335
                merchantOrderId = re.findall(r'https://www.amazon.in/gp/css/summary/edit.html\?orderID=(.*)?', url, re.IGNORECASE)[0] 
14085 amit.gupta 336
                merchantOrder = self.db.merchantOrder.find_one({"merchantOrderId":merchantOrderId})
14312 amit.gupta 337
                self.parseOrderRawHtml(merchantOrder['orderId'], merchantOrder['subTagId'], merchantOrder['userId'], rawHtml, url, False)['result']
14080 amit.gupta 338
                return 'PARSED_SUCCESS'
339
                pass
14008 amit.gupta 340
            return 'PARSED_SUCCESS_NO_ORDERS'
13995 amit.gupta 341
        except:
342
            traceback.print_exc()    
343
            return 'PARSED_FAILED'
344
 
345
    def _getStatusFromDetailedStatus(self, detailedStatus):
14061 amit.gupta 346
        if "ordered from" in detailedStatus.lower():
347
            return MStore.ORDER_PLACED 
348
 
13995 amit.gupta 349
        for key, value in self.orderStatusRegexMap.iteritems():
14032 amit.gupta 350
            if detailedStatus.lower() in value:
13995 amit.gupta 351
                return key
352
 
353
        print "Detailed Status need to be mapped"
14062 amit.gupta 354
        print "Found new order status", detailedStatus
13995 amit.gupta 355
        raise ParseException("_getStatusFromDetailedStatus", "Found new order status" + detailedStatus)
13927 amit.gupta 356
 
357
 
13774 amit.gupta 358
def main():
359
    store = getStore(1)
14464 amit.gupta 360
    #store.scrapeStoreOrders()    
361
    store.parseOrderRawHtml(1, 'saad', '21232211', readSSh('/tmp/1.html'), 'https://www.amazon.in/gp/css/summary/edit.html?orderID=12212')
362
    #store.trackOrdersForUser(8,'https://www.amazon.in/gp/css/order-history', readSSh('/tmp/User2/2015-03-03 00:29:40.165513'))
363
    #readSSh('snapdeal.csv')
14162 amit.gupta 364
def readSSh(fileName):
365
    try:
366
            str1 = open(fileName).read()
367
            return str1
368
    except:
369
        ssh_client = SSHClient()
370
        str1 = ""
371
        ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
372
        ssh_client.connect('104.200.25.40', 22, 'root', 'ecip$dtrMay2014')
373
        sftp_client = ssh_client.open_sftp()
374
        try:
14299 amit.gupta 375
            if not os.path.exists(os.path.dirname(fileName)):
376
                os.makedirs(os.path.dirname(fileName))
14162 amit.gupta 377
            sftp_client.get(fileName, fileName)
378
            try:
379
                str1 = open(fileName).read()
380
                return str1
381
            finally:
382
                pass
383
        except:
384
            "could not read"
385
        return str1
13774 amit.gupta 386
 
387
 
388
if __name__ == '__main__':
14284 amit.gupta 389
        main()