Subversion Repositories SmartDukaan

Rev

Rev 14294 | Rev 14297 | 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
13995 amit.gupta 11
from dtr.main import getStore, Store as MStore, ParseException
13774 amit.gupta 12
from dtr.sources.flipkart import todict
14162 amit.gupta 13
from paramiko import sftp
14
from paramiko.client import SSHClient
15
from paramiko.sftp_client import SFTPClient
14285 amit.gupta 16
import os.path
14162 amit.gupta 17
import paramiko
13774 amit.gupta 18
import re
14033 amit.gupta 19
import time
13809 amit.gupta 20
import traceback
13774 amit.gupta 21
 
22
ORDER_REDIRECT_URL = 'https://www.amazon.in/gp/css/summary/edit.html?orderID=%s'
13810 amit.gupta 23
ORDER_SUCCESS_URL = 'https://www.amazon.in/gp/buy/spc/handlers/static-submit-decoupled.html'
13823 amit.gupta 24
THANKYOU_URL = 'https://www.amazon.in/gp/buy/thankyou/handlers/display.html'
13774 amit.gupta 25
class Store(MStore):
13821 amit.gupta 26
 
14032 amit.gupta 27
    orderStatusRegexMap = { MStore.ORDER_PLACED : ['ordered from', 'not yet dispatched','dispatching now', 'preparing for dispatch'],
14064 amit.gupta 28
                            MStore.ORDER_SHIPPED : ['dispatched on','dispatched', 'on the way', 'out for delivery', 'Out for delivery'],
14032 amit.gupta 29
                            MStore.ORDER_CANCELLED : ['return complete', 'refunded', 'cancelled'],
30
                            MStore.ORDER_DELIVERED : ['delivered']
13821 amit.gupta 31
                           }
13774 amit.gupta 32
 
33
    def __init__(self,store_id):
34
        super(Store, self).__init__(store_id)
35
 
36
    def getName(self):
37
        return "flipkart"
38
 
14202 amit.gupta 39
    def parseOrderRawHtml(self, orderId, subTagId, userId, rawHtml, orderSuccessUrl, insert=False):
13796 amit.gupta 40
        resp = {}
13821 amit.gupta 41
        if ORDER_SUCCESS_URL in orderSuccessUrl or THANKYOU_URL in orderSuccessUrl:
13774 amit.gupta 42
            try:
43
                soup = BeautifulSoup(rawHtml)
44
                orderUrl = soup.find('div', {"id":"thank-you-box-wrapper"}).div.findAll('div', recursive=False)[1].a['href']
14202 amit.gupta 45
                merchantOrderId = re.findall(r'.*&oid=(.*)&?.*?', orderUrl)[0]
13796 amit.gupta 46
                resp["result"] = 'HTML_REQUIRED'
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
14211 amit.gupta 51
                self._saveToOrder(todict(order))
14202 amit.gupta 52
                resp["url"] = ORDER_REDIRECT_URL % (merchantOrderId)
13796 amit.gupta 53
                return resp
13774 amit.gupta 54
            except:
13796 amit.gupta 55
                resp["result"] = 'IGNORED'
56
                return resp
13774 amit.gupta 57
 
58
        else:
13781 amit.gupta 59
            try:
60
                merchantOrder = Order(orderId, userId, subTagId, self.store_id, orderSuccessUrl)
14145 amit.gupta 61
                merchantOrder.orderTrackingUrl = orderSuccessUrl
13781 amit.gupta 62
                soup = BeautifulSoup(rawHtml,from_encoding="utf-8")
13774 amit.gupta 63
 
13781 amit.gupta 64
                table = soup.body.findAll("table", recursive=False)[1]
65
                #print table
66
                tables = table.tr.td.findAll("table", recursive=False)
67
                for tr in tables[2].findAll("tr"):
68
                    boldElement = tr.td.b
69
                    if "Order Placed" in str(boldElement):
70
                        merchantOrder.placedOn = boldElement.next_sibling.strip()
71
                    if "order number" in str(boldElement):
14023 amit.gupta 72
                        merchantOrder.merchantOrderId = boldElement.next_sibling.strip()
13781 amit.gupta 73
                    if "Order Total" in str(boldElement):
13809 amit.gupta 74
                        merchantOrder.paidAmount = int(float(boldElement.find('span').contents[-1].replace(',','')))
13781 amit.gupta 75
                anchors = table.tr.td.findAll("a", recursive=False)
14293 amit.gupta 76
                paymentAnchor = anchors.pop(-1)
13774 amit.gupta 77
 
13809 amit.gupta 78
                count = 0
13781 amit.gupta 79
                subOrders = []
80
                merchantOrder.subOrders = subOrders
81
                for anchor in anchors:
13809 amit.gupta 82
                    count += 1
13781 amit.gupta 83
                    tab = anchor.next_sibling
84
                    status = MStore.ORDER_PLACED
85
                    subStr = "Delivery #" + str(count) + ":"
86
                    if subStr in  tab.find("b").text:
87
                        detailedStatus = tab.find("b").text.replace(subStr, '').strip()
88
 
89
                    tab = tab.next_sibling.next_sibling
13813 amit.gupta 90
                    trs = tab.find("table").find('tbody').findAll("tr", recursive = False)
13781 amit.gupta 91
 
92
                    estimatedDelivery = trs[0].td.find("b").next_sibling.strip()
93
 
13813 amit.gupta 94
                    orderItemTrs = trs[1].findAll("td", recursive=False)[1].table.tbody.findAll("tr", recursive = False)
13781 amit.gupta 95
                    i = -1
96
                    for orderItemTr in orderItemTrs:
97
                        i += 1
98
                        if i%2 == 0:
99
                            continue
13809 amit.gupta 100
                        quantity =  int(re.findall(r'\d+', orderItemTr.td.contents[0])[0])
13781 amit.gupta 101
 
13809 amit.gupta 102
                        productUrl = orderItemTr.td.contents[1].a["href"]
103
                        productTitle = orderItemTr.td.contents[1].a.text
104
 
105
                        unitPrice = int(float(orderItemTr.findAll('td')[1].span.text.replace('Rs. ','').replace(',','')))
106
 
13781 amit.gupta 107
 
13809 amit.gupta 108
                        subOrder = SubOrder(productTitle, productUrl, merchantOrder.placedOn, unitPrice*quantity, status, quantity)
109
                        subOrder.merchantSubOrderId = orderItemTr.find("input")["name"]
110
                        subOrder.estimatedDeliveryDate = estimatedDelivery
111
                        subOrder.productCode = productUrl.split('/')[5]
112
                        subOrder.detailedStatus = detailedStatus
113
                        (cashbackAmount, percentage) = self.getCashbackAmount(subOrder.productCode, unitPrice*quantity)
114
                        cashbackStatus = Store.CB_PENDING
115
                        if cashbackAmount <= 0:
116
                            cashbackStatus = Store.CB_NA
117
                        subOrder.cashBackStatus = cashbackStatus
118
                        subOrder.cashBackAmount = cashbackAmount
119
                        if percentage > 0:
120
                            subOrder.cashBackPercentage = percentage
121
                        subOrders.append(subOrder)
14293 amit.gupta 122
                priceList = paymentAnchor.next_sibling.next_sibling.next_sibling.table.table.tbody.tbody.tbody.findAll('tr', recursive=False)
123
                totalAmount = 0
124
                grandAmount = 0
125
                for price in priceList:
126
                    labelTd = price.td
127
                    if 'Subtotal:' in labelTd.text:
14296 amit.gupta 128
                        totalAmount += int(float(labelTd.next_sibling.next_sibling.find('span').contents[-1].strip(',','')))
14293 amit.gupta 129
                    elif 'Grand Total:' in labelTd.text:
14296 amit.gupta 130
                        grandAmount += int(float(labelTd.next_sibling.next_sibling.find('span').contents[-1].strip(',','')))
14293 amit.gupta 131
                if grandAmount < totalAmount:
132
                    diff = totalAmount - grandAmount
133
                    for subOrder in merchantOrder.subOrders:
14294 amit.gupta 134
                        subOrder.amountPaid -= int(diff*(1-subOrder.amountPaid/totalAmount))
14293 amit.gupta 135
 
14080 amit.gupta 136
                if insert:
137
                    self._saveToOrder(todict(merchantOrder))
138
                else:
139
                    self._updateToOrder(todict(merchantOrder))
13796 amit.gupta 140
                resp['result'] = 'ORDER_CREATED'
141
                return resp    
13781 amit.gupta 142
            except:
13809 amit.gupta 143
                print "Error occurred"
144
                traceback.print_exc()
13796 amit.gupta 145
                resp['result'] = 'PARSE_ERROR'
146
                return resp    
13774 amit.gupta 147
 
13868 amit.gupta 148
    #This should be exposed from api for specific sources
149
    def scrapeStoreOrders(self):
150
        pass
151
 
152
    def getTrackingUrls(self, userId):
14074 amit.gupta 153
 
154
        missingOrderUrls = []
155
        missingOrders = self._getMissingOrders({'userId':userId})
156
        for missingOrder in missingOrders:
157
            missingOrderUrls.append(ORDER_REDIRECT_URL%(missingOrder['merchantOrderId']))
13879 amit.gupta 158
        orders = self._getActiveOrders({'userId':userId})
13882 amit.gupta 159
        count = len(orders)
13879 amit.gupta 160
        print "count", count
13868 amit.gupta 161
        if count > 0:
14074 amit.gupta 162
            return missingOrderUrls + ['https://www.amazon.in/gp/css/order-history', 'https://www.amazon.in/gp/css/order-history/?orderFilter=cancelled']
13959 amit.gupta 163
        else: 
14074 amit.gupta 164
            return missingOrderUrls
13927 amit.gupta 165
 
166
    def trackOrdersForUser(self, userId, url, rawHtml):
14285 amit.gupta 167
        directory = "/tmp/User" + str(userId)
168
        if not os.path.exists(directory):
169
            os.makedirs(directory)
170
        f = open(directory + "/" + str(datetime.now()),'w')
14173 amit.gupta 171
        f.write(rawHtml) # python will convert \n to os.linesep
172
        f.close() # you can omit in most cases as the destructor will call if
173
 
13995 amit.gupta 174
        try:
175
            searchMap = {'userId':userId}
176
            collectionMap = {'merchantOrderId':1}
177
            activeOrders = self._getActiveOrders(searchMap, collectionMap)
14033 amit.gupta 178
            datetimeNow = datetime.now()
179
            timestamp = int(time.mktime(datetimeNow.timetuple()))
14009 amit.gupta 180
            print "url----------------", url
14008 amit.gupta 181
 
13995 amit.gupta 182
            if url == 'https://www.amazon.in/gp/css/order-history' or url == 'https://www.amazon.in/gp/css/order-history/?orderFilter=cancelled':
183
                soup = BeautifulSoup(rawHtml)
184
                allOrders = soup.find(id="ordersContainer").findAll('div', {'class':'a-box-group a-spacing-base order'})
185
                bulk = self.db.merchantOrder.initialize_ordered_bulk_op()
186
                for activeOrder in activeOrders:
187
                    for orderEle in allOrders:
188
                        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'})
189
                        merchantOrderId = orderdiv.find('span', {'class':'a-color-secondary value'}).text.strip()
190
                        if merchantOrderId==activeOrder['merchantOrderId']:
191
                            closed = True
192
                            shipments = orderEle.findAll('div',{'class':re.compile('.*?a-box.*?')}, recursive=False)
193
                            shipments.pop(0)
194
                            for shipment in shipments:
195
                                shipdiv = shipment.find('div', {'class':'a-box-inner'})
14050 amit.gupta 196
                                sdivs = shipment.div.div.findAll('div', recursive=False)
14065 amit.gupta 197
                                orderStatus = sdivs[0].span.text.strip()
14050 amit.gupta 198
                                status = self._getStatusFromDetailedStatus(orderStatus)
199
                                if status == MStore.ORDER_DELIVERED:
200
                                    deliveredOn = sdivs[1].find('span').text
201
                                    deliveredOn = deliveredOn.split(":")[1].strip()
202
                                else:
14065 amit.gupta 203
                                    deliveryestimatespan = sdivs[0].find('span', {'class':'a-color-success'})
14050 amit.gupta 204
                                    deliveryEstimate = None
205
                                    if deliveryestimatespan is not None:
206
                                        deliveryEstimate = deliveryestimatespan.find('span', {'class':'a-text-bold'}).text.strip()
207
                                    productDivs = shipdiv.find('div', {'class':re.compile('.*?a-spacing-top-medium.*?')}).find('div', {'class':'a-row'}).findAll('div', recursive=False)
13995 amit.gupta 208
                                trackingUrl = None
209
                                for buttonDiv in shipdiv.findAll('span', {'class':'a-button-inner'}):
210
                                    if buttonDiv.find('a').text.strip()=='Track package':
211
                                        trackingUrl = buttonDiv.find('a')['href'].strip()
212
                                        if not trackingUrl.startswith("http"):
213
                                            trackingUrl = "https://www.amazon.in/" + trackingUrl
214
                                        break
215
                                for prodDiv in productDivs:
216
                                    prodDiv.find('div', {'class':'a-fixed-left-grid-inner'})
217
                                    productTitle = prodDiv.find('div', {'class':'a-fixed-left-grid-inner'}).find("div", {'class':'a-row'}).find('a').text.strip()
218
                                    imgUrl = prodDiv.find("img")["src"]
219
                                    for subOrder in activeOrder['subOrders']:
220
                                        if subOrder['productTitle'] == productTitle:
221
                                            findMap = {"orderId": activeOrder['orderId'], "subOrders.merchantSubOrderId": subOrder.get("merchantSubOrderId")}
222
                                            updateMap = {}
223
                                            closedStatus = False
224
                                            updateMap['subOrders.$.imgUrl'] = imgUrl
14033 amit.gupta 225
                                            updateMap['subOrders.$.lastTracked'] = timestamp
13995 amit.gupta 226
                                            updateMap['subOrders.$.detailedStatus'] = orderStatus
227
                                            cashbackStatus = subOrder.get("cashBackStatus")
228
                                            updateMap['subOrders.$.status'] = status 
229
 
230
                                            if status==MStore.ORDER_DELIVERED:                               
14291 amit.gupta 231
                                                updateMap['subOrders.$.deliveredOn'] = deliveredOn
13995 amit.gupta 232
                                                closedStatus = True
233
                                                updateMap['subOrders.$.closed'] = True
234
                                                if cashbackStatus == Store.CB_PENDING:
235
                                                    updateMap['subOrders.$.cashbackStatus'] = Store.CB_APPROVED
236
                                            if status==MStore.ORDER_CANCELLED:     
237
                                                closedStatus = True
238
                                                updateMap['subOrders.$.closed'] = True
239
                                                if cashbackStatus == Store.CB_PENDING:
240
                                                    updateMap['subOrders.$.cashBackStatus'] = Store.CB_CANCELLED
241
                                            if status==MStore.ORDER_SHIPPED:   
242
                                                updateMap['subOrders.$.estimatedDeliveryDate'] = deliveryEstimate
243
                                                if trackingUrl is not None:
244
                                                    updateMap['subOrders.$.trackingUrl'] = trackingUrl
245
                                            if not closedStatus:
246
                                                closed = False
247
                                            bulk.find(findMap).update({'$set' : updateMap})
248
                                            break
249
                            bulk.find({'orderId': activeOrder['orderId']}).update({'$set':{'closed': closed}})            
14080 amit.gupta 250
                bulk.execute()
251
                return 'PARSED_SUCCESS'
252
            else:
14086 amit.gupta 253
                merchantOrderId = re.findall(r'https://www.amazon.in/gp/css/summary/edit.html\?orderID=(.*)?', url, re.IGNORECASE)[0] 
14085 amit.gupta 254
                merchantOrder = self.db.merchantOrder.find_one({"merchantOrderId":merchantOrderId})
14080 amit.gupta 255
                self.parseOrderRawHtml(merchantOrder['orderId'], merchantOrder['subTagId'], merchantOrder['userId'], rawHtml, url, False)
256
                return 'PARSED_SUCCESS'
257
                pass
14008 amit.gupta 258
            return 'PARSED_SUCCESS_NO_ORDERS'
13995 amit.gupta 259
        except:
260
            traceback.print_exc()    
261
            return 'PARSED_FAILED'
262
 
263
    def _getStatusFromDetailedStatus(self, detailedStatus):
14061 amit.gupta 264
        if "ordered from" in detailedStatus.lower():
265
            return MStore.ORDER_PLACED 
266
 
13995 amit.gupta 267
        for key, value in self.orderStatusRegexMap.iteritems():
14032 amit.gupta 268
            if detailedStatus.lower() in value:
13995 amit.gupta 269
                return key
270
 
271
        print "Detailed Status need to be mapped"
14062 amit.gupta 272
        print "Found new order status", detailedStatus
13995 amit.gupta 273
        raise ParseException("_getStatusFromDetailedStatus", "Found new order status" + detailedStatus)
13927 amit.gupta 274
 
275
 
13774 amit.gupta 276
def main():
277
    store = getStore(1)
278
 
14293 amit.gupta 279
    store.parseOrderRawHtml(1, 'saad', '212321', readSSh('/tmp/abc.html'), 'https://www.amazon.in/gp/css/summary/edit.html?orderID=12212')
280
    #store.trackOrdersForUser(2,'https://www.amazon.in/gp/css/order-history', readSSh('/tmp/order2015-02-26 11:20:18.816942'))
13774 amit.gupta 281
 
14162 amit.gupta 282
def readSSh(fileName):
283
    try:
284
            str1 = open(fileName).read()
285
            return str1
286
    except:
287
        ssh_client = SSHClient()
288
        str1 = ""
289
        ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
290
        ssh_client.connect('104.200.25.40', 22, 'root', 'ecip$dtrMay2014')
291
        sftp_client = ssh_client.open_sftp()
292
        try:
293
            sftp_client.get(fileName, fileName)
294
            try:
295
                str1 = open(fileName).read()
296
                return str1
297
            finally:
298
                pass
299
        except:
300
            "could not read"
301
        return str1
13774 amit.gupta 302
 
303
 
304
if __name__ == '__main__':
14284 amit.gupta 305
        main()